home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / diverses / leda / src / basic / _matrix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-15  |  7.1 KB  |  360 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  2.1.1                                                 11-15-1991
  4. +
  5. +
  6. +  _matrix.c
  7. +
  8. +
  9. +  Copyright (c) 1991  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15.  
  16. /*  Vektoren und Matrizen */
  17.  
  18. #include <LEDA/matrix.h>
  19.  
  20. #include <math.h>
  21.  
  22. #define ELEM(M,i,j)  M.ptr->v[i].ptr->v[j]
  23.  
  24. #define EPSILON 1e-12
  25.  
  26. //------------------------------------------------------------------------------
  27. //  matrix member functions
  28. //------------------------------------------------------------------------------
  29.  
  30.  
  31. matrix_rep::matrix_rep(int d1, int d2)  
  32. {
  33.  if (d1<0 || d2<0) 
  34.   error_handler(1,"matrix: negative dimension."); 
  35.  
  36.   dim1=d1; 
  37.   dim2=d2; 
  38.  
  39.   if (dim1 > 0) 
  40.   { v = (vector*) new char*[dim1];
  41.     while (d1--) v[d1].ptr = new vector_rep(d2); 
  42.    }
  43.   else v = nil;
  44. }
  45.  
  46. matrix_rep::matrix_rep(const matrix_rep* p)  
  47. {
  48.   int d1 = (p) ? p->dim1 : 0;
  49.   int d2 = (p) ? p->dim2 : 0;
  50.     
  51.   dim1=d1; 
  52.   dim2=d2; 
  53.  
  54.   if (dim1 > 0) 
  55.   { v = (vector*) new char*[dim1];
  56.     while (d1--) v[d1].ptr = new vector_rep(p->v[d1].ptr); 
  57.    }
  58.   else v = nil;
  59. }
  60.  
  61. matrix_rep::matrix_rep(int d1, int d2, double** p)  
  62. {
  63.   dim1=d1; 
  64.   dim2=d2; 
  65.   v = (vector*) new char*[dim1];
  66.   while (d1--) 
  67.   { v[d1].ptr = new vector_rep(dim2); 
  68.     for(int i=0;i<d2;i++) v[d1].ptr->v[i] = p[d1][i];
  69.    }
  70.  
  71.  }
  72.  
  73. matrix_rep::~matrix_rep()  
  74. { if (v)
  75.   { while (dim1--) delete v[dim1].ptr; 
  76.     delete (char*)v;
  77.    }
  78.  }
  79.  
  80. void matrix::check_dimensions(const matrix& mat) const
  81. { if (ptr->dim1 != mat.ptr->dim1 || ptr->dim2 != mat.ptr->dim2)
  82.    error_handler(1,"incompatible matrix types.");
  83.  }
  84.  
  85. matrix::matrix(const vector& vec)
  86. { int d1 = vec.ptr->dim;
  87.   ptr = new matrix_rep(d1,1);
  88.   while (d1--) ptr->v[d1].ptr->v[0] = vec.ptr->v[d1];
  89. }
  90.  
  91. matrix& matrix::operator=(const matrix& mat)
  92. { register int d1 = mat.ptr->dim1;
  93.   register int d2 = mat.ptr->dim2;
  94.   if (ptr->dim1 != d1 || ptr->dim2 != d2)
  95.   { clear();
  96.     ptr = new matrix_rep(d1,d2);
  97.    }
  98.   while (d1--) ptr->v[d1] = mat.ptr->v[d1];
  99.   return *this;
  100. }
  101.  
  102. int matrix::operator==(const matrix& x) const
  103. { int d1 = x.ptr->dim1;
  104.   int d2 = x.ptr->dim2;
  105.  
  106.   if (ptr->dim1 != d1 || ptr->dim2 != d2) return false;
  107.  
  108.   for(int i=0;i<d1;i++)
  109.     for(int j=0;j<d2;j++)
  110.       if (elem(i,j) != x.elem(i,j)) return false;
  111.  
  112.   return true;
  113. }
  114.  
  115.  
  116. vector& matrix::row(int i) const
  117. { if ( i<0 || i>=ptr->dim1 )  error_handler(1,"matrix: row index out of range");
  118.    return ptr->v[i];
  119. }
  120.  
  121.  
  122. double& matrix::operator()(int i, int j)
  123. { if ( i<0 || i>=ptr->dim1 )  error_handler(1,"matrix: row index out of range");
  124.   if ( j<0 || j>=ptr->dim2 )  error_handler(1,"matrix: col index out of range");
  125.   return ptr->v[i].ptr->v[j];
  126. }
  127.  
  128. double  matrix::operator()(int i, int j) const 
  129. { if ( i<0 || i>=ptr->dim1 )  error_handler(1,"matrix: row index out of range");
  130.   if ( j<0 || j>=ptr->dim2 )  error_handler(1,"matrix: col index out of range");
  131.   return ptr->v[i].ptr->v[j];
  132. }
  133.  
  134. vector matrix::col(int i)  const
  135. { if ( i<0 || i>=ptr->dim2 )  error_handler(1,"matrix: col index out of range");
  136.   vector result(ptr->dim1);
  137.   int j = ptr->dim1;
  138.   while (j--) result.ptr->v[j] = elem(j,i);
  139.   return result;
  140. }
  141.  
  142. matrix::operator vector() const
  143. { if (ptr->dim2!=1) 
  144.    error_handler(1,"error: cannot make vector from matrix\n");
  145.   return col(0);
  146. }
  147.  
  148. matrix matrix::operator+(const matrix& mat)
  149. { check_dimensions(mat);
  150.  
  151.   matrix result(ptr->dim1,ptr->dim2);
  152.   register int n = ptr->dim1;
  153.   while (n--) result.ptr->v[n] = ptr->v[n]+mat.ptr->v[n];
  154.   return result;
  155. }
  156.  
  157. matrix matrix::operator-(const matrix& mat)
  158. { check_dimensions(mat);
  159.  
  160.   matrix result(ptr->dim1,ptr->dim2);
  161.   register int n = ptr->dim1;
  162.   while (n--) result.ptr->v[n] = ptr->v[n]-mat.ptr->v[n];
  163.   return result;
  164. }
  165.  
  166. matrix matrix::operator*(double f)
  167. { matrix result(ptr->dim1,ptr->dim2);
  168.   register int n = ptr->dim1;
  169.   while (n--) result.ptr->v[n] = ptr->v[n]*f;
  170.   return result;
  171. }
  172.  
  173. matrix matrix::operator*(const matrix& mat)
  174. { if (ptr->dim2!=mat.ptr->dim1)
  175.      error_handler(1,"matrix multiplication: incompatible matrix types\n");
  176.   
  177.   matrix result(ptr->dim1, mat.ptr->dim2);
  178.   register int i;
  179.   register int j;
  180.  
  181.   for (i=0;i<mat.ptr->dim2;i++)
  182.   for (j=0;j<ptr->dim1;j++) ELEM(result,j,i) = ptr->v[j] * mat.col(i);
  183.  
  184.  return result;
  185.  
  186. }
  187.  
  188. double matrix::det() const
  189. {
  190.  if (ptr->dim1!=ptr->dim2)  
  191.    error_handler(1,"matrix::det: matrix not quadratic.\n");
  192.  
  193.  int n = ptr->dim1;
  194.  
  195.  matrix M(n,1);
  196.  
  197.  int flips;
  198.  
  199.  double** A = triang(M,flips);
  200.  
  201.  double Det = 1;
  202.  
  203.  for(int i=0;i<n;i++) Det *= A[i][i];
  204.  
  205.  for(i=0;i++;i<n) delete A[i];
  206.  delete A;
  207.  
  208.  return (flips % 2) ? -Det : Det;
  209.  
  210. }
  211.  
  212.  
  213. double** matrix::triang(const matrix& M, int& flips)  const
  214. {
  215.  register double **p, **q;
  216.  register double *l, *r, *s;
  217.  
  218.  register double pivot_el,tmp;
  219.  
  220.  register int i,j, col, row;
  221.  
  222.  int n = ptr->dim1;
  223.  int d = M.ptr->dim2;
  224.  int m = n+d;
  225.  
  226.  double** A = new double*[n];
  227.  
  228.  p = A;
  229.  
  230.  for(i=0;i<n;i++) 
  231.  { *p = new double[m];
  232.    l = *p++;
  233.    for(j=0;j<n;j++) *l++ = elem(i,j);
  234.    for(j=0;j<d;j++) *l++ = M.elem(i,j);
  235.   }
  236.  
  237.  flips = 0;
  238.  
  239.  for (col=0, row=0; row<n; row++, col++)
  240.  { 
  241.    // search for row j with maximal entry in current col
  242.    j = row;
  243.    for (i=row+1; i<n; i++)
  244.      if (A[j][col] < A[i][col]) j = i;
  245.  
  246.    if ( n > j && j > row) 
  247.    { SWAP(A[j],A[row]);
  248.      flips++;
  249.     }
  250.  
  251.    tmp = A[row][col];
  252.    q  = &A[row];
  253.  
  254.    if (fabs(tmp) < EPSILON) error_handler(1,"matrix has not full rank.");
  255.  
  256.    for (p = &A[n-1]; p != q; p--)
  257.    { 
  258.      l = *p+col;
  259.      s = *p+m;    
  260.      r = *q+col;
  261.  
  262.      if (*l != 0.0)
  263.      { pivot_el = *l/tmp;
  264.         while(l < s) *l++ -= *r++ * pivot_el;
  265.       }
  266.  
  267.     }
  268.  
  269.   }
  270.  
  271.  return A;
  272. }
  273.  
  274. matrix matrix::inv() const
  275. {
  276.  if (ptr->dim1!=ptr->dim2)  
  277.      error_handler(1,"matrix::inv: matrix not quadratic.\n");
  278.  int n = ptr->dim1;
  279.  matrix I(n,n);
  280.  for(int i=0; i<n; i++) I(i,i) = 1;
  281.  return solve(I);
  282. }
  283.  
  284.  
  285.  
  286. matrix matrix::solve(const matrix& M) const
  287. {
  288.  
  289. if (ptr->dim1 != ptr->dim2 || ptr->dim1 != M.ptr->dim1)
  290.      error_handler(1, "Solve: wrong dimensions\n");
  291.  
  292.  register double **p, ** q;
  293.  register double *l, *r, *s;
  294.  
  295.  int      n = ptr->dim1;
  296.  int      d = M.ptr->dim2;
  297.  int      m = n+d;
  298.  int      row, col,i;
  299.  
  300.  
  301.  double** A = triang(M,i);
  302.  
  303.  for (col = n-1, p = &A[n-1]; col>=0; p--, col--)
  304.  { 
  305.    s = *p+m;
  306.  
  307.    double tmp = (*p)[col];
  308.  
  309.    for(l=*p+n; l < s; l++) *l /=tmp;
  310.  
  311.    for(q = A; q != p; q++ )
  312.    { tmp = (*q)[col];
  313.      l = *q+n;
  314.      r = *p+n;
  315.      while(r < s)  *l++ -= *r++ * tmp;
  316.     }
  317.                  
  318.   } 
  319.  
  320.   matrix result(n,d);
  321.  
  322.   for(row=0; row<n; row++)
  323.   { l = A[row]+n;
  324.     for(col=0; col<d; col++) ELEM(result,row,col) = *l++;
  325.     delete A[row];
  326.    }
  327.  
  328.   delete A;
  329.  
  330.   return result;
  331. }
  332.  
  333.  
  334.  
  335.  
  336. matrix matrix::trans() const
  337. { matrix result(ptr->dim2,ptr->dim1);
  338.   for(int i = 0; i < ptr->dim2; i++)
  339.     for(int j = 0; j < ptr->dim1; j++)
  340.       ELEM(result,i,j) = elem(j,i);
  341.   return result;
  342. }
  343.      
  344.  
  345. ostream& operator<<(ostream& s, const matrix& M)
  346. { int i;
  347.   s <<"\n";
  348.   for (i=0;i<M.dim1();i++) s << M[i] << "\n"; 
  349.   return s;
  350. }
  351.  
  352. istream& operator>>(istream& s, matrix& M)
  353. { int i=0;
  354.   while (i<M.dim1() && s >> M[i++]);
  355.   return s;
  356. }
  357.  
  358.  
  359.