// Program to test slices and a simple N*M matrix class // pp 670-674 and 683-684 // No guarantees offered. Constructive comments to bs@research.att.com #include #include #include #include // for inner_product using namespace std; // forward declarations to allow friend declarations: template class Slice_iter; template bool operator==(const Slice_iter&, const Slice_iter&); template bool operator!=(const Slice_iter&, const Slice_iter&); template bool operator< (const Slice_iter&, const Slice_iter&); template class Slice_iter { valarray* v; slice s; size_t curr; // index of current element T& ref(size_t i) const { return (*v)[s.start()+i*s.stride()]; } public: Slice_iter(valarray* vv, slice ss) :v(vv), s(ss), curr(0) { } Slice_iter end() const { Slice_iter t = *this; t.curr = s.size(); // index of last-plus-one element return t; } Slice_iter& operator++() { curr++; return *this; } Slice_iter operator++(int) { Slice_iter t = *this; curr++; return t; } T& operator[](size_t i) { return ref(i); } // C style subscript T& operator()(size_t i) { return ref(i); } // Fortran-style subscript T& operator*() { return ref(curr); } // current element friend bool operator==<>(const Slice_iter& p, const Slice_iter& q); friend bool operator!=<>(const Slice_iter& p, const Slice_iter& q); friend bool operator< <>(const Slice_iter& p, const Slice_iter& q); }; template bool operator==(const Slice_iter& p, const Slice_iter& q) { return p.curr==q.curr && p.s.stride()==q.s.stride() && p.s.start()==q.s.start(); } template bool operator!=(const Slice_iter& p, const Slice_iter& q) { return !(p==q); } template bool operator<(const Slice_iter& p, const Slice_iter& q) { return p.curr class Cslice_iter; template bool operator==(const Cslice_iter&, const Cslice_iter&); template bool operator!=(const Cslice_iter&, const Cslice_iter&); template bool operator< (const Cslice_iter&, const Cslice_iter&); template class Cslice_iter { valarray* v; slice s; size_t curr; // index of current element const T& ref(size_t i) const { return (*v)[s.start()+i*s.stride()]; } public: Cslice_iter(valarray* vv, slice ss): v(vv), s(ss), curr(0){} Cslice_iter end() const { Cslice_iter t = *this; t.curr = s.size(); // index of one plus last element return t; } Cslice_iter& operator++() { curr++; return *this; } Cslice_iter operator++(int) { Cslice_iter t = *this; curr++; return t; } const T& operator[](size_t i) const { return ref(i); } const T& operator()(size_t i) const { return ref(i); } const T& operator*() const { return ref(curr); } friend bool operator==<>(const Cslice_iter& p, const Cslice_iter& q); friend bool operator!=<>(const Cslice_iter& p, const Cslice_iter& q); friend bool operator< <>(const Cslice_iter& p, const Cslice_iter& q); }; template bool operator==(const Cslice_iter& p, const Cslice_iter& q) { return p.curr==q.curr && p.s.stride()==q.s.stride() && p.s.start()==q.s.start(); } template bool operator!=(const Cslice_iter& p, const Cslice_iter& q) { return !(p==q); } template bool operator<(const Cslice_iter& p, const Cslice_iter& q) { return p.curr* v; // stores elements by column as described in 22.4.5 size_t d1, d2; // d1 == number of columns, d2 == number of rows public: Matrix(size_t x, size_t y); // note: no default constructor Matrix(const Matrix&); Matrix& operator=(const Matrix&); ~Matrix(); size_t size() const { return d1*d2; } size_t dim1() const { return d1; } size_t dim2() const { return d2; } Slice_iter row(size_t i); Cslice_iter row(size_t i) const; Slice_iter column(size_t i); Cslice_iter column(size_t i) const; double& operator()(size_t x, size_t y); // Fortran-style subscripts double operator()(size_t x, size_t y) const; Slice_iter operator()(size_t i) { return column(i); } Cslice_iter operator()(size_t i) const { return column(i); } Slice_iter operator[](size_t i) { return column(i); } // C-style subscript Cslice_iter operator[](size_t i) const { return column(i); } Matrix& operator*=(double); valarray& array() { return *v; } }; inline Slice_iter Matrix::row(size_t i) { return Slice_iter(v,slice(i,d1,d2)); } inline Cslice_iter Matrix::row(size_t i) const { return Cslice_iter(v,slice(i,d1,d2)); } inline Slice_iter Matrix::column(size_t i) { return Slice_iter(v,slice(i*d2,d2,1)); } inline Cslice_iter Matrix::column(size_t i) const { return Cslice_iter(v,slice(i*d2,d2,1)); } Matrix::Matrix(size_t x, size_t y) { // check that x and y are sensible d1 = x; d2 = y; v = new valarray(x*y); } Matrix::~Matrix() { delete v; } double& Matrix::operator()(size_t x, size_t y) { return column(x)[y]; } //------------------------------------------------------------- double mul(const Cslice_iter& v1, const valarray& v2) { double res = 0; for (size_t i = 0; i operator*(const Matrix& m, const valarray& v) { if (m.dim1()!=v.size()) cerr << "wrong number of elements in m*v\n"; valarray res(m.dim2()); for (size_t i = 0; i operator*(const Matrix& m, valarray& v) valarray mul_mv(const Matrix& m, valarray& v) { if (m.dim1()!=v.size()) cerr << "wrong number of elements in m*v\n"; valarray res(m.dim2()); for (size_t i = 0; i& ri = m.row(i); res[i] = inner_product(ri,ri.end(),&v[0],double(0)); } return res; } valarray operator*(valarray& v, const Matrix& m) { if (v.size()!=m.dim2()) cerr << "wrong number of elements in v*m\n"; valarray res(m.dim1()); for (size_t i = 0; i& ci = m.column(i); res[i] = inner_product(ci,ci.end(),&v[0],double(0)); } return res; } Matrix& Matrix::operator*=(double d) { (*v) *= d; return *this; } ostream& operator<<(ostream& os, Matrix& m) { for(int y=0; y c = a.column(x); c!=c.end(); ++c) cout << "\t" << *c <<"\n"; } cout <<"rows :\n"; for(int y=0; y r = a.row(y); r!=r.end(); ++r) cout << "\t" << *r ; cout <<"\n"; } } ostream& operator<<(ostream& os, const valarray& v) { for (int i = 0; i r(2,x_max); cout << "a*v: " << a*r << endl; cout << "m*v: " << mul_mv(a,r) << endl; valarray c(2,y_max); cout << "v*a: " << c*a << endl; } int main() { f(3,4); f(4,3); g(3,4); g(4,3); }