Класс Array и операции поэлементного умножения
Эта страница предназначена для обзора и объяснений использования класса Eigen's Array.
Что такое класс Array?
Класс Array предоставляет массивы общего назначения, в отличие от класса Matrix, предназначенного для линейной алгебры. Кроме того, класс Array предоставляет простой способ выполнения операций поэлементного умножения, которые могут не иметь линейно-алгебраического смысла, например, добавление константы к каждому элементу массива или умножение двух массивов поэлементно.
Типы массивов
Array — шаблон класса, принимающий те же шаблонные параметры, что и Matrix. Как и для Matrix, первые три шаблонных параметра являются обязательными:
Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
Последние три шаблонных параметра являются необязательными. Поскольку это точно так же, как и для Matrix, мы не будем это объяснять здесь снова и просто сошлемся на Класс Matrix.
Eigen также предоставляет псевдонимы типов для некоторых распространенных случаев, аналогично псевдонимам типов Matrix, но с небольшими отличиями, так как слово «массив» используется для одномерных и двумерных массивов. Мы используем соглашение, что псевдонимы типов вида ArrayNt обозначают одномерные массивы, где N и t — размер и тип скаляра, как в псевдонимах типов Matrix, описанных на этой странице. Для двумерных массивов мы используем псевдонимы типов вида ArrayNNt. Некоторые примеры показаны в следующей таблице:
| Тип | Псевдоним типа |
|---|---|
Array<float,Dynamic,1> |
ArrayXf |
Array<float,3,1> |
Array3f |
Array<double,Dynamic,Dynamic> |
ArrayXXd |
Array<double,3,3> |
Array33d |
Доступ к значениям внутри массива
Оператор скобок перегружен для обеспечения чтения и записи элементов массива, как и в случае с матрицами. Кроме того, оператор << может использоваться для инициализации массивов (через инициализацию запятой) или для их вывода.
| Пример: | Вывод: |
|---|---|
#include <Eigen/Dense> #include <iostream> using namespace Eigen; using namespace std; int main() { ArrayXXf m(2,2); // assign some values coefficient by coefficient m(0,0) = 1.0; m(0,1) = 2.0; m(1,0) = 3.0; m(1,1) = m(0,1) + m(1,0); // print values to standard output cout << m << endl << endl; // using the comma-initializer is also allowed m << 1.0,2.0, 3.0,4.0; // print values to standard output cout << m << endl; } |
1 2 3 5 1 2 3 4 |
Дополнительную информацию об инициализации запятой см. в разделе Расширенная инициализация.
Сложение и вычитание
Сложение и вычитание двух массивов аналогично работе с матрицами. Операция допустима, если оба массива имеют одинаковый размер, и сложение или вычитание выполняются поэлементно.
Массивы также поддерживают выражения вида array + scalar , которые добавляют скаляр к каждому элементу массива. Это предоставляет функциональность, которая напрямую недоступна для объектов Matrix.
| Пример: | Вывод: |
|---|---|
#include <Eigen/Dense> #include <iostream> using namespace Eigen; using namespace std; int main() { ArrayXXf a(3,3); ArrayXXf b(3,3); a << 1,2,3, 4,5,6, 7,8,9; b << 1,2,3, 1,2,3, 1,2,3; // Adding two arrays cout << "a + b = " << endl << a + b << endl << endl; // Subtracting a scalar from an array cout << "a - 2 = " << endl << a - 2 << endl; } |
a + b = 2 4 6 5 7 9 8 10 12 a - 2 = -1 0 1 2 3 4 5 6 7 |
Умножение массивов
Прежде всего, вы, конечно, можете умножить массив на скаляр, это работает так же, как и с матрицами. В чем основное отличие массивов от матриц, так это в том, как они интерпретируют умножение. Матрицы интерпретируют умножение как матричное произведение, а массивы — как поэлементное произведение. Таким образом, два массива могут быть умножены только в том случае, если они имеют одинаковые размеры.
| Пример: | Вывод: |
|---|---|
#include <Eigen/Dense> #include <iostream> using namespace Eigen; using namespace std; int main() { ArrayXXf a(2,2); ArrayXXf b(2,2); a << 1,2, 3,4; b << 5,6, 7,8; cout << "a * b = " << endl << a * b << endl; } |
a * b = 5 12 21 32 |
Другие операции поэлементного умножения
Класс Array определяет другие операции поэлементного умножения помимо операторов сложения, вычитания и умножения, описанных выше. Например, метод .abs() вычисляет абсолютное значение каждого элемента, а .sqrt() — квадратный корень из элементов. Если у вас есть два массива одинакового размера, вы можете вызвать .min(.) , чтобы создать массив, элементы которого являются минимальными из соответствующих элементов двух заданных массивов. Эти операции проиллюстрированы в следующем примере.
| Пример: | Вывод: |
|---|---|
#include <Eigen/Dense> #include <iostream> using namespace Eigen; using namespace std; int main() { ArrayXf a = ArrayXf::Random(5); a *= 2; cout << "a =" << endl << a << endl; cout << "a.abs() =" << endl << a.abs() << endl; cout << "a.abs().sqrt() =" << endl << a.abs().sqrt() << endl; cout << "a.min(a.abs().sqrt()) =" << endl << a.min(a.abs().sqrt()) << endl; } |
a = 1.36 -0.422 1.13 1.19 1.65 a.abs() = 1.36 0.422 1.13 1.19 1.65 a.abs().sqrt() = 1.17 0.65 1.06 1.09 1.28 a.min(a.abs().sqrt()) = 1.17 -0.422 1.06 1.09 1.28 |
Дополнительные операции поэлементного умножения можно найти в Быстром справочнике.
Преобразование между выражениями массива и матрицы
Когда следует использовать объекты класса Matrix, а когда — объекты класса Array? Вы не можете применять операции Matrix к массивам или операции Array к матрицам. Таким образом, если вам необходимо выполнить линейно-алгебраические операции, такие как умножение матриц, то следует использовать матрицы; если вам необходимо выполнить операции поэлементного умножения, то следует использовать массивы. Однако иногда это не так просто, и вам нужно использовать как Matrix, так и Array. В этом случае вам нужно преобразовать матрицу в массив или наоборот. Это дает доступ ко всем операциям независимо от выбора объявления объектов как массивов или как матриц.
Выражения Matrix имеют метод .array() , который «преобразует» их в выражения Array, чтобы легко применять операции поэлементного умножения. И наоборот, выражения Array имеют метод .matrix() . Как и для всех абстракций выражений Eigen, это не имеет никакой затрат во время выполнения (при условии, что вы позволите своему компилятору оптимизировать). И .array() , и .matrix() можно использовать как значения-rvalues, так и значения-lvalues.
Смешивание матриц и массивов в выражении запрещено в Eigen. Например, вы не можете напрямую сложить матрицу и массив; операнды оператора + должны быть либо матрицами, либо массивами. Однако легко преобразовать один тип в другой с помощью .array() и .matrix(). Исключением из этого правила является оператор присваивания: разрешено присваивать выражение матрицы переменной массива или выражение массива переменной матрицы.
Следующий пример показывает, как использовать операции массива с объектом Matrix с помощью метода .array() . Например, оператор result = m.array() * n.array() принимает две матрицы m и n, преобразует их обе в массив, умножает их поэлементно и присваивает результат переменной матрицы result (это допустимо, так как Eigen разрешает присваивание выражений массива переменным матриц).
На самом деле, этот случай использования настолько распространен, что Eigen предоставляет метод const .cwiseProduct(.) для матриц для вычисления поэлементного произведения. Это также показано в примере программы.
| Пример: | Вывод: |
|---|---|
#include <Eigen/Dense> #include <iostream> using namespace Eigen; using namespace std; int main() { MatrixXf m(2,2); MatrixXf n(2,2); MatrixXf result(2,2); m << 1,2, 3,4; n << 5,6, 7,8; result = m * n; cout << "-- Matrix m*n: --" << endl << result << endl << endl; result = m.array() * n.array(); cout << "-- Array m*n: --" << endl << result << endl << endl; result = m.cwiseProduct(n); cout << "-- With cwiseProduct: --" << endl << result << endl << endl; result = m.array() + 4; cout << "-- Array m + 4: --" << endl << result << endl << endl; } |
-- Matrix m*n: -- 19 22 43 50 -- Array m*n: -- 5 12 21 32 -- With cwiseProduct: -- 5 12 21 32 -- Array m + 4: -- 5 6 7 8 |
Аналогично, если array1 и array2 являются массивами, то выражение array1.matrix() * array2.matrix() вычисляет их матричное произведение.
Вот более сложный пример. Выражение (m.array() + 4).matrix() * m добавляет 4 к каждому элементу матрицы m и затем вычисляет матричное произведение результата с m. Аналогично, выражение (m.array() * n.array()).matrix() * m вычисляет поэлементное произведение матриц m и n и затем матричное произведение результата с m.
| Пример: | Вывод: |
|---|---|
#include <Eigen/Dense> #include <iostream> using namespace Eigen; using namespace std; int main() { MatrixXf m(2,2); MatrixXf n(2,2); MatrixXf result(2,2); m << 1,2, 3,4; n << 5,6, 7,8; result = (m.array() + 4).matrix() * m; cout << "-- Combination 1: --" << endl << result << endl << endl; result = (m.array() * n.array()).matrix() * m; cout << "-- Combination 2: --" << endl << result << endl << endl; } |
-- Combination 1: -- 23 34 31 46 -- Combination 2: -- 41 58 117 170 |
© Eigen.
Licensed under the MPL2 License.
https://eigen.tuxfamily.org/dox/group__TutorialArrayClass.html