Matrix.java

java · 842 lines · part of White Outline (Cartoon Shading) · raw

/*
 *	$Id: Matrix.java,v 1.2 1998/12/12 06:22:39 doug Exp $
 *
 *	Generalised nxm Matrix operations
 */



/**
 * <P>
 * The matrix.Matrix class provides a generalised 2-dimensional
 * matrix package.
 * Matrices are treated as values wherever possible, so matrix
 * operations such as multiplication produce a new matrix as the
 * result, rather than operate directly on the matrix.
 * <P>
 * This package is optimised towards the 4x4 transformation
 * matrices which can be used for 3D projections.
 * There are a number of class methods for generating transformation
 * matrices.
 *
 * @version $Revision: 1.2 $
 * @author Doug Palmer (<A HREF="mailto:dougal@projectx.com.au">dougal@projectx.com.au</A>)
 */



//  Modified by LKS to remove package and associated exceptions!



public class Matrix extends Object implements Cloneable {
	/**
	 * Matrix dimensions.
	 */
	protected int rows, cols;
	/**
	 * Matrix data.
 	 */
	protected double matrix[][];

	// Constants
	/**
	 * X-axis.
	 * Position of X-axis data in a transformation matrix.
	 */
	protected static final int X = 0;
	/**
	 * Y-axis.
 	 * Position of Y-axis data in a transformation matrix.
	 */
	protected static final int Y = 1;
	/**
	 * Z-axis.
	 * Position of Z-axis data in a transformation matrix.
	 */
	protected static final int Z = 2;
	/**
	 * Normalisation.
	 * Position of normalisation data in a transformation matrix.
	 */
	protected static final int N = 3;
	/**
	 * Transformation size.
	 * Size of a transformation matrix.
	 */
	protected static final int TD = N + 1;

	/**
	 * Isometric factor.
	 * Amount of weight to give to X and Y axes during
	 * isometric transformation.
	 */
	protected static final double ISOMETRIC = 1.0 / Math.sqrt(2.0);

	// Constructors
	/**
	 * Unit matrix.
	 * Unit matrix of size <VAR>rows</VAR> x <VAR>cols</VAR>.
	 * @param rows Number of rows in matrix.
	 * @param cols Number of columns in matrix.
	 */
	public Matrix(int rows, int cols)
	{
		int i, j;

		this.rows = rows;
		this.cols = cols;
		matrix = new double[this.rows][this.cols];
		for (i = 0; i < this.rows; i++) {
			for (j = 0; j < this.cols; j++)
				this.matrix[i][j] = 0.0;
			if (i < this.cols)
				this.matrix[i][i] = 1.0;
		}
	}
	/**
	 * Initialised matrix.
	 * Make a matrix from the 2D array <VAR>init</VAR>.
	 * @param init An array of arrays containing the initial data.
	 * @exception matrix.MatrixDimensionException Thrown if <VAR>init</VAR> contains rows of differing length.
	 */
	public Matrix(double[][] init)
	{
		int i, j;

		this.rows = init.length;
		this.cols = init[0].length;
		matrix = new double[this.rows][this.cols];
		for (i = 0; i < this.rows; i++) {
			if (init[i].length != this.cols)
				System.out.println("Matrix(double[][] init) : MatrixDimensionException(\"Uneven rows\")");
			for (j = 0; j < this.cols; j++)
				this.matrix[i][j] = init[i][j];
		}
	}
	/**
	 * Initialised matrix.
	 * Make a vector matrix from the 1D array <VAR>init</VAR>.
	 * @param init Array to initialize the matrix.
 	 */
	public Matrix(double[] init)
	{
		int i, j;

		this.rows = init.length;
		this.cols = 1;
		matrix = new double[this.rows][this.cols];
		for (i = 0; i < this.rows; i++)
			this.matrix[i][0] = init[i];
	}
	/**
	 * Copied matrix.
	 * Make a copy of <VAR>copy</VAR>.
	 * This also makes an internal copy of the matrix data,
	 * to avoid later clashes.
	 * @param copy The matrix to copy from.
	 */
	public Matrix(Matrix copy)
	{
		int i, j;

		this.rows = copy.rows;
		this.cols = copy.cols;
		this.matrix = new double[this.rows][this.cols];
		for (i = 0; i < this.rows; i++)
			for (j = 0; j < this.cols; j++)
				this.matrix[i][j] = copy.matrix[i][j];
	}

