Java中的CHOLMOD

Java中的CHOLMOD,java,matrix-decomposition,Java,Matrix Decomposition,我已经问过类似的问题,但这次我会更具体 我需要在for循环中执行通常较大的正定symmetrix矩阵的Cholesky分解(大约1000x1000)。现在,为了做到这一点,我一直在尝试: 1) Apache数学库 2) 并行柯尔特库 3) JLapack库 例如,在上述三种情况中的任何一种情况下,如果与MATLAB相比,时间消耗都非常长 因此,我想知道Java中是否有用于Cholesky分解的高度优化的外部工具:例如,我一直在思考算法,它实际上是在MATLAB和其他工具内部调用的 我真的很感谢您

我已经问过类似的问题,但这次我会更具体

我需要在
for
循环中执行通常较大的正定symmetrix矩阵的Cholesky分解(大约
1000x1000
)。现在,为了做到这一点,我一直在尝试:

1) Apache数学库

2) 并行柯尔特库

3) JLapack库

例如,在上述三种情况中的任何一种情况下,如果与MATLAB相比,时间消耗都非常长

因此,我想知道Java中是否有用于Cholesky分解的高度优化的外部工具:例如,我一直在思考算法,它实际上是在
MATLAB
和其他工具内部调用的


我真的很感谢您对此事的全面反馈。

我没有使用过这些工具中的任何一个,但我怀疑您会被Java在某些版本/某些平台上没有使用本机处理器浮点平方根指令这一事实所打击

见:


如果不要求绝对精度,您可以尝试将上述实现之一切换为使用平方根近似值(有关建议,请参阅),这应该会快一些。

以下是一些用于Java的BLAS库的良好总结:。您还可以在上看到许多这些库的基准测试

然而,根据我的经验,这些库中的大多数似乎都不适合求解大型稀疏矩阵。在我的例子中,我所做的是通过JNI实现解决方案

包括一个在CHOLMOD上

在我的例子中,通过JNI使用Eigen的解算器的8860x8860稀疏矩阵比并行colt快20倍,比我自己的稠密解算器快10倍。更重要的是,它似乎是按
n^2
而不是
n^3
进行缩放的,并且它使用的内存比我的密集解算器少得多(我在放大时内存不足)

实际上有一个名为Egen with Java的包装器,它使用JNI。但是,它没有实现稀疏矩阵求解,因此它没有封装所有内容

我最初使用JNA,但对开销不满意。维基百科有。编写函数声明后,用<代码> javac < /C>编译它们。使用<代码> java<代码>创建C++的头文件。p> 例如

//Cholesky.java
package cfd.optimisation;
//ri, ci, v : matrix row indices, column indices, and values
//y = Ax where A is a nxn matrix with nnz non-zero values
public class Cholesky {
    private static native void solve_eigenLDLTx(int[] ri, int[] ci, double[] v, double[] x, double[] y, int n, int nnz);
}
使用
javah
生成带有声明的头文件cfd\u optimization\u Cholesky.h

JNIEXPORT void JNICALL Java_cfd_optimisation_Cholesky_solve_1eigenLDLTx
        (JNIEnv *, jclass, jintArray, jintArray, jdoubleArray, jdoubleArray, jdoubleArray, jint, jint); 
下面是我如何实现解算器的

JNIEXPORT void JNICALL Java_cfd_optimisation_Cholesky_solve_1eigenLDLTx(JNIEnv *env, jclass obj, jintArray arrri, jintArray arrci, jdoubleArray arrv, jdoubleArray arrx, jdoubleArray arry, jint jn, jint jnnz) {
    int n = jn;
    int *ri = (int*)env->GetPrimitiveArrayCritical(arrri, 0);
    int *ci = (int*)env->GetPrimitiveArrayCritical(arrci, 0);
    double *v = (double*)env->GetPrimitiveArrayCritical(arrv, 0);
    int nnz = jnnz;

    double *x = (double*)env->GetPrimitiveArrayCritical(arrx, 0);
    double *y = (double*)env->GetPrimitiveArrayCritical(arry, 0);

    Eigen::SparseMatrix<double> A = colt2eigen(ri, ci, v, nnz, n);
    //Eigen::MappedSparseMatrix<double> A(n, n, nnz, ri, ci, v);

    Eigen::VectorXd a(n), b(n);
    for (int i = 0; i < n; i++) a(i) = x[i];
    //a = Eigen::Map<Eigen::VectorXd>(x, n).cast<double>(); 
    Eigen::SimplicialCholesky<Eigen::SparseMatrix<double> > solver;
    solver.setMode(Eigen::SimplicialCholeskyLDLT);
    b = solver.compute(A).solve(a);
    for (int i = 0; i < n; i++) y[i] = b(i);
    env->ReleasePrimitiveArrayCritical(arrri, ri, 0);
    env->ReleasePrimitiveArrayCritical(arrci, ci, 0);
    env->ReleasePrimitiveArrayCritical(arrv, v, 0);
    env->ReleasePrimitiveArrayCritical(arrx, x, 0);
    env->ReleasePrimitiveArrayCritical(arry, y, 0);
}
其中一个棘手的部分是从Java和Colt获取这些数组。这样做 是我干的

//y = A x: x and y are double[] arrays and A is DoubleMatrix2D
int nnz = A.cardinality();
DoubleArrayList v = new DoubleArrayList(nnz);
IntArrayList ci = new IntArrayList(nnz);
IntArrayList ri = new IntArrayList(nnz);

A.forEachNonZero((row, column, value) -> {
    v.add(value); ci.add(column); ri.add(row); return value;}
);

Cholesky.solve_eigenLDLTx(ri.elements(), ci.elements(), v.elements(), x, y, n, nnz);

那么jamal呢:@fGo:我已经知道了
JAMA
,它的性能应该比
Parallel Colt
低。此外,我不知道
CHOLMOD
是否在
JAMA
内部可用。令人惊讶的是,Java并不是数字运行的最佳解决方案。。。如果你想提高性能,可以通过JNI调用CHOLMOD……你找到解决方案了吗?我是通过用JNI实现Eigen::SparseMatrix来实现的。如果你愿意,我可以写一个答案。我还从事海上风荷载研究。我用它做了一个基于CFD的快速模拟。我真的不认为瓶颈会是
sqrt
函数,但我可以尝试一下你的建议。
//y = A x: x and y are double[] arrays and A is DoubleMatrix2D
int nnz = A.cardinality();
DoubleArrayList v = new DoubleArrayList(nnz);
IntArrayList ci = new IntArrayList(nnz);
IntArrayList ri = new IntArrayList(nnz);

A.forEachNonZero((row, column, value) -> {
    v.add(value); ci.add(column); ri.add(row); return value;}
);

Cholesky.solve_eigenLDLTx(ri.elements(), ci.elements(), v.elements(), x, y, n, nnz);