Mapping Avec Eigen Library

Résolu
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018 - Modifié le 28 sept. 2018 à 12:10
Dalfab Messages postés 706 Date d'inscription dimanche 7 février 2016 Statut Membre Dernière intervention 2 novembre 2023 - 2 oct. 2018 à 20:14
Bonjour,


Map (classe de la biblio Eigen ) : "This class represents a matrix or vector expression mapping an existing array of data. It can be used to let Eigen interface without any overhead with non-Eigen data structures, such as plain C arrays or structures from other libraries."

cette expression sert pour introduire mon problème.
En effet, j'ai un tableau 2D qui j'ai obtenu à partir d'un fichier.csv (std::vector<std::vector<double>> TAB1)
j'ai essayé de mapper mon tableau en tant que une matrice (MatrixXd) .

j'ai cette erreur : error: expected primary-expression before 'V1'.
mon code est le suivant :
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>
#include <clocale>
#include "EigenResources\Eigenvalues"

using namespace Eigen;

template <class charT, charT sep>
class punct_facet: public std::numpunct<charT> {
protected:
  charT do_decimal_point() const { return sep; }
};

double comaStod(std::string const& s)
{
  std::istringstream iss(s);
  iss.imbue(std::locale(std::cout.getloc(), new punct_facet<char, ','>));
  double d;
  if (!(iss >> d))
    throw std::invalid_argument("invalid double");

  return d;
}

int main()
{
  const std::string filename = "Measurements.csv";
  std::ifstream file(filename);

  if (!file)
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

  std::string line;
  std::vector<std::vector<double>> TAB1;
  while (std::getline(file, line))
  {
    
    std::vector<double> v;
    std::string field;
    std::stringstream ss(line);
    while (std::getline(ss, field, ';'))
    {
      try
      {
        v.push_back(comaStod(field));

      }
      catch (std::invalid_argument& e)
      {
        std::cerr << "Can't convert " << field << " to double (" << e.what() << ")" << std::endl;
        continue;
      }
    }
    if (!v.empty())
      TAB1.push_back(v);
  }

  /*std::cout << "Vec:\n";
  for (auto& vec : array)
  {
   for (auto& value : vec)
     std::cout << value << " ";
    std::cout << std::endl;
  }*/

  //affichage (deux boucles for)

  std::cout << "Vec:\n";
  for (size_t i=0; i<TAB1.size(); ++i)
    {
        for (size_t j=0; j<TAB1[i].size(); ++j)
        {
              std::cout << TAB1[i][j] << " ";
        
            std::cout<< Map <MatrixXd> V1(TAB1.data())<<std::endl; //mapping
        }

        std::cout << "\n";
    }

  
  return 0;
}



Je suis incapable de savoir pourquoi j'ai cette erreur si quelqu'un a une idée je suis preneuse :)

Merci d'avance

15 réponses

Dalfab Messages postés 706 Date d'inscription dimanche 7 février 2016 Statut Membre Dernière intervention 2 novembre 2023 11
2 oct. 2018 à 20:14
Pour gérer les complexes, il faut voir ce que la classe
std::complex<double>
offre.
 j 
n'est qu'une variable, on peut utiliser à la place
 std::complex<double{0,1} 
ou bien depuis le C++14 après avoir indiqué
 using namespace std::literals; 
on peut utiliser
 1i 
.
On a donc :
Eigen:: Matrix3cd  Z;
const std::complex<double>  j{ 0 , 1 };
Z(0,0) = res1_ohm[0] + j * res2_ohm[0];
// ou
Z(0,0) = std::complex<double>{ res1_ohm[0] , res2_ohm[0] };
// ou
using namespace literals;
Z(0,0) = res1_ohm[0] + 1i * res2_ohm[0];
1
cptpingu Messages postés 3838 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 17 juin 2024 124
Modifié le 28 sept. 2018 à 14:46
Bonjour.

Pour convertir un std::vector de std::vector en Matrice, il faut le faire "à la main", tu ne trouveras pas de méthode toute faite. Soit ta matrice est carrée et tu connais ses dimensions, et c'est facile à faire. Soit tu ne sais pas à quoi ressemble ta matrice, et tu n'as pas ses dimensions par avance, et là c'est plus compliqué.
J'ai considéré le deuxième cas (qui fonctionne aussi pour le premier) vu que tu lis à partir d'un fichier. J'ai donc écris une fonction de conversion générique. Si la matrice n'a pas ses lignes avec le même nombre de colonnes, 0 sera mis dans les "trous".

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>
#include <clocale>
#include <complex>
#include <cmath>
#include <algorithm>
#include <Eigen/Dense>

