[alt.sources] C++ Matrix class

bjaspan@athena.mit.edu (Barr3y Jaspan) (04/30/91)

Here is a general n x m Matrix class for C++.  It has been tested on a VAX
running (mostly) BSD with g++, on an IBM RT running AOS4.3 with cfront, and on
a DECstation 3100 with g++.  Your mileage may vary.

The shar file contains Matrix.C and Matrix.H.

-- 
Barr3y Jaspan, bjaspan@mit.edu

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  Matrix.C Matrix.H
# Wrapped by bjaspan@portnoy on Tue Apr 30 00:25:26 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Matrix.C' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Matrix.C'\"
else
echo shar: Extracting \"'Matrix.C'\" \(6727 characters\)
sed "s/^X//" >'Matrix.C' <<'END_OF_FILE'
X/*
X * C++ class for MxN matrices.
X *
X * $Id: Matrix.C,v 1.6 91/04/14 18:27:48 bjaspan Exp $
X */
X
X
X/*
X * (1) An m x n matrix has m rows and n columns -- ie height x width.
X * 
X * (2) nam == 1 --> nothing else is guaranteed (some code here might
X * violate that.. sigh)
X *
X * (3) Two NAM's are equal.
X */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <stdarg.h>
X#include "Matrix.H"
X
XMatrix *Matrix::M_NAM = Matrix::MakeNAM();
X
X/* Constructors */
X
Xvoid Matrix::Init(const int m, const int n)
X{
X     M_m = m;
X     M_n = n;
X     nam = 0;
X     d = new double[m*n];
X}
X
XMatrix::Matrix()
X{
X     nam = 1;
X     M_m = M_n = 0;
X     d = 0;
X}
X
XMatrix::Matrix(int m, int n)
X{
X     Init(m, n);
X}
X
XMatrix::Matrix(int m, int n, double first ...)
X{
X     int i;
X     va_list ap;
X     
X     Init(m, n);
X
X     d[0] = first;
X     va_start(ap, first);
X     for (i=1; i < m*n; i += 1)
X	  d[i] = va_arg(ap, double);
X}
X
XMatrix::Matrix(int m, int n, int first ...)
X{
X     int i;
X     va_list ap;
X     
X     Init(m, n);
X
X     d[0] = double(first);
X     va_start(ap, first);
X     for (i=1; i < m*n; i += 1)
X	  d[i] = double(va_arg(ap, int));
X}
X
XMatrix::Matrix(int m, int n, int *array)
X{
X     int i;
X
X     Init(m, n);
X     for (i=0; i < (m*n); i += 1)
X	  d[i] = double(array[i]);
X}
X
XMatrix::Matrix(int m, int n, double *array)
X{
X     int i;
X
X     Init(m, n);
X     for (i=0; i < (m*n); i += 1)
X	  d[i] = array[i];
X}
X
XMatrix::Matrix(const Matrix& m1)
X{
X     int i;
X
X     Init(m1.M_m, m1.M_n);
X     for (i=0; i < (M_m*M_n); i += 1)
X	  d[i] = m1.d[i];
X}
X
XMatrix::Matrix(const Matrix& m1, int r, int c, int m, int n)
X{
X     int i,j;
X
X     if (r<1 || c<1 || m1.Rows() < r-1+m || m1.Cols() < c-1+n)
X	  nam = 1;
X     else {
X	  Init(m,n);
X
X	  for (i=1;i<=m;i++)
X	       for (j=1;j<=n;j++)
X		    (*this)(i,j) = m1(r+i-1,c+j-1);
X     }
X}
X
XMatrix::~Matrix()
X{
X     delete [M_m*M_n] d;
X}
X
X/* Overloaded operators */
X
Xint operator==(const Matrix& m1, const Matrix& m2)
X{
X     int i;
X
X     if (m1.nam != m2.nam)
X	  return 0;
X     if (m1.nam == 1)
X	  return 1;
X     if (! m1.SameSize(m2))
X	  return 0;
X
X     for (i = 0; i < m1.M_m*m1.M_n; i++)
X	  if (m1.d[i] != m2.d[i])
X	       return 0;
X
X     return 1;
X}
X
XMatrix operator+(const Matrix& m1, const Matrix& m2)
X{
X     if (m1.M_m != m2.M_m || m1.M_n != m2.M_n ||
X	 m1 == Matrix::NAM() || m2 == Matrix::NAM())
X	  return Matrix::NAM();
X
X     Matrix m(m1);
X
X     for (int i=0; i < (m1.M_m*m1.M_n); i++)
X	  m.d[i] += m2.d[i];
X
X     return m;
X}
X
XMatrix operator-(const Matrix& m1, const Matrix& m2)
X{
X     if (m1.M_m != m2.M_m || m1.M_n != m2.M_n ||
X	 m1 == Matrix::NAM() || m2 == Matrix::NAM())
X	  return Matrix::NAM();
X
X     Matrix m(m1);
X
X     for (int i=0; i < (m1.M_m*m1.M_n); i++)
X	  m.d[i] -= m2.d[i];
X
X     return m;
X}
X
XMatrix operator*(const Matrix& m1, const Matrix& m2)
X{
X     if (m1.M_n != m2.M_m || m1 == Matrix::NAM() || m2 == Matrix::NAM())
X	  return Matrix::NAM();
X
X     Matrix m(m1.M_m, m2.M_n);
X     double val = 0.0;
X
X     for (int i=1; i <= m1.M_m; i += 1)
X     for (int j=1; j <= m2.M_n; j += 1) {
X	  m(i, j) = 0.0;
X	  for (int k=1; k <= m1.M_n; k += 1) 
X	       m(i, j) += m1(i, k) * m2(k, j);
X     }
X     
X     return m;
X}
X
XMatrix& Matrix::operator+=(const Matrix& m)
X{
X     if (M_m != m.M_m || M_n != m.M_n || *this == Matrix::NAM() ||
X	 m == Matrix::NAM())
X	  nam = 1;
X     else
X	  for (int i=0; i < (M_m*M_n); i++)
X	       d[i] += m.d[i];
X
X     return *this;
X}
X
XMatrix& Matrix::operator-=(const Matrix& m)
X{
X     if (M_m != m.M_m || M_n != m.M_n || *this == Matrix::NAM() ||
X	 m == Matrix::NAM())
X	  nam = 1;
X     else
X	  for (int i=0; i < (M_m*M_n); i++)
X	       d[i] -= m.d[i];
X
X     return *this;
X}
X
XMatrix operator*(double k, const Matrix& m)
X{
X   Matrix n(m);
X   int i;
X
X   for (i=0;i<n.M_m*n.M_n;i++) n.d[i]*=k;
X   return(n);
X}
X
XMatrix& Matrix::operator=(const Matrix& m)
X{
X     nam = m.nam;
X     
X     if (nam)
X	  ;
X     else if (M_m == m.M_m && M_n == m.M_n)
X	  bcopy(m.d, d, M_m*M_n*sizeof(double));
X     else if (M_m*M_n == m.M_m*m.M_n) {
X	  bcopy(m.d, d, M_m*M_n*sizeof(double));
X	  M_m = m.M_m;
X	  M_n = m.M_n;
X     } else {
X	  delete [M_m*M_n] d;
X	  
X	  M_m = m.M_m;
X	  M_n = m.M_n;
X	  
X	  d = new double[M_m*M_n];
X	  bcopy(m.d, d, M_m*M_n*sizeof(double));
X     }
X
X     return(*this);
X}
X
XMatrix operator|(const Matrix& m1, const Matrix& m2)
X   // Concatenates two matrices horizontally.  Requires that m1 and m2
X   // have the same number of rows.
X   // [ A ] | [ B ] --> [ A | B ]
X{
X     if (m1.Rows() != m2.Rows() || m1 == Matrix::NAM() || m2 == Matrix::NAM())
X	  return Matrix::NAM();
X
X     Matrix m(m1.Rows(), m1.Cols() + m2.Cols());
X     int r, c;
X
X     for (r = 1; r <= m1.Rows(); r += 1)
X	  for (c = 1; c <= m1.Cols(); c += 1)
X	       m(r, c) = m1(r, c);
X
X     for (r = 1; r <= m1.Rows(); r += 1)
X	  for (c = 1; c <= m2.Cols(); c += 1)
X	       m(r, c + m1.Cols()) = m2(r, c);
X
X     return m;
X}
X
XMatrix operator&(const Matrix& m1, const Matrix& m2)
X   // Concatenates two matrices vertically.  Requires that m1 and m2
X   // have the same number of columns.
X   //                   [ A ]
X   // [ A ] & [ B ] --> [ - ]
X   //                   [ B ]
X{
X     if (m1.Cols() != m2.Cols() || m1 == Matrix::NAM() || m2 == Matrix::NAM())
X	  return Matrix::NAM();
X
X     Matrix m(m1.Rows()+m2.Rows(), m1.Cols());
X     int r, c;
X
X     for (r = 1; r <= m1.Rows(); r += 1)
X	  for (c = 1; c <= m1.Cols(); c += 1)
X	       m(r, c) = m1(r, c);
X     for (r = 1; r <= m2.Rows(); r += 1)
X	  for (c = 1; c <= m2.Cols(); c += 1)
X	       m(r + m1.Rows(), c) = m2(r, c);
X     
X#if 0
X     // This doesn't work, and I don't know why.
X     bcopy(m1.d, m.d, m1.Rows()*m1.Cols()*sizeof(double));
X     bcopy(m2.d, m.d + m1.Rows()*m1.Cols()*sizeof(double),
X	   m2.Rows()*m2.Cols()*sizeof(double));
X#endif
X
X     return m;
X}
X
Xostream& operator<<(ostream& s, const Matrix& m)
X{
X     int i,j;
X     
X     if (m.nam) {
X	  s << "NAM\n";
X	  return(s);
X     }
X     
X     for (i = 1; i <= m.M_m; i++) {
X	  for (j = 1; j <= m.M_n; j++)
X#ifdef __GNUG__
X	       s.form("%6.2f ", m(i, j));
X#else
X	       s << form("%6.2f ", m(i, j));
X#endif
X	  s << "\n";
X     }
X     
X     return(s);
X}
X
X/* Member functions */
X
XMatrix Matrix::T() const
X{
X     Matrix t(M_n, M_m);
X
X     for (int i = 1; i <= M_m; i++)
X	  for (int j = 1; j <= M_n; j++)
X	       t(j, i) = (*this)(i, j);
X
X     return t;
X}
X
Xvoid Matrix::Print() const
X{
X   cout << *this;
X}
X
X/* Special matrix constructors */
XMatrix *Matrix::MakeNAM()
X{
X     Matrix *m = new Matrix(1,1);
X     m->nam = 1;
X     return m;
X}
X
X/* Matrix mutators */
Xvoid Matrix::Identify()	
X{
X     if (M_m != M_n) {
X	  nam = 1;
X	  return;
X     }
X
X     for (int i = 1; i <= M_m; i++)
X	  for (int j = 1; j <= M_n; j++)
X	       (*this)(i, j) = 0.0;
X
X     for (i = 1; i <= M_m; i++)
X	  (*this)(i, i) = 1.0;
X}
END_OF_FILE
if test 6727 -ne `wc -c <'Matrix.C'`; then
    echo shar: \"'Matrix.C'\" unpacked with wrong size!
