home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / microcrn / issue_40.arc / DAIMS.ARC / MATRIX1.CPP < prev    next >
Text File  |  1988-02-10  |  15KB  |  630 lines

  1. #include "matrix.hxx"
  2. #include <math.h>
  3. #include <ctype.h>
  4. #include <time.h>
  5. #ifndef DOS
  6. #include <sys/param.h>
  7. #endif
  8. #define UPCASE(X)  (X = islower(X) ? toupper(X) : X) /* force a char to upper case */
  9.  
  10. /* 
  11. -*++ matrix::matrix(): contructs a matrix of any size and inits to 0
  12. ** 
  13. ** (*++ history: 
  14. **      4 Dec 87    Bruce Eckel    Creation date
  15. ** ++*)
  16. ** 
  17. ** (*++ detailed: 
  18. ** ++*)
  19. */
  20.  
  21.   matrix::matrix(int rows = 1 , int cols = 1, double initval = 0)
  22.   p = new matrep;
  23.   p->m_vec = new _Vector*[rows];
  24.   p->m_rows = rows;
  25.   p->m_cols = cols;
  26.   for (int i = 0; i < rows; i++)
  27.     p->m_vec[i] = new _Vector(cols);
  28.   for (i=0; i < rows; i++)
  29.     for (int j = 0; j < cols; j++)
  30.       (*this)[i][j] = initval;
  31.   p->n = 1;            /* so far, only one reference to this data */
  32. }
  33.  
  34.  
  35. /* 
  36. -*++ matrix::matrix(): adds a new reference to an existing matrix
  37. ** 
  38. ** (*++ history: 
  39. **      4 Dec 87    Bruce Eckel    Creation date
  40. ** ++*)
  41. ** 
  42. ** (*++ detailed: "Reference counting" is a method of managing garbage.
  43. ** Instead of creating a whole new object every time you use (for instance) an
  44. ** equal sign, it makes more sense just to point at the old object.  This
  45. ** means you can have several objects all pointing at the same thing.  When
  46. ** you start destroying objects, you don't want to destroy the original thing
  47. ** until you only have one reference left.
  48. ** ++*)
  49. */
  50.  
  51.   matrix::matrix(matrix& x)
  52. {
  53.   x.p->n++;    /* we're adding another reference, so increase */
  54.   p = x.p;    /* the count. */
  55. }
  56.  
  57.  
  58. /* 
  59. -*++ ch_find(): search an input stream for a char, ignoring comments
  60. ** 
  61. ** (*++ history: 
  62. **      4 Dec 87    Bruce Eckel    Creation date
  63. ** ++*)
  64. ** 
  65. ** (*++ detailed: searches an input stream for c, ignoring comments starting
  66. ** with '#' to end of line.  Errfunc is the address of an error function,
  67. ** fname is  the name of the source file. 
  68. ** ++*)
  69. */
  70.  
  71.     void ch_find(istream& from, char ch, void (*errfunc)(char *), char * fname)
  72. {
  73.   char c;
  74.   UPCASE(ch);
  75.   while(TRUE){        
  76.     while(from >> c, UPCASE(c), c != ch && c != '#') 
  77.       if(from.eof()) errfunc(fname); /* find ch or comment start */
  78.     if (c == ch) break;
  79.     /* If we made it here, a '#' comment start was found */
  80.     while (from.get(c), c != EOL) /* 'get' doesn't skip whitespace */
  81.       if(from.eof()) errfunc(fname); /* find end-of-line */
  82.   }
  83. }
  84.  
  85.  
  86. /* 
  87. -*++ matrix::matrix(): read from a "standard" matrix file
  88. ** 
  89. ** (*++ history: 
  90. **      4 Dec 87    Bruce Eckel    Creation date
  91. ** ++*)
  92. ** 
  93. ** (*++ detailed: 
  94. ** ++*)
  95. */
  96.  
  97.   matrix::matrix(char * initfile) /* read from "standard" matrix file */
  98. {
  99.   void ch_find(istream& from, char ch, void (*errfunc)(char *), char * fname);
  100.   void nonstandard(char *);
  101.   filebuf f1;
  102.   p = new matrep;
  103.   if (f1.open(initfile,input) == 0)
  104.     error2("cannot open matrix initializer file",initfile);
  105.   istream from(&f1);
  106.  
  107.     /* Parse file initialization header  */
  108.  
  109.   ch_find(from,'r',nonstandard,initfile); /* find the 'r'... */
  110.   ch_find(from,'=',nonstandard, initfile); /* ...followed by an `=` */
  111.   from >> p->m_rows;        /* get row size */
  112.   ch_find(from,'c',nonstandard, initfile); /* find the 'p'... */
  113.   ch_find(from,'=',nonstandard, initfile); /* ...followed by an '=' */
  114.   from >> p->m_cols;        /* get column size */
  115.   ch_find(from,':',nonstandard, initfile); /* data follows ::: */
  116.   ch_find(from,':',nonstandard, initfile); 
  117.   ch_find(from,':',nonstandard, initfile); 
  118.   
  119.   p->m_vec = new _Vector*[rows()];
  120.   for (int i = 0; i < rows(); i++)
  121.     p->m_vec[i] = new _Vector(cols());
  122.   p->n = 1;            /* we just created it: only 1 reference */
  123.   for (int row = 0; row < rows(); row++)
  124.     for(int col = 0; col < cols(); col++){
  125.       from >> (*this)[row][col];
  126.       if(from.bad()) error2("problem with matrix initializer file",initfile);
  127.     }
  128. }
  129.  
  130.  
  131. /* 
  132. -*++ nonstandard(): an error message when a "non-standard" matrix file is found
  133. ** 
  134. ** (*++ history: 
  135. **      4 Dec 87    Bruce Eckel    Creation date
  136. ** ++*)
  137. ** 
  138. ** (*++ detailed: 
  139. ** ++*)
  140. */
  141.  
  142. void nonstandard(char * fname){
  143.   cout << fname << " is a `non-standard' file.\n";
  144.   cout << "A `standard' matrix file must start with\n";
  145.   cout << "the dimensions of the matrix, i.e.:\n";
  146.   cout << "rows=12 columns=14\n";
  147.   cout << "or abbreviated:\n";
  148.   cout << "r=12 c=14\n";
  149.   cout << "comments follow `#' signs to end of line\n";
  150.   cout << "data follows :::\n";
  151.   exit(1);
  152. }
  153.  
  154.  
  155. /* 
  156. -*++ matrix::matrix(): create a special square matrix
  157. ** 
  158. ** (*++ history: 
  159. **      4 Dec 87    Bruce Eckel    Creation date
  160. ** ++*)
  161. ** 
  162. ** (*++ detailed: create a special square matrix.  If the "flag" string starts
  163. ** with: 
  164. **   I: identity matrix
  165. **   R: square matrix with random values
  166. ** ++*)
  167. */
  168.  
  169.   matrix::matrix(char * flag, int dimension) 
  170. {
  171.   double drand48();
  172.   int i,j;
  173.   if (flag[0] != 'I' && flag[0] != 'R') 
  174.     error("to create identity: \"I\"; random: \"R\"");
  175.   p = new matrep;
  176.   p->m_vec = new _Vector*[dimension];
  177.   p->m_rows = dimension;
  178.   p->m_cols = dimension;
  179.   for ( i = 0; i < dimension; i++)
  180.     p->m_vec[i] = new _Vector(dimension);
  181.   p->n = 1;            /* so far, only one reference to this data */
  182.  
  183.   switch(flag[0]) {
  184.   case 'I': 
  185.     for (i=0; i < rows(); i++)
  186.       for ( j = 0; j < cols(); j++)
  187.     (*this)[i][j] = (i == j ? 1 : 0);
  188.     break;
  189.   case 'R':
  190.     for ( i=0; i < rows(); i++)
  191.       for ( j = 0; j < cols(); j++)
  192.     (*this)[i][j] = drand48();
  193.   }
  194. }
  195.  
  196.  
  197. /* 
  198. -*++ matrix::~matrix(): matrix destructor.  Probably needs examining
  199. ** 
  200. ** (*++ history: 
  201. **      4 Dec 87    Bruce Eckel    Creation date
  202. ** ++*)
  203. ** 
  204. ** (*++ detailed: 
  205. ** ++*)
  206. */
  207.  
  208.  matrix::~matrix()   // this is probably wrong.
  209. {
  210.   if (--p->n == 0) {
  211.     delete p->m_vec;        /* delete data */
  212.     delete p;
  213.   }
  214. }
  215.  
  216.  
  217. /* 
  218. -*++ matrix::write_standard(): write to a file in "standard" format
  219. ** 
  220. ** (*++ history: 
  221. **      4 Dec 87    Bruce Eckel    Creation date
  222. ** ++*)
  223. ** 
  224. ** (*++ detailed: write this matrix to filename in the 'standard' format
  225. ** ++*)
  226. */
  227.  
  228. void matrix::write_standard(char * filename, char * msg)
  229. {
  230. #ifndef DOS
  231.   char *getwd(char *pathname);
  232. #else DOS
  233.   char *getcwd(char *pathname);
  234. #endif
  235.   char pathname[100];        /* for working directory information */
  236.   filebuf f1;
  237.   if (f1.open(filename,output) == 0)
  238.     error2("cannot open or create matrix output file",filename);
  239.   ostream to(&f1);
  240.   to << "# " << filename << ": matrix file " << " written in `standard' format\n";
  241.   long clock = time(0);
  242.   to << "# " << asctime(localtime(&clock));
  243. #ifndef DOS
  244.   to << "# working directory: " << getwd(pathname) << "\n";
  245. #else DOS
  246.   to << "# working directory: " << getcwd(pathname) << "\n";
  247. #endif
  248.   to << "# " << msg << "\n";
  249.   to << "\nRows=" << rows() << "  Columns=" << cols() << "\n";
  250.   to << ":::\n";
  251.   for (int row = 0; row < rows(); row++){
  252.     for(int col = 0; col < cols(); col++){
  253.       to << form("%6.6g  ",(*this)[row][col]);
  254.       if(to.bad()) error2("problem with matrix output file",filename);
  255.     }
  256.     to << "\n";
  257.   }
  258. }
  259.  
  260.  
  261. /* 
  262. -*++ matrix::operator=(): matrix "equals" using references
  263. ** 
  264. ** (*++ history: 
  265. **      4 Dec 87    Bruce Eckel    Creation date
  266. ** ++*)
  267. ** 
  268. ** (*++ detailed: 
  269. ** ++*)
  270. */
  271.  
  272. matrix &  matrix::operator=(matrix& rval)
  273. {
  274.   rval.p->n++;            /* tell the rval it has another reference to it */
  275.   if(--p->n == 0) {        /* If nobody else is referencing us...*/
  276.     delete p->m_vec;        /* ...nobody else knows to make us go away...*/
  277.     delete p;   
  278.   }
  279.   p = rval.p;     /* ...and we're pointing somewhere else (reference into rval) */
  280.   return *this;
  281. }
  282.  
  283.  
  284. /* 
  285. -*++ matrix::operator+(): add two matrices
  286. ** 
  287. ** (*++ history: 
  288. **      4 Dec 87    Bruce Eckel    Creation date
  289. ** ++*)
  290. ** 
  291. ** (*++ detailed: 
  292. ** ++*)
  293. */
  294.  
  295. matrix & matrix::operator+(matrix& arg)
  296. {
  297.   if((rows() != arg.rows()) || (cols() != arg.cols()))
  298.     error("matrices must be of the same dimension for addition!");
  299.   matrix & sum= *new matrix(rows(),cols());
  300.   for (int i=0; i< rows(); i++)
  301.     for (int j = 0; j < cols(); j++)
  302.       sum[i][j] = (*this)[i][j] + arg[i][j];
  303.   return sum;
  304. }
  305.  
  306.  
  307. /* 
  308. -*++ matrix::operator+(): add a double value to each element
  309. ** 
  310. ** (*++ history: 
  311. **      4 Dec 87    Bruce Eckel    Creation date
  312. ** ++*)
  313. ** 
  314. ** (*++ detailed: 
  315. ** ++*)
  316. */
  317.  
  318. matrix & matrix::operator+(double arg)
  319. {
  320.   matrix & sum= *new matrix(rows(),cols());
  321.   for (int i=0; i< rows(); i++)
  322.     for (int j = 0; j < cols(); j++)
  323.       sum[i][j] = (*this)[i][j] + arg;
  324.   return sum;
  325. }
  326.  
  327.  
  328. /* 
  329. -*++ matrix::operator*(): multiply each element by a double value
  330. ** 
  331. ** (*++ history: 
  332. **      4 Dec 87    Bruce Eckel    Creation date
  333. ** ++*)
  334. ** 
  335. ** (*++ detailed: 
  336. ** ++*)
  337. */
  338.  
  339. matrix & matrix::operator*(double arg)
  340. {
  341.   matrix & sum= *new matrix(rows(),cols());
  342.   for (int i=0; i< rows(); i++)
  343.     for (int j = 0; j < cols(); j++)
  344.       sum[i][j] = (*this)[i][j] * arg;
  345.   return sum;
  346. }
  347.  
  348.  
  349. /* 
  350. -*++ matrix::operator*(): matrix multiply
  351. ** 
  352. ** (*++ history: 
  353. **      4 Dec 87    Bruce Eckel    Creation date
  354. **      9 Dec 87    Bruce Eckel    Changed the test -- I had arg1.rows !=
  355. ** arg2.cols, which was backwards
  356. ** ++*)
  357. ** 
  358. ** (*++ detailed: 
  359. ** ++*)
  360. */
  361.  
  362. matrix & matrix::operator*(matrix& arg)
  363. {
  364.   if(cols() != arg.rows())
  365.     error("# rows of second mat must equal # cols of first for multiply!");
  366.   matrix & result= *new matrix(rows(),arg.cols());
  367.   for(int row = 0; row < rows(); row++)
  368.     for(int col = 0; col < arg.cols(); col++){
  369.       double sum = 0;
  370.       for(int i = 0; i < cols(); i++)
  371.       sum += (*this)[row][i] * arg[i][col];
  372.       result[row][col] = sum;
  373.     };
  374.   return result;
  375. }
  376.  
  377.  
  378. /* 
  379. -*++ matrix::operator-(): subtract one matrix from another
  380. ** 
  381. ** (*++ history: 
  382. **      4 Dec 87    Bruce Eckel    Creation date
  383. ** ++*)
  384. ** 
  385. ** (*++ detailed: 
  386. ** ++*)
  387. */
  388.  
  389. matrix & matrix::operator-(matrix& arg)
  390. {
  391.     if((rows() != arg.rows()) || (cols() != arg.cols()))
  392.     error("matrices must be of the same dimension for subtraction!\n");
  393.     matrix & sum= *new matrix(rows(),cols());
  394.     for (int i=0; i< rows(); i++)
  395.     for (int j = 0; j < cols(); j++)
  396.         sum[i][j] = (*this)[i][j] - arg[i][j];
  397.     return sum;
  398. }
  399.  
  400.  
  401. /* 
  402. -*++ matrix::operator-(): unary minus each element in a matrix
  403. ** 
  404. ** (*++ history: 
  405. **      4 Dec 87    Bruce Eckel    Creation date
  406. ** ++*)
  407. ** 
  408. ** (*++ detailed: 
  409. ** ++*)
  410. */
  411.  
  412. matrix & matrix::operator-()
  413. {
  414.     for (int i=0; i< rows(); i++)
  415.     for (int j = 0; j < cols(); j++)
  416.         (*this)[i][j] *= -1;
  417.     return *this;
  418. }
  419.  
  420.  
  421. /* 
  422. -*++ matrix::operator==(): test for matrix eqivalence
  423. ** 
  424. ** (*++ history: 
  425. **      4 Dec 87    Bruce Eckel    Creation date
  426. ** ++*)
  427. ** 
  428. ** (*++ detailed: 
  429. ** ++*)
  430. */
  431.  
  432. int matrix::operator==(matrix& arg)
  433. {
  434.   if((rows() != arg.rows()) || (cols() != arg.cols()))
  435.     error("matrices must be of the same dimension for equivalence test!\n");
  436.   for (int i=0; i< rows(); i++)
  437.     for (int j = 0; j < cols(); j++)
  438.       if( (*this)[i][j] != arg[i][j])
  439.     return 0;
  440.   return ~0;
  441. }
  442.  
  443.  
  444. /* 
  445. -*++ matrix::operator!=(): test for matrix eqivalence
  446. ** 
  447. ** (*++ history: 
  448. **      4 Dec 87    Bruce Eckel    Creation date
  449. ** ++*)
  450. ** 
  451. ** (*++ detailed: 
  452. ** ++*)
  453. */
  454.  
  455. int matrix::operator!=(matrix& arg)
  456. {
  457.   if((rows() != arg.rows()) || (cols() != arg.cols()))
  458.     error("matrices must be of the same dimension for inequivalence!\n");
  459.   for (int i=0; i< rows(); i++)
  460.     for (int j = 0; j < cols(); j++)
  461.       if( (*this)[i][j] == arg[i][j])
  462.     return 0;
  463.   return ~0;
  464. }
  465.  
  466.  
  467. /* 
  468. -*++ matrix::operator<<: print a matrix to standard out
  469. ** 
  470. ** (*++ history: 
  471. **      4 Dec 87    Bruce Eckel    Creation date
  472. ** ++*)
  473. ** 
  474. ** (*++ detailed: 
  475. ** ++*)
  476. */
  477.  
  478. ostream& operator<<(ostream &s, matrix& mat)
  479. {
  480.   for (int i=0; i< mat.rows(); i++){
  481.     for (int j = 0; j < mat.cols(); j++)
  482.       s <<  form("%6.6g  ",mat[i][j]);
  483.     s << "\n";
  484.   }
  485.   return s;
  486. }
  487.  
  488.  
  489. /* 
  490. -*++ matrix::operator>>(): 
  491. ** 
  492. ** (*++ history: 
  493. **      4 Dec 87    Bruce Eckel    Creation date
  494. ** ++*)
  495. ** 
  496. ** (*++ detailed: 
  497. ** ++*)
  498. */
  499.  
  500. istream& operator>>(istream& s, matrix& mat)
  501. {
  502.   double val = 0;
  503.   for (int row = 0; row < mat.rows(); row++)
  504.     for(int col = 0; col < mat.cols(); col++){
  505.       s >> val;
  506.       if (s.bad()) 
  507.     mat.error("bad matrix initialization input\n");
  508.       if (s.eof()) 
  509.     mat.error("end of matrix initialization input before matrix full\n");
  510.       mat[row][col] = val;
  511.     }
  512.   return s;
  513. }
  514.   
  515.  
  516. /* 
  517. -*++ matrix::file_get(): fills a matrix from a `non-standard' ASCII file  
  518. ** 
  519. ** (*++ history: 
  520. **      4 Dec 87    Bruce Eckel    Creation date
  521. ** ++*)
  522. ** 
  523. ** (*++ detailed: fills a matrix of known size from a `non-standard' file of
  524. ** numbers  
  525. ** ++*)
  526. */
  527.  
  528. void matrix::file_get(char * infile)
  529. {
  530.   filebuf f1;
  531.   if (f1.open(infile,input) == 0)
  532.     error2("cannot open matrix initializer file",infile);
  533.   istream from(&f1);
  534.   for (int row = 0; row < rows(); row++)
  535.     for(int col = 0; col < cols(); col++){
  536.       from >> (*this)[row][col];
  537.       if(from.bad()) error2("problem with matrix initializer file",infile);
  538.     }
  539. }
  540.  
  541.  
  542. /* 
  543. -*++ matrix::file_put(): writes a matrix to a "non-standard" ASCII file
  544. ** 
  545. ** (*++ history: 
  546. **      4 Dec 87    Bruce Eckel    Creation date
  547. ** ++*)
  548. ** 
  549. ** (*++ detailed: 
  550. ** ++*)
  551. */
  552.  
  553. void matrix::file_put(char * outfile)
  554. {
  555.   filebuf f1;
  556.   if (f1.open(outfile,output) == 0)
  557.     error2("cannot open or create matrix output file",outfile);
  558.   ostream to(&f1);
  559.   for (int row = 0; row < rows(); row++){
  560.     for(int col = 0; col < cols(); col++){
  561.       to << (*this)[row][col];
  562.       to << "  ";
  563.       if(to.bad()) error2("problem with matrix output file",outfile);
  564.     }
  565.     to << "\n";
  566.   }
  567. }
  568.  
  569.  
  570. /* 
  571. -*++ operator<<(): output for XY_vec
  572. ** 
  573. ** (*++ history: 
  574. **     11 Dec 87    Bruce Eckel    Creation date
  575. ** ++*)
  576. ** 
  577. ** (*++ detailed: 
  578. ** ++*)
  579. */
  580.  
  581. ostream& operator<<(ostream &s, XY_vec& v) {
  582.     s << " X:       Y:\n";
  583.     for(int i = 0; i < v.size(); i++)
  584.     s << form("%6.6g   %6.6g\n",v.X.Indep(i),v.Y[i]);
  585.     return s;
  586. }
  587.  
  588.  
  589. /* 
  590. -*++ XY_vec::floatvect(): return a pointer to an array of floating-point #s
  591. ** 
  592. ** (*++ history: 
  593. **     14 Dec 87    Bruce Eckel    Creation date
  594. ** ++*)
  595. ** 
  596. ** (*++ detailed: What is this terminated by?
  597. ** ++*)
  598. */
  599.  
  600. float *  XY_vec::floatvect()
  601. {
  602.     float * result = new float[2 * size()];
  603.     for (int i = 0; i < size() * 2; i += 2) {
  604.     result[i] = (float)X.Indep(i/2);
  605.     result[i+1] = (float)Y[i/2];
  606.     }
  607.     return result;
  608. }
  609.  
  610.  
  611. /* 
  612. -*++ ColVec::doublvect(): returns a simple array of double numbers
  613. ** 
  614. ** (*++ history: 
  615. **     15 Jan 88    Bruce Eckel    Creation date
  616. ** ++*)
  617. ** 
  618. ** (*++ detailed: 
  619. ** ++*)
  620. */
  621.  
  622. double * ColVec::doublvect()
  623. {
  624.     double * result = new double[size()];
  625.     for (int i = 0; i < size(); i++)
  626.     result[i] = (*this)[i];
  627.     return result;
  628. }
  629.