行列式计算函数的优化
Optimization of determinant calculation function
在搜索最佳算法时,我发现有一个折衷方案:一方面是实现的复杂性和大常数,另一方面是运行时复杂性。我选择了基于LU分解的算法,因为它实现起来很简单,并且具有足够好的性能。
#include <valarray>
#include <vector>
#include <utility>
#include <cmath>
#include <cstddef>
#include <cassert>
template< typename value_type >
struct math
{
using size_type = std::size_t;
size_type const dimension_;
value_type const & eps;
value_type const zero = value_type(0);
value_type const one = value_type(1);
private :
using vector = std::valarray< value_type >;
using matrix = std::vector< vector >;
matrix matrix_;
matrix minor_;
public :
math(size_type const _dimension,
value_type const & _eps)
: dimension_(_dimension)
, eps(_eps)
, matrix_(dimension_)
, minor_(dimension_ - 1)
{
assert(1 < dimension_);
assert(!(eps < zero));
for (size_type r = 0; r < dimension_; ++r) {
matrix_[r].resize(dimension_);
}
size_type const minor_size = dimension_ - 1;
for (size_type r = 0; r < minor_size; ++r) {
minor_[r].resize(minor_size);
}
}
template< typename rhs = matrix >
void
operator = (rhs const & _matrix)
{
auto irow = std::begin(matrix_);
for (auto const & row_ : _matrix) {
auto icol = std::begin(*irow);
for (auto const & v : row_) {
*icol = v;
++icol;
}
++irow;
}
}
value_type
det(matrix & _matrix,
size_type const _dimension)
{ // calculates lower unit triangular matrix and upper triangular
assert(0 < _dimension);
value_type det_ = one;
for (size_type i = 0; i < _dimension; ++i) {
vector & ri_ = _matrix[i];
using std::abs;
value_type max_ = abs(ri_[i]);
size_type pivot = i;
{
size_type p = i;
while (++p < _dimension) {
value_type y_ = abs(_matrix[p][i]);
if (max_ < y_) {
max_ = std::move(y_);
pivot = p;
}
}
}
if (!(eps < max_)) { // regular?
return zero; // singular
}
if (pivot != i) {
det_ = -det_; // each permutation flips sign of det
ri_.swap(_matrix[pivot]);
}
value_type & dia_ = ri_[i];
det_ *= dia_; // det is multiple of diagonal elements
for (size_type j = 1 + i; j < _dimension; ++j) {
_matrix[j][i] /= dia_;
}
for (size_type a = 1 + i; a < _dimension; ++a) {
vector & a_ = minor_[a - 1];
value_type const & ai_ = _matrix[a][i];
for (size_type b = 1 + i; b < _dimension; ++b) {
a_[b - 1] = ai_ * ri_[b];
}
}
for (size_type a = 1 + i; a < _dimension; ++a) {
vector const & a_ = minor_[a - 1];
vector & ra_ = _matrix[a];
for (size_type b = 1 + i; b < _dimension; ++b) {
ra_[b] -= a_[b - 1];
}
}
}
return det_;
}
value_type
det(size_type const _dimension)
{
return det(matrix_, _dimension);
}
value_type
det()
{
return det(dimension_);
}
};
// main.cpp
#include <iostream>
#include <cstdlib>
int
main()
{
using value_type = double;
value_type const eps = std::numeric_limits< value_type >::epsilon();
std::size_t const dimension_ = 3;
math< value_type > m(dimension_, eps);
m = { // example from https://en.wikipedia.org/wiki/Determinant#Laplace.27s_formula_and_the_adjugate_matrix
{-2.0, 2.0, -3.0},
{-1.0, 1.0, 3.0},
{ 2.0, 0.0, -1.0}
};
std::cout << m.det() << std::endl; // 18
return EXIT_SUCCESS;
}
现场演示
det()
函数是算法中最热门的函数,将其作为算法的一部分。我确信det()
没有它能做到的那么快,因为运行时性能比较(使用google pprof)与整个算法的参考实现显示出对det()
的不均衡。
如何提高det()
函数的性能?哪些明显的优化可以立即应用?我应该更改索引和内存访问顺序还是其他什么?容器类型?预取?
dimension_
的典型值在3到10的范围内(但如果value_type
是mpfr或其他值,则可以是100)。
您的(来自det()
的片段)不是吗
for (size_type a = 1 + i; a < _dimension; ++a) {
vector & a_ = minor_[a - 1];
value_type const & ai_ = _matrix[a][i];
for (size_type b = 1 + i; b < _dimension; ++b) {
a_[b - 1] = ai_ * ri_[b];
}
}
for (size_type a = 1 + i; a < _dimension; ++a) {
vector const & a_ = minor_[a - 1];
vector & ra_ = _matrix[a];
for (size_type b = 1 + i; b < _dimension; ++b) {
ra_[b] -= a_[b - 1];
}
}
做与相同的事情
for (size_type a = 1 + i; a < _dimension; ++a) {
vector & ra_ = _matrix[a];
value_type ai_ = ra_[i];
for (size_type b = 1 + i; b < _dimension; ++b) {
ra_[b] -= ai_ * ri_[b];
}
}
而不需要minor_
?此外,现在可以很容易地对内部循环进行矢量化。
相关文章:
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 纯函数,为什么没有优化
- 线性优化目标函数中的绝对值
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- 何时允许编译器优化复制构造函数
- C++延迟后的优化器调用函数
- 未使用的C++未优化的静态成员函数/变量
- 我应该保留这个函数来查找第 n 个素数还是可以优化?
- 如何使用 g2o 优化多约束函数
- GCC 能否优化具有相同主体的函数的代码大小?
- 对于优化级别为 0 的 std::vector,析构函数被调用两次
- 尾递归函数未被 g++ 优化
- 函数优化传递
- 优化在网格图中查找哈密尔循环的函数?
- C++将 lambda 函数另存为成员变量,而不使用函数指针进行优化
- 使用谷神星优化多维函数
- 创建一个始终返回零但优化器不知道的函数
- 编译器优化-函数没有地址
- 整数到字符串优化函数
- c++:优化函数,没有副作用