name: MMatrix
synopsis:

>     g++ [flags ...] file ... -l /isip/tools/lib/$ISIP_BINARY/lib_math_matrix.a

>     #include <MMatrix.h>

>     MMatrix();
>     MMatrix(const MMatrix& arg);
>     MMatrix(long nrows, long ncols = DEF_SIZE,
>             Integral::MTYPE type = Integral::DEF_MTYPE);
>     boolean assign(TIntegral value);
>     boolean assign(long num_rows, long num_cols, long* arg,
>                    Integral::MTYPE type = Integral::DEF_MTYPE);
>     boolean setCapacity(const MMatrix& prototype_matrix,
>                         boolean preserve_values = true,
>                         Integral::MTYPE type = Integral::UNCHANGED);
>     boolean setDimensions(const MMatrix& prototype_matrix,
>                           boolean preserve_values = true,
>                           Integral::MTYPE type = Integral::UNCHANGED);
>     boolean mult(MMatrix& m1, MMatrix& m2);
>     boolean multv(TVector& output_vector, const TVector& input_vector);
>     boolean vmult(TVector& output_vector, const TVector& input_vector);
>     double determinant() const;
>     boolean inverse();
>     boolean transpose();

quick start:

>     MMatrix<Double, double> mat0(3, 3, Integral::FULL);
>     MMatrix<Double, double> mat2;

>     double det;

>     mat0.assign(3, 3, L"2.1, 8.3, 4.5, 4.6, 0, 8.1, 5.5, 3.2, 1.7");
>     MMatrix<Double, double> mat1(4, 4, Integral::SYMMETRIC);

>     MVector<Double, double> vec_in;
>     MVector<Double, double> vec_out1;
>     MVector<Double, double> vec_out2;

>     mat1.assign(4, 4, L"1.1, 4.5, 6.5, 3.6, 0.3, 6.7, 8.1, 2.3, 5.5, 9.2",
>                 Integral::SYMMETRIC);

>     vec_in.assign(L"2.2, 4.3, 6.5");
>     mat1.setDimensions(3, 3);

>     mat0.multv(vec_out1, vec_in);
>     mat1.vmult(vec_out2, vec_in);

>     mat0.transpose();
>     mat2.mult(mat0, mat1);

>     det = mat2.determinant();
>     mat2.inverse();
>     mat0.setCapacity(0);

description:
The MMatrix class is a matrix template class which abstracts the storage format of the matrix from the user. This allows memory space for special types of matrices such as a diagonal matrix to be minimized. Details of the storage format are hidden from the user. Most operations can be performed on the any type of matrix transparently to the user. The storage formats, which are defined in Integral.h through the enumeration Integral::MTYPE, include FULL, DIAGONAL, SYMMETRIC, LOWER_TRIANGULAR, UPPER_TRIANGULAR, and SPARSE.
The commonly used mathematical, logical and linear algebra methods for matrices are available for all these types, and implemented in this class as part of the template. All the other matrix classes are derived from this template. A matrix object can read itself from (or write itself to) an Sof file. The MMatrix methods are not supposed to be used by the user directly.
dependencies:

- MMatrixMethods
- NameMap
- VectorLong

public constants:

- define the class name:

      static const String CLASS_NAME = L"MMatrix";

- i/o related constants:

      static const String DEF_PARAM = L"";

      static const String PARAM_DATA = L"values";

      static const String PARAM_TYPE = L"type";

      static const String PARAM_NROWS = L"num_rows";

      static const String PARAM_NCOLS = L"num_cols";

      static const String PARAM_ROW_IND = L"row_indices";

      static const String PARAM_COL_IND = L"col_indices";

- matrix type-related constants: note that unchanged and unknown are not included, since they are not valid matrix types (and only useful as arguments).

      static const NameMap TYPE_MAP = L"FULL, DIAGONAL, SYMMETRIC, LOWER_TRIANGULAR, UPPER_TRIANGULAR, SPARSE";

- define a conditioning factor to be used to determine singularity:

       static const double THRESH_SINGULAR = 1e-10;

- define a threshold used to determine sparseness:

       static const double THRESH_SPARSE = 0.9;

- define a threshold used to determine balance:

       static const double THRESH_BALANCE = 0.95;

- define a threshold used to stabilize matrices:

       static const double THRESH_STABLE = 1e-20;

