// file: $isip_ifc/class/algo/Rps/rps_02.cc
// version: $Id: rps_02.cc 10484 2006-03-14 23:50:33Z srinivas $
//

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

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

  boolean Rps::diagnose(Integral::DEBUG level_a) {
  
  //---------------------------------------------------------------------------
  //
  // 0. preliminaries
  //
  //---------------------------------------------------------------------------

  // output the class name
  //
  if (level_a > Integral::NONE) {
    SysString 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();
  }

  Rps rps_1(DEF_ALGORITHM, DEF_IMPLEMENTATION, (long)4, (long)1, (float)0.01);
  Rps rps_2(rps_1);
  
  if (!rps_2.eq(rps_1)) {
    return Error::handle(name(), L"copy constructor/eq", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // testing large chunk of memory allocation
  //
  Rps::setGrowSize((long)500);

  for (long j = 1; j <= 10; j++) {
    Rps** dyn_rps = new Rps*[j * 100];
    
    // create the objects
    //
    for (long i = 0; i < j * 100; i++) {
      dyn_rps[i] = new Rps();
    }
    
    // delete objects
    //
    for (long i = (j * 100) - 1; i >= 0; i--) {
      delete dyn_rps[i];
    }
      
    delete [] dyn_rps;
  } 
  
  // test the i/o methods
  //
  Rps rps_3(DEF_ALGORITHM, DEF_IMPLEMENTATION, (long)5, (long)6, (float)0.1);
  Rps rps_4;
  Rps rps_5;

  // 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 mode
  //
  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);

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

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

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

  // read the value back
  //
  if (!rps_4.read(tmp_file0, (long)0) || !rps_4.eq(rps_3)) {
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }
  
  if (!rps_5.read(tmp_file1, (long)0) || !rps_5.eq(rps_3)) {
    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();
  }
  
  // set and get the embedding dimension
  //
  Rps rps_6;
  rps_6.setEmbedDimension((long)4);
  if (rps_6.getEmbedDimension() != (long)4) {
    return Error::handle(name(), L"set /get embedding dimension", Error::TEST,
			 __FILE__, __LINE__);
  }

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

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: computation methods...\n");
    Console::increaseIndention();
  }
  
  // setup variables for test
  //
  float samp_freq = 100.00;
  rps_6.setSampleFrequency(samp_freq);
  VectorFloat zeros(L"0,0,0,0,0, 0,0"); // 7 zeros
  long embed_dimension_zeros = 2;
  float delay_zeros = 3.0 / samp_freq;
  long svd_window_size_zeros = 3;
  MatrixFloat result_zeros_1(4, 2, L"0,0, 0,0, 0,0, 0,0");
  MatrixFloat result_zeros_2(5, 2, L"0,0, 0,0, 0,0, 0,0, 0,0");

  VectorFloat ones(L"1,1,1,1, 1,1,1,1, 1"); //9 ones
  long embed_dimension_ones = 2;
  float delay_ones = 2.0 / samp_freq;
  long svd_window_size_ones = 4;
  MatrixFloat result_ones_1(7, 2, L"1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1");
  MatrixFloat result_ones_2(6, 2, L"-2,0, -2,0, -2,0, -2,0, -2,0, -2,0");

  VectorFloat general(L"51, 46, 48, 44, 32, 55"); // 6 values
  long embed_dimension_general = 3;
  float delay_general = 1.0 / samp_freq;
  long svd_window_size_general = 5;
  MatrixFloat result_general_1(4, 3, L"51,46,48, 46,48,44, 48,44,32, 44,32,55");
  MatrixFloat result_general_2(2, 3, L"-98.9889,-13.4982,0, -101.146,13.2104,0");

  MatrixFloat out_rps;

  // case: Algorithm = TIME_DELAY_EMBEDDING, Implementation = EMBEDDING,
  //       Input = zero SIGNAL vector
  //
  rps_6.setEmbedDimension(embed_dimension_zeros);
  rps_6.setDelay(delay_zeros);
  rps_6.compute(out_rps, zeros);
  out_rps.setDimensions(out_rps.getNumRows(), out_rps.getNumColumns()-1, true);
  
  if (!out_rps.almostEqual(result_zeros_1)) {
    return  Error::handle(name(), L"apply compute from time delay embedding", ERR,
			  __FILE__, __LINE__);
  }

  // case: Algorithm = TIME_DELAY_EMBEDDING, Implementation = EMBEDDING,
  //       Input = SIGNAL vector of ones
  //
  rps_6.setEmbedDimension(embed_dimension_ones);
  rps_6.setDelay(delay_ones);
  rps_6.compute(out_rps, ones);
  out_rps.setDimensions(out_rps.getNumRows(), out_rps.getNumColumns() - 1, true);
  
  if (!out_rps.almostEqual(result_ones_1)) {
    return  Error::handle(name(), L"apply compute from time delay embedding", ERR,
			  __FILE__, __LINE__);
  }

  // case: Algorithm = TIME_DELAY_EMBEDDING, Implementation = EMBEDDING,
  //       Input = non-zero SIGNAL vector
  //
  rps_6.setEmbedDimension(embed_dimension_general);
  rps_6.setDelay(delay_general);
  rps_6.compute(out_rps, general);
  out_rps.setDimensions(out_rps.getNumRows(), out_rps.getNumColumns() - 1, true);
  
  if (!out_rps.almostEqual(result_general_1)) {
    return  Error::handle(name(), L"apply compute from time delay embedding", ERR,
			  __FILE__, __LINE__);
  }

  // case: Algorithm = SVD_EMBEDDING, Implementation = EMBEDDING,
  //
  rps_6.setAlgorithm(Rps::SVD_EMBEDDING);

  // case: Algorithm = SVD_EMBEDDING, Implementation = EMBEDDING,
  //       Input = zero SIGNAL vector
  //
  rps_6.setEmbedDimension(embed_dimension_zeros);
  rps_6.setDelay((float)1.0 / samp_freq);
  rps_6.setSVDWindowSize(svd_window_size_zeros);
  rps_6.compute(out_rps, zeros);
  out_rps.setDimensions(out_rps.getNumRows(), out_rps.getNumColumns() - 1, true);
  if (!out_rps.almostEqual(result_zeros_2)) {
    return  Error::handle(name(), L"apply compute from SVD embedding", ERR,
    		    __FILE__, __LINE__);
  }

  // case: Algorithm = SVD_EMBEDDING, Implementation = EMBEDDING,
  //       Input = SIGNAL vector of ones
  //
  rps_6.setEmbedDimension(embed_dimension_ones);
  rps_6.setDelay((float)1.0 / samp_freq);
  rps_6.setSVDWindowSize(svd_window_size_ones);
  rps_6.compute(out_rps, ones);
  out_rps.setDimensions(out_rps.getNumRows(), out_rps.getNumColumns() - 1, true);
  if (!out_rps.almostEqual(result_ones_2)) {
    return  Error::handle(name(), L"apply compute from SVD embedding", ERR,
			  __FILE__, __LINE__);
  }

  // case: Algorithm = SVD_EMBEDDING, Implementation = EMBEDDING,
  //       Input = non-zero SIGNAL vector
  //
  rps_6.setEmbedDimension(embed_dimension_general);
  rps_6.setDelay((float)1.0 / samp_freq);
  rps_6.setSVDWindowSize(svd_window_size_general);
  rps_6.compute(out_rps, general);

  out_rps.setDimensions(out_rps.getNumRows(), out_rps.getNumColumns() - 1, true);
  if (!out_rps.almostEqual(result_general_2)) {
    out_rps.debug(L"out_rps");
    result_general_2.debug(L"result_general_2");
    return  Error::handle(name(), L"apply compute from SVD embedding", ERR,
			  __FILE__, __LINE__);
  }
    
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }


  //---------------------------------------------------------------------------
  //
  // 4. print completion message
  //
  //---------------------------------------------------------------------------

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  if (level_a > Integral::NONE) {
    SysString output(L"diagnostics passed for class ");
    output.concat(name());
    output.concat(L"\n");
    Console::put(output);
  }

  // exit gracefully
  //
  return true;
}
