home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / code / bcpp / file19 / matrix.mth < prev    next >
Encoding:
Text File  |  1995-05-19  |  10.3 KB  |  342 lines

  1. /////////////////////////////////////////////////////////////
  2. // matrix.mth: Matrix class template methods
  3. // Copyright(c) 1993 Azarona Software. All rights reserved.
  4. /////////////////////////////////////////////////////////////
  5.  
  6. template<class TYPE>
  7. void Matrix<TYPE>::Copy(const Matrix<TYPE> &m)
  8. // Does a two-dimensional copy from m to this matrix,
  9. // copying as much data as possible without reallocating
  10. // this matrix. Assumes a worst case non-contiguous
  11. // submatrix.
  12. {
  13.   // sc = column vector pointer to rows of s
  14.   // tc = column vector pointer to rows of t
  15.   VecPtr<const TYPE> sc(m.data.start, m.colstride);
  16.   VecPtr<TYPE> tc(data.start, colstride);
  17.  
  18.   // sr = row vector pointer to columns of s
  19.   // tr = row vector pointer to columns of t
  20.   // We only need to initialize strides for now
  21.   VecPtr<const TYPE> sr(0, m.rowstride);
  22.   VecPtr<TYPE> tr(0, rowstride);
  23.  
  24.   unsigned nr = nrows;
  25.   if (nr > m.nrows) nr = m.nrows;
  26.   unsigned nc = ncols;
  27.   if (nc > m.ncols) nc = m.ncols;
  28.  
  29.   for (unsigned i = 0; i<nr; i++) {
  30.       // Note that only pointers are copied below, not the strides!
  31.       tr = tc; // Point to current row of t
  32.       sr = sc; // Point to current row of s
  33.       for (unsigned j = 0; j<nc; j++) {
  34.           *tr = *sr;
  35.           tr++; // Next column
  36.           sr++; // Ditto
  37.       }
  38.       tc++; // Next row
  39.       sc++; // Ditto
  40.   }
  41.   nrows = nr; // New size of matrix, may be smaller
  42.   ncols = nc;
  43. }
  44.  
  45. template<class TYPE>
  46. void Matrix<TYPE>::Share(const Matrix<TYPE> &m)
  47. // Shares data with another matrix.
  48. {
  49.   data.Share(m.data);
  50.   nrows = m.nrows; ncols = m.ncols;
  51.   colstride = m.colstride; rowstride = m.rowstride;
  52. }
  53.  
  54.  
  55. template<class TYPE>
  56. Matrix<TYPE>::Matrix(unsigned nr, unsigned nc, const TYPE *s)
  57. // Constructs a row-major matrix with nr rows and nc columns. 
  58. // If size isn't zero, and s isn't zero, then we copy the 
  59. // low-level C array s into the matrix. If null vector is
  60. // returned from data constructor, we set up the matrix 
  61. // null as well.
  62. : data(nr * nc, s)
  63. {
  64.   if (data.IsNull()) {
  65.      nrows = 0; ncols = 0; colstride = 1; rowstride = 1;
  66.   }
  67.   else {
  68.      nrows = nr; ncols = nc; colstride = nc; rowstride = 1;
  69.   }
  70. }
  71.  
  72. template<class TYPE>
  73. Matrix<TYPE>::Matrix(const Matrix<TYPE> &m)
  74. // Copy constructor that shares all of the matrix m. 
  75. : data(m.data)
  76. {
  77.   if (data.IsNull()) {
  78.      nrows = 0; ncols = 0; colstride = 1; rowstride = 1;
  79.   }
  80.   else {
  81.      nrows = m.nrows; ncols = m.ncols;
  82.      colstride = m.colstride; rowstride = m.rowstride;
  83.   }
  84. }
  85.  
  86. template<class TYPE>
  87. Matrix<TYPE>::Matrix(const Matrix<TYPE> &m, SliceType styp,
  88.                      unsigned sr, unsigned sc,
  89.                      unsigned nr, unsigned nc)
  90. // Constructor that constructs a submatrix of matrix m.
  91. // If styp==SHARED, it means to share the data with m. 
  92. // NOTE: If sharing, we initially create a null vector, and
  93. // then we immediately rebind to shared vector. If copying,
  94. // a row-major sub matrix is created, and if nr == 0, 
  95. // then m.nrows is used. If nc == 0, then m.ncols is used.
  96. // WARNING: No checks are made on the consistency of the
  97. // input parameters. Caller beware.
  98. : data((styp == SHARED) ? 
  99.         0 : ((nr ? nr : m.nrows) * (nc ? nc : m.ncols)))
  100. {
  101.   unsigned start_ofs, n;
  102.   if (nr) {
  103.      nrows = nr;
  104.   }
  105.   else {
  106.      nrows = m.nrows;
  107.      sr = 0;
  108.   }
  109.   if (nc) {
  110.      ncols = nc;
  111.   }
  112.   else {
  113.      ncols = m.ncols;
  114.      sc = 0;
  115.   }
  116.   if (styp == SHARED) { // Sharing
  117.      // When sharing, strides are always same as parent strides
  118.      colstride = m.colstride;
  119.      rowstride = m.rowstride;
  120.      // Compute length of underlying vector and offset
  121.      // Either colstride or rowstride == 1.
  122.      if (rowstride == 1) {
  123.         n = colstride * (nrows-1) + ncols;
  124.      }
  125.      else {
  126.         n = rowstride * (ncols-1) + nrows;
  127.      }
  128.      start_ofs = sr * colstride + rowstride * sc;
  129.      data.Share(Vector<TYPE>(m.data, SHARED, n, 1, start_ofs));
  130.   }
  131.   else {
  132.     if (data.IsNull()) {
  133.        nrows = 0; ncols = 0; colstride = 1; rowstride = 1;
  134.     } 
  135.     else {
  136.        // Setup as a row-major matrix
  137.        colstride = ncols; rowstride = 1;
  138.        // Copy data from shared submatrix into allocated space
  139.        // Note that the constructor is called recursively here,
  140.        // to create a shared submatrix used for the copy.
  141.        Copy(Matrix<TYPE>(m, SHARED, sr, sc, nrows, ncols));
  142.     }
  143.   }
  144. }
  145.  
  146. template<class TYPE>
  147. Matrix<TYPE> Matrix<TYPE>::Clone() const
  148. // Return a clone of this matrix. This clone will
  149. // be unique, (with vector rep refcnt = 1), and
  150. // will be row-major. (THus, it's not precisely a clone.)
  151. // Note: If allocation fails, a null matrix is returned.
  152. {
  153.   Matrix<TYPE> temp(nrows, ncols);
  154.   temp.Copy(*this);
  155.   return temp;
  156. }
  157.  
  158. template<class TYPE>
  159. int Matrix<TYPE>::EnsureUnique()
  160. // Ensures that this matrix uniquely owns its matrix data.
  161. // (ie. the vector reference count is 1).
  162. // Might have to copy matrix data to ensure this.
  163. // Returns 1 if can make unique, 0 if can't (allocation
  164. // for copy failed.)
  165. {
  166.   if (!IsUnique()) {            // Need to copy to make unique
  167.      Matrix<TYPE> &c = Clone(); // Attempt to copy
  168.      if (c.IsNull()) return 0;  // Couldn't copy
  169.      Share(c);                  // Share with copy
  170.   }
  171.   return 1;
  172. }
  173.  
  174.  
  175. template<class TYPE>
  176. Matrix<TYPE> Matrix<TYPE>::Transpose()
  177. // Returns a transpose of this matrix. Does not have to move
  178. // the elements of the matrix around, just merely changes
  179. // interpretation between row-major and column-major ordering.
  180. {
  181.   Matrix<TYPE> t(*this); // Remember, copy constructor shares
  182.  
  183.   // Interchange number of rows and cols
  184.   unsigned temp = t.nrows;
  185.   t.nrows = t.ncols;
  186.   t.ncols = temp;
  187.  
  188.   // Interchange row stride and column stride
  189.   temp = t.colstride;
  190.   t.colstride = t.rowstride;
  191.   t.rowstride = temp;
  192.   return t;
  193. }
  194.  
  195.  
  196. #ifndef NO_RANGE_CHECK
  197.  
  198. template<class TYPE>
  199. unsigned Matrix<TYPE>::CheckRow(unsigned i) const
  200. // Check for row index being in bounds. If not in
  201. // bounds, call the error handler.
  202. {
  203.   if (i >= nrows) i = HandleRangeErr(i, nrows);
  204.   return i;
  205. }
  206.  
  207. template<class TYPE>
  208. unsigned Matrix<TYPE>::CheckCol(unsigned i) const
  209. // Check for column index being in bounds. If not
  210. // in bounds, call the error handler.
  211. {
  212.   if (i >= ncols) i = HandleRangeErr(i, ncols);
  213.   return i;
  214. }
  215.  
  216. #endif
  217.  
  218.  
  219. template<class TYPE>
  220. TYPE &Matrix<TYPE>::operator()(unsigned r, unsigned c)
  221. // Two-dimensional subscripting for non-const matrices. 
  222. // Note that either colstride or rowstride will be one.
  223. {
  224.   return data.start[CHECKROW(r)*colstride + CHECKCOL(c)*rowstride];
  225. }
  226.  
  227. template<class TYPE>
  228. const TYPE &Matrix<TYPE>::operator()(unsigned r, unsigned c) const
  229. // Two-dimensional subscripting for const matrices. 
  230. // Note that either colstride or rowstride will be one.
  231. {
  232.   return data.start[CHECKROW(r)*colstride + CHECKCOL(c)*rowstride];
  233. }
  234.  
  235. template<class TYPE>
  236. Matrix<TYPE> &Matrix<TYPE>::operator=(const TYPE &x)
  237. // Set all elements in the matrix to the value x.
  238. // Assumes a worst case non-contiguous sub-matrix.
  239. {
  240.   // tc = column vector pointer to rows of t
  241.   // tr = row vector pointer to columns of t
  242.   VecPtr<TYPE> tc(data.start, colstride);
  243.   VecPtr<TYPE> tr(data.start, rowstride);
  244.   for (unsigned i = 0; i<nrows; i++) {
  245.       tr = tc; // Remember strides aren't assigned!
  246.       for (unsigned j = 0; j<ncols; j++) {
  247.           *tr = x;
  248.           tr++; // Next column
  249.       }
  250.       tc++; // Next row
  251.   }
  252.   return *this; 
  253. }
  254.  
  255.  
  256. template<class TYPE>
  257. Vector<TYPE> Matrix<TYPE>::Row(unsigned r, SliceType styp)
  258. // Return a row slice of a matrix. Remember, either colstride
  259. // or rowstride is 1.
  260. {
  261.   return Vector<TYPE>(data, styp,
  262.                       ncols, rowstride, CHECKROW(r)*colstride);
  263. }
  264.  
  265. template<class TYPE>
  266. const Vector<TYPE> Matrix<TYPE>::Row(unsigned r, SliceType styp) const
  267. // Return a row slice of a matrix. Remember, either colstride
  268. // or rowstride is 1.
  269. {
  270.   return Vector<TYPE>(data, styp,
  271.                       ncols, rowstride, CHECKROW(r)*colstride);
  272. }
  273.  
  274. template<class TYPE>
  275. Vector<TYPE> Matrix<TYPE>::Col(unsigned c, SliceType styp)
  276. // Return a column slice of a matrix. Remember, either colstride
  277. // or rowstride is 1.
  278. {
  279.   return Vector<TYPE>(data, styp,
  280.                       nrows, colstride, CHECKCOL(c)*rowstride);
  281. }
  282.  
  283. template<class TYPE>
  284. const Vector<TYPE> Matrix<TYPE>::Col(unsigned c, SliceType styp) const
  285. // Return a column slice of a matrix. Remember, either colstride
  286. // or rowstride is 1.
  287. {
  288.   return Vector<TYPE>(data, styp,
  289.                       nrows, colstride, CHECKCOL(c)*rowstride);
  290. }
  291.  
  292. template<class TYPE>
  293. Vector<TYPE> Matrix<TYPE>::Diag(SliceType styp)
  294. // Return a diagonal slice of a square matrix. If the
  295. // matrix isn't square, we use the smallest dimension
  296. // for the diagonal length.
  297. {
  298.   unsigned dlen = (nrows <= ncols) ? nrows : ncols;
  299.   unsigned diag_stride = (rowstride == 1) ? colstride : rowstride;
  300.   diag_stride++;
  301.   return Vector<TYPE>(data, styp, dlen, diag_stride, 0);
  302. }
  303.  
  304. template<class TYPE>
  305. const Vector<TYPE> Matrix<TYPE>::Diag(SliceType styp) const
  306. // Return a diagonal slice of a square matrix. If the
  307. // matrix isn't square, we use the smallest dimension
  308. // for the diagonal length.
  309. {
  310.   unsigned dlen = (nrows <= ncols) ? nrows : ncols;
  311.   unsigned diag_stride = (rowstride == 1) ? colstride : rowstride;
  312.   diag_stride++;
  313.   return Vector<TYPE>(data, styp, dlen, diag_stride, 0);
  314. }
  315.  
  316. template<class TYPE>
  317. Vector<TYPE> Matrix<TYPE>::All(SliceType styp)
  318. // Returns a 1D vector with all of the data for the matrix. 
  319. // If it isn't possible for the 1D data to be contiguous, 
  320. // (as will be the case for some submatrices), then a 
  321. // null vector is returned.
  322. // ASSUMES either colstride or rowstride == 1.
  323. {
  324.   if (ncols == colstride || nrows == rowstride)
  325.      return Vector<TYPE>(data, styp, nrows * ncols, 1, 0);
  326.      else return Vector<TYPE>(); // A null vector
  327. }
  328.  
  329.  
  330. template<class TYPE>
  331. const Vector<TYPE> Matrix<TYPE>::All(SliceType styp) const
  332. // Returns a 1D vector with all of the data for the matrix. 
  333. // If it isn't possible for the 1D data to be contiguous, 
  334. // (as will be the case for some submatrices), then a 
  335. // null vector is returned.
  336. // ASSUMES either colstride or rowstride == 1.
  337. {
  338.   if (ncols == colstride || nrows == rowstride)
  339.      return Vector<TYPE>(data, styp, nrows * ncols, 1, 0);
  340.      else return Vector<TYPE>(); // A null vector
  341. }
  342.