- default values and arguments:

      static const unichar DEF_ROW_DELIM = L',';

      static const unichar DEF_DELIM = DEF_ROW_DELIM;

      static const TIntegral DEF_VALUE = 0;

      static const long DEF_SIZE = 0;

error codes:

- error code indicating MMatrix class general error:

      static const long ERR = 24000;

- error code indicating an invalid operation for this type of matrix:

      static const long ERR_OPTYPE = 24001;

- error code indicating an invalid matrix dimension:

      static const long ERR_DIM = 24002;

- error code indicating an unknown matrix type:

      static const long ERR_UNKTYP = 24003;

- error code indicating a singlular matrix:

      static const long ERR_SINGLR = 24004;

- error code indicating a matrix is not positive definite:

      static const long ERR_POSDEF = 24005;

protected data:

- the matrix type (see Integral.h):

      Integral::MTYPE type_d;

- number of rows and columns in the matrix:

      Long nrows_d;

      Long ncols_d;

- a storage vector containing the actual elements of the matrix:

      TVector m_d;

- parameters for sparse matrix: for sparse matrices, we store the row and column indices in separate arrays.

      MVector<Long, long> row_index_d;

      MVector<Long, long> col_index_d;

- debug level:

      static Integral::DEBUG debug_level_d;

required public methods:

- static methods:

      static const String& name();

      static boolean diagnose(Integral::DEBUG debug_level);

- debug methods:

      boolean setDebug(Integral::DEBUG level);

      boolean debug(const unichar* message) const;

- destructor/constructor(s) methods:

      ~MMatrix();

      MMatrix();

      MMatrix(const MMatrix& m);

- assign methods:

      boolean assign(const MMatrix<TAScalar, TAIntegral>& arg);

- operator= methods:

      the operator= methods are omitted because they are defined in
      the classes that instantiate this template

- i/o methods:

      long sofSize() const;

      boolean read(Sof& sof, long tag, cons String& name);

      boolean write(Sof& sof, long tag, const String& name) const;

      boolean readData(Sof& sof, const String& pname, long size, boolean param, boolean nested);

      boolean writeData(Sof& sof, const String& name) const;

- equality methods:

      boolean eq(const MMatrix& arg) const;

- memory management methods: the new and delete methods are omitted because they are defined in the classes that instantiate this template

      boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);

class-specific public methods:

- debug methods:

      boolean debug(const String& name, const unichar* message) const;

- constructors:

      MMatrix(long nrows, long ncols = DEF_SIZE, Integral::MTYPE type = Integral::DEF_MTYPE);

- equality methods:

      boolean eq(TIntegral value) const;

- assign methods: this method is an overload of the required assign method that allows the user to set the type

      boolean assign(const MMatrix<TAScalar, TAIntegral>& arg, Integral::MTYPE type);

- other scalar assign methods:

      boolean assign(TIntegral value);

- array conversion methods:

      boolean assign(long num_rows, long num_cols, const TAIntegral* arg, Integral::MTYPE type = Integral::DEF_MTYPE);

- string assign methods:

      boolean assign(long num_rows, long num_cols, const String* arg, Integral::MTYPE type = Integral::DEF_MTYPE);

      boolean assign(long nrows, long ncols, const String& arg, Integral::MTYPE type = Integral::DEF_MTYPE, const Char delim = DEF_DELIM);

      boolean assign(long nrows, long ncols, const unichar* arg, Integral::MTYPE type = Integral::DEF_MTYPE, const Char delim = DEF_DELIM);

- copy methods:

      boolean copy(const MMatrix<TAScalar, TAIntegral>& arg);

- swap methods:

      boolean swap(MMatrix& arg);

