Newsgroup: it.comp.lang.c++
Titolo: Matrici 2 (che paXXe!)

Ciao ragazzi,
dopo i vostri preziosissimi aiuti sono riuscito finalmente a
implementare uno straccio di programma che calcoli il prodotto tra una
matrice triangolare superiore e la sua trasposta:
                                        A=Lsup*Linf
Il bello e´ che adesso ho la necessita´ di estendere le capacita´del
programma al fine di poter trattare matrici con numeri complessi...
Credo che in pratica si tratti "soltanto" di definire in maniera
"astuta" un nuovo tipo di dato, ma quale e´ questa maniera astuta?
E poi credo sia necessario definire nuovi tipi di operazioni, tipo
somma, sottrazione, moltiplicazione, divisione e radice quadrata (per lo
meno queste).
Vi sarei molto grato se anche questa volta qualche anima pia e (spero)
interessata al problema mi possa dare qualche dritta.
Probabilmente esistera´ gia´ qualche libreria pronta, ma a me serve il
codice sorgente...
Grazie!
Luigi L.

programma al fine di poter trattare matrici con numeri complessi...
Basta che usi i complex della libreria standard.
-- 
                    Marco Barisione (ICQ 84277092)
Se sei interessato alla creazione di it.comp.lang (per i linguaggi di
programmazione senza un gruppo apposito e per i confronti fra i
linguaggi) partecipa alla discussione sul manifesto su it.news.gruppi.

Mi serve il sorgente....


> Mi serve il sorgente....
Esempio chiarificatore:
#include <complex>
#include <iostream>
// nel template ci metti il tipo che serve a te
typedef std::complex<double> complex;
int main()
{
 std::complex a(12.3, 23.4);
 std::cout << "Re: " << a.real() << std::endl;
 std::cout << "Im: " << a.imag() << std::endl;
 std::cout << "Ro: " << abs(a) << std::endl;
 std::cout << "Teta: " << arg(a) << std::endl;
}
--
Gerolamo


Guarda complex.h
ciao
Massimo

