matrixutil.cpp

Go to the documentation of this file.
00001 #include "matrixutil.hpp"
00002 #include <cmath>
00003 #include <iostream>
00004 #include "vc6compat.h"
00005 using namespace std;
00006 
00007 #define TRACE(a) 
00008 #define TRACEX(a, b)
00009 #define SQR(X) ((X)*(X))
00010 
00011 
00012 bool QR (int zeilen, int spalten, double **A, double *d, double *b, const double epsilon) 
00013 { 
00014  if (zeilen<spalten) {
00015   throw("Matrix darf nicht weniger Zeilen als Spalten haben !");
00016  } 
00017  //
00018  bool singular=false;
00019  double altenorm,hilfsnorm,beta, produkt;
00020  altenorm=0;
00021  for (int j=0; j<spalten; j++) {
00022   // jede Spalte muss transformiert werden
00023   // hier muss als erstes ||a|| berechnet werden
00024   // dazu brauche ich eine "Hilfsnorm"
00025   hilfsnorm=0;
00026   for (int my=j+1; my<zeilen; my++) {
00027     hilfsnorm+=SQR(A[my][j]);
00028   }
00029   // jetzt ist sqrt(hilfsnorm+SQR(A[j][j]) die 2-Norm von a
00030   // berechne den Vektor b dorthin, wo a war
00031   // wenn das erste Element viel kleiner ist als die Hilfsnorm
00032   // dann kann man es als Null ansehen
00033   TRACEX("Vor der Transformation :",A);
00034   TRACE(hilfsnorm);
00035   
00036   if (SQR(A[j][j])<SQR(epsilon)*hilfsnorm) {
00037      A[j][j]=sqrt(hilfsnorm);
00038      d[j]=-A[j][j];
00039      cerr<<"Diagonal-elem. "<<j<<" = 0"<<endl;
00040   } else {
00041      d[j]=-signum(A[j][j])*sqrt(hilfsnorm+SQR(A[j][j]));
00042      // speicher k in d_j
00043 
00044      A[j][j]-=d[j];
00045   }
00046   // ein naives Abbruchkriterium:
00047   // Wenn das aktuelle k sehr viel kleiner ist als das letzte,
00048   // dann sieh die Matrix als singulär an
00049   // ich hab sonst nix gescheites gefunden
00050   // auch MATLAB und octave berechnen anstandslos die
00051   // QR-Zerlegung von singulären Matrizen
00052   
00053   if (fabs(d[j])<epsilon*altenorm) {
00054     singular=true;
00055     break;
00056   } 
00057 
00058   altenorm=fabs(d[j]);
00059   
00060   // berechne beta
00061   beta=2.0/(hilfsnorm+SQR(A[j][j]));
00062   
00063   TRACEX("nach der Transformation "<<j,A);
00064   TRACE(beta); 
00065   // jetzt sind alle Zutaten beieinander, wir können anfangen
00066   // den Rest der Matrix zu transformieren
00067   
00068   for (int k=j+1; k<spalten; k++) {
00069     // jede Spalte weiter rechts
00070     // berechne das innere Produkt aus b und der Spalte ak
00071     produkt=0;
00072     for (int z=j; z<zeilen; z++) {
00073       produkt+=A[z][j]*A[z][k];
00074     }
00075     produkt*=beta;
00076     TRACE(produkt);
00077     // hetze die Transformation auf jede Spalte a_k
00078     for (int z=j; z<zeilen; z++) {
00079       A[z][k]-=produkt*A[z][j];
00080     }  
00081   }
00082   // jetzt das gleiche nochmal mit der rechten Seite
00083   produkt=0;
00084   for (int z=j; z<zeilen; z++) {
00085     produkt+=A[z][j]*b[z];
00086   }
00087   produkt*=beta;
00088   TRACE(produkt);
00089   // hetze die Transformation auf die rechte Seite
00090   for (int z=j; z<zeilen; z++) {
00091     b[z]-=produkt*A[z][j];
00092   }
00093  
00094   TRACE(A);
00095  }
00096  if (singular) return true;
00097  return false;
00098 } 
00099 
00106 
00107 void rdsolve(int spalten, double **R, double *d, double *c, double *x)
00108 {
00109   double tempx;
00110   for (int j=spalten-1; j>=0; j--) {
00111    tempx=c[j];
00112    // umgeformte rechte Seite in tempx speichern
00113    // abziehen die bekannten Variablen
00114    for (int k=j+1; k<spalten; k++)
00115      tempx-=R[j][k]*x[k];
00116 
00117    x[j]=tempx/d[j];
00118   } // for j
00119 } // rsolve
00120 
00121 
00122 
00123 // Berechne Kovarianzmatrix, aus dem Source von Gnuplot
00124 // by Carsten Grammers, public domain
00125 //
00126 void Invert_RtR(double **R, double **I, int n)
00127 {
00128     int i, j, k;
00129 
00130     /* fill in the I matrix, and check R for regularity : */
00131 
00132     for (i = 0; i < n; i++) {
00133         for (j = 0; j < i; j++) /* upper triangle isn't needed */
00134             I[i][j] = 0;
00135         I[i][i] = 1;
00136         if (!R[i][i])
00137             throw("Singular matrix in Invert_RtR");
00138     }
00139 
00140     /* Forward substitution: Solve R^T * B = I, store B in place of I */
00141 
00142     for (k = 0; k < n; k++) {
00143         for (i = k; i < n; i++) {       /* upper half needn't be computed */
00144             double s = I[i][k];
00145             for (j = k; j < i; j++)     /* for j<k, I[j][k] always stays zero! */
00146                 s -= R[j][i] * I[j][k];
00147             I[i][k] = s / R[i][i];
00148         }
00149     }
00150     /* Backward substitution: Solve R * A = B, store A in place of B */
00151 
00152     for (k = 0; k < n; k++) {
00153         for (i = n - 1; i >= k; i--) {  /* don't compute upper triangle of A */
00154             double s = I[i][k];
00155             for (j = i + 1; j < n; j++)
00156                 s -= R[i][j] * I[j][k];
00157             I[i][k] = s / R[i][i];
00158         }
00159     }
00160 }
00161 
00162 void compute_errors(int num_param, int num_data, double **R, double *d, double *b, double *errors) 
00163 {
00164   // berechne reduziertes chi^2
00165   // Der Fehler steckt im Residualvektor der QR-Zerlegung
00166   double chisq=0;
00167   for (int i=num_param; i<num_data; i++) {
00168      chisq+=SQR(b[i]);
00169   }
00170 
00171   // geht nur für num_param<num_data - klar
00172   if (num_param>=num_data) throw("Error: Parameter errors only für num_data < num_data");
00173   chisq=sqrt(chisq/(num_data-num_param)); 
00174   
00175    // Setze Diagonalelemente in R ein
00176   for (int r=0; r<num_param; r++) {
00177     R[r][r]=d[r];
00178   }
00179  
00180   double **C;
00181   reserve_2D(C, num_param, num_param);
00182   Invert_RtR(R, C, num_param);
00183   
00184   for (int r=0; r<num_param; r++) {
00185     errors[r]=sqrt(C[r][r])*chisq;
00186   }
00187  
00188   delete_2D(C);
00189   // kovarianzmatrix löschen
00190 }  

Generated on Fri Jul 24 12:49:17 2009 for Xgrayimg Library by  doxygen 1.5.5