- operator overloads, get, set, find, and resize methods:

      TIntegral operator()(long i, long j) const;

      Integral::MTYPE getType() const;

      TIntegral getValue(long row_index, long col_index) const;

      boolean getValue(TScalar& value, long row_index, long col_index) const;

      long getNumRows() const;

      long getNumColumns() const;

      boolean getRow(TVector& vector, long row_index) const;

      boolean getColumn(TVector& vector, long col_index) const;

      boolean getDiagonal(TVector& vector) const;

      boolean getLower(MMatrix& arg) const;

      boolean getUpper(MMatrix& arg) const;

      boolean getMinor(const MMatrix& arg, long row_index, long col_index) const;

      boolean setValue(long row_index, long col_index, TIntegral value);

      boolean setValue(long row_index, long col_index, const TScalar& value);

      boolean setRow(long row_index, const TVector& vector);

      boolean setColumn(long col_index, const TVector& vector);

      boolean setDiagonal(const TVector& values);

      boolean setDiagonal(const MMatrix& source);

      boolean setDiagonal(TIntegral value);

      boolean setLower(const MMatrix& source);

      boolean setUpper(const MMatrix& source);

      boolean setBlock(long start_row, long start_col, long num_rows, long num_cols, TIntegral value);

      boolean makeDiagonal(const TVector& values, Integral::MTYPE type = Integral::DIAGONAL);

      boolean makeDiagonal(TIntegral value, long dim, Integral::MTYPE type = Integral::DIAGONAL);

      boolean makeIdentity(long dim, Integral::MTYPE type = Integral::DIAGONAL);

      boolean makeLower(const MMatrix& source, Integral::MTYPE type = Integral::LOWER_TRIANGULAR);

      boolean makeUpper(const MMatrix& source, Integral::MTYPE type = Integral::UPPER_TRIANGULAR);

      boolean nextZero(long& row_index, long& col_index, long row_start, long col_start) const;

      boolean nextNonZero(TIntegral& value, long& row_index, long& col_index, long row_start, long col_start) const;

      long findRow(const TVector& vector) const;

- resize methods:

      boolean setCapacity(long nrows, long ncols = DEF_SIZE, boolean preserve_values = true, Integral::MTYPE type = Integral::UNCHANGED);

      boolean setCapacity(const MMatrix& prototype_matrix, boolean preserve_values = true, Integral::MTYPE type = Integral::UNCHANGED);

      boolean setDimensions(long nrows, long ncols = DEF_SIZE, boolean preserve_values = true, Integral::MTYPE type = Integral::UNCHANGED);

      boolean setDimensions(const MMatrix& prototype_matrix, boolean preserve_values = true, Integral::MTYPE type = Integral::UNCHANGED);

- property checking methods:

      boolean checkDimensions(const MMatrix<TAScalar, TAIntegral>& matrix) const;

      boolean changeType(Integral::MTYPE type);

      boolean isTypePossible(Integral::MTYPE type) const;

      boolean isFull() const;

      boolean isDiagonal() const;

      boolean isSymmetric() const;

      boolean isLowerTriangular() const;

      boolean isUpperTriangular() const;

      boolean isSparse() const;

      boolean isSquare() const;

      boolean isSquare(const MMatrix& matrix) const;

      boolean isSingular(double thresh = 0) const;

      boolean isSingular(const MMatrix& matrix, double thresh = 0) const;

      boolean isOrthogonal() const;

      boolean isIdentity() const;

- relational and logical methods:

      boolean ne(TIntegral value) const;

      boolean ne(const MMatrix& matrix) const;

      boolean lt(TIntegral value) const;

      boolean le(TIntegral value) const;

      boolean gt(TIntegral value) const;

      boolean ge(TIntegral value) const;

      boolean operator == (TIntegral arg) const;

      boolean operator != (TIntegral arg) const;

      boolean operator < (TIntegral arg) const;

      boolean operator <= (TIntegral arg) const;

      boolean operator > (TIntegral arg) const;

      boolean operator >= (TIntegral arg) const;

      long numEqual(TIntegral value) const;

      long numNotEqual(TIntegral value);

      boolean almostEqual(TIntegral value, double percent = Integral::DEF_PERCENTAGE, double bound = Integral::DEF_BOUND) const;

      boolean almostEqual(const MMatrix& matrix, percent = Integral::DEF_PERCENTAGE, double bound = Integral::DEF_BOUND) const;

- concatenation methods:

      boolean concatByRow(const MMatrix& additional_rows);

      boolean concatByRow(const MMatrix& matrix1, const MMatrix& matrix2);

      boolean concatByColumn(const MMatrix& additional_cols);

      boolean concatByColumn(const MMatrix& matrix1, const MMatrix& matrix2);

- ordering methods:

      boolean reorderRows(const MVector<Long,long>& indexes);

      boolean reorderRows(const MMatrix& matrix, const MVector<Long,long>& indexes);

      boolean reorderColumns(const MVector<Long,long>& indexes);

      boolean reorderColumns(const MMatrix& matrix, const MVector<Long,long>& indexes);

      boolean swapRows(const MMatrix& arg, long row1, long row2);

      boolean swapRows(long row1, long row2);

      boolean swapColumns(const MMatrix& arg, long col1, long col2);

      boolean swapColumns(long col1, long col2);