	/**
	 * Unit transformation matrix.
	 * @return A transformation matrix.
	 */
	public static Matrix transformation()
	{
		return new Matrix(TD, TD);
	}

	/**
	 * Scaling transformation matrix.
	 * @param sx Scaling factor for X axis.
	 * @param sy Scaling factor for Y axis.
	 * @param sz Scaling factor for Z axis.
	 * @return A transformation matrix.
	 */
	public static Matrix scaling(double sx, double sy, double sz)
	{
		Matrix scaling = Matrix.transformation();

		scaling.matrix[X][X] = sx;
		scaling.matrix[Y][Y] = sy;
		scaling.matrix[Z][Z] = sz;
		return scaling;
	}

	/**
	 * Private rotation generating method.
	 */
	private static Matrix rotateAxis(double angle, int a1, int a2)
	{
		double sin = Math.sin(angle), cos = Math.cos(angle);
		Matrix rotate = Matrix.transformation();

		rotate.matrix[a1][a1] = cos;
		rotate.matrix[a1][a2] = -sin;
		rotate.matrix[a2][a2] = cos;
		rotate.matrix[a2][a1] = sin;
		return rotate;
	}
	/**
	 * Rotation matrix.
	 * Transformation matrix for a rotation about the X axis.
	 * @param angle Number of radians to rotate about the axis.
	 * @return A transformation matrix.
	 */
	public static Matrix rotateX(double angle)
	{
		return rotateAxis(angle, Y, Z);
	}
	/**
	 * Rotation matrix.
	 * Transformation matrix for a rotation about the Y axis.
	 * @param angle Number of radians to rotate about the axis.
	 * @return A transformation matrix.
	 */
	public static Matrix rotateY(double angle)
	{
		return rotateAxis(angle, X, Z);
	}
	/**
	 * Rotation matrix.
	 * Transformation matrix for a rotation about the Z axis.
	 * @param angle Number of radians to rotate about the axis.
	 * @return A transformation matrix.
	 */
	public static Matrix rotateZ(double angle)
	{
		return rotateAxis(angle, X, Y);
	}

	/**
	 * Translation matrix.
	 * Translation transformation matrix.
	 * @param tx Amount to translate a point along the X axis by.
	 * @param ty Amount to translate a point along the Y axis by.
	 * @param tz Amount to translate a point along the Z axis by.
	 * @return A transformation matrix.
	 */
	public static Matrix translate(double tx, double ty, double tz)
	{
		Matrix translation = Matrix.transformation();

		translation.matrix[X][N] = tx;
		translation.matrix[Y][N] = ty;
		translation.matrix[Z][N] = tz;
		return translation;
	}

	/**
	 * Private reflection generating method
	 */
	private static Matrix reflect(int axis)
	{
		Matrix reflect = Matrix.transformation();

		reflect.matrix[axis][axis] = -reflect.matrix[axis][axis];
		return reflect;
	}
	/**
	 * Reflection matrix.
	 * Reflect coordinates about the X axis.
	 * @return A transformation matrix.
	 */
	public static Matrix reflectX()
	{
		return Matrix.reflect(X);
	}
	/**
	 * Reflection matrix.
	 * Reflect coordinates about the Y axis.
	 * @return A transformation matrix.
	 */
	public static Matrix reflectY()
	{
		return Matrix.reflect(Y);
	}
	/**
	 * Reflection matrix.
	 * Reflect coordinates about the Z axis.
	 * @return A transformation matrix.
	 */
	public static Matrix reflectZ()
	{
		return Matrix.reflect(Z);
	}

