package mikera.matrixx.impl;
import mikera.matrixx.AMatrix;
import mikera.vectorz.AVector;
import mikera.vectorz.Vectorz;
import mikera.vectorz.impl.ArraySubVector;
import mikera.vectorz.impl.IndexedArrayVector;
/**
* Class for an upper triangular matrix packed densely by columns.
*
* Mutable only in the upper 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 UpperTriangularMatrix extends ATriangularMatrix implements IFastColumns {
private static final long serialVersionUID = 4438118586237354484L;
private UpperTriangularMatrix(double[] data, int rows, int cols) {
super(data, rows, cols);
}
private UpperTriangularMatrix(int rows, int cols) {
this (new double[(cols*(cols+1))>>1],rows,cols);
}
static UpperTriangularMatrix wrap(double[] data, int rows, int cols) {
return new UpperTriangularMatrix(data,rows,cols);
}
public static UpperTriangularMatrix createFrom(AMatrix m) {
int rc=m.rowCount();
int cc=m.columnCount();
UpperTriangularMatrix r = new UpperTriangularMatrix(rc,cc);
for (int i=0; i<rc; i++) {
for (int j=i; j<cc; j++) {
r.unsafeSet(i, j, m.unsafeGet(i, j));
}
}
return r;
}
@Override
public boolean isUpperTriangular() {
return true;
}
@Override
public int lowerBandwidthLimit() {
return 0;
}
@Override
public int lowerBandwidth() {
return 0;
}
@Override
public AVector getBand(int band) {
int n=bandLength(band);
if ((n==0)||(band<0)) return Vectorz.createZeroVector(bandLength(band));
if (n==1) return ArraySubVector.wrap(data, internalIndex(0,band), 1);
int[] ixs=new int[n];
for (int i=0; i<n; i++) {
ixs[i]=internalIndex(i,i+band);
}
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 i + ((j*(j+1))>>1);
}
@Override
public double get(int i, int j) {
checkIndex(i,j);
if (i>j) return 0.0;
return data[internalIndex(i,j)];
}
@Override
public double unsafeGet(int i, int j) {
if (i>j) 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 getColumnView(int j) {
int end=Math.min(j+1, rows);
return ArraySubVector.wrap(data, internalIndex(0,j), end).join(Vectorz.createZeroVector(rows-end));
}
@Override
public LowerTriangularMatrix getTranspose() {
return LowerTriangularMatrix.wrap(data, cols, rows);
}
@Override
public boolean equals(AMatrix a) {
if (a==this) return true;
if (a instanceof ADenseArrayMatrix) {
return equals((ADenseArrayMatrix)a);
}
if (!isSameShape(a)) return false;
for (int j = 0; j < cols; j++) {
int end=Math.min(j,rows-1);
for (int i = 0; i <= end; i++) {
if (data[internalIndex(i, j)] != a.unsafeGet(i, j)) return false;
}
for (int i = j+1; i < rows; i++) {
if (a.unsafeGet(i, j)!=0.0) return false;
}
}
return true;
}
@Override
public AMatrix exactClone() {
return new UpperTriangularMatrix(data.clone(),rows,cols);
}
}