Spec-Zone.ru › Eigen3

Суммирование, посетители и трансляция

Эта страница объясняет суммирование, посетителей и трансляцию в Eigen и как они используются с матрицами и массивами.

Суммирование

В Eigen суммирование — это функция, принимающая матрицу или массив и возвращающая одно скалярное значение. Одна из наиболее используемых функций суммирования — .sum() , возвращающая сумму всех коэффициентов внутри заданной матрицы или массива.

Пример: Вывод:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
int main()
{
  Eigen::Matrix2d mat;
  mat << 1, 2,
         3, 4;
  cout << "Here is mat.sum():       " << mat.sum()       << endl;
  cout << "Here is mat.prod():      " << mat.prod()      << endl;
  cout << "Here is mat.mean():      " << mat.mean()      << endl;
  cout << "Here is mat.minCoeff():  " << mat.minCoeff()  << endl;
  cout << "Here is mat.maxCoeff():  " << mat.maxCoeff()  << endl;
  cout << "Here is mat.trace():     " << mat.trace()     << endl;
}
Here is mat.sum():       10
Here is mat.prod():      24
Here is mat.mean():      2.5
Here is mat.minCoeff():  1
Here is mat.maxCoeff():  4
Here is mat.trace():     5

След матрицы, возвращаемый функцией trace(), — это сумма диагональных коэффициентов, и он может быть вычислен аналогично a.diagonal().sum().

Вычисление нормы

Квадрат нормы (евклидовой, т.е. \(\ell^2\)) вектора может быть получена с помощью функции squaredNorm() . Она равна скалярному произведению вектора на самого себя и, аналогично, сумме квадратов абсолютных значений его коэффициентов.

Библиотека Eigen также предоставляет метод norm() , который возвращает квадратный корень из squaredNorm() .

Эти операции также могут быть применены к матрицам; в этом случае матрица n×p рассматривается как вектор размера (n×p), поэтому, например, метод norm() возвращает норму Фробениуса или Гильберта-Шмидта. Мы избегаем упоминания нормы \(\ell^2\) матрицы, потому что это может означать разные вещи.

Если вам нужны другие коэффициентные нормы \(\ell^p\), используйте метод lpNorm<p>() . Шаблонный параметр p может принимать специальное значение Infinity, если вам нужна норма \(\ell^\infty\), которая является максимальным значением из абсолютных значений коэффициентов.

Следующий пример демонстрирует эти методы.

Пример: Вывод:
#include <Eigen/Dense>
#include <iostream>
 
using namespace std;
using namespace Eigen;
 
int main()
{
  VectorXf v(2);
  MatrixXf m(2,2), n(2,2);
  
  v << -1,
       2;
  
  m << 1,-2,
       -3,4;
 
  cout << "v.squaredNorm() = " << v.squaredNorm() << endl;
  cout << "v.norm() = " << v.norm() << endl;
  cout << "v.lpNorm<1>() = " << v.lpNorm<1>() << endl;
  cout << "v.lpNorm<Infinity>() = " << v.lpNorm<Infinity>() << endl;
 
  cout << endl;
  cout << "m.squaredNorm() = " << m.squaredNorm() << endl;
  cout << "m.norm() = " << m.norm() << endl;
  cout << "m.lpNorm<1>() = " << m.lpNorm<1>() << endl;
  cout << "m.lpNorm<Infinity>() = " << m.lpNorm<Infinity>() << endl;
}
v.squaredNorm() = 5
v.norm() = 2.23607
v.lpNorm<1>() = 3
v.lpNorm<Infinity>() = 2

m.squaredNorm() = 30
m.norm() = 5.47723
m.lpNorm<1>() = 10
m.lpNorm<Infinity>() = 4

Норма оператора: 1-норма и \(\infty\)-норма матричных норм операторов могут быть легко вычислены следующим образом:

Пример: Вывод:
#include <Eigen/Dense>
#include <iostream>
 
using namespace Eigen;
using namespace std;
 
int main()
{
  MatrixXf m(2,2);
  m << 1,-2,
       -3,4;
 
  cout << "1-norm(m)     = " << m.cwiseAbs().colwise().sum().maxCoeff()
       << " == "             << m.colwise().lpNorm<1>().maxCoeff() << endl;
 
  cout << "infty-norm(m) = " << m.cwiseAbs().rowwise().sum().maxCoeff()
       << " == "             << m.rowwise().lpNorm<1>().maxCoeff() << endl;
}
1-norm(m)     = 6 == 6
infty-norm(m) = 7 == 7

См. ниже более подробное объяснение синтаксиса этих выражений.

Булевы суммирования

Следующие суммирования работают с булевыми значениями:

  • all() возвращает true, если все коэффициенты в заданной матрице или массиве равны true.
  • any() возвращает true, если хотя бы один из коэффициентов в заданной матрице или массиве равен true.
  • count() возвращает количество коэффициентов в заданной матрице или массиве, равных true.

Они обычно используются совместно с операторами сравнения и равенства для коэффициентов, предоставляемыми массивом. Например, array > 0 — это массив того же размера, что и array, со значением true в тех позициях, где соответствующий коэффициент array положителен. Таким образом, (array > 0).all() проверяет, все ли коэффициенты array положительны. Это можно увидеть в следующем примере:

