// test_RefMatrix.cpp  (C)  2004 adolfo@di-mare.com

/** \file  test_RefMatrix.cpp
    \brief Datos de prueba para la clase \c RefMatrix

    \author Adolfo Di Mare <adolfo@di-mare.com>
    \date   2004

    - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
*/

#include <iostream>
#include <iomanip>   // setw(4)

#include "RefMatrix.h"

using namespace Mx;
using namespace std;

/// Retorna \c "true" si la matriz \c M es una matriz cuadrada
template <class E>
bool isSquare( const RefMatrix<E>& M ) {
    return M.rows() == M.cols();
}

/// Retorna \c "true" si la matriz es simétrica
template <class E>
bool isSymmetric( const RefMatrix<E>& M ) {
    assert( "This code has not been tested" );
    if (M.rows() != M.cols()) {
        return false;
    }
    for (unsigned i=1; i < M.rows(); i++) {
        for (unsigned j=0; j < i; j++) {
            if (M(i,j) != M(j,i)) {
                return false;
            }
        }
    }
    return true;
}

/// Imprime por filas el valor de \c "M"
template <class E>
void print( const char* name, RefMatrix<E> & V ) {
    cout << endl << name << '[' << V.rows() << ',' << V.cols() << ']' << endl;
    for (unsigned i=0; i < V.rows(); ++i) {
        for (unsigned j=0; j < V.cols(); ++j) {
            cout << "  " << setw(4) << V(i,j);
        }
        cout << endl;
    }
}

/// Ejemplo de uso de referencia \c lkptr< RefMatrix<unsigned> >.
void use_lkptr( unsigned M, unsigned N ) {
    lkptr< RefMatrix<unsigned> > A ( new RefMatrix<unsigned>(M,N) );
    RefMatrix<unsigned>& AA = *A; // AA(i,j) == (*A)(i,j)

    unsigned k = 0;
    for ( unsigned i=0; i < A->rows(); ++i ) {
        for ( unsigned j=0; j < A->cols(); ++j,++k ) {
            A->at(i,j) = k; AA(i,j) = k;
        }
    }

    lkptr< RefMatrix<unsigned> > B, C ( A ); // A y C comparten el valor
    assert( B.get() == 0 ); // B es un objeto nulo
    B = C; // A B y C comparten el valor
    B->reSize( B->cols(), B->rows() ); // todos fueron modificados
    assert( B == A );   // comparación de punteros
    assert( *B == *A ); // comparación de matrices
    B.reset( A->clone() ); // B tiene una copia de A
    B->reSize(N,M); // solo B cambia
    C = (C - C);
    assert( A->at(0,0) == 0 ); // porque C borró todo
    C = B + B - B;
    B->reSize( B->cols(), B->rows() ); // solo B cambia
    A = C * B; // ya ninguno comparte memoria
    assert( *A != *B && *B != *C && *C != *A ); // comparación de matrices
}

/// Programa que ejercita las principales funciones de las matrices
int main() {
    const unsigned M = 5;
    const unsigned N = 8;
    use_lkptr( M, N );
    unsigned i,j,k;
    char * above = new char [10];
    typedef RefMatrix<unsigned> RefMatrix_unsigned;
    lkptr< RefMatrix<unsigned> > V ( new RefMatrix<unsigned>(M,N) );
    char * below = new char [10];

    RefMatrix<unsigned>& VV = *V; // VV(i,j) == (*V)(i,j)
    k = 0;
    for (i=0; i < V->rows(); ++i) {
        for (j=0; j < V->cols(); ++j,++k) {
            (*V)(i,j)  = 0;         // ok
            V->operator()(i,j) = k; // ok
            V->at(i,j) = k;         // ok
            VV(i,j) = k; /* !!!! */ // ok
        //  V(i,j) = k;    // no no no no

            assert(  V->at(i,j) ==  VV(i,j) );
            assert( &V->at(i,j) == &VV(i,j) );
        }
    }

    lkptr< RefMatrix<unsigned> > A;
    A = V;
    assert( A == V );
    print("A", *A);

    V->reShape(N,M);
    print("V", *V);

    // k = 0;
    for (i=0; i < V->rows(); ++i) {
        for (j=0; j < V->cols(); ++j) {
            V->operator()(i,j) = k++;
        }
    }

    lkptr< RefMatrix<unsigned> > B;
    B = V;
    assert( B == V );
    print("B", *B);

    lkptr<RefMatrix_unsigned> C = V;
    C = C + C;
    print("C", *C);

    C = A - A;
    print( "C", *C );
    assert( ! isSquare( *C ) && ! isSymmetric( *C ) );

    B->reShape( B->cols(), B->rows() );
    print("A", *A); // A es V es B es A ==> al cambiar 1, cambian todas
    assert( A->rows() == B->rows() && A->cols() == B->cols() );
    A.reset( B->clone() ); // Ahora A tiene una copia de los valores de B
    B->reShape( B->cols(), B->rows() ); // Cambian V,B pero no cambia A
    assert( V->rows() == B->rows() && V->cols() == B->cols() );
    print("B", *B);
    C = A * B;
    print("C", *C);
    assert( isSquare( *C ) && ! isSymmetric( *C ) );

    C = (A - A) * (B + B) - C;
    print( "C", *C ); // da números locos porque la matriz es "unsigned"
    assert( isSquare( *C ) && ! isSymmetric( *C ) );

    print("A", *A);
    print("B", *B);
    C = B * A;
    print("C", *C);
    assert( isSquare( *C ) && ! isSymmetric( *C ) );

    return 0;
}

// EOF: test_RefMatrix.cpp