Boost matrix

superjabar Messages postés 8 Date d'inscription mardi 8 mars 2011 Statut Membre Dernière intervention 10 avril 2012 - 10 avril 2012 à 11:33
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 - 10 avril 2012 à 18:37
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

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
10 avril 2012 à 12:34
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
0
superjabar Messages postés 8 Date d'inscription mardi 8 mars 2011 Statut Membre Dernière intervention 10 avril 2012
10 avril 2012 à 15:38
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
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
10 avril 2012 à 16:50
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
0
superjabar Messages postés 8 Date d'inscription mardi 8 mars 2011 Statut Membre Dernière intervention 10 avril 2012
10 avril 2012 à 18:07
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
0

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

Posez votre question
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
10 avril 2012 à 18:37
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
0
Rejoignez-nous