Пример: Вывод:
#include <Eigen/Dense>
#include <iostream>
 
using namespace std;
using namespace Eigen;
 
int main()
{
  ArrayXXf a(2,2);
  
  a << 1,2,
       3,4;
 
  cout << "(a > 0).all()   = " << (a > 0).all() << endl;
  cout << "(a > 0).any()   = " << (a > 0).any() << endl;
  cout << "(a > 0).count() = " << (a > 0).count() << endl;
  cout << endl;
  cout << "(a > 2).all()   = " << (a > 2).all() << endl;
  cout << "(a > 2).any()   = " << (a > 2).any() << endl;
  cout << "(a > 2).count() = " << (a > 2).count() << endl;
}
(a > 0).all()   = 1
(a > 0).any()   = 1
(a > 0).count() = 4

(a > 2).all()   = 0
(a > 2).any()   = 1
(a > 2).count() = 2

Суммирования, определённые пользователем

TODO

В то же время вы можете ознакомиться с функцией DenseBase::redux().

Посетители

Посетители полезны, когда нужно получить местоположение коэффициента внутри матрицы или массива. Самые простые примеры — maxCoeff(&x,&y) и minCoeff(&x,&y), которые можно использовать для поиска местоположения наибольшего или наименьшего коэффициента в матрице или массиве.

Передаваемые аргументы посетителю — указатели на переменные, где будут храниться строка и столбец. Эти переменные должны быть типа Index , как показано ниже:

Пример: Вывод:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
using namespace Eigen;
 
int main()
{
  Eigen::MatrixXf m(2,2);
  
  m << 1, 2,
       3, 4;
 
  //get location of maximum
  MatrixXf::Index maxRow, maxCol;
  float max = m.maxCoeff(&maxRow, &maxCol);
 
  //get location of minimum
  MatrixXf::Index minRow, minCol;
  float min = m.minCoeff(&minRow, &minCol);
 
  cout << "Max: " << max <<  ", at: " <<
     maxRow << "," << maxCol << endl;
  cout << "Min: " << min << ", at: " <<
     minRow << "," << minCol << endl;
}
Max: 4, at: 1,1
Min: 1, at: 0,0

Обе функции также возвращают значение минимального или максимального коэффициента.

Частичные суммирования

Частичные суммирования — это суммирования, которые могут работать по столбцам или строкам матрицы или массива, применяя операцию суммирования к каждому столбцу или строке и возвращая вектор-столбец или вектор-строку с соответствующими значениями. Частичные суммирования применяются с помощью colwise() или rowwise() .

Простой пример — получение максимального значения элементов в каждом столбце заданной матрицы, сохраняя результат в векторе-строке:

Пример: Вывод:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
int main()
{
  Eigen::MatrixXf mat(2,4);
  mat << 1, 2, 6, 9,
         3, 1, 7, 2;
  
  std::cout << "Column's maximum: " << std::endl
   << mat.colwise().maxCoeff() << std::endl;
}
Column's maximum: 
3 2 7 9

Ту же операцию можно выполнить по строкам:

Пример: Вывод:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
int main()
{
  Eigen::MatrixXf mat(2,4);
  mat << 1, 2, 6, 9,
         3, 1, 7, 2;
  
  std::cout << "Row's maximum: " << std::endl
   << mat.rowwise().maxCoeff() << std::endl;
}
Row's maximum: 
9
7

Обратите внимание, что операции по столбцам возвращают вектор-строку, а операции по строкам — вектор-столбец.

Объединение частичных суммирований с другими операциями

Также можно использовать результат частичного суммирования для дальнейшей обработки. Вот ещё один пример, который находит столбец, сумма элементов которого максимальна в матрице. С помощью частичных суммирований по столбцам это можно записать так:

Пример: Вывод:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
using namespace Eigen;
int main()
{
  MatrixXf mat(2,4);
  mat << 1, 2, 6, 9,
         3, 1, 7, 2;
  
  MatrixXf::Index   maxIndex;
  float maxNorm = mat.colwise().sum().maxCoeff(&maxIndex);
  
  std::cout << "Maximum sum at position " << maxIndex << std::endl;
 
  std::cout << "The corresponding vector is: " << std::endl;
  std::cout << mat.col( maxIndex ) << std::endl;
  std::cout << "And its sum is is: " << maxNorm << std::endl;
}
Maximum sum at position 2
The corresponding vector is: 
6
7
And its sum is is: 13

В предыдущем примере применяется суммирование sum() к каждому столбцу через посетителя colwise() , получая новую матрицу размера 1x4.

Поэтому, если

\[ \mbox{m} = \begin{bmatrix} 1 & 2 & 6 & 9 \\ 3 & 1 & 7 & 2 \end{bmatrix} \]

то

\[ \mbox{m.colwise().sum()} = \begin{bmatrix} 4 & 3 & 13 & 11 \end{bmatrix} \]

Наконец, применяется суммирование maxCoeff() для получения индекса столбца, где находится максимальная сумма, в данном случае столбец 2 (третий столбец).

