我已经问过类似的问题,但是这次我将更具体。
我需要在一个for
循环中执行通常较大的正定对称矩阵(约1000x1000
)的Cholesky分解。现在,为此,我一直尝试:
1)Apache数学库
2)平行柯尔特库
3)JLapack库
在上述三种情况中的任何一种情况下,例如与MATLAB相比,时间消耗都非常长。
因此,我想知道Java中是否存在用于Cholesky分解的高度优化的外部工具:例如,我一直在思考CHOLMOD算法,该算法实际上是在内部MATLAB
以及其他工具内部调用的。
非常感谢您对此事提供详尽的反馈。
这是一些用于Java的BLAS库的很好的摘要:performance-of-java-matrix-math-
libraries。您还可以在Java-Matrix-Benchmark上查看其中许多库的基准。
但是,根据我的经验,这些库中的大多数似乎都不适合解决大型稀疏矩阵。在我的情况下,我所做的是通过JNI
使用Eigen实现解决方案。
Eigen对其线性求解器进行了很好的讨论,其中包括一个在CHOLMOD上的讨论。
以我为例,使用Eigen的求解器通过JNI生成的8860x8860稀疏矩阵比并行柯尔特快20倍,比我自己的密集求解器快10倍。更重要的是,它看起来像按比例缩放,n^2
而不是按比例缩放,n^3
并且它使用的内存比密集型求解器要少得多(我用尽了按比例扩大内存)。
实际上,Eigen有一个Java封装器,称为JEigen,它使用JNI。但是,它没有实现稀疏矩阵求解,因此不会包装所有内容。
我最初使用JNA,但对开销不满意。Wikipedia
很好地说明了如何使用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
从两个包含行和列索引以及值的双精度数组的整数数组创建一个稀疏矩阵。
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 7中有(Java 8)流 *的等效实现吗? 我熟悉(Java 8)流,但是我的项目要求是使用Java 7。 *不要与inputStream和outputStream混淆。 问题答案: 在官方API中,没有。 Java 7没有更多的公共更新。如果您是客户,您可能仍然会获得较小的更新,但是对于反向移植Stream AP
问题内容: 我正在寻找Java中的KeyValuePair类。 由于java.util大量使用接口,因此没有提供具体的实现,只有Map.Entry接口。 我可以导入一些规范的实现吗?这是我讨厌实现100倍的“管道工编程”类之一。 问题答案: 类AbstractMap.SimpleEntry是通用的,并且可能有用。
问题内容: Java 的用途是什么?有什么好处?它是如何工作的?示例代码也将很有用。 问题答案: 关键是要提供线程安全的实现。多个线程可以对其进行读写,而没有机会接收到过时或损坏的数据。 提供自己的同步,因此您不必显式同步对其的访问。 的另一个功能是它提供了该方法,如果指定的键不存在,它将 自动 添加一个映射。考虑以下代码: 此代码不是线程安全的,因为另一个线程可以在到和的调用之间添加映射。正确的
问题内容: 在Java中调用R功能的最佳方法是什么? 我正在寻找一种使用我的Java应用程序在R中制作标准2d散点图和直方图的快速,简便和可靠的方法。我想知道快速Google搜索中出现的哪些程序包/界面最方便使用。 我期待您的建议! 问题答案: 使用JRI:http ://www.rforge.net/JRI/ 。它与rJava捆绑在一起,包括一些用法示例。 一个非常简单的示例如下:
问题内容: 我正在尝试在Java中实现以下代码: 通过使用以下之一: 我浏览了许多SO的示例和问题,但没有找到正确生成iv []的方法(与C中的值相同)。似乎没有办法做到这一点,因为java允许仅以随机(而不是C语言中可用的伪随机)创建此值。这是正确的吗?有人可以帮忙解决这个问题吗? 问题答案: 收到crypt专家的提示,找到了正确的解决方案:
问题内容: 有谁知道为什么选项卡(\ t)与JOptionPane.showMessageDialog不兼容? 我的代码如下: 还有其他方法可以在JOptionPane中对齐文本吗? 问题答案: 将选项卡式文本放入JTextArea