Newsgroup: it.comp.lang.c++
Titolo: Cerco Libreria

Salve a tutti. Nessuno di voi può darmi una libreria in c++ che gestisca il
calcolo matriciale ?
Grazie a tutti per l'aiuti
Mimmo

 calcolo matriciale ?
ehm... io la stavo scrivendo... molto a tempo perso, però.
//////////////////////////////////////////////////////////////
/*
VLM Valarray-based Linear Matrix
28/3/2002
This is a valarray based standard C++ matrix class.
It's implements base operators for linear algebra.
Accept the same types managed by valarray.
*/
//////////////////////////////////////////////////////////////
#ifndef IT_COMP_LANG_CPLUSPLUS__GEO__MATRIX2D_TEMPLATE
#define IT_COMP_LANG_CPLUSPLUS__GEO__MATRIX2D_TEMPLATE
#include <valarray>
template<class T> class matrix
{
    typedef std::valarray<T> row_type; // vettore riga
    std::valarray<row_type> column_rows; // indica, sostanzialmente, la
prima colonna
                        // e, per estensione, le righe che partono da essa
    public:
    // ----------- COSTRUTTORI ----------- //
    matrix() {}
    matrix(int rows, int columns) { resize(rows, columns); }
    // ----------- CAPACITA' ----------- //
    size_t columns() const
    {
        return column_rows[0].size();
    }
    size_t rows() const
    {
        return columns()!=0 ? column_rows.size() : 0;
    }
    void sizes( size_t& r, size_t& c ) const
    {
        c=columns();
        r=rows();
        // nota: la chiamata a rows implica una seconda chiamata
        // a columns e quindi il codice non è ottimale in prestazioni.
        // però la differenza è minima e matrix::sizes non viene certo
        // chiamata ripetutamente. Inoltre un buon compilatore espande
        // il tutto inline e riesce ad ottimizzare il codice rendendolo
        // di fatto ottimale. Quindi la leggibilità deve avere la priorità.
    }
    size_t size() const
    {
        // stesso discorso di prima sulla leggibilità e sull'ottimizzazione
        // l'overflow non avviene per come implementeremo la resize.
        return rows()*columns();
    }
    void resize(size_t r, size_t c, const T& v = T() )
    {
        size_t sz = r*c;
        if ( sz==0 ) // se una delle due dimensioni e' a zero
        {
            r=1;
            c=0;
        }
        // se invece le dimensioni sono "gestibili"
        column_rows.resize(r); // ridimensiono la prima colonna
        for( size_t i=0; i < r; ++i ) // e poi tutte le righe
            column_rows[i].resize(c,v);
    }
    bool empty() { return size()==0; }
    // ----------- Operatore [] ----------- //
    std::valarray<T>& operator[](int i) { return column_rows[i]; }
    const std::valarray<T>& operator[](int i) const { return
column_rows[i];}
    // ----------- Operatore = ----------- //
    matrix<T>& operator= (const matrix& m)
    {
        size_t r = rows(); // questo mi evita una chiamata a
                    // columns() ogni volta che chiamo rows()
        if( (r != m.rows()) || (columns() != m.columns()) )
        {
            // gestire tramite eccezioni
        }
        else // se tutto è ok
        {
            for ( size_t i=0; i < r; ++i )
            {
                column_rows[i] = m.column_rows[i];
            }
        }
        return *this;
    }
    // ----------- Operatore - ----------- //
    matrix<T>& operator- ()
    {
        for ( size_t i=0; i < rows(); ++i )
        {
            column_rows[i] = -column_rows[i];
        }
        return *this;
    }
    // ----------- Operatore += ----------- //
    matrix<T>& operator+= (const matrix& m)
    {
        size_t r = rows(); // questo mi evita una chiamata a
                    // columns() ogni volta che chiamo rows()
        if( (r != m.rows()) || (columns() != m.columns()) )
        {
            // gestire tramite eccezioni
        }
        else // lo so che e' inutile, ma mi piace di piu' cosi'
        {
            for ( size_t i=0; i < r; ++i )
                column_rows[i] += m.column_rows[i];
        }
        return *this;
    }
    // ----------- Operatore -= ----------- //
    matrix<T>& operator-= (const matrix& m)
    {
        size_t r = rows(); // questo mi evita una chiamata a
                    // columns() ogni volta che chiamo rows()
        if( (r != m.rows()) || (columns() != m.columns()) )
        {
            // gestire tramite eccezioni
        }
        else // lo so che e' inutile, ma mi piace di piu' cosi'
        {
            for ( size_t i=0; i < r; ++i )
                column_rows[i] -= m.column_rows[i];
        }
        return *this;
    }
    // ----------- Operatore *= ----------- //
    matrix<T>& operator*= (const matrix& m)
    {
        size_t this_rows = rows(); // questo mi evita una chiamata a
        size_t m_rows = m.rows(); // columns() ogni volta che chiamo rows()
        if( columns() != m_rows ) // se non sono moltiplicabili
        {
            // gestire tramite eccezioni
        }
        else // se le dimensioni sono ok
        {
            // per tutta la lunghezza delle colonne di this
            // ( == per tutte le righe)
            for (size_t i=0; i< this_rows; ++i)
            {
                // crea una riga temporanea per i risultati
                row_type row_temp(T(), m.columns());
                // per tutta la lunghezza delle righe di matrice
                // ( == per ogni elemento della colonna)
                for (size_t j=0; j < m.columns(); ++j)
                {
                    // fa il prodotto vettoriale riga*colonna
                    for (size_t k=0; k< m_rows; ++k)
                    {
                        row_temp[j] += column_rows[i][k] *
m.column_rows[k][j];
                    }
                }
                // ridimensiona la riga calcolata
                column_rows[i].resize( m.columns() );
                // e vi copia il risultato
                column_rows[i] = row_temp;
            }
        }
        return *this; // restituisce la matrice cambiata
    }
    // ----------- Operatore + ----------- //
    matrix<T> operator+ (const matrix& m) const
    {
        size_t r = rows(); // questo mi evita una chiamata a
                    // columns() ogni volta che chiamo rows()
        matrix<T> result(r,columns());
        if( (r != m.rows()) || (columns() != m.columns()) )
        {
            // gestire tramite eccezioni
        }
        else // se tutto è ok
        {
            for ( size_t i=0; i < r; ++i )
            {
                result.column_rows[i] = column_rows[i] + m.column_rows[i];
            }
        }
        return result;
    }
    // ----------- Operatore - ----------- //
    matrix<T> operator- (const matrix& m) const
    {
        size_t r = rows(); // questo mi evita una chiamata a
                    // columns() ogni volta che chiamo rows()
        matrix<T> result(r,columns());
        if( (r != m.rows()) || (columns() != m.columns()) )
        {
            // gestire tramite eccezioni
        }
        else // se tutto è ok
        {
            for ( size_t i=0; i < r; ++i )
            {
                result.column_rows[i] = column_rows[i] - m.column_rows[i];
            }
        }
        return result;
    }
    // ----------- Operatore * ----------- //
    matrix<T> operator* (const matrix& m)
    {
        size_t this_rows = rows(); // questo mi evita una chiamata a
        size_t m_rows = m.rows(); // columns() ogni volta che chiamo rows()
        matrix<T> result(this_rows,m.columns()); // creo matrice risultato
        if( columns() != m_rows ) // se non sono moltiplicabili
        {
            // gestire tramite eccezioni
        }
        else // se le dimensioni sono ok
        {
            // per tutta la lunghezza delle colonne di this
            // ( == per tutte le righe)
            for (size_t i=0; i< this_rows; ++i)
            {
                // per tutta la lunghezza delle righe di matrice
                // ( == per ogni elemento della colonna)
                for (size_t j=0; j < m.columns(); ++j)
                {
                    // fa il prodotto vettoriale riga*colonna
                    for (size_t k=0; k< m_rows; ++k)
                    {
                        result[i][j] += column_rows[i][k] *
m.column_rows[k][j];
                    }
                }
            }
        }
        return result; // ritorna il risultato
    }
};
#endif
Si usa così:
#include <iostream>
using std::cout;
int main()
{
  matrix<int> m22(2,3);
  matrix<int> n22(3,4);
  matrix<int> p22(2,4);
  m22[0][0] = 1;
  m22[0][1] = 3;
  m22[1][0] = 2;
  m22[1][1] = 0;
  n22[0][0] = 1;
  n22[0][1] = 3;
  n22[1][0] = 2;
  n22[1][1] = 1;
  cout << p22[0][0] << " " << p22[0][1] << std::endl;
  cout << p22[1][0] << " " << p22[1][1] << std::endl;
  cout << std::endl;
  p22 = m22 * n22;
  cout << p22[0][0] << " " << p22[0][1] << std::endl;
  cout << p22[1][0] << " " << p22[1][1] << std::endl;
  cout << std::endl;
  m22 *= n22;
  cout << m22[0][0] << " " << m22[0][1] << std::endl;
  cout << m22[1][0] << " " << m22[1][1] << std::endl;
}
Compila correttamente con il Borland Compiler 5.5.1
e con il Visual C++
Col DevC++ (e quindi, penso, anche col gcc 2.*) da un problema
nell' operatore *= ma basta sostituire la riga:
    row_type row_temp(T(), m.columns());
