// file: $isip/class/algo/Math/math_02.cc
// version: $Id: math_02.cc 8383 2002-07-15 18:02:16Z parihar $
//

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

// method: diagnose
//
// arguments:
//  Integral::DEBUG level: (input) debug level for diagnostics
//
// return: a boolen value indicating status
//
boolean Math::diagnose(Integral::DEBUG level_a) {

  //---------------------------------------------------------------------
  //
  // 0. preliminaries
  //
  //---------------------------------------------------------------------
  
  // output the class name
  //
  if (level_a > Integral::NONE) {
    String output(L"diagnosing class ");
    output.concat(CLASS_NAME);
    output.concat(L": ");
    Console::put(output);
    Console::increaseIndention();
  } 
  
  //--------------------------------------------------------------------
  //
  // 1. required public methods
  //
  //--------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing required public methods...\n");
    Console::increaseIndention();
  }

  // test destructor/constructor(s) and memory management
  //
  Math math0;
  Math math1(math0);

  if (!math1.eq(math0)) {
    return Error::handle(name(), L"copy constructor", Error::TEST,
                         __FILE__, __LINE__);
  }

  // test large allocation construction and deletion
  //
  if (level_a == Integral::ALL) {

    Console::put(L"\ntesting large chunk memory allocation and deletion:\n");

    // set the memory to a strange block size so we can hopefully catch any
    // frame overrun errors
    //
    Math::setGrowSize((long)500);

    Math* pft = new Math();

    for (long j = 1; j <= 100; j++) {
      Math** pfts = new Math*[j * 100];

      // create the objects
      //
      for (long i = 0; i < j * 100; i++) {
        pfts[i] = new Math();
      }

      // delete objects
      //
      for (long i = (j * 100) - 1; i >= 0; i--) {
        delete pfts[i];
      }

      delete [] pfts;
    }

    delete pft;
  }

  //  test the i/o methods
  //
  Math math2;
  Math math3;
  Math math4;
  math3.setNumOperands(3);
  math2.setAlgorithm(FUNCTION_CALCULATOR);

  // we need binary and text sof files
  //
  String tmp_filename0;
  Integral::makeTemp(tmp_filename0);
  String tmp_filename1;
  Integral::makeTemp(tmp_filename1);

  // open files in write algorithm
  //
  Sof tmp_file0;
  tmp_file0.open(tmp_filename0, File::WRITE_ONLY, File::TEXT);
  Sof tmp_file1;
  tmp_file1.open(tmp_filename1, File::WRITE_ONLY, File::BINARY);

  math2.write(tmp_file0, (long)0);
  math2.write(tmp_file1, (long)0);

  // close the files
  //
  tmp_file0.close();
  tmp_file1.close();

  // open the files in read algorithm
  //
  tmp_file0.open(tmp_filename0);
  tmp_file1.open(tmp_filename1);

  // read the value back
  //
  math3.read(tmp_file0, (long)0);
  if (!math3.eq(math2)) {
    math3.debug(L"math3");
    math2.debug(L"math2");
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }

  math4.read(tmp_file0, (long)0);
  if (!math4.eq(math2)) {
    math4.debug(L"math4");
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }

  // close and  delete the temporary files
  //
  tmp_file0.close();
  tmp_file1.close();

  File::remove(tmp_filename0);
  File::remove(tmp_filename1);

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //--------------------------------------------------------------------------
  //
  // 2. class-specific public methods:
  //     set and get methods
  //
  //--------------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: set and get methods...\n");
    Console::increaseIndention();
  }

  Math math5;

  long num0 = 4;
  math5.setNumOperands(num0);

  if (math5.getNumOperands() != num0) {
    math5.debug(L"math0");
    return Error::handle(name(), L"setNumOperands", Error::TEST,
                         __FILE__, __LINE__);
  }

  String str(L"ADD, SUBTRACT, ADD, SUBTRACT");
  math5.setOperation(str);

  if (math5.operation_d(1) != (long)SUBTRACT) {
    math5.debug(L"math5");
    return Error::handle(name(), L"setOperation", Error::TEST,
                         __FILE__, __LINE__);
  }

  math5.setOperation(ASSIGN, 1);

  if (math5.operation_d(1) != (long)ASSIGN) {
    math5.debug(L"math5");
    return Error::handle(name(), L"setOperation", Error::TEST,
                         __FILE__, __LINE__);
  }

  String func(L"EXP, EXP2, EXP10, FACTORIAL");
  math5.setFunction(func);

  if ((math5.function_d(0) != (long)EXP) ||
      (math5.function_d(1) != (long)EXP2) ||
      (math5.function_d(2) != (long)EXP10) ||
      (math5.function_d(3) != (long)FACTORIAL)) {
    math5.debug(L"math5");
    return Error::handle(name(), L"setFunction", Error::TEST,
                         __FILE__, __LINE__);
  }

  math5.setFunction(SQUARE, 1);

  if (math5.function_d(1) != (long)SQUARE) {
    math5.debug(L"math5");
    return Error::handle(name(), L"setFunction", Error::TEST,
                         __FILE__, __LINE__);
  }

  VectorFloat weight(L"2.0, 1.0, 1.0, 0.5");
  math5.setWeight(weight);

  if (!(math5.getWeight()).eq(weight)) {
    math5.debug(L"math5");
    return Error::handle(name(), L"setWeight", Error::TEST,
                         __FILE__, __LINE__);
  }

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //--------------------------------------------------------------------------
  //
  // 3. class-specific public methods:
  //     computational methods
  //
  //--------------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: computational methods for float...\n");
    Console::increaseIndention();
  }

  /*
    // test Y = 2.0 * X1 + 3.0 * X2 + 2.0
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [2.0 * X1 + 3.0 * X2 + 2.0]:\n");
    }
  
    VectorLong values_00(2);
    values_00(0).assign((long)IDENTITY);
    values_00(1).assign((long)IDENTITY);

    VectorLong values_op_00(2);
    values_op_00(0).assign((long)ASSIGN);
    values_op_00(0).assign((long)ADD);
  
    Math math6;
    math6.setNumOperands(2);
    math6.setConstant(2.0);
    math6.setWeight(L"2.0, 3.0");
    math6.setFunction(values_00);
    math6.setOperation(values_op_00);

    // set up the variables for test
    //
    Vector<AlgorithmData> input(2);
    AlgorithmData output;
    VectorFloat result;

    input(0).makeVectorFloat().assign(L"1.1, 4.0, 1.5, 2.3");
    input(1).makeVectorFloat().assign(L"1.0, 1.0, 0.0, 0.0");
    math6.compute(output, input);

    result.assign(L"7.2, 13.0, 5.0, 6.6");

    if (!result.almostEqual(output.getVectorFloat())) {
    output.getVectorFloat().debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }

    // test Y = log(X1);
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1)]:\n");
    }
  
    VectorLong values_01(1);
    values_01(0).assign((long)LOG);

    VectorLong values_op_01(1);
    values_op_01(0).assign((long)ASSIGN);

    math6.clear();
    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_01);
    math6.setFunction(values_01);
  
    input.setLength(1);
    input(0).makeVectorFloat().assign(L"10.0, 40.0");

    output.clear();
    math6.compute(output, input);

    result.assign(L"2.30259, 3.6888");

    if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  
    // test Y = log(X1) + constant;
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1) + 10.0]:\n");
    }
  
    VectorLong values_02(1);
    values_02(0).assign((long)LOG);

    VectorLong values_op_02(1);
    values_op_02(0).assign((long)ASSIGN);

    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_02);
    math6.setFunction(values_02);
    math6.setConstant(10.0);
    
    input.setLength(1);
    input(0).makeVectorFloat().assign(L"10.0, 40.0");

    math6.compute(output, input);

    result.assign(L"12.30259, 13.6888");

    if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  */
  
  // test Y = X1 + 2 * X2 - log(X3) - exp(X4)
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
  }
  
  VectorLong values(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)LOG);
  values(3).assign((long)EXP);

  VectorLong values_op(4);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)SUBTRACT);
  values_op(3).assign((long)SUBTRACT);
  
  Math math6;
  math6.setNumOperands(4);
  math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setConstant(0.0);
  
  Vector<AlgorithmData> input(2);
  AlgorithmData output;
  VectorFloat result;

  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");
  math6.compute(output, input);
  
  result.assign(L"3.1, 7.6");
  
  if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }
  
  
  // test Y = X1 + 2 * X2 - log(X3) - exp(X4)
  //  test wrong input "if ASSIGN appears middle of computation
  //  everything before it will clear.
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
  }
  
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)LOG);
  values(3).assign((long)EXP);
  
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)ASSIGN);
  values_op(3).assign((long)SUBTRACT);

  math6.setNumOperands(4);
  math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setConstant(0.0);
  
  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");
  math6.compute(output, input);

  result.assign(L"-1, -1");

  if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  
  // test Y = X1 + 2 * X2 - log(X3) - exp(X4) (all zero and constant)
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)] for all zero values:\n");
  }
  
  input.setLength(4);
  input(0).makeVectorFloat().assign(L"0.0, 0.0");
  input(1).makeVectorFloat().assign(L"0.0, 0.0");
  input(2).makeVectorFloat().assign(L"1.0, 1.0");
  input(3).makeVectorFloat().assign(L"0.0, 0.0");
  math6.compute(output, input);

  result.assign(L"-1.0, -1.0");

  if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }
  
  // test Y = [ {X1* X2 + log(X3)} / exp(X4)]
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [ {X1* X2 + log(X3)} / exp(X4)]:\n");
  }

  math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)MULTIPLY);
  values_op(2).assign((long)ADD);
  values_op(3).assign((long)DIVIDE);

  math6.setOperation(values_op);
  
  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");
  math6.compute(output, input);

  result.assign(L"1.65, 9.2");

  if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  // test Y = square(X1) + 2.0 * sqrt(X2) + 3.0
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [square(X1) + 2.0 * sqrt(X2) + 3.0]:\n");
  }

  values.setLength(2);
  values(0).assign((long)SQUARE);
  values(1).assign((long)SQRT);

  math6.setNumOperands(2);
  math6.setWeight(L"1.0, 2.0");
  str.assign(L"ASSIGN, ADD");
  math6.setOperation(str);
  math6.setFunction(values);
  math6.setConstant(3.0);

  input.setLength(2);
  input(0).makeVectorFloat().assign(L"1.1, 4.0, 1.5, 2.3");
  input(1).makeVectorFloat().assign(L"4.0, 1.21, 4.0, 9.0");
  math6.compute(output, input);

  result.assign(L"8.21, 21.2, 9.25, 14.29");

  if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  // test Y = 2.0 * X1^2 + 3.0 * X2 + 3.0
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [2.0 * X1^2 + 3.0 * X2 + 3.0]:\n");
  }

  values.setLength(2);
  values(0).assign((long)SQUARE);
  values(1).assign((long)IDENTITY);

  math6.setNumOperands(2);
  math6.setWeight(L"2.0, 3.0");
  str.assign(L"ASSIGN, ADD");
  math6.setOperation(str);
  math6.setFunction(values);
  input(0).makeVectorFloat().assign(L"1.1, 4.0, 1.5, 1.1");
  input(1).makeVectorFloat().assign(L"4.0, 0.5, 4.0, 9.0");
 
  math6.compute(output, input);

  result.assign(L"17.42, 36.5, 19.5, 32.42");

  if (!result.almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  
  // test Y = X1 * X2 (vector * matrix)
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)]:\n");
  }
  
  input(0).makeVectorFloat().assign(L"1.1, 2.0, 3.0");
  input(1).makeMatrixFloat().assign(3, 3, L"1.0, 0.0, 5.0, 1.2, 2.4, 3.6, 1.8, 2.1, 9.8");
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)MULTIPLY);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0");
  math6.setConstant(0.0);
  math6.compute(output, input);
  
  result.assign(L"8.9, 11.1, 42.1");
  
  if (!(result).almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
			 __FILE__, __LINE__);
  }

  // test Y = X1 * X2 (vector * inv(matrix))
  //  
  values(0).assign((long)IDENTITY);
  values(1).assign((long)INVERSE);
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)MULTIPLY);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0");
  math6.setConstant(0.0);
  math6.compute(output, input);
  
  result.assign(L"0.2293, 0.9842, -0.1724");
  
  if (!(result).almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
			 __FILE__, __LINE__);
  }

  // test Y = X1 * X2 (vector * matrix) with vector of  zeros and constants
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)] with vector of zeros and constants:\n");
  }
  
  // test vector of zeros
  //
  input(0).makeVectorFloat().assign(L"0.0, 0.0, 0.0");
  input(1).makeMatrixFloat().assign(3, 3, L"1.0, 0.0, 5.0, 1.2, 2.4, 3.6, 1.8, 2.1, 9.8");
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)MULTIPLY);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0");
  math6.setConstant(0.0);
  math6.compute(output, input);
  
  result.assign(L"0.0, 0.0, 0.0");
  
  if (!(result).almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
                         __FILE__, __LINE__);
  }

  //test matrix of zeros
  //
  input(0).makeVectorFloat().assign(L"1.0, 1.0, 1.0");
  input(1).makeMatrixFloat().assign(3, 3, L"0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0");
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)MULTIPLY);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0");
  math6.setConstant(0.0);
  math6.compute(output, input);
  
  result.assign(L"0.0, 0.0, 0.0");
  
  if (!(result).almostEqual(output.getVectorFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
                         __FILE__, __LINE__);
  }
  
  // test Y = X1 + X2 * X3' + inv(x4)
  //  (matrix + matrix * trans(matrix) + inv(matrix))
  //

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + X2 * X3' + inv(x4)] (matrix + matrix * trans(matrix) + inv(matrix)):\n");
  }

  values.setLength(4);
  values_op.setLength(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)TRANSPOSE);
  values(3).assign((long)INVERSE);
  
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)MULTIPLY);
  values_op(3).assign((long)ADD);
  math6.setNumOperands(4);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
  math6.setConstant(0.0);
  input.setLength(4);
  input(0).makeMatrixFloat().assign(3, 3, L"1.0, 0.0, 5.0, 1.2, 2.4, 3.6, 1.8, 2.1, 9.8");
  input(1).makeMatrixFloat().assign(3, 3, L"2.0, 2.1, 3.2, 1.1, 2.1, 3.2, 4.2, 5.1, 1.1");
  input(2).makeMatrixFloat().assign(3, 3, L"1, 2, 3, 3, 2, 1, 2, 1, 1");
  input(3).makeMatrixFloat().assign(3, 3, L"5.1, 2.1, 2.2, 1.0, 1.0, 2.2, 2.1, 1.1, 2.1");

  MatrixFloat result_mat;
  math6.compute(output, input);
  
  result_mat.assign(3, 3, L"31.5808, 20.0370, 17.9575, 33.4260, 26.8712, 9.7219, 52.4151, 42.4781, 32.1548");
  
  if (!(result_mat).almostEqual(output.getMatrixFloat())) {
    output.debug(L"output");
    result_mat.debug(L"result");
    return Error::handle(name(), L"apply", Error::TEST,
                         __FILE__, __LINE__);
  }
  
  // test scalar addition
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (1):\n");
  }

  input.setLength(2);
  input(0).makeVectorFloat().assign(L"4.0");
  input(1).makeVectorFloat().assign(L"1.0, 2.0, 3.0, 4.0");

  Math math7;

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  math7.setFunction(values);
  math7.setOperation(values_op);
  math7.compute(output, input);

  VectorFloat expected(L"5.0, 6.0, 7.0, 8.0");
  if (!output.getVectorFloat().almostEqual(expected)) {
    output.debug(L"output");
    expected.debug(L"expected result");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (2):\n");
  }

  input(0).makeVectorFloat().assign(L"1.0, 2.0, 3.0, 4.0");
  input(1).makeVectorFloat().assign(L"4.0");

  math7.compute(output, input);

  expected.assign(L"5.0, 6.0, 7.0, 8.0");
  if (!output.getVectorFloat().almostEqual(expected)) {
    output.debug(L"output");
    expected.debug(L"expected result");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (3):\n");
  }
  
  MatrixFloat a(3, 3);
  a.setDiagonal(4);

  MatrixFloat b(3, 3);
  b.assign(7);
  b.setDiagonal(11);

  input(0).makeVectorFloat().assign(L"7.0");
  input(1).makeMatrixFloat().assign(a);
  
  math7.compute(output, input);

  if (!output.getMatrixFloat().almostEqual(b)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }
  
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (4):\n");
  }
    
  input(0).makeMatrixFloat().assign(a);
  input(1).makeVectorFloat().assign(L"7.0");
    
  math7.compute(output, input);

  if (!output.getMatrixFloat().almostEqual(b)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }
  
  // test scalar subtraction
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (1):\n");
  }
  
  input.setLength(2);
  input(0).makeVectorFloat().assign(L"4.0");
  input(1).makeVectorFloat().assign(L"1.0, 2.0, 3.0, 4.0");

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  math7.setFunction(values);
  
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)SUBTRACT);

  math7.setOperation(values_op);
  
  math7.compute(output, input);

  expected.assign(L"3.0, 2.0, 1.0, 0.0");
  if (!output.getVectorFloat().almostEqual(expected)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }
  
  input(0).makeVectorFloat().assign(L"1.0, 2.0, 3.0, 4.0");
  input(1).makeVectorFloat().assign(L"4.0");

  math7.compute(output, input);

  expected.assign(L"-3.0, -2.0, -1.0, 0.0");

  if (!output.getVectorFloat().almostEqual(expected)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (2):\n");
  }
  
  a.clear(Integral::RETAIN);
  a.setDiagonal(4);

  b.clear(Integral::RETAIN);
  b.assign(7);
  b.setDiagonal(11);

  input(0).makeVectorFloat().assign(L"7.0");
  input(1).makeMatrixFloat().assign(a);

  math7.compute(output, input);

  b.assign(7);
  b.setDiagonal(3.0);
  
  if (!output.getMatrixFloat().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (3):\n");
  }
  
  input(0).makeMatrixFloat().assign(a);
  input(1).makeVectorFloat().assign(L"7.0");

  b.assign(-7.0);
  b.setDiagonal(-3.0);
  math7.compute(output, input);

  if (!output.getMatrixFloat().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  // test scalar multiplication
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (1):\n");
  }
  
  values_op(1).assign((long)MULTIPLY);
  math7.setOperation(values_op);

  input(0).makeVectorFloat().assign(L"3.0");
  input(1).makeVectorFloat().assign(L"2.0, 3.0, 4.0");

  expected.assign(L"6.0, 9.0, 12.0");

  math7.compute(output, input);

  if (!output.getVectorFloat().almostEqual(expected)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
  }
  
  input(0).makeVectorFloat().assign(L"2.0, 3.0, 4.0");
  input(1).makeVectorFloat().assign(L"3.0");

  expected.assign(L"6.0, 9.0, 12.0");

  math7.compute(output, input);

  if (!output.getVectorFloat().almostEqual(expected)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
  }
  
  a.clear(Integral::RETAIN);
  a.setDiagonal(3.0);
  
  input(0).makeMatrixFloat().assign(a);
  input(1).makeVectorFloat().assign(L"3.0");

  b.clear(Integral::RETAIN);
  b.setDiagonal(9.0);

  math7.compute(output, input);

  if (!output.getMatrixFloat().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (3):\n");
  }
  
  input(0).makeVectorFloat().assign(L"3.0");
  input(1).makeMatrixFloat().assign(a);
  
  math7.compute(output, input);

  if (!output.getMatrixFloat().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  // test scalar division
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (1):\n");
  }
  
  values_op(1).assign((long)DIVIDE);
  math7.setOperation(values_op);

  input(0).makeVectorFloat().assign(L"9.0, 6.0, 3.0");
  input(1).makeVectorFloat().assign(L"3.0");

  expected.assign(L"3.0, 2.0, 1.0");

  math7.compute(output, input);

  if (!output.getVectorFloat().almostEqual(expected)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (2):\n");
  }
  
  a.clear(Integral::RETAIN);
  a.setDiagonal(6.0);
  
  input(0).makeMatrixFloat().assign(a);
  input(1).makeVectorFloat().assign(L"3.0");

  b.clear(Integral::RETAIN);
  b.setDiagonal(2.0);

  math7.compute(output, input);

  if (!output.getMatrixFloat().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //--------------------------------------------------------------------------
  //
  // 4. class-specific public methods:
  //     computational methods for Double
  //
  //--------------------------------------------------------------------------
  
  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: computational methods for double...\n");
    Console::increaseIndention();
  }
  
  /*
    // test Y = 2.0 * X1 + 3.0 * X2 + 2.0
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [2.0 * X1 + 3.0 * X2 + 2.0]:\n");
    }
    
    Math math6;
    math6.setNumOperands(2);
    math6.setConstant(2.0);
    math6.setWeight(L"2.0, 3.0");
    
    // set up the variables for test
    //
    Vector<AlgorithmData> input(2);
    AlgorithmData output;
    VectorDouble result;
    
    input(0).makeVectorDouble().assign(L"1.1, 4.0, 1.5, 2.3");
    input(1).makeVectorDouble().assign(L"1.0, 1.0, 0.0, 0.0");
    math6.compute(output, input);
    
    result.assign(L"7.2, 13.0, 5.0, 6.6");
    
    if (!result.almostEqual(output.getVectorDouble())) {
    output.getVectorDouble().debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
    
    // test Y = log(X1);
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1)]:\n");
    }
    
    VectorLong values_01(1);
    values_01(0).assign((long)LOG);
    
    VectorLong values_op_01(1);
    values_op_01(0).assign((long)ASSIGN);
    
    math6.clear();
    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_01);
    math6.setFunction(values_01);
  
    input.setLength(1);
    input(0).makeVectorDouble().assign(L"10.0, 40.0");

    output.clear();
    math6.compute(output, input);

    result.assign(L"2.30259, 3.6888");

    if (!result.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  
    // test Y = log(X1) + constant;
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1) + 10.0]:\n");
    }
  
    VectorLong values_02(1);
    values_02(0).assign((long)LOG);

    VectorLong values_op_02(1);
    values_op_02(0).assign((long)ASSIGN);

    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_02);
    math6.setFunction(values_02);
    math6.setConstant(10.0);
    
    input.setLength(1);
    input(0).makeVectorDouble().assign(L"10.0, 40.0");

    math6.compute(output, input);

    result.assign(L"12.30259, 13.6888");

    if (!result.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  */
    
  // test Y = X1 + 2 * X2 - log(X3) - exp(X4)
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
  }
  
  values.setLength(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)LOG);
  values(3).assign((long)EXP);

  values_op.setLength(4);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)SUBTRACT);
  values_op(3).assign((long)SUBTRACT);

  math6.setNumOperands(4);
  math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setConstant(0.0);
  
  input.setLength(4);
  input(0).makeVectorDouble().assign(L"1.1, 4.0");
  input(1).makeVectorDouble().assign(L"1.5, 2.3");
  input(2).makeVectorDouble().assign(L"1.0, 1.0");
  input(3).makeVectorDouble().assign(L"0.0, 0.0");
  math6.compute(output, input);

  VectorDouble result_db;
  result_db.assign(L"3.1, 7.6");

  if (!result_db.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
			 __FILE__, __LINE__);
  }

  /*
    // test Y = X1 + 2 * X2 - log(X3) - exp(X4)
    //  test wrong input "if ASSIGN appears middle of computation
    //  everything before it will clear.
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
    }
  
    values(0).assign((long)IDENTITY);
    values(1).assign((long)IDENTITY);
    values(2).assign((long)LOG);
    values(3).assign((long)EXP);

    values_op(0).assign((long)ASSIGN);
    values_op(1).assign((long)ADD);
    values_op(2).assign((long)ASSIGN);
    values_op(3).assign((long)SUBTRACT);

    math6.setNumOperands(4);
    math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
    math6.setOperation(values_op);
    math6.setFunction(values);
    math6.setConstant(0.0);
  
    input.setLength(4);
    input(0).makeVectorDouble().assign(L"1.1, 4.0");
    input(1).makeVectorDouble().assign(L"1.5, 2.3");
    input(2).makeVectorDouble().assign(L"1.0, 1.0");
    input(3).makeVectorDouble().assign(L"0.0, 0.0");
    math6.compute(output, input);

    result_db.assign(L"-1, -1");

    if (!result_db.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  
    // test Y = X1 + 2 * X2 - log(X3) - exp(X4) (all zero and constant)
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)] for all zero values:\n");
    }

    input.setLength(4);
    input(0).makeVectorDouble().assign(L"0.0, 0.0");
    input(1).makeVectorDouble().assign(L"0.0, 0.0");
    input(2).makeVectorDouble().assign(L"1.0, 1.0");
    input(3).makeVectorDouble().assign(L"0.0, 0.0");
    math6.compute(output, input);

    result_db.assign(L"-1.0, -1.0");

    if (!result_db.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  
    // test Y = [ {X1* X2 + log(X3)} / exp(X4)]
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [ {X1* X2 + log(X3)} / exp(X4)]:\n");
    }

    math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
    values_op(0).assign((long)ASSIGN);
    values_op(1).assign((long)MULTIPLY);
    values_op(2).assign((long)ADD);
    values_op(3).assign((long)DIVIDE);

    math6.setOperation(values_op);
  
    input(0).makeVectorDouble().assign(L"1.1, 4.0");
    input(1).makeVectorDouble().assign(L"1.5, 2.3");
    input(2).makeVectorDouble().assign(L"1.0, 1.0");
    input(3).makeVectorDouble().assign(L"0.0, 0.0");
    math6.compute(output, input);

    result_db.assign(L"1.65, 9.2");

    if (!result_db.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }

    // test Y = square(X1) + 2.0 * sqrt(X2) + 3.0
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [square(X1) + 2.0 * sqrt(X2) + 3.0]:\n");
    }

    values.setLength(2);
    values(0).assign((long)SQUARE);
    values(1).assign((long)SQRT);

    math6.setNumOperands(2);
    math6.setWeight(L"1.0, 2.0");
    str.assign(L"ASSIGN, ADD");
    math6.setOperation(str);
    math6.setFunction(values);
    math6.setConstant(3.0);

    input.setLength(2);
    input(0).makeVectorDouble().assign(L"1.1, 4.0, 1.5, 2.3");
    input(1).makeVectorDouble().assign(L"4.0, 1.21, 4.0, 9.0");
    math6.compute(output, input);

    result_db.assign(L"8.21, 21.2, 9.25, 14.29");

    if (!result_db.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }

    // test Y = 2.0 * X1^2 + 3.0 * X2 + 3.0
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [2.0 * X1^2 + 3.0 * X2 + 3.0]:\n");
    }

    values.setLength(2);
    values(0).assign((long)SQUARE);
    values(1).assign((long)IDENTITY);

    math6.setNumOperands(2);
    math6.setWeight(L"2.0, 3.0");
    str.assign(L"ASSIGN, ADD");
    math6.setOperation(str);
    math6.setFunction(values);
    input(0).makeVectorDouble().assign(L"1.1, 4.0, 1.5, 1.1");
    input(1).makeVectorDouble().assign(L"4.0, 0.5, 4.0, 9.0");
 
    math6.compute(output, input);

    result_db.assign(L"17.42, 36.5, 19.5, 32.42");

    if (!result_db.almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }

    
    // test Y = X1 * X2 (vector * matrix)
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)]:\n");
    }
  
    input(0).makeVectorDouble().assign(L"1.1, 2.0, 3.0");
    input(1).makeMatrixDouble().assign(3, 3, L"1.0, 0.0, 5.0, 1.2, 2.4, 3.6, 1.8, 2.1, 9.8");
    values(0).assign((long)IDENTITY);
    values(1).assign((long)IDENTITY);
    values_op.setLength(2);
    values_op(0).assign((long)ASSIGN);
    values_op(1).assign((long)MULTIPLY);
    math6.setOperation(values_op);
    math6.setFunction(values);
    math6.setWeight(L"1.0, 1.0");
    math6.setConstant(0.0);
    math6.compute(output, input);
  
    result_db.assign(L"8.9, 11.1, 42.1");
  
    if (!(result_db).almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
    __FILE__, __LINE__);
    }

    // test Y = X1 * X2 (vector * inv(matrix))
    //  
    values(0).assign((long)IDENTITY);
    values(1).assign((long)INVERSE);
    values_op.setLength(2);
    values_op(0).assign((long)ASSIGN);
    values_op(1).assign((long)MULTIPLY);
    math6.setOperation(values_op);
    math6.setFunction(values);
    math6.setWeight(L"1.0, 1.0");
    math6.setConstant(0.0);
    math6.compute(output, input);
  
    result_db.assign(L"0.2293, 0.9842, -0.1724");
  
    if (!(result_db).almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
    __FILE__, __LINE__);
    }

    // test Y = X1 * X2 (vector * matrix) with vector of  zeros and constants
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)] with vector of zeros and constants:\n");
    }

    //test vector of zeros
    //
    input(0).makeVectorDouble().assign(L"0.0, 0.0, 0.0");
    input(1).makeMatrixDouble().assign(3, 3, L"1.0, 0.0, 5.0, 1.2, 2.4, 3.6, 1.8, 2.1, 9.8");
    values(0).assign((long)IDENTITY);
    values(1).assign((long)IDENTITY);
    values_op.setLength(2);
    values_op(0).assign((long)ASSIGN);
    values_op(1).assign((long)MULTIPLY);
    math6.setOperation(values_op);
    math6.setFunction(values);
    math6.setWeight(L"1.0, 1.0");
    math6.setConstant(0.0);
    math6.compute(output, input);
  
    result_db.assign(L"0.0, 0.0, 0.0");
  
    if (!(result_db).almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
    __FILE__, __LINE__);
    }

    //test matrix of zeros
    //
    input(0).makeVectorDouble().assign(L"1.0, 1.0, 1.0");
    input(1).makeMatrixDouble().assign(3, 3, L"0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0");
    values(0).assign((long)IDENTITY);
    values(1).assign((long)IDENTITY);
    values_op.setLength(2);
    values_op(0).assign((long)ASSIGN);
    values_op(1).assign((long)MULTIPLY);
    math6.setOperation(values_op);
    math6.setFunction(values);
    math6.setWeight(L"1.0, 1.0");
    math6.setConstant(0.0);
    math6.compute(output, input);
  
    result_db.assign(L"0.0, 0.0, 0.0");
  
    if (!(result_db).almostEqual(output.getVectorDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"apply", Error::TEST,
    __FILE__, __LINE__);
    }
  */
  
  // test Y = X1 + X2 * X3' + inv(x4)
  //  (matrix + matrix * trans(matrix) + inv(matrix))
  //

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + X2 * X3' + inv(x4)] (matrix + matrix * trans(matrix) + inv(matrix)):\n");
  }

  values.setLength(4);
  values_op.setLength(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)TRANSPOSE);
  values(3).assign((long)INVERSE);
  
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)MULTIPLY);
  values_op(3).assign((long)ADD);
  math6.setNumOperands(4);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
  math6.setConstant(0.0);
  input.setLength(4);
  input(0).makeMatrixDouble().assign(3, 3, L"1.0, 0.0, 5.0, 1.2, 2.4, 3.6, 1.8, 2.1, 9.8");
  input(1).makeMatrixDouble().assign(3, 3, L"2.0, 2.1, 3.2, 1.1, 2.1, 3.2, 4.2, 5.1, 1.1");
  input(2).makeMatrixDouble().assign(3, 3, L"1, 2, 3, 3, 2, 1, 2, 1, 1");
  input(3).makeMatrixDouble().assign(3, 3, L"5.1, 2.1, 2.2, 1.0, 1.0, 2.2, 2.1, 1.1, 2.1");

  MatrixDouble result_mat_db;
  math6.compute(output, input);
  
  result_mat_db.assign(3, 3, L"31.5808, 20.0370, 17.9575, 33.4260, 26.8712, 9.7219, 52.4151, 42.4781, 32.1548");
  
  if (!(result_mat_db).almostEqual(output.getMatrixDouble())) {
    output.debug(L"output");
    result_mat_db.debug(L"result");
    return Error::handle(name(), L"apply", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // test scalar addition
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (1):\n");
  }

  input.setLength(2);
  input(0).makeVectorDouble().assign(L"4.0");
  input(1).makeVectorDouble().assign(L"1.0, 2.0, 3.0, 4.0");

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);

  math7.setFunction(values);
  math7.setOperation(values_op);
  math7.compute(output, input);

  VectorDouble expected_db(L"5.0, 6.0, 7.0, 8.0");
  if (!output.getVectorDouble().almostEqual(expected_db)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (2):\n");
    }

    input(0).makeVectorDouble().assign(L"1.0, 2.0, 3.0, 4.0");
    input(1).makeVectorDouble().assign(L"4.0");

    math7.compute(output, input);

    expected.assign(L"5.0, 6.0, 7.0, 8.0");
    if (!output.getVectorDouble().almostEqual(expected)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (3):\n");
    }
  
    MatrixDouble a(3, 3);
    a.setDiagonal(4);

    MatrixDouble b(3, 3);
    b.assign(7);
    b.setDiagonal(11);

    input(0).makeVectorDouble().assign(L"7.0");
    input(1).makeMatrixDouble().assign(a);
  
    math7.compute(output, input);

    if (!output.getMatrixDouble().almostEqual(b)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (4):\n");
    }
    
    input(0).makeMatrixDouble().assign(a);
    input(1).makeVectorDouble().assign(L"7.0");
    
    math7.compute(output, input);

    if (!output.getMatrixDouble().almostEqual(b)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
    
  // test scalar subtraction
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (1):\n");
  }
  
  input.setLength(2);
  input(0).makeVectorDouble().assign(L"4.0");
  input(1).makeVectorDouble().assign(L"1.0, 2.0, 3.0, 4.0");

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  math7.setFunction(values);
  
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)SUBTRACT);

  math7.setOperation(values_op);
  
  math7.compute(output, input);

  expected_db.assign(L"3.0, 2.0, 1.0, 0.0");
  if (!output.getVectorDouble().almostEqual(expected_db)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }
  
  input(0).makeVectorDouble().assign(L"1.0, 2.0, 3.0, 4.0");
  input(1).makeVectorDouble().assign(L"4.0");

  math7.compute(output, input);

  expected_db.assign(L"-3.0, -2.0, -1.0, 0.0");

  if (!output.getVectorDouble().almostEqual(expected_db)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(4);

    b.clear(Integral::RETAIN);
    b.assign(7);
    b.setDiagonal(11);

    input(0).makeVectorDouble().assign(L"7.0");
    input(1).makeMatrixDouble().assign(a);

    math7.compute(output, input);

    b.assign(7);
    b.setDiagonal(3.0);
  
    if (!output.getMatrixDouble().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (3):\n");
    }
  
    input(0).makeMatrixDouble().assign(a);
    input(1).makeVectorDouble().assign(L"7.0");

    b.assign(-7.0);
    b.setDiagonal(-3.0);
    math7.compute(output, input);

    if (!output.getMatrixDouble().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
    
  // test scalar multiplication
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (1):\n");
  }
  
  values_op(1).assign((long)MULTIPLY);
  math7.setOperation(values_op);

  input(0).makeVectorDouble().assign(L"3.0");
  input(1).makeVectorDouble().assign(L"2.0, 3.0, 4.0");

  expected_db.assign(L"6.0, 9.0, 12.0");

  math7.compute(output, input);

  if (!output.getVectorDouble().almostEqual(expected_db)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
    }
  
    input(0).makeVectorDouble().assign(L"2.0, 3.0, 4.0");
    input(1).makeVectorDouble().assign(L"3.0");

    expected_db.assign(L"6.0, 9.0, 12.0");

    math7.compute(output, input);

    if (!output.getVectorDouble().almostEqual(expected_db)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(3.0);
  
    input(0).makeMatrixDouble().assign(a);
    input(1).makeVectorDouble().assign(L"3.0");

    b.clear(Integral::RETAIN);
    b.setDiagonal(9.0);

    math7.compute(output, input);

    if (!output.getMatrixDouble().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (3):\n");
    }
  
    input(0).makeVectorDouble().assign(L"3.0");
    input(1).makeMatrixDouble().assign(a);
  
    math7.compute(output, input);

    if (!output.getMatrixDouble().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
    
  // test scalar division
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (1):\n");
  }
  
  values_op(1).assign((long)DIVIDE);
  math7.setOperation(values_op);

  input(0).makeVectorDouble().assign(L"9.0, 6.0, 3.0");
  input(1).makeVectorDouble().assign(L"3.0");

  expected_db.assign(L"3.0, 2.0, 1.0");

  math7.compute(output, input);

  if (!output.getVectorDouble().almostEqual(expected_db)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(6.0);
  
    input(0).makeMatrixDouble().assign(a);
    input(1).makeVectorDouble().assign(L"3.0");

    b.clear(Integral::RETAIN);
    b.setDiagonal(2.0);

    math7.compute(output, input);

    if (!output.getMatrixDouble().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
    
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
        
  //--------------------------------------------------------------------------
  //
  // 5. class-specific public methods:
  //     computational methods for complexfloat
  //
  //--------------------------------------------------------------------------
  
  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: computational methods for complexfloat...\n");
    Console::increaseIndention();
  }

  /*
    // test Y = 2.0 * X1 + 3.0 * X2 + 2.0
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [2.0 * X1 + 3.0 * X2 + 2.0]:\n");
    }

    Math math6;
    math6.setNumOperands(2);
    math6.setConstant(2.0);
    math6.setWeight(L"2.0, 3.0");

    // set up the variables for test
    //
    Vector<AlgorithmData> input(2);
    AlgorithmData output;
    VectorComplexFloat result;

    input(0).makeVectorComplexFloat().assign(L"1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j");
    input(1).makeVectorComplexFloat().assign(L"1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j");
    math6.compute(output, input);

    result.assign(L"7 + 5j, 12 + 10j, 17 + 15j, 22 + 20j");

    if (!result.almostEqual(output.getVectorComplexFloat())) {
    output.getVectorComplexFloat().debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }

    // test Y = log(X1);
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1)]:\n");
    }
  
    VectorLong values_01(1);
    values_01(0).assign((long)LOG);

    VectorLong values_op_01(1);
    values_op_01(0).assign((long)ASSIGN);

    math6.clear();
    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_01);
    math6.setFunction(values_01);
  
    input.setLength(1);
    input(0).makeVectorComplexFloat().assign(L"10.0 + 5.0j, 3.0 - 3.0j");

    output.clear();
    math6.compute(output, input);
    result.assign(L"2.41416 + 0.463648j, 1.44519 - 0.785398j");

    if (!result.almostEqual(output.getVectorComplexFloat())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  
    // test Y = log(X1) + constant;
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1) + 10.0]:\n");
    }
  
    VectorLong values_02(1);
    values_02(0).assign((long)LOG);

    VectorLong values_op_02(1);
    values_op_02(0).assign((long)ASSIGN);

    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_02);
    math6.setFunction(values_02);
    math6.setConstant(10.0);
    
    input.setLength(1);
    input(0).makeVectorComplexFloat().assign(L"10.0 + 5.0j, 3.0 - 3.0j");

    math6.compute(output, input);

    result.assign(L"12.4142 + 0.4636j, 11.4452 - 0.7854j");

    if (!result.almostEqual(output.getVectorComplexFloat())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  */
  
  // test Y = X1 + 2 * X2 - log(X3) - exp(X4)
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
  }
  
  values.setLength(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)LOG);
  values(3).assign((long)EXP);

  values_op.setLength(4);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)SUBTRACT);
  values_op(3).assign((long)SUBTRACT);

  math6.setNumOperands(4);
  math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setConstant(0.0);
  
  input.setLength(4);
  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");
  input(3).makeVectorComplexFloat().assign(L"2.0 + 2.0j, 2.0 - 2.0j");
  math6.compute(output, input);

  VectorComplexFloat result_cf;
  result_cf.assign(L"6.82836 - 3.40425j, 11.3284 + 14.5335j");

  if (!result_cf.almostEqual(output.getVectorComplexFloat())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  /*    
	// test Y = X1 + 2 * X2 - log(X3) - exp(X4)
	//  test wrong input "if ASSIGN appears middle of computation
	//  everything before it will clear.
	//
	if (level_a > Integral::BRIEF) {
	Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
	}
  
	values(0).assign((long)IDENTITY);
	values(1).assign((long)IDENTITY);
	values(2).assign((long)LOG);
	values(3).assign((long)EXP);

	values_op(0).assign((long)ASSIGN);
	values_op(1).assign((long)ADD);
	values_op(2).assign((long)ASSIGN);
	values_op(3).assign((long)SUBTRACT);

	math6.setNumOperands(4);
	math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
	math6.setOperation(values_op);
	math6.setFunction(values);
	math6.setConstant(0.0);
  
	input.setLength(4);
	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");
	input(3).makeVectorComplexFloat().assign(L"2.0 + 2.0j, 2.0 - 2.0j");
	math6.compute(output, input);

	result_cf.assign(L"3.4215 - 5.9334j, 3.42151 + 7.5042j");

	if (!result_cf.almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"compute", Error::TEST,
	__FILE__, __LINE__);
	}
  
	// test Y = X1 + 2 * X2 - log(X3) - exp(X4) (all zero and constant)
	//
	if (level_a > Integral::BRIEF) {
	Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)] for all zero values:\n");
	}

	input.setLength(4);
	input(0).makeVectorComplexFloat().assign(L"0.0, 0.0");
	input(1).makeVectorComplexFloat().assign(L"0.0, 0.0");
	input(2).makeVectorComplexFloat().assign(L"1.0, 1.0");
	input(3).makeVectorComplexFloat().assign(L"0.0, 0.0");
	math6.compute(output, input);

	result_cf.assign(L"-1.0, -1.0");

	if (!result_cf.almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"compute", Error::TEST,
	__FILE__, __LINE__);
	}
  
	// test Y = [ {X1* X2 + log(X3)} / exp(X4)]
	//
	if (level_a > Integral::BRIEF) {
	Console::put(L"\n\ttesting for Y = [ {X1* X2 + log(X3)} / exp(X4)]:\n");
	}

	math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
	values_op(0).assign((long)ASSIGN);
	values_op(1).assign((long)MULTIPLY);
	values_op(2).assign((long)ADD);
	values_op(3).assign((long)DIVIDE);

	math6.setOperation(values_op);
	input.setLength(4);
	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");
	input(3).makeVectorComplexFloat().assign(L"2.0 + 2.0j, 2.0 - 2.0j");
	math6.compute(output, input);

	result_cf.assign(L"0.4832 - 0.2727j, -2.3804 - 1.0378j");

	if (!result_cf.almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"compute", Error::TEST,
	__FILE__, __LINE__);
	}

	// test Y = square(X1) + 2.0 * sqrt(X2) + 3.0
	//
	if (level_a > Integral::BRIEF) {
	Console::put(L"\n\ttesting for Y = [square(X1) + 2.0 * sqrt(X2) + 3.0]:\n");
	}

	values.setLength(2);
	values(0).assign((long)SQUARE);
	values(1).assign((long)SQRT);

	math6.setNumOperands(2);
	math6.setWeight(L"1.0, 2.0");
	str.assign(L"ASSIGN, ADD");
	math6.setOperation(str);
	math6.setFunction(values);
	math6.setConstant(3.0);

	input.setLength(2);
	input(0).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 2.0 + 2.0j");
	input(1).makeVectorComplexFloat().assign(L"4.0 + 4.0j, 9.0 + 9.0j");
	math6.compute(output, input);

	result_cf.assign(L"7.3947 + 3.8203j, 9.5921 + 10.7305j");

	if (!result_cf.almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"compute", Error::TEST,
	__FILE__, __LINE__);
	}

	// test Y = 2.0 * X1^2 + 3.0 * X2 + 3.0
	//
	if (level_a > Integral::BRIEF) {
	Console::put(L"\n\ttesting for Y = [2.0 * X1^2 + 3.0 * X2 + 3.0]:\n");
	}

	values.setLength(2);
	values(0).assign((long)SQUARE);
	values(1).assign((long)IDENTITY);

	math6.setNumOperands(2);
	math6.setWeight(L"2.0, 3.0");
	str.assign(L"ASSIGN, ADD");
	math6.setOperation(str);
	math6.setFunction(values);
	input(0).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 2.0 + 2.0j");
	input(1).makeVectorComplexFloat().assign(L"4.0 + 4.0j, 9.0 + 9.0j");
 
	math6.compute(output, input);

	result_cf.assign(L"15.0 + 16.0j, 30 + 43j");

	if (!result_cf.almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"compute", Error::TEST,
	__FILE__, __LINE__);
	}

	// test Y = X1 * X2 (vector * matrix)
	//
	if (level_a > Integral::BRIEF) {
	Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)]:\n");
	}
  
	input(0).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 2.0 + 3.0j");
	input(1).makeMatrixComplexFloat().assign(2, 2, L"3.0 + 3.0j, 4.0 + 4.0j, 5.0 + 5.0j, 6.0 + 6.0j");
	values(0).assign((long)IDENTITY);
	values(1).assign((long)IDENTITY);
	values_op.setLength(2);
	values_op(0).assign((long)ASSIGN);
	values_op(1).assign((long)MULTIPLY);
	math6.setOperation(values_op);
	math6.setFunction(values);
	math6.setWeight(L"1.0, 1.0");
	math6.setConstant(0.0);
	math6.compute(output, input);
  
	result_cf.assign(L"-5.0 + 31j, -6 + 38j");
  
	if (!(result_cf).almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"apply", Error::TEST,
	__FILE__, __LINE__);
	}

	// test Y = X1 * X2 (vector * inv(matrix))
	//  
	values(0).assign((long)IDENTITY);
	values(1).assign((long)INVERSE);
	values_op.setLength(2);
	values_op(0).assign((long)ASSIGN);
	values_op(1).assign((long)MULTIPLY);
	math6.setOperation(values_op);
	math6.setFunction(values);
	math6.setWeight(L"1.0, 1.0");
	math6.setConstant(0.0);
	math6.compute(output, input);
  
	result_cf.assign(L"3.25 + 1.25j, -1.75 - 0.75j");
  
	if (!(result_cf).almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"apply", Error::TEST,
	__FILE__, __LINE__);
	}

	// test Y = X1 * X2 (vector * matrix) with vector of  zeros and constants
	//
	if (level_a > Integral::BRIEF) {
	Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)] with vector of zeros and constants:\n");
	}

	//test vector of zeros
	//
	input(0).makeVectorComplexFloat().assign(L"0.0, 0.0, 0.0");
	input(1).makeMatrixComplexFloat().assign(3, 3, L"1.0 + 1.0j, 0.0, 5.0 + 5.0j, 1.2 + 1.2j, 2.4 + 2.4j, 3.6 + 3.6j, 1.8 + 1.8j, 2.1 + 2.1j, 9.8 + 9.8j");
	values(0).assign((long)IDENTITY);
	values(1).assign((long)IDENTITY);
	values_op.setLength(2);
	values_op(0).assign((long)ASSIGN);
	values_op(1).assign((long)MULTIPLY);
	math6.setOperation(values_op);
	math6.setFunction(values);
	math6.setWeight(L"1.0, 1.0");
	math6.setConstant(0.0);
	math6.compute(output, input);
  
	result_cf.assign(L"0.0, 0.0, 0.0");
  
	if (!(result_cf).almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"apply", Error::TEST,
	__FILE__, __LINE__);
	}

	//test matrix of zeros
	//
	input(0).makeVectorComplexFloat().assign(L"1.0 + 2.0j, 1.0 - 2.0j, 1.0 + 3.0j");
	input(1).makeMatrixComplexFloat().assign(3, 3, L"0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0");
	values(0).assign((long)IDENTITY);
	values(1).assign((long)IDENTITY);
	values_op.setLength(2);
	values_op(0).assign((long)ASSIGN);
	values_op(1).assign((long)MULTIPLY);
	math6.setOperation(values_op);
	math6.setFunction(values);
	math6.setWeight(L"1.0, 1.0");
	math6.setConstant(0.0);
	math6.compute(output, input);
  
	result_cf.assign(L"0.0, 0.0, 0.0");
  
	if (!(result_cf).almostEqual(output.getVectorComplexFloat())) {
	output.debug(L"output");
	return Error::handle(name(), L"apply", Error::TEST,
	__FILE__, __LINE__);
	}
  */
  
  // test Y = X1 + X2 * X3' + inv(x4)
  //  (matrix + matrix * trans(matrix) + inv(matrix))
  //

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + X2 * X3' + inv(x4)] (matrix + matrix * trans(matrix) + inv(matrix)):\n");
  }

  values.setLength(4);
  values_op.setLength(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)TRANSPOSE);
  values(3).assign((long)INVERSE);
  
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)MULTIPLY);
  values_op(3).assign((long)ADD);
  math6.setNumOperands(4);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
  math6.setConstant(0.0);
  input.setLength(4);
  input(0).makeMatrixComplexFloat().assign(2, 2, L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 + 3.0j, 4.0 + 4.0j");
  input(1).makeMatrixComplexFloat().assign(2, 2, L"1.0 + 1.0j, 3.0 - 3.0j, 5.0 + 5.0j, 7.0 - 7.0j");
  input(2).makeMatrixComplexFloat().assign(2, 2, L"2.0 + 2.0j, 4.0 + 4.0j, 6.0 + 6.0j, 8.0 + 8.0j");
  input(3).makeMatrixComplexFloat().assign(2, 2, L"3.0 + 3.0j, 4.0 + 4.0j, 5.0 + 5.0j, 6.0 + 6.0j");


  MatrixComplexFloat result_mat_cf;
  math6.compute(output, input);
  
  result_mat_cf.assign(2, 2, L"22.5 + 25.5j, 49 + 55j, 57.25 + 62.75j, 111.25 + 160.75j");
  
  if (!(result_mat_cf).almostEqual(output.getMatrixComplexFloat())) {
    output.debug(L"output");
    result_mat_cf.debug(L"result");
    return Error::handle(name(), L"apply", Error::TEST,
                         __FILE__, __LINE__);
  }
 
  // test scalar addition
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (1):\n");
  }

  input.setLength(2);
  input(0).makeVectorComplexFloat().assign(L"4.0 + 4.0j");
  input(1).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);

  math7.setFunction(values);
  math7.setOperation(values_op);
  math7.compute(output, input);

  VectorComplexFloat expected_cf(L"5.0 + 5.0j, 6.0 + 6.0j, 7.0 + 1.0j, 8.0");
  if (!output.getVectorComplexFloat().almostEqual(expected_cf)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (2):\n");
    }

    input(0).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");
    input(1).makeVectorComplexFloat().assign(L"4.0 + 4.0j");
 
    math7.compute(output, input);

    if (!output.getVectorComplexFloat().almostEqual(expected_cf)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (3):\n");
    }
  
    MatrixComplexFloat a(3, 3);
    a.setDiagonal(complexfloat(4.0, 4.0));

    MatrixComplexFloat b(3, 3);
    b.assign(complexfloat(7.0, 7.0));
    b.setDiagonal(complexfloat(11.0, 11.0));

    input(0).makeVectorComplexFloat().assign(L"7.0+7.0j");
    input(1).makeMatrixComplexFloat().assign(a);
  
    math7.compute(output, input);

    if (!output.getMatrixComplexFloat().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (4):\n");
    }
    
    input(0).makeMatrixComplexFloat().assign(a);
    input(1).makeVectorComplexFloat().assign(L"7.0+7.0j");
    
    math7.compute(output, input);

    if (!output.getMatrixComplexFloat().almostEqual(b)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // test scalar subtraction
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (1):\n");
  }
  
  input.setLength(2);

  input(0).makeVectorComplexFloat().assign(L"4.0 + 4.0j");
  input(1).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  math7.setFunction(values);
  
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)SUBTRACT);

  math7.setOperation(values_op);
  
  math7.compute(output, input);

  expected_cf.assign(L"3.0 + 3.0j, 2.0 + 2.0j, 1.0 + 7.0j, 8.0j");
  if (!output.getVectorComplexFloat().almostEqual(expected_cf)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  input(0).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");
  input(1).makeVectorComplexFloat().assign(L"4.0 + 4.0j");
  
  math7.compute(output, input);

  expected_cf.assign(L"-3.0 -3.0j, -2.0 - 2.0j, -1.0 - 7.0j, -8.0j");

  if (!output.getVectorComplexFloat().almostEqual(expected_cf)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(complexfloat(4.0, 4.0));

    b.clear(Integral::RETAIN);
    b.assign(complexfloat(7.0, 7.0));
    b.setDiagonal(complexfloat(11.0, 11.0));

    input(0).makeVectorComplexFloat().assign(L"7.0+7.0j");
    input(1).makeMatrixComplexFloat().assign(a);

    math7.compute(output, input);

    b.assign(complexfloat(7.0, 7.0));
    b.setDiagonal(complexfloat(3.0, 3.0));
  
    if (!output.getMatrixComplexFloat().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (3):\n");
    }
  
    input(0).makeMatrixComplexFloat().assign(a);
    input(1).makeVectorComplexFloat().assign(L"7.0+7.0j");

    b.assign(complexfloat(-7.0, -7.0));
    b.setDiagonal(complexfloat(-3.0, -3.0));
    math7.compute(output, input);

    if (!output.getMatrixComplexFloat().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // test scalar multiplication
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (1):\n");
  }
  
  values_op(1).assign((long)MULTIPLY);
  math7.setOperation(values_op);

  input(0).makeVectorComplexFloat().assign(L"3.0 + 3.0j");
  input(1).makeVectorComplexFloat().assign(L"2.0 + 2.0j, 3.0 - 3.0j, 4.0 + 5.0j");

  expected_cf.assign(L"0 + 12j, 18 + 0j, -3 + 27j");

  math7.compute(output, input);

  if (!output.getVectorComplexFloat().almostEqual(expected_cf)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
    }

    input(0).makeVectorComplexFloat().assign(L"2.0 + 2.0j, 3.0 - 3.0j, 4.0 + 5.0j");
    input(1).makeVectorComplexFloat().assign(L"3.0 + 3.0j");
  
    expected_cf.assign(L"0 + 12j, 18 + 0j, -3 + 27j");

    math7.compute(output, input);

    if (!output.getVectorComplexFloat().almostEqual(expected_cf)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(complexfloat(3.0, 3.0));
  
    input(0).makeMatrixComplexFloat().assign(a);
    input(1).makeVectorComplexFloat().assign(L"3.0+3.0j");

    b.clear(Integral::RETAIN);
    b.setDiagonal(complexfloat(0, 18));

    math7.compute(output, input);

    if (!output.getMatrixComplexFloat().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (3):\n");
    }
  
    input(0).makeVectorComplexFloat().assign(L"3.0+3.0j");
    input(1).makeMatrixComplexFloat().assign(a);
  
    math7.compute(output, input);

    if (!output.getMatrixComplexFloat().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // test scalar division
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (1):\n");
  }
  
  values_op(1).assign((long)DIVIDE);
  math7.setOperation(values_op);

  input(0).makeVectorComplexFloat().assign(L"2.0 + 2.0j, 3.0 - 3.0j, 4.0 + 5.0j");
  input(1).makeVectorComplexFloat().assign(L"3.0 + 3.0j");

  expected_cf.assign(L"0.66666 + 0j, 0 - 1j, 1.5 + 0.16666j");

  math7.compute(output, input);

  if (!output.getVectorComplexFloat().almostEqual(expected_cf)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(complexfloat(6.0, 6.0));
  
    input(0).makeMatrixComplexFloat().assign(a);
    input(1).makeVectorComplexFloat().assign(L"2.0+3.0j");

    b.clear(Integral::RETAIN);
    b.setDiagonal(complexfloat(2.30769, -0.4615));

    math7.compute(output, input);

    if (!output.getMatrixComplexFloat().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  mag/real/imag function:\n");
    }

    math7.clear();
    input.setLength(1);
    input(0).makeVectorComplexFloat().assign(L"3 + 4j, 4 + 5j, 6 + 7j");

    values.setLength(1);
    values_op.setLength(1);
    values(0).assign((long)MAG);
    values_op(0).assign((long)ASSIGN);
    math7.setNumOperands(1);
    math7.setOperation(values_op);
    math7.setFunction(values);

    math7.setConstant(0.0);
  
    math7.compute(output, input);

    VectorFloat expected_vf;
    expected_vf.assign(L"5, 6.40312, 9.21954");
    if (!output.getVectorFloat().almostEqual(expected_vf)) {
    math7.debug(L"math");
    output.debug(L"output");
    expected_vf.debug(L"expected_vf");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    values(0).assign((long)IMAG);
    math7.setFunction(values);

    math7.compute(output, input);

    expected_vf.assign(L"4, 5, 7");
    if (!output.getVectorFloat().almostEqual(expected_vf)) {
    math7.debug(L"math");
    output.debug(L"output");
    expected_vf.debug(L"expected_vf");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    values.clear();
    values.setLength(1);
    values(0).assign((long)REAL);
    math7.setFunction(values);

    output.clear();
    math7.compute(output, input);

    expected_vf.assign(L"3, 4, 6");
    if (!output.getVectorFloat().almostEqual(expected_vf)) {
    math7.debug(L"math");
    output.debug(L"output");
    expected_vf.debug(L"expected_vf");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }    
  
  //--------------------------------------------------------------------------
  //
  // 6. class-specific public methods:
  //     computational methods for complexdouble
  //
  //--------------------------------------------------------------------------
  
  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: computational methods for complexdouble...\n");
    Console::increaseIndention();
  }
  
  /*
    // test Y = 2.0 * X1 + 3.0 * X2 + 2.0
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [2.0 * X1 + 3.0 * X2 + 2.0]:\n");
    }

    Math math6;
    math6.setNumOperands(2);
    math6.setConstant(2.0);
    math6.setWeight(L"2.0, 3.0");

    // set up the variables for test
    //
    Vector<AlgorithmData> input(2);
    AlgorithmData output;
    VectorComplexDouble result;

    input(0).makeVectorComplexDouble().assign(L"1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j");
    input(1).makeVectorComplexDouble().assign(L"1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j");
    math6.compute(output, input);

    result.assign(L"7 + 5j, 12 + 10j, 17 + 15j, 22 + 20j");

    if (!result.almostEqual(output.getVectorComplexDouble())) {
    output.getVectorComplexDouble().debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }

    // test Y = log(X1);
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1)]:\n");
    }
  
    VectorLong values_01(1);
    values_01(0).assign((long)LOG);

    VectorLong values_op_01(1);
    values_op_01(0).assign((long)ASSIGN);

    math6.clear();
    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_01);
    math6.setFunction(values_01);
  
    input.setLength(1);
    input(0).makeVectorComplexDouble().assign(L"10.0 + 5.0j, 3.0 - 3.0j");

    output.clear();
    math6.compute(output, input);
    result.assign(L"2.41416 + 0.463648j, 1.44519 - 0.785398j");

    if (!result.almostEqual(output.getVectorComplexDouble())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  
    // test Y = log(X1) + constant;
    //
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [log(X1) + 10.0]:\n");
    }
  
    VectorLong values_02(1);
    values_02(0).assign((long)LOG);

    VectorLong values_op_02(1);
    values_op_02(0).assign((long)ASSIGN);

    math6.setNumOperands(1);
    math6.setWeight(L"1.0");
    math6.setOperation(values_op_02);
    math6.setFunction(values_02);
    math6.setConstant(10.0);
    
    input.setLength(1);
    input(0).makeVectorComplexDouble().assign(L"10.0 + 5.0j, 3.0 - 3.0j");

    math6.compute(output, input);

    result.assign(L"12.4142 + 0.4636j, 11.4452 - 0.7854j");

    if (!result.almostEqual(output.getVectorComplexDouble())) {
    output.debug(L"output");
    result.debug(L"result");
    return Error::handle(name(), L"compute", Error::TEST,
    __FILE__, __LINE__);
    }
  */
  
  // test Y = X1 + 2 * X2 - log(X3) - exp(X4)
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
  }
  
  values.setLength(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)LOG);
  values(3).assign((long)EXP);

  values_op.setLength(4);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)SUBTRACT);
  values_op(3).assign((long)SUBTRACT);

  math6.setNumOperands(4);
  math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setConstant(0.0);
  
  input.setLength(4);
  input(0).makeVectorComplexDouble().assign(L"1.1 + 1.1j, 4.0 + 4.0j");
  input(1).makeVectorComplexDouble().assign(L"1.5 + 1.5j, 2.3 + 2.3j");
  input(2).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 1.0 + 1.0j");
  input(3).makeVectorComplexDouble().assign(L"2.0 + 2.0j, 2.0 - 2.0j");
  math6.compute(output, input);

  VectorComplexDouble result_cdb;
  result_cdb.assign(L"6.82836 - 3.40425j, 11.3284 + 14.5335j");

  if (!result_cdb.almostEqual(output.getVectorComplexDouble())) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  /*  
      // test Y = X1 + 2 * X2 - log(X3) - exp(X4)
      //  test wrong input "if ASSIGN appears middle of computation
      //  everything before it will clear.
      //
      if (level_a > Integral::BRIEF) {
      Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)]:\n");
      }
  
      values(0).assign((long)IDENTITY);
      values(1).assign((long)IDENTITY);
      values(2).assign((long)LOG);
      values(3).assign((long)EXP);

      values_op(0).assign((long)ASSIGN);
      values_op(1).assign((long)ADD);
      values_op(2).assign((long)ASSIGN);
      values_op(3).assign((long)SUBTRACT);

      math6.setNumOperands(4);
      math6.setWeight(L"1.0, 2.0, 1.0, 1.0");
      math6.setOperation(values_op);
      math6.setFunction(values);
      math6.setConstant(0.0);
  
      input.setLength(4);
      input(0).makeVectorComplexDouble().assign(L"1.1 + 1.1j, 4.0 + 4.0j");
      input(1).makeVectorComplexDouble().assign(L"1.5 + 1.5j, 2.3 + 2.3j");
      input(2).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 1.0 + 1.0j");
      input(3).makeVectorComplexDouble().assign(L"2.0 + 2.0j, 2.0 - 2.0j");
      math6.compute(output, input);

      result_cdb.assign(L"3.4215 - 5.9334j, 3.42151 + 7.5042j");

      if (!result_cdb.almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"compute", Error::TEST,
      __FILE__, __LINE__);
      }
  
      // test Y = X1 + 2 * X2 - log(X3) - exp(X4) (all zero and constant)
      //
      if (level_a > Integral::BRIEF) {
      Console::put(L"\n\ttesting for Y = [X1 + 2.0 * X2 - log(X3) - exp(X4)] for all zero values:\n");
      }

      input.setLength(4);
      input(0).makeVectorComplexDouble().assign(L"0.0, 0.0");
      input(1).makeVectorComplexDouble().assign(L"0.0, 0.0");
      input(2).makeVectorComplexDouble().assign(L"1.0, 1.0");
      input(3).makeVectorComplexDouble().assign(L"0.0, 0.0");
      math6.compute(output, input);

      result_cdb.assign(L"-1.0, -1.0");

      if (!result_cdb.almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"compute", Error::TEST,
      __FILE__, __LINE__);
      }
  
      // test Y = [ {X1* X2 + log(X3)} / exp(X4)]
      //
      if (level_a > Integral::BRIEF) {
      Console::put(L"\n\ttesting for Y = [ {X1* X2 + log(X3)} / exp(X4)]:\n");
      }

      math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
      values_op(0).assign((long)ASSIGN);
      values_op(1).assign((long)MULTIPLY);
      values_op(2).assign((long)ADD);
      values_op(3).assign((long)DIVIDE);

      math6.setOperation(values_op);
      input.setLength(4);
      input(0).makeVectorComplexDouble().assign(L"1.1 + 1.1j, 4.0 + 4.0j");
      input(1).makeVectorComplexDouble().assign(L"1.5 + 1.5j, 2.3 + 2.3j");
      input(2).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 1.0 + 1.0j");
      input(3).makeVectorComplexDouble().assign(L"2.0 + 2.0j, 2.0 - 2.0j");
      math6.compute(output, input);

      result_cdb.assign(L"0.4832 - 0.2727j, -2.3804 - 1.0378j");

      if (!result_cdb.almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"compute", Error::TEST,
      __FILE__, __LINE__);
      }

      // test Y = square(X1) + 2.0 * sqrt(X2) + 3.0
      //
      if (level_a > Integral::BRIEF) {
      Console::put(L"\n\ttesting for Y = [square(X1) + 2.0 * sqrt(X2) + 3.0]:\n");
      }

      values.setLength(2);
      values(0).assign((long)SQUARE);
      values(1).assign((long)SQRT);

      math6.setNumOperands(2);
      math6.setWeight(L"1.0, 2.0");
      str.assign(L"ASSIGN, ADD");
      math6.setOperation(str);
      math6.setFunction(values);
      math6.setConstant(3.0);

      input.setLength(2);
      input(0).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 2.0 + 2.0j");
      input(1).makeVectorComplexDouble().assign(L"4.0 + 4.0j, 9.0 + 9.0j");
      math6.compute(output, input);

      result_cdb.assign(L"7.3947 + 3.8203j, 9.5921 + 10.7305j");

      if (!result_cdb.almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"compute", Error::TEST,
      __FILE__, __LINE__);
      }

      // test Y = 2.0 * X1^2 + 3.0 * X2 + 3.0
      //
      if (level_a > Integral::BRIEF) {
      Console::put(L"\n\ttesting for Y = [2.0 * X1^2 + 3.0 * X2 + 3.0]:\n");
      }

      values.setLength(2);
      values(0).assign((long)SQUARE);
      values(1).assign((long)IDENTITY);

      math6.setNumOperands(2);
      math6.setWeight(L"2.0, 3.0");
      str.assign(L"ASSIGN, ADD");
      math6.setOperation(str);
      math6.setFunction(values);
      input(0).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 2.0 + 2.0j");
      input(1).makeVectorComplexDouble().assign(L"4.0 + 4.0j, 9.0 + 9.0j");
 
      math6.compute(output, input);

      result_cdb.assign(L"15.0 + 16.0j, 30 + 43j");

      if (!result_cdb.almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"compute", Error::TEST,
      __FILE__, __LINE__);
      }
  
      // test Y = X1 * X2 (vector * matrix)
      //
      if (level_a > Integral::BRIEF) {
      Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)]:\n");
      }
  
      input(0).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 2.0 + 3.0j");
      input(1).makeMatrixComplexDouble().assign(2, 2, L"3.0 + 3.0j, 4.0 + 4.0j, 5.0 + 5.0j, 6.0 + 6.0j");
      values(0).assign((long)IDENTITY);
      values(1).assign((long)IDENTITY);
      values_op.setLength(2);
      values_op(0).assign((long)ASSIGN);
      values_op(1).assign((long)MULTIPLY);
      math6.setOperation(values_op);
      math6.setFunction(values);
      math6.setWeight(L"1.0, 1.0");
      math6.setConstant(0.0);
      math6.compute(output, input);
  
      result_cdb.assign(L"-5.0 + 31j, -6 + 38j");
  
      if (!(result_cdb).almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"apply", Error::TEST,
      __FILE__, __LINE__);
      }

      // test Y = X1 * X2 (vector * inv(matrix))
      //  
      values(0).assign((long)IDENTITY);
      values(1).assign((long)INVERSE);
      values_op.setLength(2);
      values_op(0).assign((long)ASSIGN);
      values_op(1).assign((long)MULTIPLY);
      math6.setOperation(values_op);
      math6.setFunction(values);
      math6.setWeight(L"1.0, 1.0");
      math6.setConstant(0.0);
      math6.compute(output, input);
  
      result_cdb.assign(L"3.25 + 1.25j, -1.75 - 0.75j");
  
      if (!(result_cdb).almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"apply", Error::TEST,
      __FILE__, __LINE__);
      }

      // test Y = X1 * X2 (vector * matrix) with vector of  zeros and constants
      //
      if (level_a > Integral::BRIEF) {
      Console::put(L"\n\ttesting for Y = [X1 * X2 (vector * matrix)] with vector of zeros and constants:\n");
      }

      //test vector of zeros
      //
      input(0).makeVectorComplexDouble().assign(L"0.0, 0.0, 0.0");
      input(1).makeMatrixComplexDouble().assign(3, 3, L"1.0 + 1.0j, 0.0, 5.0 + 5.0j, 1.2 + 1.2j, 2.4 + 2.4j, 3.6 + 3.6j, 1.8 + 1.8j, 2.1 + 2.1j, 9.8 + 9.8j");
      values(0).assign((long)IDENTITY);
      values(1).assign((long)IDENTITY);
      values_op.setLength(2);
      values_op(0).assign((long)ASSIGN);
      values_op(1).assign((long)MULTIPLY);
      math6.setOperation(values_op);
      math6.setFunction(values);
      math6.setWeight(L"1.0, 1.0");
      math6.setConstant(0.0);
      math6.compute(output, input);
  
      result_cdb.assign(L"0.0, 0.0, 0.0");
  
      if (!(result_cdb).almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"apply", Error::TEST,
      __FILE__, __LINE__);
      }

      //test matrix of zeros
      //
      input(0).makeVectorComplexDouble().assign(L"1.0 + 2.0j, 1.0 - 2.0j, 1.0 + 3.0j");
      input(1).makeMatrixComplexDouble().assign(3, 3, L"0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0");
      values(0).assign((long)IDENTITY);
      values(1).assign((long)IDENTITY);
      values_op.setLength(2);
      values_op(0).assign((long)ASSIGN);
      values_op(1).assign((long)MULTIPLY);
      math6.setOperation(values_op);
      math6.setFunction(values);
      math6.setWeight(L"1.0, 1.0");
      math6.setConstant(0.0);
      math6.compute(output, input);
  
      result_cdb.assign(L"0.0, 0.0, 0.0");
  
      if (!(result_cdb).almostEqual(output.getVectorComplexDouble())) {
      output.debug(L"output");
      return Error::handle(name(), L"apply", Error::TEST,
      __FILE__, __LINE__);
      }
  */
  
  // test Y = X1 + X2 * X3' + inv(x4)
  //  (matrix + matrix * trans(matrix) + inv(matrix))
  //

  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting for Y = [X1 + X2 * X3' + inv(x4)] (matrix + matrix * trans(matrix) + inv(matrix)):\n");
  }

  values.setLength(4);
  values_op.setLength(4);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);
  values(2).assign((long)TRANSPOSE);
  values(3).assign((long)INVERSE);
  
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);
  values_op(2).assign((long)MULTIPLY);
  values_op(3).assign((long)ADD);
  math6.setNumOperands(4);
  math6.setOperation(values_op);
  math6.setFunction(values);
  math6.setWeight(L"1.0, 1.0, 1.0, 1.0");
  math6.setConstant(0.0);
  input.setLength(4);
  input(0).makeMatrixComplexDouble().assign(2, 2, L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 + 3.0j, 4.0 + 4.0j");
  input(1).makeMatrixComplexDouble().assign(2, 2, L"1.0 + 1.0j, 3.0 - 3.0j, 5.0 + 5.0j, 7.0 - 7.0j");
  input(2).makeMatrixComplexDouble().assign(2, 2, L"2.0 + 2.0j, 4.0 + 4.0j, 6.0 + 6.0j, 8.0 + 8.0j");
  input(3).makeMatrixComplexDouble().assign(2, 2, L"3.0 + 3.0j, 4.0 + 4.0j, 5.0 + 5.0j, 6.0 + 6.0j");


  MatrixComplexDouble result_mat_cdb;
  math6.compute(output, input);
  
  result_mat_cdb.assign(2, 2, L"22.5 + 25.5j, 49 + 55j, 57.25 + 62.75j, 111.25 + 160.75j");
  
  if (!(result_mat_cdb).almostEqual(output.getMatrixComplexDouble())) {
    output.debug(L"output");
    result_mat_cdb.debug(L"result");
    return Error::handle(name(), L"apply", Error::TEST,
                         __FILE__, __LINE__);
  }
 
  // test scalar addition
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (1):\n");
  }

  input.setLength(2);
  input(0).makeVectorComplexDouble().assign(L"4.0 + 4.0j");
  input(1).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)ADD);

  math7.setFunction(values);
  math7.setOperation(values_op);
  math7.compute(output, input);

  VectorComplexDouble expected_cdb(L"5.0 + 5.0j, 6.0 + 6.0j, 7.0 + 1.0j, 8.0");
  if (!output.getVectorComplexDouble().almostEqual(expected_cdb)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (2):\n");
    }

    input(0).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");
    input(1).makeVectorComplexDouble().assign(L"4.0 + 4.0j");
 
    math7.compute(output, input);

    if (!output.getVectorComplexDouble().almostEqual(expected_cdb)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (3):\n");
    }
  
    MatrixComplexDouble a(3, 3);
    a.setDiagonal(ComplexDouble(4.0, 4.0));

    MatrixComplexDouble b(3, 3);
    b.assign(complexdouble(7.0, 7.0));
    b.setDiagonal(complexdouble(11.0, 11.0));

    input(0).makeVectorComplexDouble().assign(L"7.0+7.0j");
    input(1).makeMatrixComplexDouble().assign(a);
  
    math7.compute(output, input);

    if (!output.getMatrixComplexDouble().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar addition (4):\n");
    }
    
    input(0).makeMatrixComplexDouble().assign(a);
    input(1).makeVectorComplexDouble().assign(L"7.0+7.0j");
    
    math7.compute(output, input);

    if (!output.getMatrixComplexDouble().almostEqual(b)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // test scalar subtraction
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (1):\n");
  }
  
  input.setLength(2);

  input(0).makeVectorComplexDouble().assign(L"4.0 + 4.0j");
  input(1).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");

  values.setLength(2);
  values(0).assign((long)IDENTITY);
  values(1).assign((long)IDENTITY);

  math7.setFunction(values);
  
  values_op.setLength(2);
  values_op(0).assign((long)ASSIGN);
  values_op(1).assign((long)SUBTRACT);

  math7.setOperation(values_op);
  
  math7.compute(output, input);

  expected_cdb.assign(L"3.0 + 3.0j, 2.0 + 2.0j, 1.0 + 7.0j, 8.0j");
  if (!output.getVectorComplexDouble().almostEqual(expected_cdb)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  input(0).makeVectorComplexDouble().assign(L"1.0 + 1.0j, 2.0 + 2.0j, 3.0 - 3.0j, 4.0 - 4.0j");
  input(1).makeVectorComplexDouble().assign(L"4.0 + 4.0j");
  
  math7.compute(output, input);

  expected_cdb.assign(L"-3.0 -3.0j, -2.0 - 2.0j, -1.0 - 7.0j, -8.0j");

  if (!output.getVectorComplexDouble().almostEqual(expected_cdb)) {
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(complexdouble(4.0, 4.0));

    b.clear(Integral::RETAIN);
    b.assign(complexdouble(7.0, 7.0));
    b.setDiagonal(complexdouble(11.0, 11.0));

    input(0).makeVectorComplexDouble().assign(L"7.0+7.0j");
    input(1).makeMatrixComplexDouble().assign(a);

    math7.compute(output, input);

    b.assign(complexdouble(7.0, 7.0));
    b.setDiagonal(complexdouble(3.0, 3.0));
  
    if (!output.getMatrixComplexDouble().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar subtraction (3):\n");
    }
  
    input(0).makeMatrixComplexDouble().assign(a);
    input(1).makeVectorComplexDouble().assign(L"7.0+7.0j");

    b.assign(complexdouble(-7.0, -7.0));
    b.setDiagonal(complexdouble(-3.0, -3.0));
    math7.compute(output, input);

    if (!output.getMatrixComplexDouble().almostEqual(b)) {
    output.debug(L"output");
    b.debug(L"b");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // test scalar multiplication
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (1):\n");
  }
  
  values_op(1).assign((long)MULTIPLY);
  math7.setOperation(values_op);

  input(0).makeVectorComplexDouble().assign(L"3.0 + 3.0j");
  input(1).makeVectorComplexDouble().assign(L"2.0 + 2.0j, 3.0 - 3.0j, 4.0 + 5.0j");

  expected_cdb.assign(L"0 + 12j, 18 + 0j, -3 + 27j");

  math7.compute(output, input);

  if (!output.getVectorComplexDouble().almostEqual(expected_cdb)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
    }

    input(0).makeVectorComplexDouble().assign(L"2.0 + 2.0j, 3.0 - 3.0j, 4.0 + 5.0j");
    input(1).makeVectorComplexDouble().assign(L"3.0 + 3.0j");
  
    expected_cdb.assign(L"0 + 12j, 18 + 0j, -3 + 27j");

    math7.compute(output, input);

    if (!output.getVectorComplexDouble().almostEqual(expected_cdb)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(complexdouble(3.0, 3.0));
  
    input(0).makeMatrixComplexDouble().assign(a);
    input(1).makeVectorComplexDouble().assign(L"3.0+3.0j");

    b.clear(Integral::RETAIN);
    b.setDiagonal(complexdouble(0, 18));

    math7.compute(output, input);

    if (!output.getMatrixComplexDouble().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar multiplication (3):\n");
    }
  
    input(0).makeVectorComplexDouble().assign(L"3.0+3.0j");
    input(1).makeMatrixComplexDouble().assign(a);
  
    math7.compute(output, input);

    if (!output.getMatrixComplexDouble().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // test scalar division
  //
  if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (1):\n");
  }
  
  values_op(1).assign((long)DIVIDE);
  math7.setOperation(values_op);

  input(0).makeVectorComplexDouble().assign(L"2.0 + 2.0j, 3.0 - 3.0j, 4.0 + 5.0j");
  input(1).makeVectorComplexDouble().assign(L"3.0 + 3.0j");

  expected_cdb.assign(L"0.66666 + 0j, 0 - 1j, 1.5 + 0.16666j");

  math7.compute(output, input);

  if (!output.getVectorComplexDouble().almostEqual(expected_cdb)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
  }

  /*
    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  scalar division (2):\n");
    }
  
    a.clear(Integral::RETAIN);
    a.setDiagonal(complexdouble(6.0, 6.0));
  
    input(0).makeMatrixComplexDouble().assign(a);
    input(1).makeVectorComplexDouble().assign(L"2.0+3.0j");

    b.clear(Integral::RETAIN);
    b.setDiagonal(complexdouble(2.30769, -0.4615));

    math7.compute(output, input);

    if (!output.getMatrixComplexDouble().almostEqual(b)) {
    output.debug(L"output");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    if (level_a > Integral::BRIEF) {
    Console::put(L"\n\ttesting  mag/real/imag function:\n");
    }

    math7.clear();
    input.setLength(1);
    input(0).makeVectorComplexDouble().assign(L"3 + 4j, 4 + 5j, 6 + 7j");

    values.setLength(1);
    values_op.setLength(1);
    values(0).assign((long)MAG);
    values_op(0).assign((long)ASSIGN);
    math7.setNumOperands(1);
    math7.setOperation(values_op);
    math7.setFunction(values);

    math7.setConstant(0.0);
  
    math7.compute(output, input);

    VectorDouble expected_vf;
    expected_vf.assign(L"5, 6.40312, 9.21954");
    if (!output.getVectorDouble().almostEqual(expected_vf)) {
    math7.debug(L"math");
    output.debug(L"output");
    expected_vf.debug(L"expected_vf");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    values(0).assign((long)IMAG);
    math7.setFunction(values);

    math7.compute(output, input);

    expected_vf.assign(L"4, 5, 7");
    if (!output.getVectorDouble().almostEqual(expected_vf)) {
    math7.debug(L"math");
    output.debug(L"output");
    expected_vf.debug(L"expected_vf");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }

    values.clear();
    values.setLength(1);
    values(0).assign((long)REAL);
    math7.setFunction(values);

    output.clear();
    math7.compute(output, input);

    expected_vf.assign(L"3, 4, 6");
    if (!output.getVectorDouble().almostEqual(expected_vf)) {
    math7.debug(L"math");
    output.debug(L"output");
    expected_vf.debug(L"expected_vf");
    return Error::handle(name(), L"compute", Error::TEST, __FILE__, __LINE__);
    }
  */
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //--------------------------------------------------------------------
  //
  // 7. print completion message
  //
  //--------------------------------------------------------------------

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  if (level_a > Integral::NONE) {
    String output(L"diagnostics passed for class ");
    output.concat(name());
    output.concat(L"\n");
    Console::put(output);
  }
  
  // exit gracefully
  //
  return true;
}