- basic mathematical methods:

      boolean add(const MMatrix<TAScalar, TAIntegral>& m1);

      boolean add(const MMatrix& m1, const MMatrix<TAScalar, TAIntegral>& m2);

      boolean add(TIntegral value);

      boolean add(TIntegral value);

      boolean sub(const MMatrix<TAScalar, TAIntegral>& m1);

      boolean sub(const MMatrix& m1, const MMatrix<TAScalar, TAIntegral>& m2);

      boolean sub(TIntegral value);

      boolean sub(TIntegral value);

      boolean mult(const MMatrix<TAScalar, TAIntegral>& m1);

      boolean mult(const MMatrix& m1, const MMatrix<TAScalar, TAIntegral>& m2);

      boolean mult(TIntegral value);

      boolean div(TIntegral value);

      boolean neg();

      boolean neg(const MMatrix& m1);

- other mathematical methods:

      TIntegral min() const;

      TIntegral min(long& row_index, long& col_index) const;

      TIntegral max() const;

      TIntegral max(long& row_index, long& col_index) const;

      double minMag() const;

      double minMag(long& row_index, long& col_index) const;

      double maxMag() const;

      double maxMag(long& row_index, long& col_index) const;

      boolean rand(Random& generator = Random::GLOBAL_UNIFORM);

      boolean rand(TIntegral min_val, TIntegral max_val, Random& generator = Random::GLOBAL_UNIFORM);

      boolean grand(TIntegral mean, TIntegral stdev, Random& generator = Random::GLOBAL_GAUSSIAN);

- linear algebra related methods:

      double determinant() const;

      boolean inverse();

      boolean inverse(const MMatrix& matrix);

      boolean transpose();

      boolean transpose(const MMatrix& matrix);

      long rank() const;

      TIntegral trace() const;

      boolean decompositionLU(MMatrix& lower_trig, MMatrix& upper_trig) const;

      boolean decompositionLU(MMatrix& lower_trig, MMatrix& upper_trig, MVector<Long, long>& index, long& sign, double stabilize = THRESH_STABLE) const;

      boolean decompositionCholesky(MMatrix& lower_trig) const;

      boolean decompositionSVD(MMatrix& u, MMatrix& w, MMatrix& v, boolean economy_mode = true) const;

      boolean decompositionQR(MMatrix& q, MMatrix& r);

      boolean eigen(TVector& eigvals, MMatrix& eigvects) const;

      boolean luSolve(MVector<TScalar, TIntegral>& out_vec, const MMatrix& l, const MMatrix& u, const MVector<TScalar, TIntegral>& in_vec);

      boolean luSolve(MVector<TScalar, TIntegral>& out_vec, const MMatrix& l, const MMatrix& u, const VectorLong& index, const MVector<TScalar, TIntegral>& in_vec);

      boolean choleskySolve(MVector<TScalar, TIntegral>& out_vec, const MMatrix& l, const MVector<TScalar, TIntegral>& in_vec);

      boolean svdSolve(MVector<TScalar, TIntegral>& out_vec, const MMatrix& u, const MMatrix& w, const MMatrix& v, const MVector<TScalar, TIntegral>& in_vec, boolean zero_singulars = false);

      boolean multv(TVector& output_vector, const TVector& input_vector) const;

      boolean vmult(TVector& output_vector, const TVector& input_vector) const;

      boolean quadratic(TIntegral& output, const TVector& in_vec) const;

      boolean quadratic(MMatrix& output, const MMatrix& input) const;

      boolean outerProduct();

      boolean outerProduct(const MMatrix& m1);

      boolean outerProduct(const MMatrix& m1, const MMatrix& m2);

      boolean outerProduct(const TVector& v1);

      boolean outerProduct(const TVector& v1, MVector& v2);

- other matrix to scalar mathematical methods:

      TIntegral sum() const;

      TIntegral sumSquare() const;

      TIntegral sumColumn(long col_index) const;

      TIntegral sumRow(long row_index) const;

      TIntegral mean() const;

      TIntegral rms() const;

      double var() const;

private methods:

