Newsgroup: it.comp.lang.c++
Titolo: vector di valarray

mi serve, all'interno di una classe, una cosa del tipo:
std::vector<std::valarray<float> > m_pos;
che sia un vector di N valarray di M elementi.
Come specifico N e M?
grazie!
--
Gerolamo

 Come specifico N e M?
Ridimensioni m_pos con resize(N), cicli sugli elementi e ridimensioni
ciascuno con resize(M), oppure inizializzi m_pos con
     m_pos( N, std::valarray<float>(M) )
Max

      m_pos( N, std::valarray<float>(M) )
Chiarissimo!
praticamente lo faccio come nel caso normale!
...il template di template mi aveva mandato in confusione, eheh...
Mi e' nato un altro problema pero' nel frattempo.
Ho una cosa del tipo:
class SistemaDiParticelle
{
    std::vector<std::valarray<float> >    m_Pos;
    std::vector<std::valarray<float> >    m_VecchiaPos;
    void   Aggiorna();
}
void SistemaDiParticelle::Aggiorna()
{
    std::vector<std::valarray<float> >::iterator fine_vettore = m_Pos.end();
    for ( std::vector<std::valarray<float> >::iterator i = m_Pos.begin(); i
!= fine_vettore; ++i)
    {
        m_Pos[i] += m_Pos[i] - m_VecchiaPos[i]; // qui mi da l'errore
    }
}
L'errore e':
Error E2094 sistemadiparticelle.hpp 39: 'operator+' not implemented in type
'std::vector<std::valarray<float>,std::allocator<std::valarray<float> > >'
for arguments of type 'std::valarray<float> *' in function
SistemaDiParticelle::Aggiorna()
e io proprio non capisco, primo perche' l'operatore e' "+=" e non "+"
e poi perche' dovrebbe essere applicato ad un m_Pos[i] che e' di
tipo "valarray<float>" e quindi dovrebbe essere gia' implementato
nella libreria standard.
Dover sbaglio?
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: Tori Amos - I Don't Like Mondays

 }
Ma poi mi viene un'altro dubbio (lo so, vi sto assillando, pieta!)
Posso usare l'iteratore "i = m_Pos.begin()" come indice di
"m_VecchiaPos[i]" ???
Perche' se non posso quasi mi conviene fare il ciclo
"for" con gli interi...
--
Gerolamo

 SistemaDiParticelle::Aggiorna()
Stai cercando di usare un iteratore come indice per accedere agli
elementi di m_pos; questo non ha alcun senso. L'iteratore č una
generalizzazione della nozione di puntatore, per accedere all'elemento a
cui esso si riferisce devi dereferenziarlo tramite l'operatore *;
L'origine di quel bizzarro messaggio d'errore č, credo, da rintracciare
nel fatto che l'espressione
      m_pos[ i ]
in mancanza di un appropriato operator[], viene considerata equivalente a
      m_pos + i
Puoi riscrivere Aggiorna() cosě:
 Assumendo:
     typedef std::valarray<float>      row_type;
     typedef std::vector< row_type  >  vector_type;
     // consiglio: usa typedef ogni volta che incorpori instanziazioni
     // di template nelle tue classi:  semplifica la lettura e rende piů
     // semplice apportare successive modiche all'implementazione
 void SistemaDiParticelle::Aggiorna()
 {
     vector_type::iterator  i =  m_Pos.begin();
     vector_type::iterator  iv =  m_VecchiaPos.begin();
 
     while( i != m_Pos.end() && iv != m_VecchiaPos.end() )
     {
         *i += *i - *iv;
         ++i; ++iv;
     }
 }
Max
 

 Puoi riscrivere Aggiorna() cosě:
Ottimo, grazie!
Ne ho scritta anche una versione con un normale ciclo for, visto
che so a compile-time quanti sono gli elementi.
A dire il vero la versione "stile C" mi risulta piu' leggibile, e
temo anche che sia piu' performante.
In effetti... che vantaggi ha, in generale usare gli iteratori invece
degli indici?
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: Bon Jovi - Bed of Roses

 degli indici?
Un vantaggio è senz'altro la maggiore genericità del codice.
Con la mia versione puoi sostituire std::vector con std::list senza dover
modificare nient'altro.
Max

 Quella che usa gli indici? E per quale motivo?