fi
# end of 'Matrix.C'
fi
if test -f 'Matrix.H' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Matrix.H'\"
else
echo shar: Extracting \"'Matrix.H'\" \(2542 characters\)
sed "s/^X//" >'Matrix.H' <<'END_OF_FILE'
X#ifndef __MATRIX_H__
X#define __MATRIX_H__
X
X/* $Id: Matrix.H,v 1.4 91/04/16 18:03:17 bjaspan Exp $ */
X
X#include <assert.h>  /* for abort() */
X#include <stream.h>
X
Xclass Matrix {
Xpublic:
X     /* Constructors */
X     Matrix();
X     Matrix(int, int);
X     Matrix(int, int, int *);
X     Matrix(int, int, double *);
X     Matrix(int, int, int ...);
X     Matrix(int, int, double ...);
X     Matrix(const Matrix&);
X     Matrix(const Matrix&,int,int,int,int);
X     ~Matrix();
X
X     /* Member functions */
X     Matrix T() const;
X     inline int Rows() const;
X     inline int Cols() const;
X     inline int SameSize(const Matrix&) const;
X     inline double& operator()(int, int) const;
X     inline double *Row(int) const;
X     void Print() const;
X
X     /* Overloaded operators */
X     friend Matrix operator+(const Matrix&, const Matrix&);
X     friend Matrix operator-(const Matrix&, const Matrix&);
X     friend Matrix operator*(const Matrix&, const Matrix&);
X     friend Matrix operator*(double, const Matrix&);
X     Matrix& operator+=(const Matrix&);
X     Matrix& operator-=(const Matrix&);
X     inline friend Matrix& operator*=(Matrix&, const Matrix&);
X     inline friend Matrix operator/(const Matrix&, double);
X     friend int operator==(const Matrix&, const Matrix&);
X     friend Matrix operator|(const Matrix&, const Matrix&);
X     friend Matrix operator&(const Matrix&, const Matrix&);
X     Matrix& operator=(const Matrix&);
X     friend ostream& operator<<(ostream&, const Matrix&);
X
X     /* Special matrix creators */
X     static inline const Matrix& NAM();
X
X     /* Matrix mutators */
X     void Identify();
X
Xprivate:
X     void Init(const int, const int);
X
X     static Matrix *M_NAM;
X     static Matrix *MakeNAM();
X     
X     int M_m, M_n, nam;
X     double *d;
X};
X
Xinline int Matrix::Rows() const
X{
X     return M_m;
X}
X
Xinline int Matrix::Cols() const
X{
X     return M_n;
X}
X
Xinline Matrix& operator*=(Matrix& m1, const Matrix& m)
X{
X   return(m1 = m1*m);
X}
X
Xinline Matrix operator/(const Matrix& m, double k)
X{
X   return((1.0/k)*m);
X}
X
Xinline double& Matrix::operator()(int m, int n) const
X{
X     /* My kingdom for exception handling ... */
X     if (m > M_m || n > M_n || m < 1 || n < 1)
X	  abort();
X     
X     return d[M_n*(m-1) + n - 1];
X}
X
Xinline double *Matrix::Row(int r) const
X{
X   return(d+(r-1)*M_n);
X}
X
Xinline const Matrix& Matrix::NAM()
X{
X     return *Matrix::M_NAM;
X}
X
Xinline int Matrix::SameSize(const Matrix& m) const
X{
X     return (M_m == m.M_m && M_n == m.M_n);
X}
X
X/* DO NOT ADD ANYTHING AFTER THIS #endif */
X#endif /* __MATRIX_H__ */
END_OF_FILE
if test 2542 -ne `wc -c <'Matrix.H'`; then
    echo shar: \"'Matrix.H'\" unpacked with wrong size!
fi
# end of 'Matrix.H'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0