content: package tim.prune.function.estimate.jama;
  
  /**
   * The Java Matrix Class provides the fundamental operations of numerical linear algebra.
   * Original authors The MathWorks, Inc. and the National Institute of Standards and Technology
   * The original public domain code has now been modified and reduced to only contain
   * the use of QR Decomposition of rectangular matrices, to solve least squares regression,
   * and is placed under GPL2 with the rest of the GpsPrune code.
   */
  public class Matrix
  {
  
  	/** Array for internal storage of elements */
  	private double[][] _matrix;
  
  	/** Row and column dimensions */
  	private int _m, _n;
  
  
  	/**
  	 * Construct an m-by-n matrix of zeros
  	 * @param inM  Number of rows
  	 * @param inN  Number of colums
  	 */
  	public Matrix(int inM, int inN)
  	{
  		_m = inM;
  		_n = inN;
  		_matrix = new double[inM][inN];
  	}
  
  	/**
  	 * Construct a matrix from a 2-D array
  	 * @param A   Two-dimensional array of doubles.
  	 * @exception IllegalArgumentException All rows must have the same length
  	 */
  	public Matrix(double[][] A)
  	{
  		_m = A.length;
  		_n = A[0].length;
  		for (int i = 0; i < _m; i++) {
  			if (A[i].length != _n) {
  				throw new IllegalArgumentException("All rows must have the same length.");
  			}
  		}
  		_matrix = A;
  	}
  
  	/**
  	 * Construct a matrix quickly without checking arguments.
  	 * @param inA   Two-dimensional array of doubles.
  	 * @param inM   Number of rows
  	 * @param inN   Number of columns
  	 */
  	public Matrix(double[][] inA, int inM, int inN)
  	{
  		_matrix = inA;
  		_m = inM;
  		_n = inN;
  	}
  
  	/*
  	 * ------------------------ Public Methods ------------------------
  	 */
  
  
  	/**
  	 * Set a value in a cell of the matrix
  	 * @param inRow row index
  	 * @param inCol column index
  	 * @param inValue value to set
  	 */
  	public void setValue(int inRow, int inCol, double inValue)
  	{
  		_matrix[inRow][inCol] = inValue;
  	}
  
  	/**
  	 * Access the internal two-dimensional array.
  	 * @return Pointer to the two-dimensional array of matrix elements.
  	 */
  	public double[][] getArray() {
  		return _matrix;
  	}
  
  	/**
  	 * Copy the internal two-dimensional array.
  	 * @return Two-dimensional array copy of matrix elements.
  	 */
  	public double[][] getArrayCopy()
  	{
  		double[][] C = new double[_m][_n];
  		for (int i = 0; i < _m; i++) {
  			for (int j = 0; j < _n; j++) {
  				C[i][j] = _matrix[i][j];
  			}
  		}
  		return C;
  	}
  
  	/**
  	 * Get a single element.
  	 * @param inRow   Row index
  	 * @param inCol   Column index
  	 * @return A(inRow,inCol)
  	 * @exception ArrayIndexOutOfBoundsException
  	 */
  	public double get(int inRow, int inCol) {
  		return _matrix[inRow][inCol];
  	}
  
  	/** @return number of rows _m */
  	public int getNumRows() {
  		return _m;
  	}
  
  	/** @return number of columns _n */
  	public int getNumColumns() {
  		return _n;
  	}
  
  	/**
  	 * Get a submatrix
  	 * @param i0  Initial row index
  	 * @param i1  Final row index
  	 * @param j0  Initial column index
  	 * @param j1  Final column index
  	 * @return A(i0:i1,j0:j1)
  	 * @exception ArrayIndexOutOfBoundsException
  	 */
  	public Matrix getMatrix(int i0, int i1, int j0, int j1)
  	{
  		Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1);
  		double[][] B = X.getArray();
  		try {
  			for (int i = i0; i <= i1; i++) {
  				for (int j = j0; j <= j1; j++) {
  					B[i - i0][j - j0] = _matrix[i][j];
  				}
  			}
  		} catch (ArrayIndexOutOfBoundsException e) {
  			throw new ArrayIndexOutOfBoundsException("Submatrix indices");
  		}
  		return X;
  	}
  
  
  	/**
  	 * Linear algebraic matrix multiplication, A * B
  	 * @param B   another matrix
  	 * @return Matrix product, A * B
  	 * @exception IllegalArgumentException if matrix dimensions don't agree
  	 */
  	public Matrix times(Matrix B)
  	{
  		if (B._m != _n) {
  			throw new IllegalArgumentException("Matrix inner dimensions must agree.");
  		}
  		Matrix X = new Matrix(_m, B._n);
  		double[][] C = X.getArray();
  		double[] Bcolj = new double[_n];
  		for (int j = 0; j < B._n; j++) {
  			for (int k = 0; k < _n; k++) {
  				Bcolj[k] = B._matrix[k][j];
  			}
  			for (int i = 0; i < _m; i++) {
  				double[] Arowi = _matrix[i];
  				double s = 0;
  				for (int k = 0; k < _n; k++) {
  					s += Arowi[k] * Bcolj[k];
  				}
  				C[i][j] = s;
  			}
  		}
  		return X;
  	}
  
  	/**
  	 * Subtract the other matrix from this one
  	 * @param B   another matrix
  	 * @return difference this - B
  	 * @exception IllegalArgumentException if matrix dimensions don't agree
  	 */
  	public Matrix minus(Matrix B)
  	{
  		if (B._m != _m || B._n != _n) {
  			throw new IllegalArgumentException("Matrix dimensions must agree.");
  		}
  		Matrix result = new Matrix(_m, _n);
  		for (int i = 0; i < _m; i++) {
  			for (int j = 0; j < _n; j++) {
  				result.setValue(i, j, get(i, j) - B.get(i, j));
  			}
  		}
  		return result;
  	}
  
  	/**
  	 * Divide each element of this matrix by the corresponding element in the other one
  	 * @param B   another matrix
  	 * @return this[i,j]/other[i,j]
  	 * @exception IllegalArgumentException if matrix dimensions don't agree
  	 */
  	public Matrix divideEach(Matrix B)
  	{
  		if (B._m != _m || B._n != _n) {
  			throw new IllegalArgumentException("Matrix dimensions must agree.");
  		}
  		Matrix result = new Matrix(_m, _n);
  		for (int i = 0; i < _m; i++) {
  			for (int j = 0; j < _n; j++) {
  				result.setValue(i, j, get(i, j) / B.get(i, j));
  			}
  		}
  		return result;
  	}
  
  	/**
  	 * Solve A*X = B
  	 * @param B   right hand side
  	 * @return least squares solution
  	 */
  	public Matrix solve(Matrix B) {
  		return new QRDecomposition(this).solve(B);
  	}
  
  	/**
  	 * @return the average absolute value of all the elements in the matrix
  	 */
  	public double getAverageAbsValue()
  	{
  		double total = 0.0;
  		for (int i = 0; i < _m; i++) {
  			for (int j = 0; j < _n; j++) {
  				total += Math.abs(_matrix[i][j]);
  			}
  		}
  		return total / _m / _n;
  	}
  
  	/**
  	 * Primitive output for debugging
  	 */
  	public String toString()
  	{
  		StringBuilder builder = new StringBuilder();
  		builder.append('(');
  		for (int i = 0; i < _m; i++) {
  			builder.append('(');
  			for (int j = 0; j < _n; j++) {
  				builder.append((_matrix[i][j]));
  				builder.append(", ");
  			}
  			builder.append(") ");
  		}
  		builder.append(')');
  		return builder.toString();
  	}
  }
  