Собственное эффективное прохождение матриц - PullRequest
0 голосов
/ 08 сентября 2018

Я использую Eigen в своем приложении, и через профилирование я нашел код похожим на следующее, чтобы быть узким местом. Проблема в том, что память копирование по мере передачи данных на использование (см. ниже).

Как видно из кода, «данные», используемые для функции matmat, могут иметь один из двух источников, один хранится в частном порядке в классе SMM, а другой должен динамически генерироваться на лету. Этот раскол необходим для моего приложение, но это затрудняет оптимизацию. Был ли источник только из внутреннего вектора данных мне кажется, что const Eigen :: Refs быть простым решением. Возможно, это связано с тем, как написан мой код, но копия elision, кажется, не делает так много, как я бы надеялся. я Рассматривается использование shared_ptr для предотвращения копирования матриц вокруг (что может быть довольно большим), но я не уверен, что это правильное направление.

Следует отметить, что результат matmat никогда не нужно хранить, он используется только как временная переменная в собственном выражении

Как можно эффективно передавать матрицы в этом случае?

Следующий код является упрощением используемой мной установки.

#include <Eigen/Dense>
#include <Eigen/StdVector>
#include <iostream>

using namespace Eigen;
typedef MatrixXd MMatrix;

enum class Storage {Normal, On_The_Fly };

MMatrix matrixGen(int additional_data) {
  return additional_data *  MMatrix::Random(5, 5);
}

class SMM {
  private:
    std::vector<MMatrix, Eigen::aligned_allocator<MMatrix> > data_;

   //Provides controlled access to the data
    MMatrix get_data(int i, Storage mem, int additional_data = 0) {
      if (mem != Storage::On_The_Fly) {
        return data_[i];
      }
      else {
        return matrixGen(additional_data);
      }
    }
  public:
   // Only a placeholder constructor, in my actual program the building
   // is significantly more complex, and doesn't build the data immediately
   SMM(Storage mem) {
     if (mem == Storage::Normal) {
       for (int i = 0; i < 5; i++) {
         data_.emplace_back(matrixGen(5));
       }
     }
    }


    //Similar to a matrix * matrix product
    MMatrix matmat(const MMatrix& A, int index, Storage mem, int additional_data = 0) {
      if (mem == Storage::On_The_Fly) {
        return this->get_data(index, mem, additional_data) * A;
      }
      else {
        return this->get_data(index, mem) * A;
      }
    }
};

int main() {
  Storage mem1 = Storage::Normal;
  Storage mem2 = Storage::On_The_Fly;
  SMM smm1 = SMM(mem1);
  SMM smm2 = SMM(mem2);
  MMatrix A = MMatrix::Random(5, 5);

  MMatrix B = MMatrix::Random(5, 5);
  MMatrix C = MMatrix::Random(5, 5);

  B += smm1.matmat(A, 2, mem1);
  C += smm2.matmat(A, 2, mem2, 5);
  std::cout << B << std::endl << std::endl;
  std::cout << C << std::endl;
}

1 Ответ

0 голосов
/ 09 сентября 2018

Простым решением является использование переменной-члена кэша:

class SMM {
  ...
  MMatrix cache_;
  const MMatrix& get_data(int i, Storage mem, int additional_data = 0) {
    if (mem != Storage::On_The_Fly) { return data_[i]; }
    else {
      matrixGenInPlace(additional_data,cache_);
      return cache_;
    }
  }
  ...
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...