- index methods:

      long index(long row_index, long col_index) const;

      long index(long row_index, long col_index, long num_rows, long num_cols, Integral::MTYPE type = Integral::UNCHANGED) const;

      boolean reverseIndex(long& row_index, long& col_index, long vec_index) const;

- start and stop row/column methods: these methods return the column indices of the first and last available elements of a particular row of the matrix

      long startRow(long row_index, Integral::MTYPE type_1, Integral::MTYPE type_2 = Integral::UNCHANGED) const;

      long stopRow(long row_index, Integral::MTYPE type_1, Integral::MTYPE type_2 = Integral::UNCHANGED) const;

      long startColumn(long row_index, Integral::MTYPE type_1, Integral::MTYPE type_2 = Integral::UNCHANGED) const;

      long stopColumn(long row_index, Integral::MTYPE type_1, Integral::MTYPE type_2 = Integral::UNCHANGED) const;

      long vecLength() const;

      long vecLength(long nrows, long ncols, Integral::MTYPE type) const;

      boolean vecResetCapacity(long nrows, long ncols, Integral::MTYPE type) const;

      boolean vecResizeCapacity(long nrows, long ncols);

      boolean vecCreateLength(long nrows, long ncols, Integral::MTYPE type);

      boolean vecDimensionLength(long nrows, long ncols, boolean preserve_values);

- sparse-specific methods:

      boolean randIndicesSparse(Random& generator = Random::GLOBAL_UNIFORM);

      boolean sortSparse();

- linear algebra-related methods:

      TIntegral multiplyRowByColumn(const MMatrix& matrix_for_row, const MMatrix<TAScalar, TAIntegral>& matrix_for_col, long row_index, long col_index) const;

      TIntegral multiplyRowByRow(const MMatrix& matrix_for_row1, const MMatrix<TAScalar, TAIntegral>& matrix_for_row2, long row1_index, row2_index) const;

      double determinantLU() const;

      double determinantLU(const MMatrix& matrix) const;

      double determinantMinor() const;

      double determinantMinor(const MMatrix& matrix) const;

      boolean eigenComputeVector(MVector<TScalar,TIntegral>& eigvect, TIntegral eigval);

      boolean eigenBalance();

      boolean eigenEliminateHessenberg();

      boolean eigenHessenbergQR(MVector<Double, double>& eigval_real, MVector<Double, double>& eigval_imag) const;

- type conversion and streaming methods:

      boolean checkSquare(long nrows, long ncols, Integral::MTYPE type) const;

      Integral::MTYPE checkType(Integral::MTYPE type) const;

      boolean assignStream(long nrows, long ncols, const TVector& vec, Integral::MTYPE type);

examples:

- MMatrix is never used directly. See the other matrix types for examples of computational methods. Here, we present an example that demonstrations the basic I/O capabilities:

      long data[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

      MMatrix<Long, long> mat1;
      mat1.assign(3, 3, data);
      MMatrix<Long, long> mat2;

      String file_name(L"foo");
      Sof tmp_file;
      tmp_file.open(file_name, File::WRITE_ONLY, File::TEXT);

      // write the values
      //
      mat1.write(tmp_file, (long)0);

      // close the files
      //
      tmp_file.close();

      // open the files in read mode
      //
      tmp_file.open(file_name);

      // read the values back in
      //
      if (!mat2.read(tmp_file, (long)0) || (!mat2.almostEqual(mat1))) {
             mat1.debug(L"mat g1");
             mat2.debug(L"mat2");
             return Error::handle(mat2.name(), L"read-text", Error::TEST,
                                  __FILE__,__LINE__);
      }
      tmp_file.close();

notes:

- We use two storage formats for the six types of matrices. All types except SPARSE are stored in a single vector. Sparse matrices are represented by a vector containing row indices, a vector containing the column indices and a vector containing the values for the non-zero elements.
- We use setCapacity and setDimension to expand the matrix. The setCapacity method sets the capacity of the matrix to the specified number of rows and columns or to be the same as the capacity of the input matrix. It preserves the values in the matrix only when the boolean flag is set to true. The setDimension method sets the dimension of the matrix and capacity of the matrix is adjusted accordingly.
- We implemented quadratic form for complex matrices using generalized dot product to produce a magnitude from it.
- Refer to the definitions of ISIP typedefs specifying hardware independent type sizes.