	/**
	 * Private permutation generating method
	 */
	private static Matrix permute(int xt, int yt, int zt)
	{
		Matrix permute = Matrix.transformation();

		permute.matrix[X][X] = 0.0;
		permute.matrix[Y][Y] = 0.0;
		permute.matrix[Z][Z] = 0.0;
		permute.matrix[xt][X] = 1.0;
		permute.matrix[yt][Y] = 1.0;
		permute.matrix[zt][Z] = 1.0;
		return permute;
	}
	/**
	 * Permutation matrix.
	 * Permute coordinates <VAR>(x, y, z) -> (y, z, x)</VAR>
	 * @return A transformation matrix.
	 */
	public static Matrix permuteYZX()
	{
		return permute(Z, X, Y);
	}
	/**
	 * Permutation matrix.
	 * Permute coordinates <VAR>(x, y, z) -> (z, x, y)</VAR>
	 * @return A transformation matrix.
	 */
	public static Matrix permuteZXY()
	{
		return permute(Y, Z, X);
	}
	/**
	 * Permutation matrix.
	 * Permute coordinates <VAR>(x, y, z) -> (y, x, z)</VAR>
	 * @return A transformation matrix.
	 */
	public static Matrix permuteYXZ()
	{
		return permute(Y, X, Z);
	}
	/**
	 * Permutation matrix.
	 * Permute coordinates <VAR>(x, y, z) -> (x, z, y)</VAR>
	 * @return A transformation matrix.
	 */
	public static Matrix permuteXZY()
	{
		return permute(X, Z, Y);
	}
	/**
	 * Permutation matrix.
	 * Permute coordinates <VAR>(x, y, z) -> (z, y, x)</VAR>
	 * @return A transformation matrix.
	 */
	public static Matrix permuteZYX()
	{
		return permute(Z, Y, X);
	}

	/**
	 * Isometric matrix.
	 * Isometric transform along the Z axis.
	 * @return A transformation matrix.
	 */
	public static Matrix isometric()
	{
		Matrix isometric = Matrix.transformation();

		isometric.matrix[X][Z] = ISOMETRIC;
		isometric.matrix[Y][Z] = ISOMETRIC;
		return isometric;
	}

	/**
	 * Cavalier projection.
	 * Cavalier projection onto the X-Y plane at <VAR>angle</VAR>
	 * @param angle Angle of rotation in radians
	 * @return A transformation matrix.
	 */
	public static Matrix cavalier(double angle)
	{
		double c = Math.cos(angle);
		double s = Math.sin(angle);
		Matrix cavalier = Matrix.transformation();

		cavalier.matrix[X][Z] = c;
		cavalier.matrix[Y][Z] = s;
		return cavalier;
	}

	/**
	 * Cabinet projection.
	 * Cabinet projection onto the X-Y plane at <VAR>angle</VAR>
	 * @param angle Angle of rotation in radians
	 * @return A transformation matrix.
	 */
	public static Matrix cabinet(double angle)
	{
		double c = Math.cos(angle) / 2;
		double s = Math.sin(angle) / 2;
		Matrix cabinet = Matrix.transformation();

		cabinet.matrix[X][Z] = c;
		cabinet.matrix[Y][Z] = s;
		return cabinet;
	}

	/**
	 * Perspective matrix.
	 * Perspective transformation along the Z axis,
	 * with a vanishing point at <VAR>(0, 0, vz)</VAR>.
	 * @param vz Z coordinate of vanishing point.
	 * @return A transformation matrix.
	 */
	public static Matrix perspective(double vz)
	{
		Matrix perspective = Matrix.transformation();

		perspective.matrix[N][Z] = 1.0 / vz;
		return perspective;
	}

	/**
	 * @return Matrix rank (2).
	 */
	public int getRank()
	{
		return 2;
	}
	/**
	 * @return Number of rows in matrix.
	 */
	public int getRows()
	{
		return this.rows;
	}
	/**
	 * @return Number of columns in matrix.
	 */
	public int getCols()
	{
		return this.cols;
	}
	/**
	 * @param i Row number of element.
	 * @param j Column number of element.
	 * @return Element at <VAR>(i, j)</VAR>.
	 */
	public double at(int i, int j)
	{
		return this.matrix[i][j];
	}
	/**
	 * @param i Row number of element.
	 * @param j Column number of element.
	 * @param val Value to set <VAR>(i, j)</VAR> to.
	 */
	public void put(int i, int j, double val)
	{
		this.matrix[i][j] = val;
	}

	/**
	 * Private copying method.
	 */
	protected void copyFrom(Matrix copy)
	{
		int i, j, cpn, cpm;

		cpn = Math.min(this.rows, copy.rows);
		cpm = Math.min(this.cols, copy.cols);
		for (i = 0; i < cpn; i++)
			for (j = 0; j < cpm; j++)
				this.matrix[i][j] = copy.matrix[i][j];
	}
	/**
	 * Copying
	 * @returns Cloned matrix.
	 */
	public Object clone()
	{
		return new Matrix(this);
	}
	/**
	 * Copying.
	 * Clone this matrix with a new size of
	 * <VAR>rows</VAR> x <VAR>cols</VAR>.
	 * As much of the matrix that can be copied will be copied, with
	 * excess parts being discarded, and remaining parts of the
	 * copy filled with a unit matrix.
	 * @param rows New number of rows.
	 * @param cols New number of columns.
	 * @return Cloned matrix.
	 */
	protected Object clone(int rows, int cols)
	{
		Matrix res = new Matrix(rows, cols);
		res.copyFrom(this);
		return res;
	}