template <class charT, charT sep>
class punct_facet: public std::numpunct<charT> {
protected:
  charT do_decimal_point() const { return sep; }
};

double comaStod(std::string const& s)
{
  std::istringstream iss(s);
  iss.imbue(std::locale(std::cout.getloc(), new punct_facet<char, ','>));
  double d;
  if (!(iss >> d))
    throw std::invalid_argument("invalid double");

  return d;
}

// Will convert any vector of vector to Eigen::Matrix, but it's slow...
Eigen::MatrixXd convertToEigenMatrix(const std::vector<std::vector<double>>& array)
{
  // Search max_col_size
  size_t max_col_size = 0;
  for (size_t row = 0; row < array.size(); ++row)
    max_col_size = std::max(max_col_size, array[row].size());

  Eigen::MatrixXd matrix(array.size(), max_col_size);
  for (size_t row = 0; row < array.size(); ++row)
  {
    for (size_t col = 0; col < array[row].size(); ++col)
      matrix(row, col) = array[row][col];
    // Fill any too short columns with 0.
    for (size_t col = array[row].size(); col < max_col_size; ++col)
      matrix(row, col) = 0;
  }

  return matrix;
}

int main()
{
  const std::string filename = "Measurements.csv";
  std::ifstream file(filename);

  if (!file)
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

  std::string line;
  std::vector<std::vector<double>> array;
  while (std::getline(file, line))
  {
    // Ignore line starting with #
    if (line.empty() || line[0] == '#')
      continue;

    std::vector<double> v;
    std::string field;
    std::stringstream ss(line);
    while (std::getline(ss, field, ';'))
    {
      try
      {
        v.push_back(comaStod(field));
      }
      catch (std::invalid_argument& e)
      {
        //std::cerr << "Can't convert " << field << " to double (" << e.what() << ")" << std::endl;
        continue;
      }
    }

    if (!v.empty())
      array.push_back(v);
  }

  auto matrix = convertToEigenMatrix(array);
  std::cout << "Nb rows: " << matrix.rows() << ", nb cols: " << matrix.cols() << ", total size: " << matrix.size() << std::endl;
  std::cout << "Matrix:\n" << matrix << std::endl;

  return 0;
}


0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
28 sept. 2018 à 14:59
je te remercie pour ta réponse :)
de mon coté j'ai essayé le prog suivant, il m'a donné des bon résultats mais je sais pas il vaut mieux utiliser mon code ou bien le tien ?
voici mon code:
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>
#include <clocale>
#include <cmath>
#include <complex>
#include "EigenResources\Eigenvalues"

template <class charT, charT sep>
class punct_facet: public std::numpunct<charT> {
protected:
  charT do_decimal_point() const { return sep; }
};
//conversion , to .
double comaStod(std::string const& s)
{
  std::istringstream iss(s);
  iss.imbue(std::locale(std::cout.getloc(), new punct_facet<char, ','>));
  double d;
  if (!(iss >> d))
    throw std::invalid_argument("invalid double");

  return d;
}

//Eigen Matrix 

Eigen::MatrixXd ConvertToEigenMatrix(std::vector<std::vector<double>> data)
{
    Eigen::MatrixXd eMatrix(data.size(), data[0].size());
    for (int i = 0; i < data.size(); ++i)
        eMatrix.row(i) = Eigen::VectorXd::Map(&data[i][0], data[0].size());
    return eMatrix;
}

int main()
{
  const std::string filename = "Measurements.csv";
  std::ifstream file(filename);

  if (!file)
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

  std::string line;
  std::vector<std::vector<double>> TAB1;
  while (std::getline(file, line))
  {
    // Ignore line starting with #
    //if (line.empty() || line[0] == '#')
      //continue;
    std::vector<double> v;
    std::string field;
    std::stringstream ss(line);
    while (std::getline(ss, field, ';'))
    {
      try
      {
        v.push_back(comaStod(field));

      }
      catch (std::invalid_argument& e)
      {
        std::cerr << "Can't convert " << field << " to double (" << e.what() << ")" << std::endl;
        continue;
      }
    }
    if (!v.empty())
      TAB1.push_back(v);
  }

  //affichage (deux boucles for)

  std::cout << "Vec:\n";
  for (size_t i=0; i<TAB1.size(); ++i)
    {
        for (size_t j=0; j<TAB1[i].size(); ++j)
        {
              //std::cout << TAB1[i][j] << " ";
             
        }
         std::cout << "\n";
    }
 //appel de la fonction pour la conversion Eigen Matrix
 Eigen::MatrixXd ma_matrice;
 ma_matrice = ConvertToEigenMatrix (TAB1);
 std::cout << ma_matrice <<std::endl;

  return 0;
}



