package hep.physics.matrix; import java.io.Serializable; /** * A simple implementation of a symmetric matrix. A symmmetric matrix * is a square matrix for which <code>e(i,j) == e(j,i)</code>. * @author tonyj * @version $Id: SymmetricMatrix.java 9205 2006-10-24 06:06:07Z tonyj $ */ public class SymmetricMatrix implements MutableMatrix, Serializable { static final long serialVersionUID = -7824887420997633477L; private final double[] values; private final int[] startIndex; private final int size; /** * Creates a new instance of SymmetricMatrix with all elements * set to zero. * @param size The rank of the matrix */ public SymmetricMatrix(int size) { this.size = size; startIndex = new int[size]; int ii = 0; for (int i=0; i<size; ) { startIndex[i] = ii; i++; ii += i; } values = new double[ii]; } /** * Construct a SymmetricMatrix by copying an existing matrix. * If the input matrix is a SymmetricMatrix it is copied exactly. * Otherwise if the input matrix is square the lower left elements are copied * If the matrix is not square an illegal argument exception is thrown. */ public SymmetricMatrix(Matrix mIn) { this(mIn.getNRows()); if (mIn instanceof SymmetricMatrix) { SymmetricMatrix m = (SymmetricMatrix) mIn; System.arraycopy(m.values,0,values,0,values.length); } else { int nRows = mIn.getNRows(); if (nRows != mIn.getNColumns()) throw new IllegalArgumentException("Input matrix is not square"); for (int i=0; i<nRows; i++) { for (int j=0; j<=i; j++) { values[elementIndex(i,j)] = mIn.e(i,j); } } } } /** * Creates a new instance of SymmetricMatrix with the * given initial values. * @param size The rank of the matrix * @param initialValues The initial values for the matrix * @param isLower If true initial values must be m(0,0), m(1,0), m(1,1), ... otherwise m(0,0), m(0,1), m(0,2), ... */ public SymmetricMatrix(int size, double[] initialValues, boolean isLower) { this(size); if (values.length != initialValues.length) throw new IllegalArgumentException("initialValues have invalid length"); copy(initialValues,values,!isLower); } /** * Returns the matrix as a packed array * @param isLower if true array is packed m(0,0), m(1,0), m(1,1),... else m(0,0), m(0,1), m(0,2), ... */ public double[] asPackedArray(boolean isLower) { double[] result = new double[values.length]; copy(values,result,!isLower); return result; } private void copy(double[] source, double[] dest, boolean flip) { if (flip) { int k = 0; for (int i=0; i<size; i++) { for (int j=i; j<size; j++) { dest[elementIndex(i,j)] = source[k++]; } } } else { System.arraycopy(source,0,dest,0,dest.length); } } public int getNRows() { return size; } public int getNColumns() { return size; } /** * Returns the diagonal element for the given row/column */ public double diagonal(int index) { return values[elementIndex(index,index)]; } /** * Returns a specific element */ public double e(int x, int y) { return values[elementIndex(x,y)]; } /** * Set a specific element */ public void setElement(int x, int y, double value) { values[elementIndex(x,y)] = value; } /** * Increment a specific element */ public void incrementElement(int x, int y, double value) { values[elementIndex(x,y)] += value; } private int elementIndex(int x, int y) { return x>=y ? startIndex[x]+y : startIndex[y]+x; } public double det() { return MatrixOp.det(this); } public String toString() { return MatrixOp.toString(this); } public void invert() throws MatrixOp.IndeterminateMatrixException { MatrixOp.inverse(this,this); } public void transpose() { // Noop for symmetric matrix } }