gpt4 book ai didi

java - Java 中的 CHOLMOD

转载 作者:搜寻专家 更新时间:2023-10-31 19:56:08 26 4
gpt4 key购买 nike

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

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

1) Apache 数学库

2) 并行 Colt 库

3) JLapack 库

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

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

如果能就此问题提供全面的反馈,我将不胜感激。

最佳答案

以下是一些适用于 Java 的 BLAS 库的很好的总结:performance-of-java-matrix-math-libraries .您还可以在 Java-Matrix-Benchmark 查看其中许多库的基准测试。 .

但是,根据我的经验,这些库中的大多数似乎都没有针对求解大型稀疏矩阵进行调整。在我的例子中,我所做的是使用 Eigen 实现解决方案。通过 JNI。

Eigen has a good discussion on its linear solvers包括一个关于 CHOLMOD 的。

在我的案例中,通过 JNI 使用 Eigen 求解器的 8860x8860 稀疏矩阵比并行 colt 快 20 倍,比我自己的密集求解器快 10 倍。更重要的是,它似乎扩展为 n^2 而不是 n^3 并且它使用的内存比我的密集求解器少得多(我的内存已用完扩展).

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

我最初使用 JNA,但对开销不满意。维基百科有 a good example on how to use JNI .一旦您编写了函数声明并使用 javac 编译它们,您就可以使用 javah 创建 C++ 的头文件。

例如

//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_optimization_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);
}

函数 colt2eigen 从包含行和列索引的两个整数数组和一个 double 组创建一个稀疏矩阵。

Eigen::SparseMatrix<double> colt2eigen(int *ri, int *ci, double* v, int nnz, int n) {
std::vector<Eigen::Triplet<double>> tripletList;
for (int i = 0; i < nnz; i++) {
tripletList.push_back(Eigen::Triplet<double>(ri[i], ci[i], v[i]));
}
Eigen::SparseMatrix<double> m(n, n);
m.setFromTriplets(tripletList.begin(), tripletList.end());
return m;
}

其中一个棘手的部分是从 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);

关于java - Java 中的 CHOLMOD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17046585/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com