une question bête : pourquoi t'as ajouté const ici Eigen::MatrixXd convertToEigenMatrix(const std::vector<std::vector<double>>& array)??

Merci :)
0
cptpingu Messages postés 3838 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 17 juin 2024 124
Modifié le 28 sept. 2018 à 22:41
C'est ce que je t'ai dis dans mon précédent post: La fonction que utilises est bien si tu es sûr que ta structure est fixe. Si elle ne l'est pas, vu qu'aucune erreur n'est gérée, ton programme plantera (au mieux) ou fera n'importe quoi.
La fonction que je te propose permet d'être plus flexible. Le programme ne plantera jamais, mais tu peux avoir des colonnes à 0, si le format lu est incorrect.
Enfin, la meilleure solution serait peut être de vérifier le format attendu et de prévenir si celui-ci est incorrect (en d'autre terme faire échouer le programme si la matrice n'est pas "rectangulaire" et entièrement remplie).

une question bête : pourquoi t'as ajouté const ici Eigen::MatrixXd convertToEigenMatrix(const std::vector<std::vector<double>>& array)??

Il n'y a pas de modification de array, donc on le marque comme n'étant pas modifiable. C'est une sécurité, car en mettant const, j'ai l'assurance que la fonction ne pourra pas modifier array.

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
28 sept. 2018 à 16:57
je te remercie pour ta réponse détaillée et très claire ;)
0
Bonjour,

une question concernant la multiplication vecteur élément par élément.
expl :
V 1 = (1,2,3) V2 = (4,5,6) V3 = V1*V2 = (4,10,18)

j'ai essayé d'appliquer cette opération avec mes vecteurs colonnes en utilisant une boucle for . Mais j'ai eu cette erreur :" Assertion failed: index >= 0 index < size(), file c:\Users\Desktop\Projet1\EigenResources\src/core/DenseCoeffsBase/h, Line 408"
est ce que cette erreur signifie que j'ai dépassé la taille de mon vecteur ?

Merci :)

ci dessous mon code :
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>
#include <clocale>
#include <complex>
#include <cmath>
#include <algorithm>
#include <Eigen/Dense>

template <class charT, charT sep>
class punct_facet: public std::numpunct<charT> {
protected:
  charT do_decimal_point() const { return sep; }
};

double comaStod(std::string const& s)
{
  std::istringstream iss(s);
  iss.imbue(std::locale(std::cout.getloc(), new punct_facet<char, ','>));
  double d;
  if (!(iss >> d))
    throw std::invalid_argument("invalid double");

  return d;
}

// Will convert any vector of vector to Eigen::Matrix, but it's slow...
Eigen::MatrixXd convertToEigenMatrix(const std::vector<std::vector<double>>& array)
{
  // Search max_col_size
  size_t max_col_size = 0;
  for (size_t row = 0; row < array.size(); ++row)
    max_col_size = std::max(max_col_size, array[row].size());

  Eigen::MatrixXd matrix(array.size(), max_col_size);
  for (size_t row = 0; row < array.size(); ++row)
  {
    for (size_t col = 0; col < array[row].size(); ++col)
      matrix(row, col) = array[row][col];
    // Fill any too short columns with 0.
    for (size_t col = array[row].size(); col < max_col_size; ++col)
      matrix(row, col) = 0;
  }

  return matrix;
}

int main()
{
  const std::string filename = "Measurements.csv";
  std::ifstream file(filename);

  if (!file)
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

  std::string line;
  std::vector<std::vector<double>> array;
  while (std::getline(file, line))
  {
    std::vector<double> v;
    std::string field;
    std::stringstream ss(line);
    while (std::getline(ss, field, ';'))
    {
      try
      {
        v.push_back(comaStod(field));
      }
      catch (std::invalid_argument& e)
      {
        //std::cerr << "Can't convert " << field << " to double (" << e.what() << ")" << std::endl;
        continue;
      }
    }

    if (!v.empty())
      array.push_back(v);
  }

  auto matrix = convertToEigenMatrix(array);
  std::cout << "Nb rows: " << matrix.rows() << ", nb cols: " << matrix.cols() << ", total size: " << matrix.size() << std::endl;
  std::cout << "Matrix:\n" << matrix << std::endl;

// Vecteurs colonnes : 
Eigen:: VectorXd R2,r2;
R2 = matrix.col(2); //2éme colonnes de la matrice
//Multiplication element par element du vecteur R2:
for (int k=0; k< R2.size(); ++k)
{
r2[k]=R2[k]*R2[k];
} 

  return 0;
}

