package math.matrix;

import exception.IllegalDimensionException;

/**
 * Diagonal matrix object d<sub>ij</sub>&isin;&#x211D;, i&ne;j=0
 * with m rows and n columns
 * @author Daniel Weschke
 */
public class Diagonal extends Matrix{

	/**
	 * UID
	 */
	private static final long serialVersionUID = 3206696282474150081L;
	
	public Diagonal(int n){
		this(n,n);
	}
	
	public Diagonal(int m, int n){
		this.m = m;
		this.n = n;
		data = new double[m>n?m:n];
	}
	
	public Diagonal(double... d){
		this(d.length);
		int i;
        for(i=0; i<n; i++)
        	set(i, d[i]);
	}
	
	public Diagonal(Vector d){
		this(d.n());
		int i;
        for(i=0; i<n; i++)
        	set(i, d.get(i));
	}
	
	/**
	 * Create diagonal matrix with given main diagonal entries
	 * @param d matrix
	 */
	public Diagonal(Matrix d){
		this(d.getM(), d.getN());
		int i;
        for(i=0; i<(m>n?m:n); i++)
        	set(i, d.get(i, i));
	}
	
	/**
	 * Generate an n-by-n identity matrix.
	 * An n-by-n matrix with ones on the diagonal and zeros elsewhere.
	 * @param n rows/columns
	 * @return n-by-n identity matrix
	 */
	public static Diagonal identity(int n){
		int i;
        Diagonal c = new Diagonal(n);
        for(i=0; i<n; i++)
        	c.set(i, 1);
        return c;
	}
	
	/**
	 * Generate an m-by-n identity matrix.
	 * An m-by-n matrix with ones on the diagonal and zeros elsewhere.
	 * @param n rows/columns
	 * @return n-by-n identity matrix
	 */
	public static Diagonal identity(int m, int n){
		int i;
        Diagonal c = new Diagonal(m, n);
        for(i=0; i<(m<n?m:n); i++)
        	c.set(i, 1);
        return c;
	}
	
	public void set(int i, double d){
		data[i] = d;
	}
	
	public Matrix set(int i, int j, double d){
		if(i==j) set(i,d);
		return this;
	}
	
	public double get(int i){
		return data[i];
	}
	
	public double get(int i, int j){
		if(i==j) return get(i);
		else return 0;
	}

    /**
     * Unary minus
     * @return -D
     */
    public Diagonal uminus(){
    	Diagonal X = new Diagonal(m,n);
    	int i;
    	for(i=0; i<n; i++)
    		X.set(i, -get(i));
    	return X;
    }
    
    /**
     * Scalar multiplication. Multiply a matrix element-wise by a scalar.
     * @param s scalar
     * @return <b>C</b> = s <b>A</b>
     */
    public Diagonal times(double s){
    	int i;
    	Diagonal c = new Diagonal(m,n);
    	for(i=0; i<m; i++)
    		c.set(i, s * get(i));
        return c;
    }
    
    /**
     * Scalar multiplication. Multiply a matrix element-wise by a scalar.
     * @param s scalar
     * @return <b>D</b> = s <b>D</b>
     */
    public Diagonal timesEquals(double s){
    	int i;
    	for(i=0; i<m; i++)
    		set(i, s * get(i));
        return this;
    }
	
    /**
     * Multiply by a vector right. matrix-vector multiplication
     * @param b vector
     * @return <b>C</b> = <b>A</b> • <b>b</b> = <b>A</b> <b>b</b>
     * @throws IllegalDimensionException Illegal vector dimensions.
     */
	public Vector times(Vector b) throws IllegalDimensionException{
		int i;
        if(n != b.n()) throw new IllegalDimensionException("Illegal vector dimensions.");
		Vector c = new Vector(m);
    	for(i=0; i<m; i++)
    		c.set(i, get(i) * b.get(i));
		return c;
	}
	
	/**
	 * @param e exponent
	 * @return the matrix to the power of e
	 */
	public Diagonal pow(double e){
		int i;
		Diagonal C = new Diagonal(m,n);
		for(i=0; i<(m<n?m:n); i++)
			C.set(i, Math.pow(get(i), e));
		return C;
	}
	
	public double det(){
		int i;
		double det = 1;
		for(i=0; i<m; i++)
			det *= get(i);
		return det;
	}

	public String toString(){
		return Matrix.diag(data).toString();
	}
	
    public static void main(String[] args){
		Diagonal d1 = new Diagonal(1.);
		System.out.println(d1);
		Diagonal d2 = new Diagonal(1., 2.);
		System.out.println(d2);
	}
}
