Суммирование, посетители и трансляция
Эта страница объясняет суммирование, посетителей и трансляцию в 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