Собственная ленивая оценка и временные показатели: некоторые тематические исследования - PullRequest
1 голос
/ 03 апреля 2020

Следуя советам из этого поста Идентификация создания временных объектов в 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 создается больше временных элементов

Что касается вышеупомянутых случаев, есть ли уловки, чтобы лучше выполнять и избегать временных?

...