con:
    T t;
    row_type row_temp(t, m.columns());
Ovviamente è ancora incompleto.
Mancano le eccezioni, e la loro gestione nei casi di dimensioni
sballate, il calcolo di determinante, rango e un sacco di altre
cose che si possono fare....
Insomma... dipende da che ci vuoi fare...
P.S.
Se qualcuno mi segnala errori o da suggerimenti/commenti
ne sono felice...
--
Gerolamo

 ha scritto nel messaggio
news:z36q8.104040$%g7.33...@twister2.libero.it...

Grazie ciao.
Mimmo

 ha scritto nel messaggio
news:z36q8.104040$%g7.33...@twister2.libero.it...

Un ultima domanda; potresti spiegarmi l'algoritmo per il determinante e per
il rango ? Grazie ancora
Mimmo

 supermegagalakticultrasmadonnantesnip!
Scusa,
nei tuoi prossimi reply potresti farci il favore di tagliare tutte le parti
del testo a cui rispondi, che non servono?
Sono gia' due volte che ci fai scaricare 11 kbytes di roba inutile.
Grazie
Maurus

"Gerolamo" ha scritto
...
:
:     // ----------- Operatore - ----------- //
:     matrix<T>& operator- ()
:     {
:         for ( size_t i=0; i < rows(); ++i )
:         {
:             column_rows[i] = -column_rows[i];
:         }
:         return *this;
:     }
Questo operator -() non mi convince. Hai provato ad usarlo?
int main()
{
  matrix<int> a(1,1);
  a[0][0] = 1;
  matrix<int> b = -a;
  cout << a[0][0] << std::endl;
  cin.get();
}
:
:     // ----------- Operatore += ----------- //
:     matrix<T>& operator+= (const matrix& m)
:     {
:         size_t r = rows(); // questo mi evita una chiamata a
:                     // columns() ogni volta che chiamo rows()
:         if( (r != m.rows()) || (columns() != m.columns()) )
:         {
:             // gestire tramite eccezioni
:         }
:         else // lo so che e' inutile, ma mi piace di piu' cosi'
:         {
:             for ( size_t i=0; i < r; ++i )
:                 column_rows[i] += m.column_rows[i];
:         }
:         return *this;
:     }
:
:
...
:
:     // ----------- Operatore + ----------- //
:     matrix<T> operator+ (const matrix& m) const
:     {
:         size_t r = rows(); // questo mi evita una chiamata a
:                     // columns() ogni volta che chiamo rows()
:
:         matrix<T> result(r,columns());
:
:         if( (r != m.rows()) || (columns() != m.columns()) )
:         {
:             // gestire tramite eccezioni
:         }
:         else // se tutto è ok
:         {
:             for ( size_t i=0; i < r; ++i )
:             {
:                 result.column_rows[i] = column_rows[i] + m.column_rows[i];
:             }
:         }
:         return result;
:     }
:
Quando implementi operator +=, poi operator + puo` essere facilmente
implementato in termini del primo, senza inutili e pericolose ripetizioni
di codice. Lo stesso vale per -, *, etc. (io, tra l'altro, preferisco
mettere nel primo ramo di un if il codice che mi aspetto venga eseguito
piu` frequentemente)
matrix<T>& operator+= (const matrix& m)
{
  if( (rows() == m.rows()) && (columns() == m.columns()) )
  {
    column_rows += m.column_rows;
  }
  else
  { // gestire tramite eccezioni }
  return *this;
}
matrix<T> operator+ (const matrix& m) const
{
  return matrix<T>(*this) += m;
}
Infine io aggiungerei, abbastanza precocemente nello sviluppo della classe,
una funzione membro che popoli la matrice con valori random, e un
operator == che confronti due matrici (tenuto conto che per i floating point
l'uguaglianza deve essere espressa come abs(b-a).max() < epsilon).
In questo modo potresti testare le varie operazioni abbastanza
semplicemente:
matrix<int> a(4,5), b(4,5);
a.rand_fill();
b.rand_fill();
matrix<int> c = a + b;
assert( a == (c - b) );
oppure:
matrix<float> a(4,5);
a.rand_fill();
matrix<float> a = -b;
assert( (a + b) == matrix<int>(4,5) );
e cosi` via.
ciao
Massimo

 e per il rango ? Grazie ancora
Ora come ora non ho sottomano nessun algoritmo preconfezionato,
ma per il determinante l'algoritmo ricorsivo dovrebbe essere
questo:
Data una matrice A di dimensioni n*n di elementi a(i,j) con
i, j che indicano la posizione dell'elemento 'a' e dove A(i)
indica la matrice A di dimensioni (n-1)*(n-1) ottenuta sopprimendo
la i-esima riga e la prima colonna.
if n==1: det(A)=a(1,1)
if n >= 2:
   for k in range(1,n+1)   # 1 <= k < n
      det(A)+= pow(-1,k+1) * a(i,j) * det(A(i))
non so se esista qualche implementazione più furba per il determinante.
--
Gerolamo

 l'uguaglianza deve essere espressa come abs(b-a).max() < epsilon).
Domanda. Ma usando i valarray come classe di appoggio non
mi basta fare un:
for (size_t i = 0; i < rows(); ++i)
{
    if (column_rows[i] != altra.column_rows[i])
       return false;
    return true;
}
(scritto di getto...)
o qualcosa del genere?
Insomma... i valarray non risolvono da soli il problema?
Intanto grazie per i preziosi suggerimenti.
--
Gerolamo

    for k in range(1,n+1)   # 1 <= k < n
ooops... intendevo 1 <= k <= n
--
Gerolamo

"Gerolamo" ha scritto
: >
: > Questo operator -() non mi convince. Hai provato ad usarlo?
: >
: > int main()
: > {
: >   matrix<int> a(1,1);
: >   a[0][0] = 1;
: >
: >   matrix<int> b = -a;
: >   cout << a[0][0] << std::endl;
: >   cin.get();
: > }
:
: Mi da '-1'
: Era esattamente quel che volevo (invertire il segno di tutti gli elementi)
:
: Non capisco... quale sarebbe il problema?
:
#include <valarray>
#include <iostream>
using namespace std;
int main()
{
  int a = 1;
  int b = -a;
  cout << a << endl;;
  valarray<int> va(1,1);
  valarray<int> vb = -va;
  cout << va[0] << endl;
  cin.get();
}
Ha un comportamento diverso dai tipi predefiniti e da quelli simili
contenuti nello std. Oltre ad assegnare la matrice 'opposta' al lhs,
modifichi il rhs.
: > una funzione membro che popoli la matrice con valori random, e un
: > operator == che confronti due matrici (tenuto conto che per i floating
: point
: > l'uguaglianza deve essere espressa come abs(b-a).max() < epsilon).
:
: Domanda. Ma usando i valarray come classe di appoggio non
: mi basta fare un:
:
: for (size_t i = 0; i < rows(); ++i)
: {
:     if (column_rows[i] != altra.column_rows[i])
:        return false;
:     return true;
: }
:
: (scritto di getto...)
: o qualcosa del genere?
: Insomma... i valarray non risolvono da soli il problema?
Considerando anche matrici di float e double io farei cosi`:
template <typename T>
bool operator == (const matrix<T>& lhs, const matrix<T>& rhs)
{
  if( (lhs.rows() == rhs.rows()) && (lhs.columns() == rhs.columns()) ) {
    for ( size_t j=0; j<lhs.rows(); ++j ) {
      if ( abs( lhs[j] - rhs[j] ).max() > 0.0001 )
        return false;
    }
    return true;
  }
  return false;
}
Se si confronta il risultato di qualche operazione matriciale svolta
in due modi diversi, e` facile avere piccole differenze dovute
ad errori di approssimazione. Per cui e` meglio usare un operator ==
che stabilisca che le due matrici sono uguali a meno di errori di
approssimazione e non che siano identiche.
Volendo aggiungere anche il supporto per i complex la cosa si
complica poiche` non e` possibile confrontare due complex con
l'operator < e quindi si deve scrivere una versione apposita.
Piu` o meno:
#include <complex>
#include <algorithm>
#include <functional>
template <typename U> struct complex_less :
  std::binary_function<bool,std::complex<U>, std::complex<U> >
{
  bool operator()(const std::complex<U>& l, const std::complex<U>& r)
  {  return abs( l ) < abs( r ); }
};
template <typename U>
bool operator ==
  ( const matrix<std::complex<U> >& lhs, const matrix<std::complex<U> >&
rhs)
{
  if( (lhs.rows() == rhs.rows()) && (lhs.columns() == rhs.columns()) ) {
    for ( size_t j=0; j<lhs.rows(); ++j )
    {
      std::valarray<std::complex<U> > diff = lhs[j] - rhs[j];
      std::complex<U> max_err =
  *max_element( &diff[0], &diff[lhs.columns()], complex_less<U>() );
      if ( abs( max_err ) > 0.0001 )
        return false;
    }
    return true;
  }
  return false;
}
ma non sono sicuro che lo std garantisca che i valarray conservino
i dati in aree contigue, d'altronde non avendo iteratori...
ciao
Massimo

 Considerando anche matrici di float e double io farei cosi`:
Interessante... ma la devo riguardare attentamente soprattutto quella
dei complex.
Comunque appoggiandosi sempre ai valarray forse si puo'
implementare cosě (non testata):
bool operator== (const matrix& m)
{
    matrix<bool> mb(rows(), columns());
    if( (rows() == m.rows()) && (columns() == m.columns()) )
    {
        for (size_t i = 0; i < rows(); ++i)
        {
            mb[i]=first_column[i]==m.first_column[i];
            for (size_t j = 0; j<columns(); ++j)
            {
                if(mb[i][j]==false) return false;
            }
        }
        return true;
    }
    return false;
}
che ne dici?
--
Gerolamo

>       result.first_column[i] = -first_column[i];
vabbč... sono fesso.
sostituisci tutti i "first_column" con "column_rows"
--
Gerolamo

"Gerolamo" ha scritto
: Modificato cosě:
:
:  // ----------- Operatore - ----------- //
: matrix<T> operator- ()
: {
:    matrix<T> result(rows(),columns());
:    for ( size_t i=0; i < rows(); ++i )
:    {
:       result.first_column[i] = -first_column[i];
:    }
:    return result;
: }
:
matrix<T> operator- () const
{
   matrix<T> result;
   result.first_column = -first_column;
   return result;
}
:
: Comunque appoggiandosi sempre ai valarray forse si puo'
: implementare cosě (non testata):
:
: bool operator== (const matrix& m)
: {
:     matrix<bool> mb(rows(), columns());
:     if( (rows() == m.rows()) && (columns() == m.columns()) )
:     {
:         for (size_t i = 0; i < rows(); ++i)
:         {
:             mb[i]=first_column[i]==m.first_column[i];
Si certo e` giusto appoggiarsi ai valarray, e mi pare che la versione
precedente fosse ancora piu` sintetica e chiara.
Quello che ti volevo suggerire era di prevedere la possibilita` di
verificare i risultati eseguendo le operazioni inverse, ma di non
aspettarti di ottenere risultati esatti.
Effettivamente, e` piu` corretto implementare operator == in modo
che verifichi l'identita` di due matrici, oltre ad un operator < e una
funzione abs. In questo modo per gli int e simili, e operazioni 'esatte',
puoi scrivere dei test nella forma:
  matrix<int> a(n,m);
  // popoli a
  matrix<int> b = -a;
  assert( (a + b) == matrix<int>(n,m) );
mentre per i float e derivati diventeranno:
  matrix<float> a(n,n),b(n,n);
  // popoli a e b
  matrix<float> c = b * a;
  assert( abs((c - (a *= b)) < 0.0001 );
ciao
Massimo

 aspettarti di ottenere risultati esatti.
Non sono sicuro di capire quello che intendi dire.
Quel che ho capito è che devo tener conto della limitata
precisione di calcolo e per questo mi conviene impostare
un limite minimo sotto il quale 2 numeri sono considerati
indistinguibili.
Ho capito giusto?
Se è così la mia obbiezione è: ma i valarray tengono conto
di questo problema?
Se si ho risolto perchè tanto mi appoggio a loro.
Se no mi chiedo: visto che la mia classe si basa sui valarray
è giusto che abbia un comportamento diverso da questi ultimi?
A questo proposito mi viene un altro dubbio:
pensando all'operatore == mi è venuto naturale fargli restituire
un bool, ma poi mi sono accorto che i valarray restituiscono
un valarray<bool> nella quale sono inseriti i risultati delle
uguaglianze elemento per elemento.
A questo punto, sempre per conformarmi al comportamento
dei valarray non mi converrebbe restituire un matrix<bool> ?
Eventualmente potrei poi fare un
bool operator== (const bool b)
che mi controlla se tutti i membri sono true o false.
A quel punto però un'uguaglianza andrebbe scritta come:
int main()
{
  matrix<float> ma(1,1);
  matrix<float> mb(1,1);
  ma[0][0] = 0.2;
  mb[0][0] = 1.0/5.0;
  cout << "ma[0][0]: " << ma[0][0] << std::endl;
  cout << "mb[0][0]: " << mb[0][0] << std::endl;
  if((ma == mb) == true )
  {
     cout << "Uguali";
  }
}
...perdendo un po' di leggibilità.
Che ne pensi?
--
Gerolamo

"Gerolamo" ha scritto
...
: > : Comunque appoggiandosi sempre ai valarray forse si puo'
: > : implementare così (non testata):
: > :
: > : bool operator== (const matrix& m)
: > Quello che ti volevo suggerire era di prevedere la possibilita` di
: > verificare i risultati eseguendo le operazioni inverse, ma di non
: > aspettarti di ottenere risultati esatti.
:
: Non sono sicuro di capire quello che intendi dire.
:
: Quel che ho capito è che devo tener conto della limitata
: precisione di calcolo e per questo mi conviene impostare
: un limite minimo sotto il quale 2 numeri sono considerati
: indistinguibili.
: Ho capito giusto?
Si, il punto e` che per certi problemi si puo` avere solo una soluzione
approssimata, per cui e` comodo avere gli strumenti per effettare delle
verifiche con poche righe di codice. Pero` non ci si puo` limitare ad
un operator ==, ma si deve anche avere una funzione che calcoli il valore
assoluto ed un operator < .
:
: Se è così la mia obbiezione è: ma i valarray tengono conto
: di questo problema?
Il 'problema' non e` un problema dei valarray o della tua matrix,
il problema si pone quando effettui i test. Come ti ho detto
nell'utlimo post e` giusto implementare i vari operator in modo che
facciano quello che dichiarano. Una volta che hai questi a
disposizione e` comunque facile tenere conto degli errori di
approssimazione.
: Se si ho risolto perchè tanto mi appoggio a loro.
: Se no mi chiedo: visto che la mia classe si basa sui valarray
: è giusto che abbia un comportamento diverso da questi ultimi?
:
Il comportamento dei valarray e` un buon esempio.
In altre parole, dovresti implementare sia == che <, e, se vuoi,
puoi implementare gli altri in termini di questi.
: A questo proposito mi viene un altro dubbio:
: pensando all'operatore == mi è venuto naturale fargli restituire
: un bool, ma poi mi sono accorto che i valarray restituiscono
: un valarray<bool> nella quale sono inseriti i risultati delle
: uguaglianze elemento per elemento.
: A questo punto, sempre per conformarmi al comportamento
: dei valarray non mi converrebbe restituire un matrix<bool> ?
Io direi di no, io restituirei un bool. Per gli usi che posso immaginare,
non vedo motivo di restituire una matrice intera, mi sembra uno spreco.
Boh.
:
: Eventualmente potrei poi fare un
: bool operator== (const bool b)
: che mi controlla se tutti i membri sono true o false.
:
: A quel punto però un'uguaglianza andrebbe scritta come:
:
...
:   if((ma == mb) == true )
:   {
:      cout << "Uguali";
:   }
: }
:
: ...perdendo un po' di leggibilità.
: Che ne pensi?
Come detto sopra, mi sembra piu` semplice restituire un bool.
ciao
Massimo