package mikera.matrixx.impl;
// import java.util.HashMap;
// import java.util.Map.Entry;
import mikera.matrixx.AMatrix;
import mikera.matrixx.Matrix;
import mikera.vectorz.AVector;
import mikera.vectorz.Op;
import mikera.vectorz.Vector;
import mikera.vectorz.impl.RepeatedElementVector;
import mikera.vectorz.util.VectorzException;
/**
* Abstract base class for matrices that store sparse rows or columns.
*
* @author Mike
*
*/
public abstract class ASparseRCMatrix extends ARectangularMatrix {
private static final long serialVersionUID = -4153075712517555814L;
protected final AVector[] data;
protected ASparseRCMatrix(int rows, int cols, AVector[] data) {
super(rows, cols);
this.data=data;
}
protected void unsafeSetVec(int i, AVector vec) {
data[i] = vec;
}
/**
* Gets a vector from the internal data array
*
* The vector may be null (indicating a zero row or column)
*
*/
public AVector unsafeGetVector(int i) {
return data[i];
}
@Override
public boolean isSparse() {
return true;
}
@Override
public void fill(double value) {
RepeatedElementVector v=RepeatedElementVector.create(lineLength(), value);
long n=componentCount();
for (int i = 0; i < n; i++) {
unsafeSetVec(i, v);
}
}
@Override
public void reciprocal() {
AVector rr=RepeatedElementVector.create(lineLength(), 1.0/0.0);
long n=componentCount();
for (int i=0; i<n; i++) {
AVector line=data[i];
if (line==null) {
data[i] = rr;
} else {
if (!line.isFullyMutable()) {
line = line.sparseClone();
data[i] = line;
}
line.reciprocal();
}
}
}
@Override
public void abs() {
long n=componentCount();
for (int i=0; i<n; i++) {
AVector line=data[i];
if (line==null) {
// OK;
} else {
if (!line.isFullyMutable()) {
line = line.absCopy();
data[i] = line;
} else {
line.abs();
}
}
}
}
@Override
public void pow(double exponent) {
long n=componentCount();
for (int i=0; i<n; i++) {
AVector line=data[i];
if (line==null) {
// OK;
} else {
if (!line.isFullyMutable()) {
line = line.sparseClone();
data[i] = line;
}
line.pow(exponent);
}
}
}
@Override
public void square() {
long n=componentCount();
for (int i=0; i<n; i++) {
AVector line=data[i];
if (line==null) {
// OK;
} else {
if (!line.isFullyMutable()) {
line = line.sparseClone();
data[i] = line;
}
line.square();
}
}
}
@Override
public void sqrt() {
long n=componentCount();
for (int i=0; i<n; i++) {
AVector line=data[i];
if (line==null) {
// OK;
} else {
if (!line.isFullyMutable()) {
line = line.sparseClone();
data[i] = line;
}
line.sqrt();
}
}
}
@Override
public void exp() {
AVector rr = RepeatedElementVector.create(lineLength(), 1.0);
long n=componentCount();
for (int i = 0; i < n; i++) {
AVector line = data[i];
if (line == null) {
data[i] = rr;
} else {
if (!line.isFullyMutable()) {
line = line.sparseClone();
data[i] = line;
}
line.exp();
}
}
}
@Override
public void log() {
AVector rr=RepeatedElementVector.create(lineLength(), Math.log(0.0));
long n=componentCount();
for (int i=0; i<n; i++) {
AVector line=data[i];
if (line==null) {
data[i] = rr;
} else {
if (!line.isFullyMutable()) {
line = line.sparseClone();
data[i] = line;
}
line.log();
}
}
}
@Override
public final boolean isMutable() {
return true;
}
@Override
public final boolean isFullyMutable() {
return true;
}
@Override
public final boolean isZero() {
for (AVector vec: data) {
if (! ((vec == null) || (vec.isZero()))) return false;
}
return true;
}
@Override
public AMatrix innerProduct(AMatrix a) {
return SparseRowMatrix.innerProduct(this,a);
}
@Override
public AVector innerProduct(AVector a) {
return SparseRowMatrix.innerProduct(this,a);
}
@Override
public AVector getRowClone(int row) {
return getRow(row).sparseClone();
}
@Override
public AVector getColumnClone(int column) {
return getColumn(column).sparseClone();
}
@Override
public void copyRowTo(int i, double[] dest, int destOffset) {
getRow(i).copyTo(dest, destOffset);
}
@Override
public void copyColumnTo(int j, double[] dest, int destOffset) {
getColumn(j).copyTo(dest, destOffset);
}
@Override
public double elementSum() {
double result=0.0;
for (AVector vec: data) {
if (vec != null) result += vec.elementSum();
}
return result;
}
@Override
public double elementSquaredSum() {
double result=0.0;
for (AVector vec: data) {
if (vec != null) result += vec.elementSquaredSum();
}
return result;
}
@Override
public double elementMin() {
AVector fvec=data[0];
double result=(fvec==null)?0.0:fvec.elementMin();
for (int i=1 ; i<data.length; i++) {
AVector vec=data[i];
double v = (vec == null) ? 0.0 : vec.elementMin();
if (v<result) result=v;
}
return result;
}
@Override
public double elementMax() {
AVector fvec=data[0];
double result=(fvec==null)?0.0:fvec.elementMax();
for (int i=1 ; i<data.length; i++) {
AVector vec=data[i];
double v = (vec == null) ? 0.0 : vec.elementMax();
if (v>result) result=v;
}
return result;
}
@Override
public void applyOp(Op op) {
boolean stoch = op.isStochastic();
AVector rr = (stoch) ? null : RepeatedElementVector.create(lineLength(), op.apply(0.0));
long n=componentCount();
for (int i = 0; i < n; i++) {
AVector v = unsafeGetVector(i);
if (v == null) {
if (!stoch) {
unsafeSetVec(i, rr);
continue;
}
v = Vector.createLength(lineLength());
unsafeSetVec(i, v);
} else if (!v.isFullyMutable()) {
v = v.sparseClone();
unsafeSetVec(i, v);
}
v.applyOp(op);
}
}
@Override
public final long nonZeroCount() {
long result=0;
for (AVector vec: data) {
if (vec != null) result+=vec.nonZeroCount();
}
return result;
}
@Override
public double[] toDoubleArray() {
double[] result=Matrix.createStorage(rowCount(),columnCount());
// since this array is sparse, fastest to use addToArray to modify only non-zero elements
addToArray(result,0);
return result;
}
@Override
public Matrix dense() {
return toMatrix();
}
@Override
public AMatrix sparse() {
return this;
}
@Override
public abstract int componentCount();
@Override
public abstract AVector getComponent(int k);
protected abstract int lineLength();
@Override
public void validate() {
super.validate();
int dlen = data.length;
if (dlen != componentCount()) throw new VectorzException("Too many rows");
for (int i = 0; i < dlen; ++i) {
AVector vec = unsafeGetVector(i);
int vlen = (vec == null) ? lineLength() : vec.length();
if (vlen!=lineLength()) throw new VectorzException("Wrong length data line vector, length "+vlen+" at position: "+i);
}
}
}