	/**
	 * Equality.
	 * Two matrices are equal if they have the same size and
	 * equal elements.
	 * @param obj Object to test matrix against.
	 * @return Boolean equality value.
	 */
	public boolean equals(Object obj)
	{
		Matrix mat;
		int i, j;

		if (!(obj instanceof Matrix))
			return false;
		mat = (Matrix) obj;
		if (this.rows != mat.rows || this.cols != mat.cols)
			return false;
		for (i = 0; i < this.rows; i++)
			for (j = 0; j < this.cols; j++)
				if (this.matrix[i][j] != mat.matrix[i][j])
					return false;
		return true;
	}
	/**
	 * Operations.
	 * Hash value for insertion into hash tables.
	 * @return Hash value.
	 */
	public int hashCode()
	{
		int i, n = Math.min(this.rows, this.cols);
		int sum = 32767;
		double v;

		for (i = 0; i < n; i++) {
			v = this.matrix[i][i];
			if (v > Integer.MIN_VALUE && v < Integer.MAX_VALUE)
				sum ^= (int) v;
		}
		return sum;
	}

	/**
	 * Operations.
	 * The trace of a matrix is the sum of the elements along
	 * it's major diagonal:
	 * <VAR>M.trace() = Sum<SUB>i=0</SUB><SUP>n</SUP> M<SUB>ii</SUB></VAR>.
	 * @return Trace.
	 */
	public double trace()
	{
		int i, n = Math.min(this.rows, this.cols);
		double sum = 0.0;

		for (i = 0; i < n; i++)
			sum += this.matrix[i][i];
		return sum;
	}

