Boost matrix

Signaler
Messages postés
8
Date d'inscription
mardi 8 mars 2011
Statut
Membre
Dernière intervention
10 avril 2012
-
Messages postés
3819
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
28 septembre 2020
-
Bonjour à tous, j'essaye de coder une méthode du fameux Numerical Recipes 3rd Ed et j'ai un problème sur un membre d'une classe.

Dans la structure Cholesky (pages 101-102 pour ceux qui ont le livre), il faut déclarer une matrice comme membre et je fais le choix de :
boost::numerical::ublas::matrix<double> que je passe en référence (même par valeur il plantait, je n'ai pas testé par pointeur car comme je m'en sers dans un autre code, ça me faisait tripoter trop de code d'un coup).

Le hic est qu'il n'y a pas de destructeur et que ça plante à la compilation "process returns 3" ce qui doit surement être sa manière au compilo (mingw sous codeblocks 10) de me dire qu'il n'arrive pas à s'en débarasser.

Quelqu'un a-t-il une suggestion sur comment utiliser des matrices de boost comme membres de mes classes?

Merci d'avance,
Sam

PS : voilà une version raccourcie du code, juste avec la partie constructeur, vu que je plante après avoir construit mon objet.

#ifndef CHOLESKY_H
#define CHOLESKY_H

#include 
#include 

namespace ub = boost::numeric::ublas;

struct Cholesky
{
    int n;
    ub::matrix<double> &el;

    /// Given a positive definite matrix A, returns A = L.L^t
        Cholesky(ub::matrix<double> &a) : n(a.size1() ), el(a)
        {
            int i, j , k;
            ub::vector<double> tmp;
            double sum;
            if(el.size2() != n) throw("need square matrix");
            for(i=0; i<n; i++)
            {
                for(j=i; j<n; j++)
                {
                    for(sum=el(i,j), k=i-1; k>=0; k--)
                    {
                        sum -= el(i,k)*el(j,k);
                    }
                    if(i==j)
                    {
                        if(sum<=0)
                        throw("need semi positive definite matrix");
                        el(i,i) = sqrt(sum);//else
                    }
                    else
                    {
                        el(j,i) = sum/el(i,i);
                    }
                }
            }
            for(i=0; i<n; i++)
            for(j=i; j<n; j++)
            el(j,i) = 0.;
        }

};

#endif //CHOLESKY_H

5 réponses

Messages postés
3819
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
28 septembre 2020
113
Bonjour.

Quelle version de gcc utilises-tu ? Quelle version de boost ?
J'ai testé chez moi, sous ArchLinux, avec un g++ 4.7.0 et boost 1.49.0, et tout fonctionne bien.

J'ai compilé ceci avec succès, sans erreur d'exécution (j'ai légèrement "proprisé" ton code, mais aucun changement fondamental):
#ifndef CHOLESKY_H
#define CHOLESKY_H

#include 
#include 

namespace ub = boost::numeric::ublas;

struct Cholesky
{
  /// Given a positive definite matrix A, returns A = L.L^t
  Cholesky(ub::matrix<double>& mat)
    : _n(mat.size1()), _el(mat)
  {
    ub::vector<double> tmp;
    if (_el.size2() != _n)
      throw("need square matrix");
    for (unsigned int i = 0; i < _n; ++i)
    {
      for (unsigned int j = i; j < _n; ++j)
      {
        double sum = _el(i, j);
        for (int k = i - 1; k >= 0; --k)
          sum -= _el(i, k) * _el(j, k);

        if (i == j)
        {
          if (sum <= 0)
            throw("need semi positive definite matrix");
          _el(i, i) = sqrt(sum);
        }
        else
          _el(j, i) = sum / _el(i, i);
      }
    }
    for (unsigned int i = 0; i < _n; ++i)
      for (unsigned int j = i; j < _n; ++j)
        _el(j, i) = 0;
  }

  unsigned int _n;
  ub::matrix<double>& _el;
};

#endif //CHOLESKY_H

int main()
{
  ub::matrix<double> mat;
  Cholesky c(mat);

  return 0;
}


________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Messages postés
8
Date d'inscription
mardi 8 mars 2011
Statut
Membre
Dernière intervention
10 avril 2012

Bonjour, merci pour cette réponse aussi rapide.

Concernant ma version du compilateur, c'est celle installée d'office avec codeblocks 10.05, visiblement gcc 4.4.1 (c'est du mingw, je bosse sous windows, j'essaye d'y prendre goût mais dur dur sans le shell quand on a appris là-dessus).

Dans les mêmes conditions que toi, je compile aussi.

Par contre, donnes une taille à la matrice (il faut qu'elle soit carrée donc déclare mat(2,2) par exemple) et dis moi si tu n'as pas le même problème.

En tout cas, moi ça me le fait.

A+ Sam
Messages postés
3819
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
28 septembre 2020
113
Il n'y a pas d'erreur technique pour moi. Ton throw se déclenche, et comme tu n'attrapes pas l'exception, ça plante. C'est tout.

#ifndef CHOLESKY_H
#define CHOLESKY_H

#include 
#include 

namespace ub = boost::numeric::ublas;

struct Cholesky
{
  /// Given a positive definite matrix A, returns A = L.L^t
  Cholesky(ub::matrix<double>& mat)
    : _n(mat.size1()), _el(mat)
  {
    ub::vector<double> tmp;
    if (_el.size2() != _n)
      throw("need square matrix");
    for (unsigned int i = 0; i < _n; ++i)
    {
      for (unsigned int j = i; j < _n; ++j)
      {
        double sum = _el(i, j);
        for (int k = i - 1; k >= 0; --k)
          sum -= _el(i, k) * _el(j, k);

        if (i == j)
        {
          if (sum <= 0)
            throw("need semi positive definite matrix"); // Penser à lancer une "vraie" exception plutôt qu'un char*...
          _el(i, i) = sqrt(sum);
        }
        else
          _el(j, i) = sum / _el(i, i);
      }
    }
    for (unsigned int i = 0; i < _n; ++i)
      for (unsigned int j = i; j < _n; ++j)
        _el(j, i) = 0;
  }

  unsigned int _n;
  ub::matrix<double>& _el;
};

#endif //CHOLESKY_H

int main()
{
  ub::matrix<double> mat(2,2);

  try
  {
    Cholesky c(mat);
  }
  catch (const char* err)
  {
    std::cerr << "Error is: " << err << std::endl;
    return 1;
  }

  return 0;
}


________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Messages postés
8
Date d'inscription
mardi 8 mars 2011
Statut
Membre
Dernière intervention
10 avril 2012

Merci beaucoup, je ne savais pas me servir des try-catch et grâce à toi j'ai un exemple fonctionnel.

J'ai mis une matrice réellement positive et ça a marché.

J'espère que ce n'était que ça sinon me voilà parti pour une session debug à la maison.

A bientôt,
Sam
Messages postés
3819
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
28 septembre 2020
113
Pense à te créer une classe d'exception pour ton projet. En l'état, jeter un "const char*" c'est très moche :(.
Pour faire une bonne classe d'exception, tu peux hériter de "std::exception" (dans le header <exception>) et personnaliser la classe comme tu l'entends.

Voici un petit exemple tout simple:
#ifndef CHOLESKY_H
#define CHOLESKY_H

#include <exception>

#include 
#include 

namespace ub = boost::numeric::ublas;

class CholeskyException: public std::exception
{
public:
  CholeskyException(const std::string& msg)
    : _msg(msg)
  {
  }

  virtual ~CholeskyException() throw()
  {
  }

  virtual const char* what() const throw()
  {
    return _msg.c_str();
  }

private:
  const std::string _msg;
};


class Cholesky
{
public:
  /// Given a positive definite matrix A, returns A = L.L^t
  Cholesky(ub::matrix<double>& mat)
    : _n(mat.size1()), _el(mat)
  {
    ub::vector<double> tmp;
    if (_el.size2() != _n)
      throw CholeskyException("need square matrix");
    for (unsigned int i = 0; i < _n; ++i)
    {
      for (unsigned int j = i; j < _n; ++j)
      {
        double sum = _el(i, j);
        for (int k = i - 1; k >= 0; --k)
          sum -= _el(i, k) * _el(j, k);

        if (i == j)
        {
          if (sum <= 0)
            throw CholeskyException("need semi positive definite matrix");
          _el(i, i) = sqrt(sum);
        }
        else
          _el(j, i) = sum / _el(i, i);
      }
    }
    for (unsigned int i = 0; i < _n; ++i)
      for (unsigned int j = i; j < _n; ++j)
        _el(j, i) = 0;
  }

private:
  unsigned int _n;
  ub::matrix<double>& _el;
};

#endif //CHOLESKY_H

int main()
{
  ub::matrix<double> mat(2,2);

  try
  {
    Cholesky c(mat);
  }
  catch (const CholeskyException& err)
  {
    std::cerr << "Error is: " << err.what() << std::endl;
    return 1;
  }

  return 0;
}


________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question