Newsgroup: it.comp.lang.c++
Titolo: Contenitore matrix

Per imparare meglio il C++ ho pensato di implementare una
classe template matrix che abbia tutte le caratteristiche del
contenitore standard.
Se gia' a questo punto vi pare una brutta idea, vi prego,
FERMATEMI!!
Altrimenti vorrei valutare con voi l'implementazione che
sto facendo, almeno per evitare i grossolani errori
che ci infilero' sicuramente dentro...
Vi posto quello che ho fatto fino ad ora, sperando di non
aver fatto troppi errori... e confidando nei vostri commenti.
Ah! Esiste da qualche parte una classe matrix come quella che
sto facendo (ma fatta bene!!! ) da cui posso prendere spunto?
Ecco il codice:
#include <valarray>
#include <iostream>
template<class T> class matrix
{
    typedef std::valarray<T> colonna; // colonne...
    std::valarray<colonna> body; // righe (di colonne)
    // ridimensiona Colonne e Righe
    void setSize(int numero_colonne, int numero_righe)
    {
        body.resize(0); // getta tutto
        body.resize(numero_righe); // riparte
        for(int i=0; i<numero_righe; ++i)
        {
            body[i].resize(0); // questa riga e' inutile, giusto?
            body[i].resize(numero_colonne);
        }
    }
    public:
    // ----------- COSTRUTTORI ----------- //
    matrix() {}
    matrix(int colonne, int righe) { setSize(colonne, righe); }
    // ----------- OPERATORI UNARI ----------- //
    // ----------- Operatore [] ----------- //
    std::valarray<T>& operator[](int i) { return body[i]; }
    const std::valarray<T>& operator[](int i) const { return body[i];}
    // ----------- Operatore += ----------- //
    matrix<T>& operator+= (matrix& matrice)
    {
        for (int i=0; i < body[i].size(); ++i)
        {
            body[i] += matrice.body[i]; // somma membro a membro
        }
        return *this;
    }
    // ----------- Operatore *= ----------- //
    matrix<T>& operator*= (matrix& matrice)
    {
        if(body.size() == matrice[0].size())
        {
            // crea la matrice risultato
            matrix<T> temp(body.size(), matrice[0].size() );
            // per tutta la lunghezza delle colonne di matrice
            // ( == per tutte le righe)
            for (unsigned int i=0; i < matrice.body.size(); ++i)
            {
                // per tutta la lunghezza delle righe di this
                // ( == per ogni elemento della colonna)
                for (unsigned int j=0; j< body[i].size(); ++j)
                {
                    // fa il prodotto vettoriale riga*colonna
                    for (unsigned int k=0; k< body[i].size(); ++k)
                    {
                        temp[i][j] += body[k][i] * matrice[j][k];
                    }
                }
            }
            // per tutte le righe
            for (unsigned int i=0; i < body.size(); ++i)
            {
                // per ogni elemento della colonna
                for (unsigned int j=0; j < body[i].size(); ++j)
                {
                    // copia temp in this->body elemento per elemento
                    body[i][j] = temp[i][j];
                }
            }
            return *this; // restituisce la matrice cambiata
        }
        // se invece le colonne della prima matrice non sono tante
        //  quente le righe  della prima matrice
        else
        {
            // stampa un messaggio di errore (ecco l' <iostream> )
            std::cout << "Errore dimensioni!" << std::endl;
            std::cout << "Lunghezza Righe    prima     matrice: ";
            std::cout << body.size() << std::endl;
            std::cout << "Lunghezza Colonne prima     matrice: ";
            std::cout << body[0].size() << std::endl;
            std::cout << "Lunghezza Righe seconda    matrice: ";
            std::cout  << matrice.body.size() << std::endl;
            std::cout << "Lunghezza Colonne seconda matrice: ";
            std::cout  << matrice[0].size() << std::endl;
            return *this;   // e ritorna la matrice senza averla cambiata
        }
    }
};
Che ne dite?
Come suggerite di agire quando le dimensioni delle matrici sono
sbagliate per determinate operazioni?
(a parte l'obrobrio qui sopra del messaggio di errore)
Quali caratteristiche deve avere per essere un contenitore standard?
Grazie a tutti anticipatamente.
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: Pink Floyd - Confortably Numb

Mi sono accorto di avere fatto dei casini con righe e colonne
Ecco il codice "corretto":
#include <valarray>
#include <iostream>
template<class T> class matrix
{
    typedef std::valarray<T> colonna; // colonne...
    std::valarray<colonna> body; // righe (di colonne)
    // ridimensiona Colonne e Righe
    void setSize(int numero_righe, int numero_colonne)
    {
        body.resize(0); // getta tutto
        body.resize(numero_colonne); // riparte
        for(int i=0; i<numero_colonne; ++i)
        {
            body[i].resize(0); // questa riga e'inutile, giusto?
            body[i].resize(numero_righe);
        }
    }
    public:
    // ----------- COSTRUTTORI ----------- //
    matrix() {}
    matrix(int righe, int colonne) { setSize(righe, colonne); }
    // ----------- OPERATORI UNARI ----------- //
    // ----------- Operatore [] ----------- //
    std::valarray<T>& operator[](int i) { return body[i]; }
    const std::valarray<T>& operator[](int i) const { return body[i];}
    // ----------- Operatore += ----------- //
    matrix<T>& operator+= (matrix& matrice)
    {
        for (int i=0; i < body[i].size(); ++i)
        {
            body[i] += matrice.body[i]; // somma membro a membro
        }
        return *this;
    }
    // ----------- Operatore *= ----------- //
    matrix<T>& operator*= (matrix& matrice)
    {
        if(body.size() == matrice[0].size())
        {
            // crea la matrice risultato
            matrix<T> temp(body[0].size(), matrice.body.size() );
            // per tutta la lunghezza delle colonne di matrice
            // ( == per tutte le righe)
            for (unsigned int i=0; i < body[i].size(); ++i)
            {
                // per tutta la lunghezza delle righe di this
                // ( == per ogni elemento della colonna)
                for (unsigned int j=0; j< matrice.body.size(); ++j)
                {
                    // fa il prodotto vettoriale riga*colonna
                    for (unsigned int k=0; k< body.size(); ++k)
                    {
                        temp[i][j] += body[k][i] * matrice[j][k];
                    }
                }
            }
            // ridimensiona this
            setSize(body[0].size(), matrice.body.size() );
            // per tutte le righe
            for (unsigned int i=0; i < body.size(); ++i)
            {
                // per ogni elemento della colonna
                for (unsigned int j=0; j < matrice.body.size(); ++j)
                {
                    // copia temp in this->body elemento per elemento
                    body[i][j] = temp[i][j];
                }
            }
            return *this; // restituisce la matrice cambiata
        }
        // se invece le colonne della prima matrice non sono tante
        //  quente le righe  della prima matrice
        else
        {
            // stampa un messaggio di errore (ecco l' <iostream> )
            std::cout << "Errore dimensioni!" << std::endl;
            std::cout << "Lunghezza Righe    prima     matrice: ";
            std::cout << body.size() << std::endl;
            std::cout << "Lunghezza Colonne prima     matrice: ";
            std::cout << body[0].size() << std::endl;
            std::cout << "Lunghezza Righe seconda    matrice: ";
            std::cout  << matrice.body.size() << std::endl;
            std::cout << "Lunghezza Colonne seconda matrice: ";
            std::cout  << matrice[0].size() << std::endl;
            return *this;   // e ritorna la matrice senza averla cambiata
        }
    }
};
--
Gerolamo

"Gerolamo" ha scritto
: Mi sono accorto di avere fatto dei casini con righe e colonne
: Ecco il codice "corretto":
:
: #include <valarray>
: #include <iostream>
:
: template<class T> class matrix
: {
:     typedef std::valarray<T> colonna; // colonne...
:     std::valarray<colonna> body; // righe (di colonne)
Non condivido l'idea di considerare una matrice un vettore di colonne:
il primo indice denota la riga, mentre body[i] individua la
i-esima colonna, e body[i][j] l'elemento alla riga j e colonna i.
Controintuitivo e foriero di errori.
:
:     // ridimensiona Colonne e Righe
...
:
:
:     // ----------- Operatore += ----------- //
:     matrix<T>& operator+= (matrix& matrice)
:     {
Qui, visto che matrice non viene modificata, dovrebbe essere
dichiarata costante. Inoltre puoi anche effettuare un controllo
sulle dimensioni.
:         for (int i=0; i < body[i].size(); ++i)
:         {
:             body[i] += matrice.body[i]; // somma membro a membro
:         }
:         return *this;
:     }
:
:
:     // ----------- Operatore *= ----------- //
:     matrix<T>& operator*= (matrix& matrice)
:     {
Idem per il const.
:         if(body.size() == matrice[0].size())
:         {
:             // crea la matrice risultato
:             matrix<T> temp(body[0].size(), matrice.body.size() );
In realta` ti basta una riga temporanea.
:
:             // per tutta la lunghezza delle colonne di matrice
:             // ( == per tutte le righe)
:             for (unsigned int i=0; i < body[i].size(); ++i)
:             {
Il test di uscita e` equivoco. body[i] e` un array. body[i].size() e`
la sua dimensione. Ma tu usi i per iterare su body. E se body avesse
dimensioni piu` piccine di body[i]?
:                 // per tutta la lunghezza delle righe di this
:                 // ( == per ogni elemento della colonna)
:                 for (unsigned int j=0; j< matrice.body.size(); ++j)
:                 {
:                     // fa il prodotto vettoriale riga*colonna
:                     for (unsigned int k=0; k< body.size(); ++k)
:                     {
:                         temp[i][j] += body[k][i] * matrice[j][k];
Io ho sempre visto a[i][j] = Sum( body[i][k] * [matrice[k][j] ),
ma per sistemare bisogna ricominciare dalla definizione di body.
ciao
Massimo

 Massimo
Grazie per i suggerimenti!
--
Gerolamo

Ok... credo di avere applicato i suggerimenti dati...
(e ho aggiunto anche un po' di roba)
Cosa ne dite?
#include <valarray>
#include <iostream>
template<class T> class matrix
{
    typedef std::valarray<T> righe; // righe...
    std::valarray<righe> colonna; // colonna (di righe)
    // ridimensiona Colonne e Righe
    void setSize(int numero_righe, int numero_colonne)
    {
        colonna.resize(0); // getta tutto
        colonna.resize(numero_righe); // riparte
        for(int i=0; i<numero_righe; ++i)
        {
            colonna[i].resize(0); // questa riga e' inutile, giusto?
            colonna[i].resize(numero_colonne);
        }
    }
    public:
    // ----------- COSTRUTTORI ----------- //
    matrix() {}
    matrix(int righe, int colonne) { setSize(righe, colonne); }
    // ----------- CAPACITA' ----------- //
    // questo č legale o rischio un overflow di size_t ??
    size_t size() const { return (colonna.size() * colonna[0].size()); }
    size_t max_size()
    {
        return (colonna.max_size() * colonna[0].max_size());
    }
    void resize(size_t righe, size_t colonne)
    {
        colonna.resize(righe);
        for(unsigned int i=0; i < colonna.size();  ++i)
        {
            colonna[i].resize(colonne);
        }
    }
    void resize(size_t righe, size_t colonne, T valore)
    {
        colonna.resize(righe, valore);
        for(unsigned int i=0; i < body.size();  ++i)
        {
            colonna[i].resize(colonne, valore);
        }
    }
    bool empty(){ return (colonna.empty() || colonna[0].empty()); }
    // ----------- OPERATORI UNARI ----------- //
    // ----------- Operatore [] ----------- //
    std::valarray<T>& operator[](int i) { return colonna[i]; }
    const std::valarray<T>& operator[](int i) const { return colonna[i];}
    // ----------- Operatore += ----------- //
    matrix<T>& operator+= (const matrix& matrice)
    {
        if( (colonna.size() == matrice.colonna.size() ) &&
            (colonna[0].size() == matrice.colonna[0].size()) )
        {
            for (unsigned int i=0; i < colonna.size(); ++i)
            {
                colonna[i] += matrice.colonna[i]; // somma membro a membro
            }
        }
        return *this;
    }
    // ----------- Operatore *= ----------- //
    matrix<T>& operator*= (const matrix& matrice)
    {
        // se sono moltiplicabili
        if( colonna[0].size() == matrice.colonna.size() )
        {
            // per tutta la lunghezza delle colonne di this
            // ( == per tutte le righe)
            for (unsigned int i=0; i< colonna.size(); ++i)
            {
                // crea una riga temporanea per i risultati
                righe riga_temp( matrice.colonna[i].size() );
                // per tutta la lunghezza delle righe di matrice
                // ( == per ogni elemento della colonna)
                for (unsigned int j=0; j < matrice.colonna[i].size(); ++j)
                {
                    // fa il prodotto vettoriale riga*colonna
                    for (unsigned int k=0; k< colonna[i].size(); ++k)
                    {
                        riga_temp[j] +=
                        colonna[i][k] * matrice.colonna[k][j];
                    }
                }
                // ridimensiona la riga calcolata
                colonna[i].resize( matrice.colonna[i].size() );
                // e vi copia il risultato
                colonna[i] = riga_temp;
            }
            return *this; // restituisce la matrice cambiata
        }
        // se invece le colonne della prima matrice non sono tante
        //  quante le colonne della seconda matrice
        else
        {
            // stampa un messaggio di errore (ecco l' <iostream> )
            std::cout << "Errore dimensioni!" << std::endl;
            std::cout << "Lunghezza Colonne    prima     matrice: ";
            std::cout << colonna.size() << std::endl;
            std::cout << "Lunghezza Righe prima     matrice: ";
            std::cout << colonna[0].size() << std::endl;
            std::cout << "Lunghezza Colonne seconda    matrice: ";
            std::cout  << matrice.colonna.size() << std::endl;
            std::cout << "Lunghezza Righe seconda matrice: ";
            std::cout  << matrice.colonna[0].size() << std::endl;
