public class Matrix {
	public double[][] M;
	public int rows;
	public int cols;
	
	public Matrix (int rows, int cols) {
		M = new double[rows][cols];
		this.rows = rows;
		this.cols = cols;
	}
	
	public Matrix(double[][] M) {
		rows = M.length;
		cols = M[0].length;
		
		this.M = new double[rows][cols];
		
		for (int row = 0; row < rows; row++) {
			for (int col = 0; col < cols; col++) {
				this.M[row][col] = M[row][col];
			}
		}		
	}
	
	public Matrix(String data, String delimeter) {
		String[] rowStrings = data.split("\n");
		String[][] fieldStrings = new String[rowStrings.length][];
		
		for (int i = 0; i < rowStrings.length; i++) {
			fieldStrings[i] = rowStrings[i].split(delimeter);
		}
		
		this.rows = fieldStrings.length;
		this.cols = fieldStrings[0].length;
		
		M = new double[rows][cols];
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				M[i][j] = Double.parseDouble(fieldStrings[i][j]);
			}
		}
	}
	
	public Matrix add(Matrix A) {
		Matrix sum = new Matrix(new double[A.M.length][A.M[0].length]);
		for (int row = 0; row < M.length; row++) {
			for (int col = 0; col < M[0].length; col++) {
				sum.M[row][col] = this.M[row][col] + A.M[row][col]; 
			}
		}
		return sum;
	}
	
	public Matrix multiply(double a) {
		Matrix product = new Matrix(new double[this.M.length][this.M[0].length]);
		// Compute the product
		for (int row = 0; row < M.length; row++) {
			for (int col = 0; col < M[0].length; col++) {
				product.M[row][col] = M[row][col] * a; 
			}
		}
		return product;
	}
	
	public static double dot(double[] A, double[] B) {
		double dot = 0;
		for (int col = 0; col < A.length; col++) {
			dot += A[col] * B[col];
		}
		return dot;
	}
	
	public static double[] colToArray(Matrix A, int col) {
		double[] row = new double[A.M.length];
		for (int i = 0; i < A.M.length; i++) {
			row[i] = A.M[i][col];
		}
		return row;
	}
	
	public static double[] removeCol(double[] a, int col) {
		double[] b = new double[a.length-1];
		int j = 0;
		for (int i = 0; i < a.length; i++) {
			if (i != col) b[j++] = a[i];
		}
		return b;
	}
	
	public static double[][] removeRow(double[][] a, int row) {
		double[][] b = new double[a.length-1][a[0].length];
		int j = 0;
		for (int i = 0; i < a.length; i++) {
			if (i != row) b[j++] = a[i];
		}
		return b;
	}
		
	public Matrix multiplyM(Matrix A) {
		Matrix product = new Matrix(new double[M.length][A.M[0].length]);
		for (int row = 0; row < M.length; row++) {
			for (int col = 0; col < A.M[0].length; col++) {
				product.M[row][col] = dot(this.M[row], colToArray(A, col)); 
			}
		}
		return product;
	}
	
	public Matrix transpose() {
		Matrix transpose = new Matrix(new double[M[0].length][M.length]);
		for (int row = 0; row < M[0].length; row++) {
			for (int col = 0; col < M.length; col++) {
				transpose.M[row][col] = M[col][row];
			}
		}
		return transpose;
	}
	
	public Matrix minorMatrix(int row, int col) {
		double[][] a = removeRow(M, row);
			
		for (int i = 0; i < M.length - 1; i++) {
			a[i] = removeCol(a[i], col);
		}

		return new Matrix(a);
	}
	
	public Matrix matrixOfMinors() {
		Matrix matrixOfMinors = new Matrix(new double[M.length][M[0].length]);	
		for (int row = 0; row < M.length; row++) {
			for (int col = 0; col < M[0].length; col++) {
				matrixOfMinors.M[row][col] = minorMatrix(row, col).det();
			}
		}
		return matrixOfMinors;
	}
	
	public double det() {		
		if (M.length == 1) return M[0][0];

		int det = 0;
		for (int col = 0; col < M[0].length; col++) {
			det += Math.pow(-1, col) * M[0][col] * minorMatrix(0, col).det();
		}
		return det;
	}
	
	public Matrix cofactorMatrix() {
		boolean flipSign = M[0].length % 2 == 0;
		Matrix matrixOfMinors = matrixOfMinors();
		Matrix cofactorMatrix = new Matrix(new double[matrixOfMinors.M.length][matrixOfMinors.M[0].length]);
		int sign = 1;
		
		for (int row = 0; row < M.length; row++) {
			for (int col = 0; col < M[0].length; col++) {
				cofactorMatrix.M[row][col] = sign * matrixOfMinors.M[row][col];
				sign *= -1;
			}
			if (flipSign) sign *= -1;
		}
		return cofactorMatrix;
	}
	
	public Matrix inverse() {
		Matrix adjugate = cofactorMatrix().transpose();
		return adjugate.multiply(1/det());
	}
	
	public String toString() {
		String s = "";
		for (int row = 0; row < M.length; row++) {
			for (int col = 0; col < M[0].length; col++) {
				s += M[row][col] + " ";
			}
			s+="\n";
		}	
		return s;
	}
}