	/**
	 * Arithmetic.
	 * Add two matrices together using the rules of matrix arithmetic:
	 * <VAR>M.add(N)<SUB>ij</SUB> = M<SUB>ij</SUB> + N<SUB>ij</SUB></VAR>.
	 * @param arg Matrix to add to this matrix.
	 * @return A new matrix which is the sum of this matrix and <VAR>arg</VAR>.
	 * @exception matrix.MatrixDimensionException Thrown if the two matrices do not have the same size.
	 */
	public Matrix add(Matrix arg)
	{
		Matrix result;
		int i, j;

		if (this.rows != arg.rows || this.cols != arg.cols)
			System.out.println("Matrix add(Matrix arg) : MatrixDimensionException(\"Attempted to add incompatible matrices\")");
		result = (Matrix) this.clone();
		for (i = 0; i < this.rows; i++)
			for (j = 0; j < this.cols; j++)
				result.matrix[i][j] = this.matrix[i][j] + arg.matrix[i][j];
		return result;
	}
	/**
	 * Arithmetic.
	 * Add <VAR>arg</VAR> to each element of the main diagonal.
	 * Similar to adding a diagonal matrix of <VAR>arg</VAR>.
	 * @param arg The value to add to this matrix.
	 * @return A new matrix which is the sum of <VAR>this</VAR> and <VAR>arg</VAR>.
	 * @see matrix.Matrix#add(Matrix)
	 */
	public Matrix add(double arg)
	{
		Matrix result;
		int i;

		result = (Matrix) this.clone();
		for (i = 0; i < this.rows; i++)
			result.matrix[i][i] += arg;
		return result;
	}
	/**
	 * Arithmetic.
	 * Subtract two matrices using the rules of matrix arithmetic:
	 * <VAR>M.subtract(N)<SUB>ij</SUB> = M<SUB>ij</SUB> - N<SUB>ij</SUB></VAR>.
	 * @param arg Matrix to subtract from this matrix.
	 * @return A new matrix which is the difference between this matrix and <VAR>arg</VAR>.
	 * @exception matrix.MatrixDimensionException Thrown if the two matrices do not have the same size.
	 */
	public Matrix subtract(Matrix arg)
	{
		Matrix result;
		int i, j;

		if (this.rows != arg.rows || this.cols != arg.cols)
			System.out.println("subtract(Matrix arg) : MatrixDimensionException(\"Attempted to subtacr incompatible matrices\")");
		result = (Matrix) this.clone();
		for (i = 0; i < this.rows; i++)
			for (j = 0; j < this.cols; j++)
				result.matrix[i][j] = this.matrix[i][j] - arg.matrix[i][j];
		return result;
	}
	/**
	 * Arithmetic.
	 * Subtract <VAR>arg</VAR> from each element of the main diagonal.
	 * Similar to subtracting a diagonal matrix of <VAR>arg</VAR>.
	 * @param arg The value to subtract from this matrix.
	 * @return A new matrix which is the difference between <VAR>this</VAR> and <VAR>arg</VAR>.
	 * @see matrix.Matrix#subtract(Matrix)
	 */
	public Matrix subtract(double arg)
	{
		Matrix result;
		int i;

		result = (Matrix) this.clone();
		for (i = 0; i < this.rows; i++)
			result.matrix[i][i] -= arg;
		return result;
	}
	/**
	 * Arithmetic.
	 * Multiply this matrix by <VAR>arg</VAR> using the rules of
	 * matrix arithmetic:
	 * <VAR>M.multiply(N)<SUB>ij</SUB> =
	 * Sum<SUB>k = 0</SUB><SUP>n</SUP> M<SUB>ik</SUB> * N<SUB>kj</SUB></VAR>.
	 * @param arg The matrix to multiply this matrix by.
	 * @return A new matrix which is the product of this matrix and <VAR>arg</VAR>
	 * @exception matrix.MatrixDimensionException Thrown if <VAR>arg</VAR> does not have the same number of rows as
	 * this matrix has columns.
	 */
	public Matrix multiply(Matrix arg)
	{
		Matrix result;
		int i, j, k;
		double sum;

		if (this.cols != arg.rows)
			System.out.println("multiply(Matrix arg) : MatrixDimensionException(\"Attempted to multiply incompatible matrices\")");
		result = (Matrix) this.clone(this.rows, arg.cols);
		for (i = 0; i < this.rows; i++)
			for (j = 0; j < arg.cols; j++) {
				sum = 0.0;
				for (k = 0; k < this.cols; k++)
					sum += this.matrix[i][k] * arg.matrix[k][j];
				result.matrix[i][j] = sum;
			}
		return result;
	}
	/**
	 * Arithmetic.
	 * Multiply this matrix by <VAR>arg</VAR> using the rules of
	 * matrix arithmetic.
	 * <VAR>arg</VAR> is treated as a n x 1 vector for this purpose.
	 * @param arg The matrix to multiply this matrix by.
	 * @return An array containing the resultant vector.
	 * @exception matrix.MatrixDimensionException Thrown if <VAR>arg</VAR> does not have the same number of rows as this matrix has columns.
	 * @see matrix.Matrix#multiply(Matrix)
	 */
	public double[] multiply(double arg[])
	{
		double result[];
		int i, j;
		double sum;

		if (arg.length == TD && this.rows == TD && this.rows == TD)
			return specialMultiply(arg);
		if (this.cols != arg.length)
			System.out.println("double[] multiply(double arg[]) : MatrixDimensionException(\"Attempted to multiply incompatible matrices\")");
		result = new double[this.rows];
		for (i = 0; i < this.rows; i++) {
			sum = 0.0;
			for (j = 0; j < this.rows; j++)
				sum += this.matrix[i][j] * arg[j];
			result[i] = sum;
		}
		return result;
	}