Трансляция

Концепция трансляции похожа на частичные суммирования, с той разницей, что трансляция строит выражение, где вектор (столбец или строка) интерпретируется как матрица путём его копирования в одном направлении.

Простой пример — добавление определённого столбцового вектора к каждому столбцу матрицы. Это можно сделать с помощью:

Пример: Вывод:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
int main()
{
  Eigen::MatrixXf mat(2,4);
  Eigen::VectorXf v(2);
  
  mat << 1, 2, 6, 9,
         3, 1, 7, 2;
         
  v << 0,
       1;
       
  //add v to each column of m
  mat.colwise() += v;
  
  std::cout << "Broadcasting result: " << std::endl;
  std::cout << mat << std::endl;
}
Broadcasting result: 
1 2 6 9
4 2 8 3

Мы можем интерпретировать инструкцию mat.colwise() += v двумя эквивалентными способами. Она добавляет вектор v к каждому столбцу матрицы. В качестве альтернативы, её можно интерпретировать как повторение вектора v четыре раза для формирования матрицы 4x2, которая затем добавляется к mat:

\[ \begin{bmatrix} 1 & 2 & 6 & 9 \\ 3 & 1 & 7 & 2 \end{bmatrix} + \begin{bmatrix} 0 & 0 & 0 & 0 \\ 1 & 1 & 1 & 1 \end{bmatrix} = \begin{bmatrix} 1 & 2 & 6 & 9 \\ 4 & 2 & 8 & 3 \end{bmatrix}. \]

Операторы -=, + и - также могут использоваться по столбцам и строкам. Для массивов также можно использовать операторы *=, /=, * и / для выполнения поэлементного умножения и деления по столбцам или строкам. Эти операторы недоступны для матриц, так как неясно, что они должны делать. Если вы хотите умножить 0-й столбец матрицы mat на v(0), 1-й столбец на v(1) и так далее, используйте mat = mat * v.asDiagonal().

Важно отметить, что вектор, который необходимо добавить по столбцам или по строкам, должен быть типа Vector, а не Matrix. В противном случае вы получите ошибку времени компиляции. Это также означает, что операции вещания могут применяться только с объектом типа Vector при работе с Matrix. То же самое относится к классу Array, где эквивалентом VectorXf является ArrayXf. Как всегда, вы не должны смешивать массивы и матрицы в одном выражении.

Для выполнения той же операции по строкам можно сделать следующее:

Пример: Результат:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
int main()
{
  Eigen::MatrixXf mat(2,4);
  Eigen::VectorXf v(4);
  
  mat << 1, 2, 6, 9,
         3, 1, 7, 2;
         
  v << 0,1,2,3;
       
  //add v to each row of m
  mat.rowwise() += v.transpose();
  
  std::cout << "Broadcasting result: " << std::endl;
  std::cout << mat << std::endl;
}
Broadcasting result: 
 1  3  8 12
 3  2  9  5

Объединение вещания с другими операциями

Вещание также можно объединить с другими операциями, такими как операции с Matrix или Array, редукции и частичные редукции.

Теперь, когда вещание, редукции и частичные редукции были введены, мы можем перейти к более сложному примеру, который находит ближайшего соседа вектора v среди столбцов матрицы m. В этом примере будет использоваться евклидово расстояние, вычисляя квадрат евклидова расстояния с помощью частичной редукции, названной squaredNorm() :

Пример: Результат:
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
using namespace Eigen;
 
int main()
{
  Eigen::MatrixXf m(2,4);
  Eigen::VectorXf v(2);
  
  m << 1, 23, 6, 9,
       3, 11, 7, 2;
       
  v << 2,
       3;
 
  MatrixXf::Index index;
  // find nearest neighbour
  (m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
 
  cout << "Nearest neighbour is column " << index << ":" << endl;
  cout << m.col(index) << endl;
}
Nearest neighbour is column 0:
1
3

Строка, выполняющая задачу, выглядит следующим образом:

(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);

Мы разберем пошагово, что происходит:

  • m.colwise() - v — это операция вещания, вычитающая v из каждого столбца в m. Результатом этой операции является новая матрица, размер которой такой же, как у матрицы m:

    \[ \mbox{m.colwise() - v} = \begin{bmatrix} -1 & 21 & 4 & 7 \\ 0 & 8 & 4 & -1 \end{bmatrix} \]

  • (m.colwise() - v).colwise().squaredNorm() — это частичная редукция, вычисляющая квадрат нормы по столбцам. Результатом этой операции является строковый вектор, где каждый коэффициент — это квадрат евклидова расстояния между каждым столбцом в m и v:

    \[ \mbox{(m.colwise() - v).colwise().squaredNorm()} = \begin{bmatrix} 1 & 505 & 32 & 50 \end{bmatrix} \]

  • Наконец, minCoeff(&index) используется для получения индекса столбца в m, который наиболее близок к v в терминах евклидова расстояния.

© Eigen.
Licensed under the MPL2 License.
https://eigen.tuxfamily.org/dox/group__TutorialReductionsVisitorsBroadcasting.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API