Эйген: как я могу заменить положительные значения матрицы на 1 и 0 в противном случае?

Я хочу написать следующий код Matlab в Eigen (где K равно pxp, а W равно pxb):

H = (K*W)>0;

Однако единственное, что я придумал до сих пор, это:

H = ((K*W.array() > 0).select(1,0)); 

Этот код работает не так, как объяснено здесь, но замена 0 на VectorXd::Constant(p,0) (как предлагается в вопрос по ссылке) генерирует ошибку времени выполнения:

Eigen::internal::variable_if_dynamic<T, Value>::variable_if_dynamic(T) [with T = long int; int Value = 1]: Assertion `v == T(Value)' failed.

Как я могу это решить?


person justHelloWorld    schedule 14.07.2016    source источник


Ответы (1)


Вам не нужно .select(). Вам просто нужно преобразовать массив bool в массив типа компонента H.

H = ((K * W).array() > 0.0).cast<double>();

Ваша первоначальная попытка не удалась, поскольку размер вашего постоянного массива 1/0 не соответствует размеру H. Использование VectorXd::Constant не является хорошим выбором, когда H равно MatrixXd. У вас также есть проблема со скобками. Я думаю, вы хотите *, а не .* в нотации Matlab.

#include <iostream>
#include <Eigen/Eigen>
using namespace Eigen;

int main() {
  const int p = 5;
  const int b = 10;
  MatrixXd H(p, b), K(p, p), W(p, b);
  K.setRandom();
  W.setRandom();
  H = ((K * W).array() > 0.0).cast<double>();
  std::cout << H << std::endl << std::endl;

  H = ((K * W).array() > 0).select(MatrixXd::Constant(p, b, 1),
                                   MatrixXd::Constant(p, b, 0));
  std::cout << H << std::endl;
  return 0;
}

При вызове функции-члена шаблона в шаблоне необходимо использовать ключевое слово template.

#include <iostream>
#include <Eigen/Eigen>
using namespace Eigen;

template<typename Mat, typename Vec>
void createHashTable(const Mat &K, Eigen::MatrixXi &H, Mat &W, int b) {
  Mat CK = K;
  H = ((CK * W).array() > 0.0).template cast<int>();
}

int main() {
  const int p = 5;
  const int b = 10;
  Eigen::MatrixXi H(p, b);
  Eigen::MatrixXf W(p, b), K(p, p);
  K.setRandom();
  W.setRandom();
  createHashTable<Eigen::MatrixXf, Eigen::VectorXf>(K, H, W, b);
  std::cout << H << std::endl;
  return 0;
}

См. это для некоторого объяснения.

Приведение типов C++ Eigen::Matrix через шаблоны

person kangshiyin    schedule 14.07.2016
comment
Спасибо за Ваш ответ. Не лучше ли .cast<int>()? - person justHelloWorld; 14.07.2016
comment
в зависимости от типа H. Поскольку вы не указали тип H, я предполагаю, что это MatrixXd - person kangshiyin; 14.07.2016
comment
Спасибо. Однако я получаю эту ошибку компиляции: ../Math.hpp:82:32: error: expected primary-expression before ‘int’ H = ((CK*W).array()>0.0).cast<int>(); ^ ../Math.hpp:82:32: error: expected ‘;’ before ‘int’ - person justHelloWorld; 14.07.2016
comment
Можете ли вы показать полный пример кода, как у меня, чтобы я мог воспроизвести вашу проблему? - person kangshiyin; 14.07.2016
comment
Обновлено с полным кодом. Я разместил все это, так как не знаю, где может быть ошибка, и я не хочу забывать основной пункт ошибки. - person justHelloWorld; 14.07.2016
comment
Слишком много неизвестных вещей, таких как Mat и то, как вы вызываете свою функцию. Возможно, вы сможете изменить мой код и воспроизвести свою проблему, начиная с #include до return 0;. - person kangshiyin; 14.07.2016
comment
Обновлено, извините, если это отнимает у вас так много времени :( - person justHelloWorld; 14.07.2016
comment
Но первое решение (используя select) компилируется и работает корректно - person justHelloWorld; 14.07.2016
comment
@justHelloWorld см. обновление. вам нужно использовать .template cast<int>() - person kangshiyin; 14.07.2016