Собственный: вектор или матрица покомпонентно в степень?

Имея вектор вещественных чисел c и вектор целых чисел rw, я хочу создать вектор z с элементами z_i=c_i^rw_i. Я пытался сделать это с помощью покомпонентной функции pow, но получаю ошибку компилятора.

#include <Eigen/Core>

typedef Eigen::VectorXd RealVector;
typedef Eigen::VectorXi IntVector; // dynamically-sized vector of integers
RealVector c; c << 2, 3, 4, 5;
IntVector rw; rw << 6, 7, 8, 9;
RealVector z = c.pow(rw);    **compile error**

Ошибка компилятора

error C2664: 'const Eigen::MatrixComplexPowerReturnValue<Derived> Eigen::MatrixBase<Derived>::pow(const std::complex<double> &) const': cannot convert argument 1 from 'IntVector' to 'const double &'
      with
      [
          Derived=Eigen::Matrix<double,-1,1,0,-1,1>
      ]
c:\auc\sedanal\LammSolve.h(117): note: Reason: cannot convert from 'IntVector' to 'const double'
c:\auc\sedanal\LammSolve.h(117): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

Что не так с этим кодом? И, предполагая, что это можно исправить, как мне выполнить ту же операцию, когда с является реальной матрицей, а не вектором, чтобы вычислить c_ij^b_i для всех элементов с?

Компилятор — Visual Studio 2015, работающий под 64-битной Windows 7.


person Woody20    schedule 30.05.2017    source источник


Ответы (1)


Во-первых, MatrixBase::pow — это функция, которая вычисляет матричную степень квадратной матрицы (если матрица имеет разложение по собственным значениям, это та же матрица, но с собственными значениями, возведенными в заданную степень).

Что вам нужно, так это поэлементная сила, которая, поскольку в MatrixBase нет функции cwisePow, требует переключения на Array-домен. Кроме того, для степеней не существует целочисленной специализации (это может быть эффективно, но только до определенного порога, а проверка этого порога для каждого элемента приведет к пустой трате времени вычислений), поэтому вам нужно привести показатели к типу вашей матрицы.

Чтобы также ответить на ваш бонус-вопрос:

#include <iostream>
#include <Eigen/Core>

int main(int argc, char **argv) {
    Eigen::MatrixXd A; A.setRandom(3,4);
    Eigen::VectorXi b = (Eigen::VectorXd::Random(3)*16).cast<int>();

    Eigen::MatrixXd C = A.array() // go to array domain
        .pow(                 // element-wise power
             b.cast<double>() // cast exponents to double
            .replicate(1, A.cols()).array() // repeat exponents to match size of A
        );

    std::cout << A << '\n' << b << '\n' << C << '\n';
}

По сути, это вызовет C(i,j) = std::pow(A(i,j), b(i)) для каждого i, j. Если все ваши показатели малы, вы можете быть быстрее, чем с простым вложенным циклом, который вызывает специализированную реализацию pow(double, int) (например, __builtin_powi в gcc), но вы должны сравнить это с фактическими данными.

person chtz    schedule 30.05.2017
comment
Я полагался на Каталог математических функций с коэффициентами (eigen.tuxfamily.org/dox/group__CoeffwiseMathFunctions. html), в котором говорится, что Power functions a.pow(b);pow(a,b); возводит число в заданную степень ($a_i^{b_i}$) a и b могут быть либо массивом, либо скаляром. используя std::pow; мощность (а [я], б [я]); (плюс встроенный для целочисленных типов) - person Woody20; 31.05.2017
comment
Пытаюсь понять то же самое :)) - person Emilian Solardust; 29.02.2020