Следуя советам из этого поста Идентификация создания временных объектов в Eigen , я провел несколько тестов, чтобы понять, когда создаются временные объекты Eigen. Этот код используется для определения временных значений:
static long int nb_temporaries;
inline void on_temporary_creation( long int size ) {
if ( size != 0 ) nb_temporaries++;
}
#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { on_temporary_creation(size); }
Все тесты были выполнены с использованием VisualStudio 2017 (v15.9.20) с Eigen 3.3.7 и следующих объектов:
const int n = 100;
MatrixXd A( n, n );
VectorXd x( n );
VectorXd y( n );
VectorXd a( n );
VectorXd b( n );
Map<MatrixXd> A_map( A.data(), n, n );
Map<VectorXd> x_map( x.data(), n );
Map<VectorXd> y_map( y.data(), n );
Map<VectorXd> a_map( a.data(), n );
Map<VectorXd> b_map( b.data(), n );
SparseMatrix<double> As( n, n );
As.reserve( nnz );
As.makeCompressed();
Map<SparseMatrix<double>> As_map( n, n, nnz,
As.outerIndexPtr(), As.innerIndexPtr(), As.valuePtr(), nullptr );
Matrix2d A2;
Vector2d x2;
Vector2d b2;
Map<Matrix2d> A2_map( A2.data() );
Map<Vector2d> x2_map( x2.data() );
Map<Vector2d> b2_map( b2.data() );
Тест A: операции с коэффициентами
Ни одно из следующих временных созданий не создается:
x = a + b;
x.array() = a.array() / b.array();
x_map.array() = a_map.array() / b_map.array();
Тест B: продукт с плотной матрицей-вектором
Оба следующие создают 1 временный размер n:
y.noalias() = A * x + b;
y_map.noalias() = A_map * x_map + b_map;
Чтобы избежать этого, вы должны сделать:
y.noalias() = A.lazyProduct( x ) + b;
y_map.noalias() = A_map.lazyProduct( x_map ) + b_map;
Оба следующих создают 1 временный с размером n:
y.noalias() = A.selfadjointView<Eigen::Lower>() * x + b;
y_map.noalias() = A_map.selfadjointView<Eigen::Lower>() * x_map + b_map;
Чтобы этого избежать, вы следует выполнить:
y.noalias() = A.selfadjointView<Eigen::Lower>() * x;
y += b;
и
y_map.noalias() = A_map.selfadjointView<Eigen::Lower>() * x_map;
y_map += b_map;
Тест C: продукт с разреженным матричным вектором
Следующее создает 1 временный размер n:
y.noalias() = As * x + b;
Чтобы избежать этого, вы должны сделать:
y.noalias() = As * x;
y += b;
Следующее создает 4 временных размера (2, 2, n, 2):
y_map.noalias() = As_map * x_map + b_map;
Чтобы избежать Dynami c выделенные временные шкалы, которые вы должны сделать (есть еще 2 выделенных временных стека с размером 2):
y_map.noalias() = As_map * x_map;
y_map += b_map;
Следующее создание es 1 временный размер n:
y.noalias() = As.selfadjointView<Eigen::Lower>() * x + b;
Чтобы избежать этого, вы должны сделать:
y.noalias() = As.selfadjointView<Eigen::Lower>() * x;
y += b;
Следующее создает 6 временных шаблонов с размером (2, 2, 2, n, 2, 2):
y_map.noalias() = As_map.selfadjointView<Eigen::Lower>() * x_map + b_map;
Чтобы избежать динамически выделенных временных интервалов c, вы должны сделать это (есть еще 4 выделенных временных стека с размером 2):
y_map.noalias() = As_map.selfadjointView<Eigen::Lower>() * x_map;
y_map += b_map;
Тест D: QR-решение с фиксированной матрицей 2x2
Следующее создает 5 временных с размером (4, 2, 2, 2, 1):
x2.noalias() = A2.householderQr().solve( b2 );
Следующее создает 6 временных с размером (4, 4, 2, 2, 2, 1):
x2_map.noalias() = A2_map.householderQr().solve( b2_map );
Тест E: Разрешение разреженной матрицы LDLT
Следующее создает 8 временных размеров (n, n, n + 1, n, n , n, n, n):
SimplicialLDLT<SparseMatrix<double>> solver;
solver.analyzePattern( As );
Следующее создает 2 временных размера (n, n):
solver.factorize( As );
Если используется факторизация (см. Разложить матричные разложения ), а затем метод factorize создает 1 временный размер n. В этом случае явный вызов метода factorize полезен только в том случае, если некоторые элементы A изменились, но шаблон разрежения остается прежним.
Следующие элементы не создают временных значений:
x = solver.solve( b );
Подведение итогов:
- Коэффициенты мудрых операций не создают временных переменных
- Плотный матричный вектор продукт не создает временных значений, если используются lazyProduct и noalias
- Разреженная матрица не обеспечивает lazyProduct
- При использовании Map создается больше временных элементов
Что касается вышеупомянутых случаев, есть ли уловки, чтобы лучше выполнять и избегать временных?