/*********************************/
/* Application Test Routine      */
/*                               */
/* Version 2.0 math_matrix       */
/* author: Patrick Theobald (PT) */
/*********************************/

#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <fstream.h>
#include <LiDIA:bigint.h>
#include <LiDIA:bigmod.h>
#include <LiDIA:bigrational.h>
#include <LiDIA:bigfloat.h>
#include <LiDIA:bigcomplex.h>
#include <LiDIA:math_matrix.h>
#else
#include <fstream.h>
#include <LiDIA/bigint.h>
#include <LiDIA/bigmod.h>
#include <LiDIA/bigrational.h>
#include <LiDIA/bigfloat.h>
#include <LiDIA/bigcomplex.h>
#include <LiDIA/math_matrix.h>
#endif

main()
{
  ifstream in(IN_NAME);
  ofstream dz(OUT_NAME);

  register int i, j;

  /* pointer */
  TYPE *pointer_1 = NULL;
  TYPE *pointer_2 = NULL;
  TYPE *pointer_3 = new TYPE[4];
  TYPE *pointer_4 = new TYPE[6];
  TYPE *pointer_5 = new TYPE[4];
  TYPE *pointer_6 = new TYPE[6];

  /* vectors */
  math_vector < TYPE > v1, v2;
  math_vector < TYPE > v3(4, 4);
  math_vector < TYPE > v4(6, 6);
  
  /* scalar */
  TYPE scalar_1, scalar_2, scalar_3;
  in >> scalar_2 ;
  //cout << scalar_2 << flush;
  in >> scalar_3;
  //cout << scalar_2 << scalar_3 << flush;
  lidia_size_t r,c;

  /* array */
  TYPE **wertearray = new TYPE *[2];
  for (i = 0; i < 2; i++)
    {
      wertearray[i] = new TYPE[3];
      for (j = 0; j < 3; j++)
	{
	  in >> wertearray[i][j];
	  //cout << wertearray[i][j] << flush;
	}
    }
  
  cout << "**********************************************************" << endl;
  cout << "***             Test for class math_matrix             ***" << endl;
  cout << "***                     Version 2.0                    ***" << endl;
  cout << "**********************************************************" << endl;
  cout.flush();

  cout << "\ntesting constructors" << flush;
  dz << "testing constructor" << endl << flush;
  math_matrix < TYPE > A(3, 1);
  math_matrix < TYPE > B(2, 3);
  math_matrix < TYPE > C(2, 3, (const TYPE **)wertearray);
  math_matrix < TYPE > D(C);
  math_matrix < TYPE > E = C;
  math_matrix < TYPE > F = C;
  // dz << A << B << C << D << E << F << flush;
  cout << ".............................completed" << endl << flush;

  A.read_from_stream(in);
  B.read_from_stream(in);
  C.read_from_stream(in);
  
  cout << "testing set_print_mode" << flush;
  dz << "testing set_print_mode" << endl << flush;
  dz << " set A BEAUTY_MODE" << endl << flush;
  A.set_print_mode(BEAUTY_MODE);
  dz << " set B LIDIA_MODE" << endl << flush;
  B.set_print_mode(LIDIA_MODE);
  dz << " set C GP_MODE" << endl << flush;
  C.set_print_mode(GP_MODE);
  dz << " set D MAPLE_MODE" << endl << flush;
  D.set_print_mode(MAPLE_MODE);
  dz << " set E MATHEMATICA_MODE" << endl << flush;
  E.set_print_mode(MATHEMATICA_MODE);
  dz << " set E KASH_MODE" << endl << flush;
  E.set_print_mode(KASH_MODE);
  cout << "...........................completed" << endl << flush;
  
  cout << "testing get_print_mode" << flush;
  dz << "testing get_print_mode" << endl << flush;
  dz << A.get_print_mode() << endl << flush;
  dz << B.get_print_mode() << endl << flush;
  dz << C.get_print_mode() << endl << flush;
  dz << D.get_print_mode() << endl << flush;
  dz << E.get_print_mode() << endl << flush; 
  dz << F.get_print_mode() << endl << flush;
  cout << "...........................completed" << endl << flush;
  
  cout << "testing write_to_stream" << flush;
  dz << "testing write_to_stream" << endl << flush;
  ofstream out1("LIDIA");
  D.write_to_stream(out1);
  out1.close();
  cout << "..........................completed" << endl << flush; 
  
  cout << "testing write_to_gp" << flush;
  dz << "testing write_to_gp" << endl << flush;
  ofstream out2("GP");
  D.write_to_gp(out2);
  out2.close();
  cout << "..............................completed" << endl << flush; 
  
  cout << "testing write_to_maple" << flush;
  dz << "testing write_to_maple" << endl << flush;
  ofstream out3("MAPLE");
  D.write_to_maple(out3);
  out3.close();
  cout << "...........................completed" << endl << flush; 

  cout << "testing write_to_mathematica" << flush;
  dz << "testing write_to_mathematica" << endl << flush;
  ofstream out4("MATHEMATICA");
  D.write_to_mathematica(out4);
  out4.close(); 
  cout << ".....................completed" << endl << flush; 

  cout << "testing write_to_kash" << flush;
  dz << "testing write_to_kash" << endl << flush;
  ofstream out5("KASH");
  D.write_to_kash(out5);
  out5.close(); 
  cout << "............................completed" << endl << flush; 
  
  A.set_print_mode(BEAUTY_MODE);
  B.set_print_mode(BEAUTY_MODE);
  C.set_print_mode(BEAUTY_MODE);
  D.set_print_mode(BEAUTY_MODE);
  E.set_print_mode(BEAUTY_MODE);
  F.set_print_mode(BEAUTY_MODE);
  
  cout << "testing read_from_stream" << flush;
  dz << "testing read_from_stream" << endl << flush;
  ifstream in1("LIDIA");
  D.read_from_stream(in1);
  dz << D << flush;
  in1.close();
  cout << ".........................completed" << endl << flush; 

  cout << "testing read_from_gp" << flush;
  dz << "testing read_from_gp" << endl << flush;
  ifstream in2("GP");
  D.read_from_gp(in2);
  dz << D << flush;	
  in2.close();
  cout << ".............................completed" << endl << flush; 

  cout << "testing read_from_maple" << flush;
  dz << "testing read_from_maple" << endl << flush;
  ifstream in3("MAPLE");
  D.read_from_maple(in3);
  dz << D << flush;
  in3.close();
  cout << "..........................completed" << endl << flush; 

  cout << "testing read_from_mathematica" << flush;
  dz << "testing read_from_mathematica" << endl << flush;
  ifstream in4("MATHEMATICA");
  D.read_from_mathematica(in4);
  dz << D << flush;
  in4.close();
  cout << "....................completed" << endl << flush; 

  cout << "testing read_from_kash" << flush;
  dz << "testing read_from_kash" << endl << flush;
  ifstream in5("KASH");
  D.read_from_kash(in5);
  in5.close();
  cout << "...........................completed" << endl << flush; 

  cout << "testing member" << flush;
  dz << "testing member" << endl << flush;
  scalar_1 = A.member(2, 1);
  dz << scalar_1 << endl;
  scalar_1 = A(2,1);
  dz << scalar_1 << endl << flush;
  cout << "...................................completed" << endl << flush;

  cout << "testing column" << flush;
  dz << "testing column" << endl << flush;
  v1 = A(0);
  dz << v1 << endl << flush;
  dz << endl << flush;
  pointer_1 = A.column(1);
  for (i = 0; i < 4; i++)
    dz << pointer_1[i] << " " << flush;
  dz << endl << flush; 
  A.column(pointer_1, 2);
  for (i = 0; i < 4; i++)
    dz << pointer_1[i] << " " << flush;
  dz << endl << flush; 
  A.column_vector(v1, 2);
  dz << v1 << endl << flush;
  cout << "...................................completed" << endl << flush;

  cout << "testing row" << flush;
  dz << "testing row" << endl << flush;
  v2 = A[0];
  dz << v2 << endl << flush;
  dz << endl << flush;
  pointer_2 = A.row(1);
  for (i = 0; i < 6; i++)
    dz << pointer_2[i] << " " << flush;
  dz << endl << flush;
  A.row(pointer_2, 2);
  for (i = 0; i < 6; i++)
    dz << pointer_2[i] << " " << flush;
  dz << endl << flush; 
  A.row_vector(v2, 2);
  dz << v2 << endl << flush;
  cout << "......................................completed" << endl << flush;
  
  cout << "testing sto" << flush;
  E = A;
  dz << "testing sto" << endl << flush;
  E.sto(2, 0, scalar_2);
  dz << E << flush;
  cout << "......................................completed" << endl << flush;
  
  cout << "testing sto_column" << flush;
  dz << "testing sto_column" << endl << flush;
  E = A;
  E.sto_column(pointer_1, 3, 0);
  dz << E << flush;
  E.sto_column_vector(v1, 3, 1);
  dz << E << flush;
  cout << "...............................completed" << endl << flush;

  cout << "testing sto_row" << flush;
  dz << "testing sto_row" << endl << flush;
  E = A;
  E.sto_row(pointer_2, 4, 0);
  dz << E << flush;
  E.sto_row_vector(v2, 4, 1);
  dz << E << flush;
  cout << "..................................completed" << endl << flush;

  cout << "testing get_data" << flush;
  dz << "testing get_data" << endl << flush;
  r = E.get_no_of_rows();
  c = E.get_no_of_columns();
  TYPE **value = E.get_data();
  for (i = 0; i < r; i++)
    for (j = 0; j < c; j++)
      dz << value[i][j] << " ";
  dz << endl << flush;
  for (i = 0; i < r; i++)
    delete[] value[i];
  delete[] value;
  cout << ".................................completed" << endl << flush;

  cout << "testing swap" << flush;
  dz << "testing swap" << endl << flush;
  dz << E << A << flush;
  swap(E, A);
  dz << E << A << flush;
  swap(E, A);
  cout << ".....................................completed" << endl << flush;

  cout << "testing swap_columns" << flush;
  dz << "testing swap_columns" << endl << flush;
  E = A;
  E.swap_columns(0, 5);
  dz << E << flush;
  cout << ".............................completed" << endl << flush;
  
  cout << "testing swap_rows" << flush;
  dz << "testing swap_rows" << endl << flush;
  E = A;
  E.swap_rows(3, 0);
  dz << E << flush;
  cout << "................................completed" << endl << flush;

  cout << "testing split_t" << flush;
  dz << "testing split_t" << endl << flush;
  math_matrix < TYPE > Part1(2, 4), Part2(3, 2), Part3(2, 4), Part4(1, 2);
  A.split_t(Part1, Part2, Part3, Part4);
  dz << Part1 << Part2 << Part3 << Part4 << flush;
  cout << "..................................completed" << endl << flush;

  cout << "testing split_h" << flush;
  dz << "testing split_h" << endl << flush;
  math_matrix < TYPE > Part5(4, 4), Part6(4, 2);
  math_matrix < TYPE > PartA(4, 5), PartB(4, 5), PartC(4, 5), PartD(4, 5);
  A.split_h(Part5, Part6);
  dz << Part5 << Part6 << flush;
  
  A.split_h(pointer_1, PartA);
  dz << PartA;
  for (i = 0; i< 4; i++)
    dz << pointer_1[i] << " ";
  dz << endl << flush;
  A.split_h(v1, PartB);
  dz << PartB << v1 << endl << flush;

  A.split_h(PartC, pointer_3);
  dz << PartC;
  for (i = 0; i< 4; i++)
    dz << pointer_3[i] << " ";
  dz << endl << flush;
  A.split_h(PartD, v3);
  dz << PartD << v3 << endl << flush;
  cout << "..................................completed" << endl << flush;

  cout << "testing split_v" << flush;
  dz << "testing split_v" << endl << flush;
  math_matrix < TYPE > Part7(1, 6), Part8(3, 6);
  math_matrix < TYPE > PartE(3, 6), PartF(3, 6), PartG(3, 6), PartH(3, 6);
  A.split_v(Part7, Part8);
  dz << Part7 << Part8 << flush;

  A.split_v(pointer_2, PartE);
  dz << PartE;
  for (i = 0; i< 6; i++)
    dz << pointer_2[i] << " ";
  dz << endl << flush;
  A.split_v(v2, PartF);
  dz << PartF << v2 << endl << flush;

  A.split_v(PartG, pointer_4);
  dz << PartG;
  for (i = 0; i< 6; i++)
    dz << pointer_4[i] << " ";
  dz << endl << flush;
  A.split_v(PartH, v4);
  dz << PartH << v4 << endl << flush;
  cout << "..................................completed" << endl << flush;

  cout << "testing compose_t" << flush;
  dz << "testing compose_t" << endl << flush;
  {
    math_matrix < TYPE > TMP(4, 6);
    TMP.compose_t(Part1, Part2, Part3, Part4);
    dz << TMP << flush;
  }
  cout << "................................completed" << endl << flush;

  cout << "testing compose_h" << flush;
  dz << "testing compose_h" << endl << flush;
  {
    math_matrix < TYPE > TMP(4, 6);
    TMP.compose_h(Part5, Part6);
    dz << TMP << flush;

    TMP.compose_h(pointer_1, PartA);
    dz << TMP << flush;

    TMP.compose_h(v1, PartB);
    dz << TMP << flush;

    TMP.compose_h(PartC, pointer_3);
    dz << TMP << flush;

    TMP.compose_h(PartD, v3);
    dz << TMP << flush;
  }
  cout << "................................completed" << endl << flush;

  cout << "testing compose_v" << flush;
  dz << "testing compose_v" << endl << flush;
  {
    math_matrix < TYPE > TMP(4, 6);
    TMP.compose_v(Part7, Part8);
    dz << TMP << flush;

    TMP.compose_v(pointer_2, PartE);
    dz << TMP << flush;

    TMP.compose_v(v2, PartF);
    dz << TMP << flush;

    TMP.compose_v(PartG, pointer_4);
    dz << TMP << flush;

    TMP.compose_v(PartH, v4);
    dz << TMP << flush;
  }
  cout << "................................completed" << endl << flush;

  cout << "testing get_no_of_columns" << flush;
  dz << "testing get_no_of_columns" << endl << flush;
  scalar_1 = A.get_no_of_columns();
  dz << scalar_1 << endl << flush;
  cout << "........................completed" << endl << flush;

  cout << "testing get_no_of_rows" << flush;
  dz << "testing get_no_of_rows" << endl << flush;
  scalar_1 = A.get_no_of_rows();
  dz << scalar_1 << endl << flush;
  cout << "...........................completed" << endl << flush;

  cout << "testing set_no_of_columns" << flush;
  dz << "set_no_of_columns" << endl << flush;
  E = A;
  E.set_no_of_columns(3);
  dz << E << flush;
  cout << "........................completed" << endl << flush; 

  cout << "testing set_no_of_rows" << flush;
  dz << "set_no_of_rows" << endl << flush;
  E.set_no_of_rows(3);
  dz << E << flush;
  cout << "...........................completed" << endl << flush;
  
  cout << "testing assign" << flush;
  dz << "testing assign" << endl << flush;
  E = A;
  dz << E << flush;
  E.assign(A);
  dz << E << flush;
  assign(E, A);
  dz << E << flush;
  cout << "...................................completed" << endl << flush;

  cout << "testing trans" << flush;
  dz << "testing trans" << endl << flush;
  E = trans(A);
  dz << E << flush;
  E = E.trans();
  dz << E << flush;
  E.trans(E);
  dz << E << flush;
  trans(E, E);
  dz << E << flush;
  cout << "....................................completed" << endl << flush; 

  cout << "testing diag" << flush;
  dz << "diag" << endl << flush;
  E.diag(scalar_1, scalar_2);
  dz << E << flush;
  diag(E, scalar_2, scalar_3);
  dz << E << flush;
  cout << ".....................................completed" << endl << flush; 

  /***************************** END   OF PART: BASE_MATIRX ****************/
  /***************************** BEGIN Of PART: MATH_MATRIX ****************/
  
  dz << A << B << C << D << E << flush;
  dz << v1 << v2 << v3 << v4 << flush;

  cout << "testing addition" << flush;
  dz << "testing addition" << endl << flush;
  A += B;
  dz << A << flush;
  add(A, A, B);
  dz << A << flush;
  F = A + B;
  dz << F << flush;
  add(F, A, B);
  dz << F << flush;
  cout << ".................................completed" << endl << flush;

  cout << "testing subtraction" << flush;
  dz << "testing subtraction" << endl << flush;
  A -= B;
  dz << A << flush;
  subtract(A, A, B);
  dz << A << flush;
  F = A - B;
  dz << F << flush;
  subtract(F, A, B);
  dz << F << flush;
  cout << "..............................completed" << endl << flush;

  cout << "testing negate" << flush;
  dz << "testing negate" << endl << flush;
  F = -A;
  dz << F << flush;
  negate(F, A);
  dz << F << flush;
  cout << "...................................completed" << endl << flush;

  cout << "testing multiplication" << flush;
  dz << "testing multiplication" << endl << flush;
  E = A, F = A;
  E *= C;
  dz << E << flush;
  E = A * C;
  dz << E << flush;
  multiply(F, A, C);
  dz << F << flush;
  cout << "...........................completed" << endl << flush;

  cout << "testing addition with scalar" << flush;
  dz << "testing addition with scalar" << endl << flush;
  A += scalar_2;
  dz << A << flush;
  F = A + scalar_2;
  dz << F << flush;
  add(F, A, scalar_2);
  dz << F << flush;
  cout << ".....................completed" << endl << flush;

  cout << "testing subtraction with scalar" << flush;
  dz << "testing subtraction with scalar" << endl << flush;
  A -= scalar_2;
  dz << A << flush;
  F = A - scalar_2;
  dz << F << flush;
  subtract(F, A, scalar_2);
  dz << F << flush;
  cout << "..................completed" << endl << flush;

  cout << "testing multiplication with scalar" << flush;
  dz << "testing multiplication with scalar" << endl << flush;
  F = A;
  F *= scalar_3;
  dz << F << flush;
  F = A * scalar_3;
  dz << F << flush;
  multiply(F, A, scalar_3);
  dz << F << flush;
  cout << "...............completed" << endl << flush;

  cout << "testing multiplication with array" << flush;
  dz << "testing multiplication with array" << endl << flush;
  pointer_3 = A * pointer_2;
  for (i = 0; i < 4; i++)
    dz << pointer_3[i] << " ";
  dz << endl << flush;
  multiply(pointer_5, A, pointer_2);
  for (i = 0; i < 4; i++)
    dz << pointer_5[i] << " ";
  dz << endl << flush;
  
  pointer_4 = pointer_1 * A;
  for (i = 0; i < 6; i++)
    dz << pointer_4[i] << " ";
  dz << endl << flush;
  multiply(pointer_6, pointer_1, A);
  for (i = 0; i < 6; i++)
    dz << pointer_6[i] << " ";
  dz << endl << flush;
  cout << "................completed" << endl << flush; 
  
  cout << "testing multiplication with vector" << flush;
  dz << "testing multiplication with vector" << endl << flush;
  v3 = A * v2;
  dz << v3 << endl << flush;
  multiply(v3, A, v2);
  dz << v3 << endl << flush;
  
  v4 = v1 * A;
  dz << v4 << endl << flush;
  multiply(v4, v1, A);
  dz << v4 << endl << flush;
  cout << "...............completed" << endl << flush; 

  cout << "testing trace" << flush;
  dz << "testing trace" << endl << flush;
  F = A * trans(A);
  scalar_1 = F.trace(); 
  dz << scalar_1 << endl << flush;
  F.trace(scalar_1);
  dz << scalar_1 << endl << flush;
  scalar_1 = trace(F); 
  dz << scalar_1 << endl << flush;
  cout << "....................................completed" << endl << flush; 

  dz.close(); 
  cout << "\nPlease use now the 'diff' or 'cmp' command to verify" << endl;
  cout << "the equality of math_matrix_appl.dat";
  cout << " and math_matrix_appl.out." << endl << flush;
}