0
cptpingu Messages postés 3838 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 17 juin 2024 124
Modifié le 30 sept. 2018 à 15:13
Nommer ses variables R2 et r2, c'est une très très mauvaise idée :).
Évite les majuscules, et les noms de variables identiques qui ne diffèrent que par leur casse. C'est un bon moyen de vite s'emmêler. D'une manière générale, essaie de donner un nom explicite à tes variables. Une lettre simple n'étant pas super claire (sauf pour des index par exemple).

Pour répondre à ta question, "R2" existe et à une taille, mais "r2" n'est pas initialisé, et a vraisemblablement une taille de 0. Il te faut donc lui donner une taille, et vérifier quand tu utilises des index que ceux-ci soient compatibles avec ce que tu utilises (c'est-à-dire par hors bornes).

0
oui t'as raison :)
c'est bon j'ai donné des noms explicites à mes variables
et j'ai déclaré la taille de mon vecteur et ça marche très bien
je te remercie :)
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
Modifié le 1 oct. 2018 à 11:09
Bonjour,
est ce qu'il y a une autre manière pour créer une matrice complexe avec Eigen à part la méthode que j'ai utilisé ci dessous?
(j'ai pas mis le code entier et je sais pas est ce que je peux poser cette question ici ou bien je dois créer un nouveau sujet )

Merci :)

Eigen::Matrix3cd matrice_Z1;

matrice_Z1.real()<<res1_ohm[0],0,0,0,res2_ohm[0],0,0,0,res3_ohm[0]; //partie réelle
matrice_Z1.imag()<< pulsation[0]*induc1_henry[0],pulsation[0]*mutuelle12[0],pulsation[0]*mutuelle13[0],pulsation[0]*mutuelle12[0],pulsation[0]*induc2_henry[0],pulsation[0]*mutuelle23[0],pulsation[0]*mutuelle13[0],pulsation[0]*mutuelle23[0],pulsation[0]*induc3_henry[0]; // partie imaginaire
std::cout << "la matrice Z: "<< matrice_Z1 << est::endl;
0
cptpingu Messages postés 3838 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 17 juin 2024 124
1 oct. 2018 à 11:11
Je ne sais pas trop ce que tu cherches et je ne connais pas bien Eigen (j'ai lu la documentation pour la première fois suite à ton post).

D'après la documentation, tu as une initialisation comme tu l'as faite (avec des ","), et il y a une prédéclaration (tu donnes la tailles de ta matrice et tu remplis les cases comme suit: matrice(i, j) = valeur).
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
Modifié le 1 oct. 2018 à 12:04
Oui tout à fait, on peut remplir les cases de cette façon : matrice (i,j) = val, mais vu que j'ai des nombres complexes (a+jb) j'ai pas pu utiliser cette écriture. J'ai essayé de faire comme suit:

Eigen:: Matrix3cd matrice_Z;
Z(0,0)= res1_ohm[0]+j * res2_ohm[0];


Et j'ai eu un msg d'erreur : 'j' was not declared in this scope.
En tous cas les fonctions .real et .imag m'ont donné des bons résultats :)
je te remercie :)
0
cptpingu Messages postés 3838 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 17 juin 2024 124
1 oct. 2018 à 12:05
Ton message d'erreur veut juste dire que "j" n'existe pas, ce n'est pas lié aux matrices ou aux nombres complexes.
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
1 oct. 2018 à 12:13
dans ce cas je dois déclarer "j" c'est ça ?
si je vais déclarer "j", je vais le déclarer comme quoi ? quel type ?
0
cptpingu Messages postés 3838 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 17 juin 2024 124
1 oct. 2018 à 12:23
Je n'en ai aucune idée. Je peux aider techniquement, mais je ne peux pas deviner tes intentions. Tu es la personne la mieux placée pour savoir ce que tu cherches à réaliser.
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
1 oct. 2018 à 12:38
je vais travailler avec .real et .imag :p
c plus simple :D
merci :)
0
Rejoignez-nous