public LUDecomposition(Matrix A, boolean autoPivot) { LU = A.copy(); int m = LU.m, n = LU.n; pivsign = 1; piv = new int[m]; for (int i = 0; i < m; i++) piv[i] = i; // Outer loop. for (int j = 0; j < n; j++) { if (n > 1000) System.out.printf("%d / %d\r", j, n); // Make a copy of the j-th column to localize references. Vec LUcolj = LU.getColumn(j); // Apply previous transformations. for (int i = 0; i < m; i++) { Vec LUrowi = LU.getRow(i); // Most of the time is spent in the following dot product. int kmax = Math.min(i, j); double s = LUrowi.dotProduct(LUcolj, 0, kmax - 1); LUcolj.plusEquals(i, -s); LUrowi.plusEquals(j, -s); } // Find pivot and exchange if necessary. int p = j; if (autoPivot) { for (int i = j + 1; i < m; i++) { if (Math.abs(LUcolj.get(i)) > Math.abs(LUcolj.get(p))) { p = i; } } } if (p != j) { LU.swapRows(p, j); int k = piv[p]; piv[p] = piv[j]; piv[j] = k; pivsign = -pivsign; } // Compute multipliers. if (j < n && j < m && LU.get(j, j) != 0.0) { double LUjj = LU.get(j, j); for (int i = j + 1; i < m; i++) { LU.timesEquals(i, j, 1.0 / LUjj); } } } }
@Override public void mutablePairwiseDivide(Vec b) { if (this.length() != b.length()) throw new ArithmeticException("Vectors must have the same length"); clearCaches(); for (int i = 0; i < used; i++) values[i] /= b.get(indexes[i]); // zeros stay zero }
public Tensor3 setRow(final int i, final int j, final Vec val) { if (val.dim() != dim3) throw new IllegalArgumentException( "val.dim() != dim3, val.dim() = " + val.dim() + ", dim3 = " + dim3); final int index = index(i, j, 0); for (int l = 0; l < dim3; l++) vec.set(index + l, val.get(l)); return this; }
@Override public boolean equals(Object obj) { if (!(obj instanceof Vec)) return false; Vec otherVec = (Vec) obj; if (this.length() != otherVec.length()) return false; int z = 0; for (int i = 0; i < length(); i++) { // Move through until we hit the next null element, comparing the other vec to zero while (z < used && indexes[z] > i) if (otherVec.get(i++) != 0) return false; // We made it! (or are at the end). Is our non zero value the same? if (z < used && indexes[z] == i) if (values[z++] != otherVec.get(i)) return false; } return true; }
@Override public double pNormDist(double p, Vec y) { if (this.length() != y.length()) throw new ArithmeticException("Vectors must be of the same length"); double norm = 0; if (y instanceof SparseVector) { int p1 = 0, p2 = 0; SparseVector b = (SparseVector) y; while (p1 < this.used && p2 < b.used) { int a1 = indexes[p1], a2 = b.indexes[p2]; if (a1 == a2) { norm += Math.pow(Math.abs(this.values[p1] - b.values[p2]), p); p1++; p2++; } else if (a1 > a2) norm += Math.pow(Math.abs(b.values[p2++]), p); else // a1 < a2, this vec has a value, other does not norm += Math.pow(Math.abs(this.values[p1++]), p); } // One of them is now empty. // So just sum up the rest of the elements while (p1 < this.used) norm += Math.pow(Math.abs(this.values[p1++]), p); while (p2 < b.used) norm += Math.pow(Math.abs(b.values[p2++]), p); } else { int z = 0; for (int i = 0; i < length(); i++) { // Move through until we hit the next null element, comparing the other vec to zero while (z < used && indexes[z] > i) norm += Math.pow(Math.abs(-y.get(i++)), p); // We made it! (or are at the end). Is our non zero value the same? if (z < used && indexes[z] == i) norm += Math.pow(Math.abs(values[z] - y.get(i)), p); } } return Math.pow(norm, 1.0 / p); }
@Override public double dot(Vec v) { double dot = 0; if (v instanceof SparseVector) { SparseVector b = (SparseVector) v; int p1 = 0, p2 = 0; while (p1 < used && p2 < b.used) { int a1 = indexes[p1], a2 = b.indexes[p2]; if (a1 == a2) dot += values[p1++] * b.values[p2++]; else if (a1 > a2) p2++; else p1++; } } else // it is dense for (int i = 0; i < used; i++) dot += values[i] * v.get(indexes[i]); return dot; }
@Override public void mutableAdd(double c, Vec v) { clearCaches(); if (c == 0.0) return; if (v instanceof SparseVector) { SparseVector b = (SparseVector) v; int p1 = 0, p2 = 0; while (p1 < used && p2 < b.used) { int a1 = indexes[p1], a2 = b.indexes[p2]; if (a1 == a2) { values[p1] += c * b.values[p2]; p1++; p2++; } else if (a1 > a2) { // 0 + some value is that value, set it this.set(a2, c * b.values[p2]); /* * p2 must be increment becase were moving to the next value * * p1 must be be incremented becase a2 was less thenn the current index. * So the inseration occured before p1, so for indexes[p1] to == a1, * p1 must be incremented * */ p1++; p2++; } else // a1 < a2, thats adding 0 to this vector, nothing to do. { p1++; } } // One of them is now empty. // If b is not empty, we must add b to this. If b is empty, we would be adding zeros to this // [so we do nothing] while (p2 < b.used) this.set(b.indexes[p2], c * b.values[p2++]); // TODO Can be done more efficently } else if (v.isSparse()) { if (v.nnz() == 0) return; int p1 = 0; Iterator<IndexValue> iter = v.getNonZeroIterator(); IndexValue iv = iter.next(); while (p1 < used && iv != null) { int a1 = indexes[p1]; int a2 = iv.getIndex(); if (a1 == a2) { values[p1++] += c * iv.getValue(); if (iter.hasNext()) iv = iter.next(); else break; } else if (a1 > a2) { this.set(a2, c * iv.getValue()); p1++; if (iter.hasNext()) iv = iter.next(); else break; } else p1++; } } else { // Else it is dense for (int i = 0; i < length(); i++) this.set(i, this.get(i) + c * v.get(i)); } }