public class Matrix {
	
	private double[][] mat;
	private int R;
	private int C;
	
	// Generates an identiy matrix of size N x N.
	public Matrix(int N) {
		R = N;
		C = N;
		mat = new double[N][N];
		for (int i=0; i<N; i++)
			mat[i][i] = 1;
	}
	
	// Generates a matrix equivalent to a.
	public Matrix(double[][] a) {
		R = a.length;
		C = a[0].length;
		mat = new double[R][C];
		for (int i=0; i<a.length; i++)
			for (int j=0; j<a[0].length; j++)
				mat[i][j] = a[i][j];
	}
	
	public Matrix add(Matrix m) {
		
		// Can't add these.
		if (this.R != m.R || this.C != m.C) return null;
		
		// Just add corresponding slots.
		double[][] ans = new double[R][C];
		for (int i=0; i<R; i++)
			for (int j=0; j<C; j++)
				ans[i][j] = this.mat[i][j] + m.mat[i][j];
		
		return new Matrix(ans);
	}
	
	public Matrix multiply(Matrix m) {
		
		// Can't multiply these.
		if (this.C != m.R) return null;
		
		// Allocate the right amount of space.
		double[][] ans = new double[this.R][m.C];
		
		// This is how we multiply.
		for (int i=0; i<this.R; i++) 
			for (int j=0; j<m.C; j++) 
				for (int k=0; k<m.R; k++)
					ans[i][j] += (this.mat[i][k]*m.mat[k][j]);
			
		return new Matrix(ans);
	}
	
	public Matrix pow(int exp) {
		
		// Can't do this.
		if (R != C) return null;
		
		// Base cases.
		if (exp == 0) return new Matrix(R);
		if (exp == 1) return new Matrix(mat);
		
		// Time savings here - even exponent case.
		if (exp%2 == 0) {
			Matrix tmp = pow(exp/2);
			return tmp.multiply(tmp);
		}
		
		// Usual recursive breakdown for odd case.
		else {
			Matrix tmp = pow(exp-1);
			return this.multiply(tmp);
		}
		
	}
	
	// Just for testing purposes.
	public String toString() {
		
		String ans = "";
		for (int i=0; i<R; i++) {
			for (int j=0; j<C; j++)
				ans = ans + mat[i][j] + " ";
			ans = ans + "\n";
		}
		return ans;
	}
}