	public void multiply(double src[], double result[])
	{
		int i, j;
		double sum;

		for (i = 0; i < this.rows; i++)
		{
			sum = 0.0;
			for (j = 0; j < this.rows; j++)
				sum += this.matrix[i][j] * src[j];
			result[i] = sum;
		}
	}
	/**
	 * Arithmetic.
	 * Special case multiplication for transformation matrices and vectors.
	 * This method is automatically invoked by multiply when needed.
	 * @see matrix.Matrix#multiply(double[])
	 */
	protected double[] specialMultiply(double arg[])
	{
		// Fast multiply for transformations
		double x = arg[0];
		double y = arg[1];
		double z = arg[2];
		double n = arg[3];
		double result[] = new double[TD];

		result[0] =
			this.matrix[0][0] * x + this.matrix[0][1] * y +
			this.matrix[0][2] * z + this.matrix[0][3] * n;
		result[1] =
			this.matrix[1][0] * x + this.matrix[1][1] * y +
			this.matrix[1][2] * z + this.matrix[1][3] * n;
		result[2] =
			this.matrix[2][0] * x + this.matrix[2][1] * y +
			this.matrix[2][2] * z + this.matrix[2][3] * n;
		result[3] =
			this.matrix[3][0] * x + this.matrix[3][1] * y +
			this.matrix[3][2] * z + this.matrix[3][3] * n;
		return result;
	}
	/**
	 * Arithmetic.
	 * Multiply a matrix by a scalar:
	 * <VAR>M.multiply(a)<SUB>ij</SUB> = M<SUB>ij</SUB> * a</VAR>.
	 * @param arg The scalar to multiply by.
	 * @return A new matrix with each element of this matrix multiplied by <VAR>arg</VAR>.
	 * @see matrix.Matrix#multiply(Matrix)
	 */
	public Matrix multiply(double arg)
	{
		Matrix result;
		int i, j;

		result = (Matrix) this.clone();
		for (i = 0; i < this.rows; i++)
			for (j = 0; j < this.cols; j++)
				result.matrix[i][j] *= arg;
		return result;
	}

	/**
	 * Operations.
 	 * Transpose a matrix:
	 * <VAR>M.transposed()<SUB>ij</SUB> = M<SUB>ji</SUB></VAR>
	 * @return A new matrix which is this matrix transposed.
 	 */
	public Matrix transposed()
	{
		int i, j;
		Matrix result = new Matrix(this.cols, this.rows);

		for (i = 0; i < this.rows; i++)
			for (j = 0; j < this.cols; j++)
				result.matrix[j][i] = this.matrix[i][j];
		return result;
	}

	/**
	 * Operations.
	 * Negate a matrix:
	 * <VAR>M.negated()<SUB>ij</SUB> = -M<SUB>ij</SUB></VAR>.
	 * @return A new matrix which is this matrix with each element negated.
	 */
	public Matrix negated()
	{
		int i, j;
		Matrix result = new Matrix(this.cols, this.rows);

		for (i = 0; i < this.rows; i++)
			for (j = 0; j < this.cols; j++)
				result.matrix[i][j] = - this.matrix[i][j];
		return result;
	}

	/**
	 * Operations.
	 * Invert a square matrix:
	 * <VAR>M * M.inverted() = I</VAR>.
	 * @return A new matrix which is the inverse of this matrix.
	 * @exception matrix.MatrixDimensionException if the matrix is not a sqaure matrix.
	 * @exception matrix.MatrixSingularException if the matrix cannot be inverted (is singular).
	 */
	public Matrix inverted()
	{
		Matrix inverted = new Matrix(this.rows, this.cols);
		Matrix copy = (Matrix) this.clone();
		double scale;
		int i, j, k;

		if (this.rows != this.cols)
			System.out.println("Matrix inverted() : MatrixDimensionException(\"Can only invert square matrices\")");
		for (i = 0; i < this.rows; i++) {
			scale = copy.matrix[i][i];
			if (scale == 0.0)
				System.out.println("Matrix inverted() : MatrixSingularException()");
			for (j = 0; j < this.cols; j++) {
				copy.matrix[i][j] /= scale;
				inverted.matrix[i][j] /= scale;
			}
			for (j = 0; j < this.rows; j++)
				if (i != j) {
					scale = copy.matrix[j][i];
					for (k = 0; k < this.cols; k++) {
						copy.matrix[j][k] -= copy.matrix[i][k] * scale;
						inverted.matrix[j][k] -= inverted.matrix[i][k] * scale;
					}
				}
		}
		return inverted;
	}

	/**
	 * Printing.
	 * Converts the matrix into a string of form
	 * <EM>
	 *  [[m<SUB>00</SUB>, ..., m<SUB>0c</SUB>],
	 *  ...,
	 *  [m<SUB>r0</SUB>, ..., m<SUB>cc</SUB>]]
	 * </EM>
	 * @return The string representation of this matrix.
	 */
	public String toString()
	{
		StringBuffer sb = new StringBuffer();
		int i, j;

		sb.append("[");
		for (i = 0; i < this.rows; i++) {
			sb.append("[");
			for (j = 0; j < this.cols; j++) {
				sb.append(this.matrix[i][j]);
				if (j == this.cols - 1)
					sb.append("]");
				else
					sb.append(", ");
			}
			if (i < this.rows - 1)
				sb.append(", ");
		}
		sb.append("]");
		return sb.toString();
	}
}