>  std::complex a(12.3, 23.4);
Ma dove??? Copia incolla maledetto! :-)
Possibile che non mi riesce mai di postare il codice senza errori?
Correggi in:
#include <complex>
#include <iostream>
typedef std::complex<double> complex;
int main()
{


 > <<Basta che usi i complex della libreria standard.>>
Appunto. Usa std::complex che sono template e quindi sono forniti
completi di sorgente.
--
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

 Guarda complex.h
Non contraddirti. Prima scrivi #include <complex> e poi dici di guardare
complex.h. Non esiste complex.h ma bensì complex, senza il .h



Non mi sono contraddetto io ho complex.h che includo con quell'istruzione:
#ifndef __COMPLEX_H
#define __COMPLEX_H
#pragma option push -b -a8 -pc -Vx- -Ve- -w-inl -w-aus -w-sig
// -*- C++ -*-
#ifndef __STD_COMPLEX
#define __STD_COMPLEX
/***************************************************************************
 *
 * complex - Declaration for the Standard Library complex class
 *
 ***************************************************************************
...
tratto da complex.h della Rogue Wave.
Pero` guardando ora la STLport ho notato che ha un complex.h che include
../complex giusto per il BCB. Ma, per curiosare, io uso la Rogue
Wave che e` fornita di default con BCB e che mi consente di navigarci
piu` comodamente, e questa ha complex.h e complex.cc, per cui avevo concluso
che la norma fosse includo <complex> e lui ci attacca l'estensione...
Leggendo nel draft prevotazione
...
16.2
-2- A preprocessing directive of the form
# include <h-char-sequence> new-line
searches a sequence of implementation-defined places for a header
identified uniquely by the specified sequence between the < and >
delimiters, and causes the replacement of that directive by the
entire contents of the header. How the places are specified or the
header identified is implementation-defined.
...
sembrerebbe che la sequenza di caratteri identifichi univocamente
l'header, ma non sembra necessario che sia il nome, per cui sarei
portato a concludere che il comportamento del BCB non sia neanche
una non conformita`.
ciao
Massimo

 che la norma fosse includo <complex> e lui ci attacca l'estensione...
No. Non so cosa intendi con norma ma lo standard dice in modo molto
chiaro cosa deve essere fornito con una implementazione conforme.
Secondo lo standard DEVE essere possibile scrivere:
#include <complex>
e avere la classe complex così come descritta dallo standard stesso (e
naturalmente averla nel namespace std).
Lo standard non dice che quando scrivi
#include <complex>
il compilatore debba leggere un header. Per un dato compilatore quella
riga potrebbe essere equivalente a:
#pragma use_standard_complex_header
e non esserci nessun file chiamato "complex" da nessuna parte.
Ma DI FATTO tutti i compilatori attuali credo proprio che interpretino
#include <complex>
come un comando che include un header il cui nome del file è "complex"
senza .h
Se poi il tuo compilatore ti fornisce anche un altro header chiamato
complex.h, allora puoi usarlo fino a che resti nell'ambito di quella
versione di quel compilatore. Però di quell'header e di cosa ci sta
dentro dovresti parlare nel NG relativo a quel compilatore perchè non fa
parte dello standard C++. E' un header fornito con quel compilatore.
Come conio.h o windows.h


Come conio.h o windows.h
Obbediro`

 perche` "DI FATTO tutti ... credo proprio ... interpretino"?
Perchč la tendenza comune č che il produttore del compilatore e il
produttore della STL sono separati. Poi il produttore del compilatore ti
fornisce di serie anche una data implementazione della STL. Ma molti
utenti la sostituiscono con una alternativa. Perchč questo sia possibile
bisogna che il compilatore interpreti #include <nomefile> nel modo piů
ovvio (apre e legge quel file).
Questa č al momento la tendenza. Perň non conosco il borland quindi puň
anche essere l'eccezione.


interessata al problema mi possa dare qualche dritta.
Ti hanno già risposto con degli esempi che usano i template. 
Se però li vuoi evitare, ti basta scrivere funzioni analoghe a quelle
per i double, ma con i cmplx. 
Attenzione, *analoghe*, non uguali: infatti la trasposta di una
matrice complessa (o meglio, la sua hermitiana), ha tutti gli elementi
coniugati, oltre che scambiati di posto, e il prodotto Lsup*Lsup' non
è simmetrico ma simmetrico coniugato.
Ad esempio:
// inizio file mc.cpp
#include <iostream>
#include <complex>
typedef std::complex<double> cmplx;
double** new_matrice( int nr, int nc )
{
  double** A = new double*[nr+1];
  A[1] = new double[nr*nc+1];
  for( int i=2; i<=nr; ++i ) 
    A[i]=A[i-1]+nc;
  return A;
}
cmplx** new_matrice_cmplx( int nr, int nc )
{
  cmplx** A = new cmplx*[nr+1];
  A[1] = new cmplx[nr*nc+1];
  for( int i=2; i<=nr; ++i ) 
    A[i]=A[i-1]+nc;
  return A;
}
void delete_matrice( double** A )
{
  delete[] A[1];
  delete[] A;
}
void delete_matrice( cmplx** A )
{
  delete[] A[1];
  delete[] A;
}
void stampa( double** A, int n, char* commento=0 )
{
  using namespace std;
  if( commento ) 
    cout<<" "<<commento<<":"<<endl<<endl;
  for( int i=1; i<=n; ++i )
    {
      for( int j=1; j<=n; ++j )
        cout<<A[i][j]<<"\t";
      cout<<endl;
    }
  cout<<endl;
}
void stampa( cmplx** A, int n, char* commento=0 )
{
  using namespace std;
  if( commento ) 
    cout<<" "<<commento<<":"<<endl<<endl;
  for( int i=1; i<=n; ++i )
    {
      for( int j=1; j<=n; ++j )
        cout<<A[i][j]<<"\t";
      cout<<endl;
    }
  cout<<endl;
}
int main()
{
  int n=2;
  // caso reale
  {
    double** A = new_matrice(n,n);
    A[1][1]=1; A[1][2]=2;
    A[2][1]=0; A[2][2]=4;
    stampa(A,n,"A");
 
    double** B = new_matrice(n,n);
    for( int i=1; i<=n; ++i )
      for( int j=i; j<=n; ++j ) 
        {
          B[i][j]=0.0;
          for( int k=j; k<=n; ++k )
            B[i][j] += A[i][k] * A[j][k];
          B[j][i] = B[i][j];
        }  
    stampa(B,n,"A*A'");
    delete_matrice(A);
    delete_matrice(B);
  }
  // caso complesso
  {
    cmplx** A = new_matrice_cmplx(n,n);
    A[1][1]=cmplx(1,1);  A[1][2]=cmplx(1,2);
    A[2][1]=0;           A[2][2]=cmplx(0,1);
    stampa(A,n,"A");
 
    cmplx** B = new_matrice_cmplx(n,n);
    for( int i=1; i<=n; ++i )
      for( int j=i; j<=n; ++j )
        {
          B[i][j]=0.0;
          for( int k=j; k<=n; ++k )
            B[i][j] += A[i][k] * conj(A[j][k]);  
          B[j][i] = conj(B[i][j]);
        }
 
    stampa(B,n,"B*B'");
    delete_matrice(A);
    delete_matrice(B);
  }
  return 0;
}
// fine file mc.cpp
Nota: mi par di capire che Visual C++ non definisce "conj", quindi se
usi questo compilatore devi aggiungere la funzione:
inline cmplx conj( const cmplx& x )
{
  return cmplx( x.real(), -x.imag() );
}
-- 
Ciao, Marvin


Una matrice si dice Hermitiana se e` uguale alla propria trasposta
coniugata e per 'analogia' viene considerata l'equivalente complesso
di una matrice reale simmetrica. Cio` non toglie che anche di una
matrice complessa esista la trasposta (la cui definizione e` indispensabile
per definire l'Hermitiana) e che, viste le definizioni del prodotto
tra matrici e le proprieta` del prodotto tra numeri complessi, il
prodotto di una matrice complessa per la propria trasposta sia una
matrice complessa simmetrica (non Hermitiana).
ciao
Massimo

Grazie nuovamente,
mi sembra di aver capito abbastanza per tentare un primo approccio...
ho solo un dubbio da chiarire, intanto ve lo posto: sto lavorando con un DSP,
nella directory concernente il suo ambiente di sviluppo il file complex (o
complex.h) non c´e´... ho cmq a disposizione tale file (da Microsoft Visual
C++).
Posso fare un banale copia e incolla?
Intuitivamente credo di si....adesso ci provo!
Come faccio invece ad invocare la radice quadrata di un numero complesso?
Per analogia con gli esempi che avete postato mi verrebbe da dire a.sqrt()
e´giusto?
A prestissimo.
Luigi.


Mi rispondo da solo... NO!
nel mio programma aggiungo (dopo aver copiato il file nella giusta dir)
#include <complex>
provo a compilare e mi chiede   "ymath.h"
lo aggiungo.
provo a compilare e mi chiede "wctype.h"
lo aggiungo.
provo a compilare e mi dice
fatal error: #error directive: ERROR: Only Mac or Win32 targets supported!
oddio...please, aiutatemi!
C´e´ una scappatoia?
Grazie,
Luigi.

:

D'accordo, la distinzione tra "trasposta" e "trasposta coniugata"
esiste e va mantenuta con più precisione di quanto non abbia detto io
nel precedente messaggio, ma ricorda che Luigi voleva *estendere* al
dominio complesso l'operazione A*A', e per far questo occorre usare la
trasposta coniugata. (A*A' con trasposta semplice non ha senso, se non
come esercizio informatico, visto che, ad esempio, va persa la
struttura metrica.)
Per curiosità, ho provato a farne una versione template estendendo il
"conj" della STL (all'inizio del file che segue). E` questo il modo
giusto per aggiungere un tipo tra quelli riconosciuti di default?
/////// inizio file mct.cpp
#include <iostream>
#include <complex>
// estensione di conj
template<typename T>
T conj( const T& x );
template<>
inline double conj( const double& x )
{
  return x;
}
typedef std::complex<double> cmplx;
template<typename T>
T** new_matrice( int nr, int nc )
{
  T** A = new T*[nr+1];
  A[1] = new T[nr*nc+1];
  for( int i=2; i<=nr; ++i ) 
    A[i]=A[i-1]+nc;
  return A;
}
template<typename T>
void delete_matrice( T** A )
{
  delete[] A[1];
  delete[] A;
}
template<typename T>
void stampa( T** A, int n, char* commento=0 )
{
  using namespace std;
  if( commento ) 
    cout<<" "<<commento<<":"<<endl<<endl;
  for( int i=1; i<=n; ++i )
    {
      for( int j=1; j<=n; ++j )
        cout<<A[i][j]<<"\t";
      cout<<endl;
    }
  cout<<endl;
}
// calcola B=A*A'
template<typename T>
void AxAt( T** A, int n, T** B )
{
  for( int i=1; i<=n; ++i )
    for( int j=1; j<=n; ++j )
      {
        B[i][j]=0;
        for( int k=j; k<=n; ++k )
          B[i][j] += A[i][k] * conj(A[j][k]);
        B[j][i]=conj(B[i][j]);
      }
}
int main()
{
  int n=2;
  // caso reale 
  double** A = new_matrice<double>(n,n);
  A[1][1]=1; A[1][2]=2;
  A[2][1]=0; A[2][2]=4;
  stampa(A,n,"A");
 
  double** B = new_matrice<double>(n,n);
  AxAt(A, n, B);
  stampa(B,n,"A*A'");
  delete_matrice(A);
  delete_matrice(B);
  // caso complesso
  cmplx** C = new_matrice<cmplx>(n,n);
  C[1][1]=cmplx(1,1);  C[1][2]=cmplx(1,2);
  C[2][1]=0;           C[2][2]=cmplx(0,1);
  stampa(C,n,"C");
 
  cmplx** D = new_matrice<cmplx>(n,n);
  AxAt(C, n, D);
  stampa(D,n,"C*C'");
  delete_matrice(C);
  delete_matrice(D);
  return 0;
}
/////// fine file mct.cpp
Nota: come prima, Visual C++ non riconosce il template conj, quindi
bisogna sostituire l'estensione con:
inline cmplx conj( const cmplx& x )
{
  return cmplx( x.real(), -x.imag() );
}
inline double conj( const double& x )
{
  return x;
}
-- 
Ciao, Marvin


ciao
Massimo

complex.h) non c´e´... 
Potresti dirci che compilatore / ambiente di sviluppo usi?
-- 
Ciao, Marvin

 Ciao, Marvin
Lavoro con il C6200 Code Composer Studio della TI
il compilatore non so che nome abbia, utilizza una sintassi del genere per
compilare il sorgente...
cl6x -gk -mwx -o3 -frD:path + nomefile.c
ciao Luigi

 wrote in message
news:3BF24712...@libero.it...

Sei sicuro che sia un compilatore C++ con un minimo di conformità? Se è
così dovrebbe avere l'header <complex>. E in ogni caso dovresti poter
usare l'header <complex> di una qualunque implementazione STL conforme
(salvo il fatto che devi prendere la versione free-standing se lavori
con un DSP. Oppure modificarti la versione hosted rimuovendo le parti
che non sono supportabili in ambiente free-standing).


 che non sono supportabili in ambiente free-standing.
Con i vostri numerosi esempi e sbirciando in questo header (complex) sono
riuscito a crearmi qualcosa di utile, dovrebbe funzionare.
Ad oggi pomeriggio il test!
Grazie ancora del vostro intenso interessamento!
Luigi

cl6x -gk -mwx -o3 -frD:path + nomefile.c
Non lo conosco, però mi sembra impossibile che non abbia un minimo
supporto per i numeri complessi: persino il Turbo C++ 1.0 del 1990
aveva il suo complex.h!
Dovresti cercare qualcuno che conosca il tuo ambiente di sviluppo, e
farti dare qualche dritta...
-- 
Ciao, Marvin