Una función genérica para almacenar la matriz Eigen en un archivo binario

Resuelto Soo asked hace 10 meses • 0 respuestas

Sé que el siguiente código se puede utilizar para escribir los datos de una matriz propia con tipo de datos como doubleen un archivo binario.

template<class  T> 
void WriteEigenMatrix(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m, const char* fileName)
{
    std::ofstream outFile(fileName, std::ios_base::out | std::ios_base::binary);
    outFile.write(m.data(), m.rows()*m.cols());
    outFile.close();`
}

¿Cómo puedo generalizar esta función para aceptar otros tipos de datos propios como Eigen::Vectory Eigen::Arraycomo entradas?
Si uso Eigen::EigenBase, sé que la función aceptará todos esos tipos de datos. Sin embargo, el problema es que ya no puedo usarlo m.data(), ya que no está definido en la clase base.
¿Alguna sugerencia para resolver este problema?

Soo avatar Feb 16 '24 21:02 Soo
Aceptado

Si desea permitir sólo objetos "densos", puede hacerlo de la siguiente manera:

template<class Derived>
void WriteEigen(const Eigen::DenseBase<Derived>& dense, const char* fileName) {
    std::ofstream outFile(fileName, std::ios_base::out | std::ios_base::binary);
    outFile.write(reinterpret_cast<const char*>(dense.derived().data()), dense.rows() * dense.cols());
    outFile.close();
}

Todas las matrices densas (incluidos los vectores y las matrices) heredan de DenseBase, al llamar derivedle DenseBasedevolverán el tipo de matriz concreto.

O usa cualquier Base que quieras.

Después de los comentarios de @chtz y @Homer512, esta versión utiliza PlainObjectBasey reshapeden combinación con el algoritmo STL para escribir en el archivo, evitando reinterpret_castel char*posible fallo en caso de que se produzca un error innerStride() != 1.

template<class Derived>
void WriteEigen(const Eigen::PlainObjectBase<Derived>& dense, std::string_view fileName) {
    std::ofstream outFile(fileName, std::ios_base::out | std::ios_base::binary);
    const auto& reshaped = dense.reshaped();
    std::copy(reshaped.begin(), reshaped.end(), std::ostream_iterator<typename Derived::Scalar>(outFile));
}

reshaped()permite iterar sobre todas las entradas en forma STL ( ver ejemplo) , que se encargará de todos los avances posibles. Los rangos de C++20 permiten mejores

std::ranges::copy(reshaped, std::ostream_iterator<typename Derived::Scalar>(outFile));

El uso std::ostream_iteratorpermite utilizar std::(ranges::)copyen lugar de ostream::write()which opera en bytes. Para obtener el tipo de datos subyacente del objeto propio, Dense::Scalarse puede utilizar.

0xbachmann avatar Feb 16 '2024 14:02 0xbachmann