// file: $isip_ifc/class/algo/Generator/gen_02.cc
// version: $Id: gen_02.cc 10391 2006-01-25 03:32:38Z prasad $
//

// isip include files
//
#include "Generator.h"
#include <VectorFloat.h>
#include <MatrixFloat.h>
#include <String.h>
#include <Console.h>
#include <Float.h>

// method: diagnose
//
// arguments:
//  Integral::DEBUG level: (input) debug level for diagnostics
//
// return: logical error status
//
// this is the diagnostics method
//
//  level               function
//
//  NONE                test nothing
//  BRIEF               fully test functionality, no output
//  DETAILED            fully test functionality, stub output
//  ALL                fully test functionality, full output
//
boolean Generator::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();
  }
  
  Generator gen0;
  Generator gen1(gen0);

  if (!gen1.eq(gen0)) {
    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
    //
    Generator::setGrowSize((long)500);

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

  // 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();
  }
  
  Generator gen2;
  Generator gen3;
  Generator gen4;
  gen2.setAlgorithm(GAUSSIAN);
  gen2.setComputeMode(ACCUMULATE);
  float mean0 = 1.5;
  float variance0 = 2.0;
  gen2.setGaussian(mean0, variance0);

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

  gen2.write(tmp_file0, (long)0);
  gen2.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
  // 
  gen3.read(tmp_file0, (long)0);
  if (!gen3.eq(gen2)) {
    gen3.debug(L"gen3");
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }

  gen4.read(tmp_file1, (long)0);
  if (!gen4.eq(gen2)) {
    gen4.debug(L"gen4");
    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();
  }
  
  //--------------------------------------------------------------------------
  //
  // 3. 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();
  }

  // declare an object
  //
  Generator gen5;

  // set the parameters manually
  //
  double sample_freq0 = 600.0;
  double sample_freq1;
  gen5.setSampleFrequency(sample_freq0);
  sample_freq1 = gen5.getSampleFrequency();
  double frame_duration0 = 1.0;
  double frame_duration1;
  gen5.setFrameDuration(frame_duration0);
  frame_duration1 = gen5.getFrameDuration();
  float freq0 = 100.0;
  float freq1;
  gen5.setFrequency(freq0);
  freq1 = gen5.getFrequency();
  float amp0 = 2.0;
  float amp1;
  gen5.setAmplitude(amp0);
  amp1 = gen5.getAmplitude();
  
  if (sample_freq0 != sample_freq1) {
    return Error::handle(name(), L"setSampleFrequency", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (frame_duration0 != frame_duration1) {
    return Error::handle(name(), L"setFrameDuration", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (freq0 != freq1) {
    return Error::handle(name(), L"setFrequency", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (amp0 != amp1) {
    return Error::handle(name(), L"setFrequency", Error::TEST,
                         __FILE__, __LINE__);
  }

  // declare an object
  //
  Generator gen6;

  // set the parameters manually
  //
  float mean1 = 1.2;
  float mean2;
  gen6.setAlgorithm(GAUSSIAN);
  gen6.setComputeMode(ACCUMULATE);
  gen6.setMean(mean1);
  mean2 = gen6.getMean();
  float var0 = 0.8;
  float var1;
  gen6.setVariance(var0);
  var1 = gen6.getVariance();

  
  if (mean1 != mean2) {
    return Error::handle(name(), L"setMean", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (var0 != var1) {
    return Error::handle(name(), L"setVariance", Error::TEST,
                         __FILE__, __LINE__);
  }

  // declare the object
  //
  Generator gen7;

  // set the parameters manually
  //
  float val0 = 50.0;
  float val1;
  gen7.setAlgorithm(PULSE);
  gen7.setComputeMode(ACCUMULATE);
  val1 = gen7.getDutyCycle();
  float phase0 = (-22.0) / (2 * 7.0);
  float phase1, phase2;
  gen7.setPhase(phase0);
  phase1 = gen7.getPhase();
  gen7.setPhaseMode(RANDOM);
  gen7.setSeed(800);
  gen7.setPhase(phase0);
  phase2 = gen7.getPhase();
  float bias0 = 0;
  float bias1;
  gen7.setBias(bias0);
  bias1 = gen7.getBias();
  
  if (val0 != val1) {
    return Error::handle(name(), L"setDutyCycle", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (phase0 != phase1) {
    return Error::handle(name(), L"setPhase", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (gen7.getPhaseMode() != RANDOM) {
    return Error::handle(name(), L"setPhaseMode", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (bias0 != bias1) {
    return Error::handle(name(), L"setBias", Error::TEST,
                         __FILE__, __LINE__);
  }
  else if (gen7.getAlgorithm() != PULSE) {
    return Error::handle(name(), L"setAlgorithm", Error::TEST,
                         __FILE__, __LINE__);
  }

  // declare an object
  //
  Generator gen8;

  // set the parameters manually
  //
  float freq2;
  float amp2;
  gen8.setSine(freq0, amp0, phase0, bias0);
  gen8.setComputeMode(ACCUMULATE);
  freq2 = gen8.getFrequency();
  amp2 = gen8.getAmplitude();

  if ((freq2 != freq0) || (amp2 != amp0)) {
    return Error::handle(name(), L"setSine", Error::TEST,
                         __FILE__, __LINE__);
  }

  // declare an object
  //
  Generator gen9;

  // set the parameters manually
  //
  float mean3;
  float var2;
  gen9.setAlgorithm(GAUSSIAN);
  gen9.setComputeMode(ACCUMULATE); 
  gen9.setGaussian(mean1, var0);
  mean3 = gen9.getMean();
  var2 = gen9.getVariance();

  if ((mean2 != mean1) || (var2 != var0)) {
    return Error::handle(name(), L"setGaussian", Error::TEST,
                         __FILE__, __LINE__);
  }

  // declare an object
  //
  Generator gen10;

  // set the parameters manually
  //
  float freq4;
  float amp4;
  float val2;
  gen10.setAlgorithm(TRIANGLE);
  gen10.setComputeMode(ACCUMULATE);
  gen10.setTriangle(freq0, amp0, phase0, val0, bias0);
  freq4 = gen10.getFrequency();
  amp4 = gen10.getAmplitude();
  val2 = gen10.getDutyCycle();
  
  if ((freq4 != freq0) || (amp4 != amp0) || (val2 != val0)) {
    return Error::handle(name(), L"setTriangle", Error::TEST,
                         __FILE__, __LINE__);
  }

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

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

  // test SINE algorithm with sample_frequency = 40, frame_duration = 0.5
  // signal_duration = 1, amplitude = 1, frequency = 2, phase = 0.0,
  // bias = 0.0.
  // 
  Generator gen11;
  Vector< CircularBuffer<AlgorithmData> > in;
  Vector<AlgorithmData> out;
  AlgorithmData data;  
  gen11.setChannel(2);
  out.setLength(2);
  VectorFloat output;
  VectorFloat input;
  VectorFloat ans;
  Vector<VectorFloat> result;
  result.setLength(2);

  // set parameters for computing sine signal samples 
  //
  gen11.setAlgorithm(SINE);
  gen11.setComputeMode(ACCUMULATE);
  gen11.setSampleFrequency(40);
  gen11.setGenSampleFrequency(40);
  gen11.setFrameDuration(0.5);
  gen11.setSignalDuration(1);
  gen11.setAmplitude(1);
  gen11.setFrequency(2);
  gen11.setPhase(0);
  gen11.setBias(0); 
  Vector<Long> temAccumFrame;
  temAccumFrame.setLength(2);
  gen11.setAccumFrame(temAccumFrame);

  // compare out with correct result
  //
  result(0).assign(L"0.0, 0.309017, 0.587785, 0.809017, 0.951057, 1, 0.951057, 0.809017, 0.587785, 0.309017, -0, -0.309017, -0.587785, -0.809017, -0.951507, -1, -0.951057, -0.809017, -0.587785, -0.309017");
  result(1).assign(L"0.0, 0.309017, 0.587785, 0.809017, 0.951057, 1, 0.951057, 0.809017, 0.587785, 0.309017, -0, -0.309017, -0.587785, -0.809017, -0.951507, -1, -0.951057, -0.809017, -0.587785, -0.309017");
  for (long i = 0; i < 2; i++) {
    gen11.apply(out, in);
    for (long k = 0; k < 2; k++) {
      if (!result(i).almostEqual(out(k).getVectorFloat())) {
	result(k).debug(L"expected result");
	out(k).debug(L"sine output");
	return Error::handle(name(), L"compute", Error::TEST,
			     __FILE__, __LINE__);
      }
    }
  }
  
  // test PULSE algorithm with sample_frequency = 40, frame_duration = 0.5
  // signal_duration = 0.5, amplitude = 1, frequency = 2, phase = 0.0,
  // bias = 0.0.
  //
  Generator gen12;

  // set parameters for computing pulse signal samples 
  //
  gen12.setAlgorithm(PULSE);
  gen12.setComputeMode(ACCUMULATE);
  Vector<Long> temAccumFrame1;
  temAccumFrame1.setLength(1);
  gen12.setAccumFrame(temAccumFrame1);
  gen12.setSampleFrequency(40);
  gen12.setGenSampleFrequency(40);
  gen12.setAmplitude(1);
  gen12.setFrequency(2);
  gen12.setSignalDuration(0.5);
  gen12.setFrameDuration(0.5);
  gen12.setPhase(0);
  gen12.setBias(0);
  gen12.setDutyCycle(50);
  
  // compare out with correct result
  //
  gen12.compute(output, input);
  ans.assign(L"1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0");

  if (!ans.almostEqual(output)) {
    ans.debug(L"expected result");
    output.debug(L"pulse output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }
  
  // test SQUARE algorithm with sample_frequency = 40, frame_duration = 0.5
  // signal_duration = 1, amplitude = 1, frequency = 2, phase = 0.0,
  // bias = 0.0, duty_cycle = 50.
  //
  Generator gen13;
  
  // set parameters for computing square signal samples 
  //  
  gen13.setAlgorithm(SQUARE);
  gen13.setComputeMode(ACCUMULATE);
  Vector<Long> temAccumFrame2;
  temAccumFrame2.setLength(1);
  gen13.setAccumFrame(temAccumFrame2);
  gen13.setSampleFrequency(40);
  gen13.setGenSampleFrequency(40);  
  gen13.setAmplitude(1);
  gen13.setFrequency(2);
  gen13.setSignalDuration(1);
  gen13.setFrameDuration(0.5);
  gen13.setPhase(0.0);
  gen13.setBias(0);
  gen13.setDutyCycle(50);
  
  // compare out with correct result
  //
  gen13.compute(output, input);
  ans.assign(L"0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5");

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

  // test TRIANGLE algorithm with sample_frequency = 40, frame_duration = 0.5
  // signal_duration = 0.5, amplitude = 1, frequency = 2, phase = 0.25 PI,
  // bias = 0.0, duty_cycle = 50.
  //
  Generator gen14;

  // set parameters for computing triangle signal samples 
  //
  gen14.setAlgorithm(TRIANGLE);
  gen14.setComputeMode(ACCUMULATE);
  Vector<Long> temAccumFrame3;
  temAccumFrame3.setLength(1);
  gen14.setAccumFrame(temAccumFrame3);
  gen14.setSampleFrequency(40);
  gen14.setGenSampleFrequency(40);    
  gen14.setAmplitude(1);
  gen14.setFrequency(2);
  gen14.setSignalDuration(0.5);
  gen14.setFrameDuration(0.5); 
  gen14.setPhase(0.25 * Integral::PI);
  gen14.setBias(0);
  gen14.setDutyCycle(50);

  // compare out with correct result
  //
  gen14.compute(output, input);
  ans.assign(L"0.6, 0.8, 1, 0.8, 0.6, 0.4, 0.2, 0, -0.2, -0.4, -0.6, -0.8, -1.0, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4");
  if (!ans.almostEqual(output)) {
    ans.debug(L"expected result");
    output.debug(L"triangle output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  // test GAUSSIAN algorithm with sample_frequency = 40, frame_duration = 1,
  // signal_duration = 1, mean = 1.5, variance = -0.5
  //
  Generator gen15;
  VectorFloat in15;
  VectorFloat out15;
  VectorFloat ans15;

  // set parameters for computing gaussian signal samples 
  //
  gen15.setAlgorithm(GAUSSIAN);
  gen15.setComputeMode(ACCUMULATE);
  gen15.setMean(1.5);
  gen15.setSampleFrequency(40);
  gen15.setGenSampleFrequency(40);
  gen15.setSignalDuration(1);
  gen15.setFrameDuration(1);
  gen15.setVariance(-0.5);
  gen15.setSeed(80);
  
  // compare out with correct result
  //
  gen15.compute(out15, in15);
  ans15.assign(L"0.910724, 0.952605, 1.43932, 1.33778, 2.2354, 1.19658, 1.04011, 1.82564, 1.52397, 1.78422, 1.57108, 0.904335, 2.51376, 1.23344, 1.86863, 1.85403, 1.58034, 1.21719, 1.20197, 1.3536, 1.2777, 0.802797, 1.5905, 2.50756, 0.990713, 1.67548, 1.68828, 1.29188, 2.12157, 1.52868, 1.33, 1.94327, 2.46537, 0.304354, 1.40373, 1.10345, 1.26428, 0.613523, 1.31932, 1.74106");
  if (!ans15.almostEqual(out15)) {
    ans15.debug(L"expected result");
    out15.debug(L"GAUSSIAN output");
    return Error::handle(name(), L"compute", Error::TEST,
                         __FILE__, __LINE__);
  }

  // test SINE algorithm with sample_frequency = 8000, frame_duration = 0.01
  // signal_duration = 0.01, amplitude = 1000, frequency = 200, random phase,
  // bias = 0.0.
  //   
  Generator gen16;

  // set parameters for computing sine signal samples 
  //
  gen16.setAlgorithm(SINE);
  gen16.setComputeMode(ACCUMULATE);
  gen16.setPhaseMode(RANDOM);
  Vector<Long> temAccumFrame4;
  temAccumFrame4.setLength(1);
  gen16.setAccumFrame(temAccumFrame4);
  gen16.setSampleFrequency(8000);
  gen16.setGenSampleFrequency(8000);
  gen16.setAmplitude(1000);
  gen16.setFrequency(200);
  gen16.setSignalDuration(0.01);
  gen16.setFrameDuration(0.01);
  gen16.setSeed(80); 
  gen16.setPhase();
  gen16.setBias(0);

  // As the phase is random, we cannot get expected result.
  // Therefore, ignore comparing out with correct result.
  //
  gen16.compute(output, input);

  // Test the Lorentz and Rossler Chaotic series Generation
  //
  Generator gen17;

  // Check for various set and get methods
  //
  float chaos_check_a, chaos_check_b, chaos_check_c;
  float chaos_check_x0, chaos_check_y0, chaos_check_z0;
  long chaos_check_integrate_upsample;
  
  gen17.setChaosParams((float)0.5, (float)0.7, (float)0.9);
  gen17.setChaosInitialValues((float)0.1, (float)0.2, (float)0.3);
  gen17.setChaosIntegrateUpsample((long)10);
  chaos_check_a = gen17.getChaosA();
  chaos_check_b = gen17.getChaosB();
  chaos_check_c = gen17.getChaosC();
  chaos_check_x0 = gen17.getChaosX0();
  chaos_check_y0 = gen17.getChaosY0();
  chaos_check_z0 = gen17.getChaosZ0();
  chaos_check_integrate_upsample = gen17.getChaosIntegrationUpsample();  
  
  if ((chaos_check_a != (float)0.5) || (chaos_check_b != (float)0.7)
      || (chaos_check_c != (float)0.9) || (chaos_check_x0 != (float)0.1)
      || (chaos_check_y0 != (float)0.2) || (chaos_check_z0 != (float)0.3)
      || (chaos_check_integrate_upsample != (long)10)) {
    return Error::handle(name(), L"setChaosParams", Error::TEST,
			 __FILE__, __LINE__);
  }

  // Testing the Lorentz time series generated by computeLorentz
  // The system parameters are: 0.15, 0.2, 10
  // The initial conditions are: 0.5, 0.5, 0.5
  //
  Generator gen18;
  VectorFloat test_generation, dummy, test_expected;
  gen18.set(Generator::LORENTZ);
  gen18.setSampleFrequency((float)100);
  gen18.setGenSampleFrequency((float)100);
  gen18.setSignalDuration(1);
  gen18.setFrameDuration(1);
  gen18.setLorentz((float)0.15, (float)0.2, (float)10, (float)0.5, (float)0.5 , (float)0.5, (long)1);
  gen18.compute(test_generation, dummy);
  test_expected.assign(L"0.499996, 0.499982, 0.49996, 0.499928, 0.499889, 0.499842, 0.499787, 0.499725, 0.499656, 0.49958, 0.499498, 0.499409, 0.499314, 0.499213, 0.499106, 0.498993, 0.498875, 0.498751, 0.498622, 0.498488, 0.498349, 0.498205, 0.498056, 0.497902, 0.497744, 0.497581, 0.497414, 0.497242, 0.497066, 0.496885, 0.4967, 0.496512, 0.496319, 0.496122, 0.495921, 0.495717, 0.495508, 0.495296, 0.49508, 0.49486, 0.494637, 0.494411, 0.49418, 0.493947, 0.49371, 0.493469, 0.493226, 0.492979, 0.492728, 0.492475, 0.492218, 0.491959, 0.491696, 0.491431, 0.491162, 0.49089, 0.490616, 0.490339, 0.490059, 0.489776, 0.48949, 0.489202, 0.488911, 0.488617, 0.488321, 0.488022, 0.487721, 0.487417, 0.487111, 0.486803, 0.486492, 0.486178, 0.485862, 0.485544, 0.485224, 0.484902, 0.484577, 0.48425, 0.483921, 0.48359, 0.483256, 0.482921, 0.482584, 0.482245, 0.481903, 0.48156, 0.481215, 0.480868, 0.480519, 0.480168, 0.479816, 0.479461, 0.479105, 0.478747, 0.478388, 0.478027, 0.477664, 0.477299, 0.476933, 0.476565");

  if (!test_generation.almostEqual(test_expected)) {
    test_expected.debug(L"expected result");
    test_generation.debug(L"LORENTZ output");
    return Error::handle(name(), L"computeLorentz", Error::TEST,
                         __FILE__, __LINE__);
  }

  // Testing the Rossler time series generated by computeRossler
  // The system parameters are: 0.15, 0.2, 10
  // The initial conditions are: 0.5, 0.5, 0.5
  //
  Generator gen19;
  gen19.set(Generator::ROSSLER);
  gen19.setSampleFrequency((float)100);
  gen19.setGenSampleFrequency((float)100);
  gen19.setSignalDuration(1);
  gen19.setFrameDuration(1);
  gen19.setRossler((float)0.15, (float)0.2, (float)10, (float)0.5, (float)0.5 , (float)0.5, (long)1);
  gen19.compute(test_generation, dummy);
  test_expected.assign(L"0.490172, 0.480706, 0.471565, 0.462716, 0.454127, 0.445772, 0.437624, 0.429661, 0.421863, 0.41421, 0.406685, 0.399273, 0.391959, 0.384731, 0.377578, 0.370488, 0.363453, 0.356463, 0.349512, 0.342592, 0.335696, 0.32882, 0.321959, 0.315107, 0.30826, 0.301416, 0.29457, 0.28772, 0.280863, 0.273998, 0.267121, 0.260232, 0.253328, 0.246408, 0.239472, 0.232518, 0.225545, 0.218553, 0.211541, 0.204509, 0.197455, 0.190381, 0.183286, 0.17617, 0.169032, 0.161873, 0.154693, 0.147493, 0.140271, 0.13303, 0.125768, 0.118486, 0.111185, 0.103865, 0.0965268, 0.0891704, 0.0817965, 0.0744055, 0.066998, 0.0595747, 0.052136, 0.0446825, 0.0372149, 0.0297337, 0.0222397, 0.0147334, 0.00721543, -0.000313443, -0.00785259, -0.0154013, -0.022959, -0.0305248, -0.0380982, -0.0456784, -0.0532647, -0.0608563, -0.0684527, -0.0760529, -0.0836564, -0.0912623, -0.0988699, -0.106479, -0.114087, -0.121696, -0.129303, -0.136908, -0.14451, -0.152109, -0.159704, -0.167294, -0.174877, -0.182455, -0.190025, -0.197587, -0.20514, -0.212683, -0.220216, -0.227738, -0.235248, -0.242746");

  if (!test_generation.almostEqual(test_expected)) {
    test_expected.debug(L"expected result");
    test_generation.debug(L"ROSSLER output");
    return Error::handle(name(), L"computeRossler", Error::TEST,
                         __FILE__, __LINE__);
  }
 
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //--------------------------------------------------------------------------
  //
  // 5. 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;
}
