package mikera.matrixx.impl; import java.util.Arrays; import mikera.matrixx.AMatrix; import mikera.vectorz.AVector; import mikera.vectorz.Vectorz; import mikera.vectorz.impl.ArraySubVector; import mikera.vectorz.impl.IndexedArrayVector; /** * Class for a lower triangular matrix packed densely by rows. * * Mutable only in the lower triangular elements * * Mostly useful for space efficiency when storing triangular matrices, but is also optimised * for certain common operations on triangular matrices. * * @author Mike * */ public final class LowerTriangularMatrix extends ATriangularMatrix implements IFastRows { private static final long serialVersionUID = 8413148328738646551L; private LowerTriangularMatrix(double[] data, int rows, int cols) { super(data, rows, cols); } private LowerTriangularMatrix(int rows, int cols) { this (new double[(rows*(rows+1))>>1],rows,cols); } static LowerTriangularMatrix wrap(double[] data, int rows, int cols) { return new LowerTriangularMatrix(data,rows,cols); } public static LowerTriangularMatrix createFrom(AMatrix m) { int rc=m.rowCount(); int cc=m.columnCount(); LowerTriangularMatrix r = new LowerTriangularMatrix(rc,cc); for (int j=0; j<cc; j++) { for (int i=j; i<rc; i++) { r.unsafeSet(i, j, m.unsafeGet(i, j)); } } return r; } @Override public boolean isLowerTriangular() { return true; } @Override public int upperBandwidthLimit() { return 0; } @Override public int upperBandwidth() { return 0; } @Override public AVector getBand(int band) { int n=bandLength(band); if ((n==0)||(band>0)) return Vectorz.createZeroVector(bandLength(band)); int[] ixs=new int[n]; for (int i=0; i<n; i++) { ixs[i]=internalIndex(i-band,i); } return IndexedArrayVector.wrap(data, ixs); } @Override protected int index(int i, int j) { if (i>=j) return internalIndex(i,j); throw new IndexOutOfBoundsException("Can't compute array index for sparse entry!"); } private int internalIndex(int i, int j) { return j + ((i*(i+1))>>1); } @Override public double get(int i, int j) { checkIndex(i,j); if (j>i) return 0.0; return data[internalIndex(i,j)]; } @Override public double unsafeGet(int i, int j) { if (j>i) return 0.0; return data[internalIndex(i,j)]; } @Override public void unsafeSet(int i, int j, double value) { data[internalIndex(i,j)]=value; } @Override public AVector getRowView(int i) { int end=Math.min(i+1, cols); return ArraySubVector.wrap(data, internalIndex(i,0), end).join(Vectorz.createZeroVector(cols-end)); } @Override public void copyRowTo(int i, double[] dest, int offset) { int nn=Math.min(i+1,cols); System.arraycopy(data, internalIndex(i,0), dest, offset, nn); if (nn<cols) Arrays.fill(dest, offset+nn, offset+cols, 0.0); } @Override public UpperTriangularMatrix getTranspose() { return UpperTriangularMatrix.wrap(data, cols, rows); } @Override public AMatrix exactClone() { return new LowerTriangularMatrix(data.clone(),rows,cols); } }