// file: $isip_ifc/class/pr/RelevanceVectorMachine/rvm_02.cc
// version: $Id: rvm_02.cc 10424 2006-02-10 20:37:45Z raghavan $
//

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

// method: diagnose
//
// arguments:
//  Integral::DEBUG level: (input) debug level for diagnostics
//
// return: a boolean value indicating status
//
// this is the diagnose method
//
boolean RelevanceVectorMachine::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
  //     class constructors
  //
  //--------------------------------------------------------------------------

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

  RelevanceVectorMachine rvm1(rvm0);
  
  if (!rvm1.eq(rvm0)) {
    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
    //
    
    RelevanceVectorMachine::setGrowSize((long)500);
    
    RelevanceVectorMachine* prvm = new RelevanceVectorMachine();

    for (long j = 1; j <= 100; j++) {
      RelevanceVectorMachine** prvms = new RelevanceVectorMachine*[j * 100];
      
      // create the objects
      //
    for (long i = 0; i < j * 100; i++) {
      prvms[i] = new RelevanceVectorMachine();
    }
    
    // delete objects
    //
    for (long i = (j * 100) - 1; i >= 0; i--) {
      delete prvms[i];
    }
    
    delete [] prvms;
    } 
    
    delete prvm;
  }

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //--------------------------------------------------------------------------
  //
  // 2. required public methods
  //     i/o methods 
  //
  //--------------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing required public methods: i/o methods...\n");
    Console::increaseIndention();
  }
  
  // declare a kernel to be stored with the object
  //
  Kernel rvm_kern(Kernel::RBF);
  Vector<VectorFloat> vecs0(3);
  for (long i = 0; i < 3; i++) {
    vecs0(i).setLength(3);
    vecs0(i).rand();
  }
  VectorByte targets0(3);
  targets0.rand();
  VectorFloat weights(3);
  weights.ramp(0, 1);
  rvm0.weights_d.assign(weights);
  rvm0.targets_d.assign(targets0);
  rvm0.vectors_d.assign(vecs0);
  rvm0.bias_d = 0.975;
  VectorFloat constants(1);
  constants(0).assign(2.5);
  rvm_kern.setConstants(constants);
  rvm0.setKernel(rvm_kern);

  // 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);
  
  rvm0.write(tmp_file0, (long)0);
  
  // close the files
  //
  tmp_file0.close();
  
  // open the files in read mode
  //
  tmp_file0.open(tmp_filename0);
  
  // read the object back
  //
  rvm1.clear();
  rvm1.read(tmp_file0, (long)0);

  rvm1.clear();  
  
  // close and delete the temporary files
  //
  tmp_file0.close();
  File::remove(tmp_filename0);
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //--------------------------------------------------------------------------
  //
  // 3. class-specific public methods
  //
  //--------------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing training methods...");
    Console::increaseIndention();
  }
  
  RelevanceVectorMachine rvm_full;
  VectorFloat x(50);
  x.grand(0, 0.01);
  VectorFloat y(50);
  y.grand(1, 0.01);
  VectorFloat tmp(2);
  rvm_full.in_class_data_d.setLength(50);
  rvm_full.out_class_data_d.setLength(50);
  
  long  j = 0;
  for (long i = 0; i < 50; i++) {
    tmp(0) = x(j);
    tmp(1) = x(j);
    rvm_full.in_class_data_d(i).assign(tmp);
    j++;
  }
  j = 0;
  for (long i = 0; i < 50; i++) {
    tmp(0) = x(j);
    tmp(1) = y(j);
    rvm_full.out_class_data_d(i).assign(tmp);
    j++;
  }
  
  rvm_kern.setAlgorithm(Kernel::RBF);
  constants.setLength(1);
  constants(0).assign(0.5);
  rvm_kern.setConstants(constants);
  rvm_full.setKernel(rvm_kern);
  RVMTrainData tdata_full;
  tdata_full.alpha_thresh_d = 1e4;
  tdata_full.max_rvm_its_d = 1000;
  tdata_full.subset_size_d = 20;
  tdata_full.min_allowed_weight_d = 1e-12;
  rvm_full.setDebug(Integral::BRIEF);
  rvm_full.train(tdata_full, ITERATIVE_REFINEMENT);

  if (level_a > Integral::NONE) {
    VectorFloat tp;
    Float to;
    float output = 0;
    tp.assign(L"0.0,0.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    tp.assign(L"0.0,1.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    tp.assign(L"1.0,0.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    tp.assign(L"1.0,1.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    
    tp.assign(L"-400.0,0.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    
    tp.assign(L"400.0,0.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    
    tp.assign(L"0.0, -400.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    
    tp.assign(L"0.0, 400.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    
    tp.assign(L"0.25,0.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    
    tp.assign(L"0.5,0.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
    
    tp.assign(L"0.75,0.0");
    rvm_full.evaluate(output, tp);
    to = output;
    tp.debug(L"tp");
    to.debug(L"to");
  }
  
  // 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;
}
