我不确定这是一个maths.se还是一个SO问题,但是我认为这与我的Java有关。
我正在关注高斯过程(R&W)的教科书并在Java中实现一些示例。几个示例的一个常见步骤是生成协方差矩阵的Cholesky分解。在我的尝试中,我可以获得有限大小(33x33)的矩阵的成功结果。然而,对于任何更大的NaN出现在对角线上(在32,32处),因此矩阵中的所有后续值同样是NaN。
代码如下所示,NaN的来源以cholesky
方式显示。基本上协方差元素a[32][32]
是1.0,但sum
的值略高于此(1.0000001423291431),因此平方根是虚数。所以我的问题是:
请注意,我不是在寻找使用库的建议。这只是为了我自己的理解。
道歉,但我试图提供一个完整的MWE:
import static org.junit.Assert.assertFalse;
import org.junit.Test;
public class CholeskyTest {
@Test
public void testCovCholesky() {
final int n = 34; // Test passes for n<34
final double[] xData = getSpread(-5, 5, n);
double[][] cov = covarianceSE(xData);
double[][] lower = cholesky(cov);
for(int i=0; i<n; ++i) {
for(int j=0; j<n; ++j) {
assertFalse("NaN at " + i + "," + j, Double.isNaN(lower[i][j]));
}
}
}
/**
* Generate n evenly space values from min to max inclusive
*/
private static double[] getSpread(final double min, final double max, final int n) {
final double[] values = new double[n];
final double delta = (max - min)/(n - 1);
for(int i=0; i<n; ++i) {
values[i] = min + i*delta;
}
return values;
}
/**
* Calculate the covariance matrix for the given observations using
* the squared exponential (SE) covariance function.
*/
private static double[][] covarianceSE (double[] v) {
final int m = v.length;
double[][] k = new double[m][];
for(int i=0; i<m; ++i) {
double vi = v[i];
double row[] = new double[m];
for(int j=0; j<m; ++j) {
double dist = vi - v[j];
row[j] = Math.exp(-0.5*dist*dist);
}
k[i] = row;
}
return k;
}
/**
* Calculate lower triangular matrix L such that LL^T = A
* Using Cholesky decomposition from
* https://rosettacode.org/wiki/Cholesky_decomposition#Java
*/
private static double[][] cholesky(double[][] a) {
final int m = a.length;
double[][] l = new double[m][m];
for(int i = 0; i< m;i++){
for(int k = 0; k < (i+1); k++){
double sum = 0;
for(int j = 0; j < k; j++){
sum += l[i][j] * l[k][j];
}
l[i][k] = (i == k) ? Math.sqrt(a[i][i] - sum) : // Source of NaN at 32,32
(1.0 / l[k][k] * (a[i][k] - sum));
}
}
return l;
}
}
答案 0 :(得分:2)
在实践中,可能需要添加一小部分 单位矩阵$ \ epsilon I $到协方差矩阵的数值 原因。这是因为矩阵K的特征值可以衰减 非常迅速[...]并且没有这种稳定的Cholesky 分解失败。对生成的样本的影响是添加 额外的独立方差噪声$ epsilon $。
所以以下改变似乎就足够了:
private static double[][] cholesky(double[][] a) {
final int m = a.length;
double epsilon = 0.000001; // Small extra noise value
double[][] l = new double[m][m];
for(int i = 0; i< m;i++){
for(int k = 0; k < (i+1); k++){
double sum = 0;
for(int j = 0; j < k; j++){
sum += l[i][j] * l[k][j];
}
l[i][k] = (i == k) ? Math.sqrt(a[i][i]+epsilon - sum) : // Add noise to diagonal values
(1.0 / l[k][k] * (a[i][k] - sum));
}
}
return l;
}
答案 1 :(得分:0)
我刚刚用C ++和JavaScript编写了我自己的Cholesky分解例程版本。而不是计算L,它计算U,但我很想用导致NaN错误的矩阵测试它。你能在这里发布矩阵,或者联系我(Profile中的信息。)