In effetti non mi sono spiegato.
Posto il codice (azz... non ho ancora fatto i typedef :-):
// Variabili
std::vector<std::valarray<float> >    m_Pos;
std::vector<std::valarray<float> >    m_VecchiaPos;
std::vector<std::valarray<float> >    m_Acc;
std::valarray<float>                         m_Grav;
float                                                m_PassoTemporale;
// Versione C-Like
for (int i=0; i <= 99; ++i)
{
    std::vector<std::valarray<float> > temp_vect(m_Pos);
    m_Pos[i] += (m_Pos[i] - m_VecchiaPos[i] + (m_Acc[i] * m_PassoTemporale *
m_PassoTemporale));
}
m_VecchiaPos = temp_vect;
// Versione Pure C++
std::vector<std::valarray<float> >::iterator iter_m_Pos =  m_Pos.begin();
std::vector<std::valarray<float> >::iterator iter_m_VecchiaPos =
m_VecchiaPos.begin();
std::vector<std::valarray<float> >::iterator iter_m_Acc = m_Acc.begin();
std::vector<std::valarray<float> > temp_vect(m_Pos);
while( iter_m_Pos  != m_Pos.end()                       &&
      iter_m_VecchiaPos != m_VecchiaPos.end()    &&
      iter_m_Acc != m_Acc.end())
{
     *iter_m_Pos += *iter_m_Pos  - *iter_m_VecchiaPos +
         (*iter_m_Acc * m_PassoTemporale * m_PassoTemporale);
    ++iter_m_Pos;
    ++iter_m_VecchiaPos;
    ++iter_m_Acc;
}
m_VecchiaPos = temp_vect;
Beh... la versione con gli iteratori sara' pure piu' generica...
...ma a me pare proprio un obbrobrio!
Quantomeno mi risulta meno leggibile.
Che ne pensi?
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: Dream Theater - The Silent Man

 for (int i=0; i <= 99; ++i)
ehm... mancava un dettaglio... e c'era pure un errore.. uff...
diciamo che cosi' e' meglio:
const int DIM_VECTOR = 99;
std::vector<std::valarray<float> > temp_vect(m_Pos);
for (int i=0; i <= DIM_VECTOR; ++i)
{
    m_Pos[i] += (m_Pos[i] - m_VecchiaPos[i] +
                        (m_Acc[i] * m_PassoTemporale * m_PassoTemporale));
}
m_VecchiaPos = temp_vect;
--
Gerolamo

 Quantomeno mi risulta meno leggibile.
Mah, non saprei. E' una questione di abitudine.
Tu avevi anche parlato di performance, però.
Max

 Quantomeno mi risulta meno leggibile.
Ci credo che non è molto leggibile.
Vediamo di ripartire dalla versione in stile C tanto per definire meglio
come stanno le cose:
class SistemaDiParticelle
{
public:
  typedef float support_t;
  typedef std::valarray<support_t> particle_t;
  typedef std::vector<particle_t> system_t;
private:
  system_t  m_Pos;
  system_t  m_VecchiaPos;
  system_t  m_Acc;
  support_t m_PassoTemporale;
public:
  void Aggiorna();
};
void SistemaDiParticelle::Aggiorna()
{
  static const int DIM_VECTOR = 99;
  system_t temp(m_Pos);
  for ( int i=0; i <= DIM_VECTOR; ++i ) {
    m_Pos[i] += m_Pos[i] - m_VecchiaPos[i] +
                     (m_Acc[i] * m_PassoTemporale * m_PassoTemporale);
  }
  m_VecchiaPos = temp;
}
Supponendo che sia giusto possiamo trasformare il tutto in questo modo:
class SistemaDiParticelle
{
public:
  typedef float support_t;
  typedef std::valarray<support_t> particle_t;
  typedef std::valarray<particle_t> system_t; // nota che ora è un
valarray
private:
  system_t  m_Pos;
  system_t  m_VecchiaPos;
  system_t  m_Acc;
  support_t m_PassoTemporale;
public:
  void Aggiorna();
};
void SistemaDiParticelle::Aggiorna()
{
  system_t adjustedAcc(m_Acc);
  adjustedAcc *= m_PassoTemporale*m_PassoTemporale;
  system_t vecchiaPos(m_Pos);
  m_Pos += m_Pos - m_VecchiaPos + adjustedAcc;
  m_VecchiaPos = vecchiaPos;
}
Che non mi sembra poi tanto illeggibile.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

 Che non mi sembra poi tanto illeggibile.
