/*
* Apache License
* Version 2.0, January 2004
* http://www.apache.org/licenses/
*
* Copyright 2013 Aurelian Tutuianu
* Copyright 2014 Aurelian Tutuianu
* Copyright 2015 Aurelian Tutuianu
* Copyright 2016 Aurelian Tutuianu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package rapaio.math.linear;
import rapaio.math.linear.dense.EigenvalueDecomposition;
import rapaio.math.linear.dense.SolidRM;
import rapaio.math.linear.dense.SolidRV;
/**
* Linear algebra tool bag class.
* Contains various utilities to create and manipulate linear algbra constructs like {@link RM} or {@link RV}
* <p>
* Created by <a href="mailto:padreati@yahoo.com">Aurelian Tutuianu</a> at 2/6/15.
*/
public final class Linear {
public static RM chol2inv(RM R) {
return chol2inv(R, SolidRM.identity(R.rowCount()));
}
public static RM chol2inv(RM R, RM B) {
RM ref = R.t();
if (B.rowCount() != R.rowCount()) {
throw new IllegalArgumentException("Matrix row dimensions must agree.");
}
// Copy right hand side.
RM X = B.solidCopy();
// Solve L*Y = B;
for (int k = 0; k < ref.rowCount(); k++) {
for (int j = 0; j < X.colCount(); j++) {
for (int i = 0; i < k; i++) {
X.increment(k, j, -X.get(i, j) * ref.get(k, i));
}
X.set(k, j, X.get(k, j) / ref.get(k, k));
}
}
// Solve L'*X = Y;
for (int k = ref.rowCount() - 1; k >= 0; k--) {
for (int j = 0; j < X.colCount(); j++) {
for (int i = k + 1; i < ref.rowCount(); i++) {
X.increment(k, j, -X.get(i, j) * ref.get(i, k));
}
X.set(k, j, X.get(k, j) / ref.get(k, k));
}
}
return X;
}
/*
public static EigenPair pdEigenDecomp(RM s, int maxRuns, double tol) {
// runs QR decomposition algorithm for maximum of iterations
// to provide a solution which has other than diagonals under
// tolerance
// this works only for positive definite
// here we check only symmetry
if (s.rowCount() != s.colCount())
throw new IllegalArgumentException("This eigen pair method works only for positive definite matrices");
QR qr = s.qr();
s = qr.getR().dot(qr.getQ());
RM ev = qr.getQ();
for (int i = 0; i < maxRuns - 1; i++) {
qr = s.qr();
s = qr.getR().dot(qr.getQ());
ev = ev.dot(qr.getQ());
if (inTolerance(s, tol))
break;
}
return EigenPair.from(s.diag(), ev.solidCopy());
}*/
public static EigenPair eigenDecomp(RM s, int maxRuns, double tol) {
int n = s.colCount();
EigenvalueDecomposition evd = new EigenvalueDecomposition(s);
double[] _values = evd.getRealEigenvalues();
RM _vectors = evd.getV();
RV values = SolidRV.empty(n);
RM vectors = SolidRM.empty(n, n);
for (int i = 0; i < values.count(); i++) {
values.set(values.count() - i - 1, _values[i]);
}
for (int i = 0; i < vectors.rowCount(); i++) {
for (int j = 0; j < vectors.colCount(); j++) {
vectors.set(i, vectors.colCount() - j - 1, _vectors.get(i, j));
}
}
return EigenPair.from(values, vectors);
}
public static RM pdPower(RM s, double power, int maxRuns, double tol) {
EigenPair p = eigenDecomp(s, maxRuns, tol);
RM U = p.vectors();
RM lambda = p.expandedValues();
for (int i = 0; i < lambda.rowCount(); i++) {
//TODO quick fix
// this is because negative numbers can be produced for small quantities
lambda.set(i, i, Math.pow(Math.abs(lambda.get(i, i)), power));
}
return U.dot(lambda).dot(U.t());
}
private static boolean inTolerance(RM s, double tol) {
for (int i = 0; i < s.rowCount(); i++) {
for (int j = i + 1; j < s.colCount(); j++) {
if (Math.abs(s.get(i, j)) > tol)
return false;
}
}
return true;
}
}