Anzi! Bastava sapere cosa usare :-)
Pero' devo implementare l'operatore "+=" , infatti mi dice che:
Error E2094 sistemadiparticelle2.hpp 65:
'operator*=' not implemented in type 'std::valarray<std::valarray<float> >'
for arguments of type 'float' in function SistemaDiParticelle::Aggiorna()
Ma non dovrebbe esserci gia'?
(se no perche' usare i valarray...)
uff... comunque comincio ad odiare i valarray!
Ho passato un quarto d'ora ad incazzarmi su un errore che non capivo,
prima di realizzare che il valarray ha i parametri del costruttore al
contrario
del vector (e di tutti gli altri contenitori).
Ma perche' hanno fatto una cosa simile????
intanto grazie!
--
Gerolamo

 Ma perche' hanno fatto una cosa simile????
Forse perche' i valarray non sono dei container ma degli array di
valori. Tanto è vero che non hanno neppure gli iteratori!
Infatti il difetto della mia soluzione è proprio questo: parto dal
presupposto che system_t sia in realtà sistema di particelle (ovvero un
array di particelle cuascuna delle quali è un valore, anche se a sua
volta composito). Se così non fosse dovresti tornare a vector. E usare i
template dell'header algorithm (ed eventualmente dell'header functional)
quando è possibile.


 quando è possibile.
???
non mi e' chiaro... ma domani spero che lo sara' di piu' :-)
intanto grazie!
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: The Cure - Friday I'm in Love

 cio' che ho scritto, pero'...
Probabile. Ma quello che devi fare è
1) scrivi la versione più leggibile
2) verifica che funzioni e misura il tempo di esecuzione
3) se il tempo di esecuzione è accettabile FERMATI. Lo scopo non è
scrivere codice il più veloce possibile ma scriverlo il più velocemente
possibile (e soprattutto facilitare al massimo la manutanzione del
codice) quindi la leggibilità conta più dell'efficienza.
4) SE la velocità non è sufficiente indica nel commento l'esatto
paragrafo delle specifiche di progetto che viene violato dalla velocità
raggiunta, poi commenta (non rimuovere) il codice leggibile e scrivi
codice alternativo che fa la stessa identica cosa più velocemente.
Testalo. Se la specifica è soddisfatta fermati, altrimenti trova una
versione ancora più veloce etc.etc.


 versione ancora più veloce etc.etc.
La versione piu' veloce e' questa:
(praticamente un copia-incolla del tutorial da cui l'ho presa, usando
come vettore tridimensionale un valarray di 3 elementi.)
#define NUMERO_ELEMENTI 100000
typedef float td_TipoDati;
typedef std::valarray<td_TipoDati> td_Particelle;
// Adesso sono array di td_Particelle
// non esiste piu' il td_Sistema
td_Particelle     m_Pos[NUMERO_ELEMENTI];
td_Particelle     m_VecchiaPos[NUMERO_ELEMENTI];
td_Particelle     m_Acc[NUMERO_ELEMENTI];
td_TipoDati    m_PassoTemporale;
void SistemaDiParticelle::AggiornaConVerlet()
{
    for(int i=0; i<NUMERO_ELEMENTI; i++)
    {
        td_Particelle& x = m_Pos[i];
        td_Particelle temp = x;
        td_Particelle& oldx = m_VecchiaPos[i];
        td_Particelle& a = m_Acc[i];
        x += x-oldx+a*m_PassoTemporale*m_PassoTemporale;
        oldx = temp;
    }
}
che ci mette, dall'inizio alla fine, circa 540 millisecondi
Insomma... la differenza non e' poca!
In compenso direi che e' molto meno leggibile...
Commenti?
Comunque io userei la prima versione (che mi piace di piu'),
tenendo l'altra di riserva. Pero' un po' mi scoccia usare la versione
"lenta" :-))
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: Afterhours - Voglio un pensiero superficiale