Advertisement
DragonOsman

Matrix.h

Mar 17th, 2017
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 28.01 KB | None | 0 0
  1. /*
  2. warning: this small multidimensional matrix library uses a few features
  3. not taught in ENGR112 and not explained in elementary textbooks
  4.  
  5. (c) Bjarne Stroustrup, Texas A&M University.
  6.  
  7. Use as you like as long as you acknowledge the source.
  8. */
  9.  
  10. #ifndef MATRIX_LIB
  11. #define MATRIX_LIB
  12.  
  13. #include<string>
  14. #include<algorithm>
  15. #include<iostream>
  16. #include "std_lib_facilities.h"
  17.  
  18. namespace Numeric_lib {
  19.  
  20.     //-----------------------------------------------------------------------------
  21.  
  22.     struct Matrix_error {
  23.         std::string name;
  24.         Matrix_error(const char* q) :name(q) { }
  25.         Matrix_error(std::string n) :name(n) { }
  26.     };
  27.  
  28.     //-----------------------------------------------------------------------------
  29.  
  30.     inline void error(const char* p)
  31.     {
  32.         throw Matrix_error(p);
  33.     }
  34.  
  35.     //-----------------------------------------------------------------------------
  36.  
  37.     typedef long Index;    // I still dislike unsigned
  38.  
  39.                            //-----------------------------------------------------------------------------
  40.  
  41.                            // The general Matrix template is simply a prop for its specializations:
  42.     template<class T = double, int D = 1> class Matrix {
  43.         // multidimensional matrix class
  44.         // ( ) does multidimensional subscripting
  45.         // [ ] does C style "slicing": gives an N-1 dimensional matrix from an N dimensional one
  46.         // row() is equivalent to [ ]
  47.         // column() is not (yet) implemented because it requires strides.
  48.         // = has copy semantics
  49.         // ( ) and [ ] are range checked
  50.         // slice() to give sub-ranges
  51.     private:
  52.         Matrix();    // this should never be compiled
  53.                      // template<class A> Matrix(A);
  54.     };
  55.  
  56.     //-----------------------------------------------------------------------------
  57.  
  58.     template<class T = double, int D = 1> class Row;    // forward declaration
  59.  
  60.                                                         //-----------------------------------------------------------------------------
  61.  
  62.                                                         // function objects for various apply() operations:
  63.  
  64.     template<class T> struct Assign {
  65.         void operator()(T& a, const T& c) { a = c; }
  66.     };
  67.  
  68.     template<class T> struct Add_assign {
  69.         void operator()(T& a, const T& c) { a += c; }
  70.     };
  71.     template<class T> struct Mul_assign {
  72.         void operator()(T& a, const T& c) { a *= c; }
  73.     };
  74.     template<class T> struct Minus_assign {
  75.         void operator()(T& a, const T& c) { a -= c; }
  76.     };
  77.     template<class T> struct Div_assign {
  78.         void operator()(T& a, const T& c) { a /= c; }
  79.     };
  80.     template<class T> struct Mod_assign {
  81.         void operator()(T& a, const T& c) { a %= c; }
  82.     };
  83.     template<class T> struct Or_assign {
  84.         void operator()(T& a, const T& c) { a |= c; }
  85.     };
  86.     template<class T> struct Xor_assign {
  87.         void operator()(T& a, const T& c) { a ^= c; }
  88.     };
  89.     template<class T> struct And_assign {
  90.         void operator()(T& a, const T& c) { a &= c; }
  91.     };
  92.  
  93.     template<class T> struct Not_assign {
  94.         void operator()(T& a) { a = !a; }
  95.     };
  96.  
  97.     template<class T> struct Not {
  98.         T operator()(T& a) { return !a; }
  99.     };
  100.  
  101.     template<class T> struct Unary_minus {
  102.         T operator()(T& a) { return -a; }
  103.     };
  104.  
  105.     template<class T> struct Complement {
  106.         T operator()(T& a) { return ~a; }
  107.     };
  108.  
  109.     //-----------------------------------------------------------------------------
  110.  
  111.     // Matrix_base represents the common part of the Matrix classes:
  112.     template<class T> class Matrix_base {
  113.         // matrixs store their memory (elements) in Matrix_base and have copy semantics
  114.         // Matrix_base does element-wise operations
  115.     protected:
  116.         T* elem;    // vector? no: we couldn't easily provide a vector for a slice
  117.         const Index sz;
  118.         mutable bool owns;
  119.         mutable bool xfer;
  120.     public:
  121.         Matrix_base(Index n) :elem(new T[n]()), sz(n), owns(true), xfer(false)
  122.             // matrix of n elements (default initialized)
  123.         {
  124.             // std::cerr << "new[" << n << "]->" << elem << "\n";
  125.         }
  126.  
  127.         Matrix_base(Index n, T* p) :elem(p), sz(n), owns(false), xfer(false)
  128.             // descriptor for matrix of n elements owned by someone else
  129.         {
  130.         }
  131.  
  132.         ~Matrix_base()
  133.         {
  134.             if (owns) {
  135.                 // std::cerr << "delete[" << sz << "] " << elem << "\n";
  136.                 delete[]elem;
  137.             }
  138.         }
  139.  
  140.         // if necessay, we can get to the raw matrix:
  141.         T* data() { return elem; }
  142.         const T* data() const { return elem; }
  143.         Index    size() const { return sz; }
  144.  
  145.         void copy_elements(const Matrix_base& a)
  146.         {
  147.             if (sz != a.sz) error("copy_elements()");
  148.             for (Index i = 0; i<sz; ++i) elem[i] = a.elem[i];
  149.         }
  150.  
  151.         void base_assign(const Matrix_base& a) { copy_elements(a); }
  152.  
  153.         void base_copy(const Matrix_base& a)
  154.         {
  155.             if (a.xfer) {          // a is just about to be deleted
  156.                                    // so we can transfer ownership rather than copy
  157.                                    // std::cerr << "xfer @" << a.elem << " [" << a.sz << "]\n";
  158.                 elem = a.elem;
  159.                 a.xfer = false;    // note: modifies source
  160.                 a.owns = false;
  161.             }
  162.             else {
  163.                 elem = new T[a.sz];
  164.                 // std::cerr << "base copy @" << a.elem << " [" << a.sz << "]\n";
  165.                 copy_elements(a);
  166.             }
  167.             owns = true;
  168.             xfer = false;
  169.         }
  170.  
  171.         // to get the elements of a local matrix out of a function without copying:
  172.         void base_xfer(Matrix_base& x)
  173.         {
  174.             if (owns == false) error("cannot xfer() non-owner");
  175.             owns = false;     // now the elements are safe from deletion by original owner
  176.             x.xfer = true;    // target asserts temporary ownership
  177.             x.owns = true;
  178.         }
  179.  
  180.         template<class F> void base_apply(F f) { for (Index i = 0; i<size(); ++i) f(elem[i]); }
  181.         template<class F> void base_apply(F f, const T& c) { for (Index i = 0; i<size(); ++i) f(elem[i], c); }
  182.     private:
  183.         void operator=(const Matrix_base&);    // no ordinary copy of bases
  184.         Matrix_base(const Matrix_base&);
  185.     };
  186.  
  187.     //-----------------------------------------------------------------------------
  188.  
  189.     template<class T> class Matrix<T, 1> : public Matrix_base<T> {
  190.         const Index d1;
  191.  
  192.     protected:
  193.         // for use by Row:
  194.         Matrix(Index n1, T* p) : Matrix_base<T>(n1, p), d1(n1)
  195.         {
  196.             // std::cerr << "construct 1D Matrix from data\n";
  197.         }
  198.  
  199.     public:
  200.  
  201.         Matrix(Index n1) : Matrix_base<T>(n1), d1(n1) { }
  202.  
  203.         Matrix(Row<T, 1>& a) : Matrix_base<T>(a.dim1(), a.p), d1(a.dim1())
  204.         {
  205.             // std::cerr << "construct 1D Matrix from Row\n";
  206.         }
  207.  
  208.         // copy constructor: let the base do the copy:
  209.         Matrix(const Matrix& a) : Matrix_base<T>(a.size(), 0), d1(a.d1)
  210.         {
  211.             // std::cerr << "copy ctor\n";
  212.             this->base_copy(a);
  213.         }
  214.  
  215.         template<int n>
  216.         Matrix(const T(&a)[n]) : Matrix_base<T>(n), d1(n)
  217.             // deduce "n" (and "T"), Matrix_base allocates T[n]
  218.         {
  219.             // std::cerr << "matrix ctor\n";
  220.             for (Index i = 0; i<n; ++i) this->elem[i] = a[i];
  221.         }
  222.  
  223.         Matrix(const T* p, Index n) : Matrix_base<T>(n), d1(n)
  224.             // Matrix_base allocates T[n]
  225.         {
  226.             // std::cerr << "matrix ctor\n";
  227.             for (Index i = 0; i<n; ++i) this->elem[i] = p[i];
  228.         }
  229.  
  230.         template<class F> Matrix(const Matrix& a, F f) : Matrix_base<T>(a.size()), d1(a.d1)
  231.             // construct a new Matrix with element's that are functions of a's elements:
  232.             // does not modify a unless f has been specifically programmed to modify its argument
  233.             // T f(const T&) would be a typical type for f
  234.         {
  235.             for (Index i = 0; i<this->sz; ++i) this->elem[i] = f(a.elem[i]);
  236.         }
  237.  
  238.         template<class F, class Arg> Matrix(const Matrix& a, F f, const Arg& t1) : Matrix_base<T>(a.size()), d1(a.d1)
  239.             // construct a new Matrix with element's that are functions of a's elements:
  240.             // does not modify a unless f has been specifically programmed to modify its argument
  241.             // T f(const T&, const Arg&) would be a typical type for f
  242.         {
  243.             for (Index i = 0; i<this->sz; ++i) this->elem[i] = f(a.elem[i], t1);
  244.         }
  245.  
  246.         Matrix& operator=(const Matrix& a)
  247.             // copy assignment: let the base do the copy
  248.         {
  249.             // std::cerr << "copy assignment (" << this->size() << ',' << a.size()<< ")\n";
  250.             if (d1 != a.d1) error("length error in 1D=");
  251.             this->base_assign(a);
  252.             return *this;
  253.         }
  254.  
  255.         ~Matrix() { }
  256.  
  257.         Index dim1() const { return d1; }    // number of elements in a row
  258.  
  259.         Matrix xfer()    // make an Matrix to move elements out of a scope
  260.         {
  261.             Matrix x(dim1(), this->data()); // make a descriptor
  262.             this->base_xfer(x);                  // transfer (temporary) ownership to x
  263.             return x;
  264.         }
  265.  
  266.         void range_check(Index n1) const
  267.         {
  268.             // std::cerr << "range check: (" << d1 << "): " << n1 << "\n";
  269.             if (n1<0 || d1 <= n1) error("1D range error: dimension 1");
  270.         }
  271.  
  272.         // subscripting:
  273.         T& operator()(Index n1) { range_check(n1); return this->elem[n1]; }
  274.         const T& operator()(Index n1) const { range_check(n1); return this->elem[n1]; }
  275.  
  276.         // slicing (the same as subscripting for 1D matrixs):
  277.         T& operator[](Index n) { return row(n); }
  278.         const T& operator[](Index n) const { return row(n); }
  279.  
  280.         T& row(Index n) { range_check(n); return this->elem[n]; }
  281.         const T& row(Index n) const { range_check(n); return this->elem[n]; }
  282.  
  283.         Row<T, 1> slice(Index n)
  284.             // the last elements from a[n] onwards
  285.         {
  286.             if (n<0) n = 0;
  287.             else if (d1<n) n = d1;// one beyond the end
  288.             return Row<T, 1>(d1 - n, this->elem + n);
  289.         }
  290.  
  291.         const Row<T, 1> slice(Index n) const
  292.             // the last elements from a[n] onwards
  293.         {
  294.             if (n<0) n = 0;
  295.             else if (d1<n) n = d1;// one beyond the end
  296.             return Row<T, 1>(d1 - n, this->elem + n);
  297.         }
  298.  
  299.         Row<T, 1> slice(Index n, Index m)
  300.             // m elements starting with a[n]
  301.         {
  302.             if (n<0) n = 0;
  303.             else if (d1<n) n = d1;    // one beyond the end
  304.             if (m<0) m = 0;
  305.             else if (d1<n + m) m = d1 - n;
  306.             return Row<T, 1>(m, this->elem + n);
  307.         }
  308.  
  309.         const Row<T, 1> slice(Index n, Index m) const
  310.             // m elements starting with a[n]
  311.         {
  312.             if (n<0) n = 0;
  313.             else if (d1<n) n = d1;    // one beyond the end
  314.             if (m<0) m = 0;
  315.             else if (d1<n + m) m = d1 - n;
  316.             return Row<T, 1>(m, this->elem + n);
  317.         }
  318.  
  319.         // element-wise operations:
  320.         template<class F> Matrix& apply(F f) { this->base_apply(f); return *this; }
  321.         template<class F> Matrix& apply(F f, const T& c) { this->base_apply(f, c); return *this; }
  322.  
  323.         Matrix& operator=(const T& c) { this->base_apply(Assign<T>(), c);       return *this; }
  324.  
  325.         Matrix& operator*=(const T& c) { this->base_apply(Mul_assign<T>(), c);   return *this; }
  326.         Matrix& operator/=(const T& c) { this->base_apply(Div_assign<T>(), c);   return *this; }
  327.         Matrix& operator%=(const T& c) { this->base_apply(Mod_assign<T>(), c);   return *this; }
  328.         Matrix& operator+=(const T& c) { this->base_apply(Add_assign<T>(), c);   return *this; }
  329.         Matrix& operator-=(const T& c) { this->base_apply(Minus_assign<T>(), c); return *this; }
  330.  
  331.         Matrix& operator&=(const T& c) { this->base_apply(And_assign<T>(), c);   return *this; }
  332.         Matrix& operator|=(const T& c) { this->base_apply(Or_assign<T>(), c);    return *this; }
  333.         Matrix& operator^=(const T& c) { this->base_apply(Xor_assign<T>(), c);   return *this; }
  334.  
  335.         Matrix operator!() { return xfer(Matrix(*this, Not<T>())); }
  336.         Matrix operator-() { return xfer(Matrix(*this, Unary_minus<T>())); }
  337.         Matrix operator~() { return xfer(Matrix(*this, Complement<T>())); }
  338.  
  339.         template<class F> Matrix apply_new(F f) { return xfer(Matrix(*this, f)); }
  340.  
  341.         void swap_rows(Index i, Index j)
  342.             // swap_rows() uses a row's worth of memory for better run-time performance
  343.             // if you want pairwise swap, just write it yourself
  344.         {
  345.             if (i == j) return;
  346.             /*
  347.             Matrix<T,1> temp = (*this)[i];
  348.             (*this)[i] = (*this)[j];
  349.             (*this)[j] = temp;
  350.             */
  351.             Index max = (*this)[i].size();
  352.             for (Index ii = 0; ii<max; ++ii) std::swap((*this)(i, ii), (*this)(j, ii));
  353.         }
  354.     };
  355.  
  356.     //-----------------------------------------------------------------------------
  357.  
  358.     template<class T> class Matrix<T, 2> : public Matrix_base<T> {
  359.         const Index d1;
  360.         const Index d2;
  361.  
  362.     protected:
  363.         // for use by Row:
  364.         Matrix(Index n1, Index n2, T* p) : Matrix_base<T>(n1*n2, p), d1(n1), d2(n2)
  365.         {
  366.             //  std::cerr << "construct 3D Matrix from data\n";
  367.         }
  368.  
  369.     public:
  370.  
  371.         Matrix(Index n1, Index n2) : Matrix_base<T>(n1*n2), d1(n1), d2(n2) { }
  372.  
  373.         Matrix(Row<T, 2>& a) : Matrix_base<T>(a.dim1()*a.dim2(), a.p), d1(a.dim1()), d2(a.dim2())
  374.         {
  375.             // std::cerr << "construct 2D Matrix from Row\n";
  376.         }
  377.  
  378.         // copy constructor: let the base do the copy:
  379.         Matrix(const Matrix& a) : Matrix_base<T>(a.size(), 0), d1(a.d1), d2(a.d2)
  380.         {
  381.             // std::cerr << "copy ctor\n";
  382.             this->base_copy(a);
  383.         }
  384.  
  385.         template<int n1, int n2>
  386.         Matrix(const T(&a)[n1][n2]) : Matrix_base<T>(n1*n2), d1(n1), d2(n2)
  387.             // deduce "n1", "n2" (and "T"), Matrix_base allocates T[n1*n2]
  388.         {
  389.             // std::cerr << "matrix ctor (" << n1 << "," << n2 << ")\n";
  390.             for (Index i = 0; i<n1; ++i)
  391.                 for (Index j = 0; j<n2; ++j) this->elem[i*n2 + j] = a[i][j];
  392.         }
  393.  
  394.         template<class F> Matrix(const Matrix& a, F f) : Matrix_base<T>(a.size()), d1(a.d1), d2(a.d2)
  395.             // construct a new Matrix with element's that are functions of a's elements:
  396.             // does not modify a unless f has been specifically programmed to modify its argument
  397.             // T f(const T&) would be a typical type for f
  398.         {
  399.             for (Index i = 0; i<this->sz; ++i) this->elem[i] = f(a.elem[i]);
  400.         }
  401.  
  402.         template<class F, class Arg> Matrix(const Matrix& a, F f, const Arg& t1) : Matrix_base<T>(a.size()), d1(a.d1), d2(a.d2)
  403.             // construct a new Matrix with element's that are functions of a's elements:
  404.             // does not modify a unless f has been specifically programmed to modify its argument
  405.             // T f(const T&, const Arg&) would be a typical type for f
  406.         {
  407.             for (Index i = 0; i<this->sz; ++i) this->elem[i] = f(a.elem[i], t1);
  408.         }
  409.  
  410.         Matrix& operator=(const Matrix& a)
  411.             // copy assignment: let the base do the copy
  412.         {
  413.             // std::cerr << "copy assignment (" << this->size() << ',' << a.size()<< ")\n";
  414.             if (d1 != a.d1 || d2 != a.d2) error("length error in 2D =");
  415.             this->base_assign(a);
  416.             return *this;
  417.         }
  418.  
  419.         ~Matrix() { }
  420.  
  421.         Index dim1() const { return d1; }    // number of elements in a row
  422.         Index dim2() const { return d2; }    // number of elements in a column
  423.  
  424.         Matrix xfer()    // make an Matrix to move elements out of a scope
  425.         {
  426.             Matrix x(dim1(), dim2(), this->data()); // make a descriptor
  427.             this->base_xfer(x);            // transfer (temporary) ownership to x
  428.             return x;
  429.         }
  430.  
  431.         void range_check(Index n1, Index n2) const
  432.         {
  433.             // std::cerr << "range check: (" << d1 << "," << d2 << "): " << n1 << " " << n2 << "\n";
  434.             if (n1<0 || d1 <= n1) error("2D range error: dimension 1");
  435.             if (n2<0 || d2 <= n2) error("2D range error: dimension 2");
  436.         }
  437.  
  438.         // subscripting:
  439.         T& operator()(Index n1, Index n2) { range_check(n1, n2); return this->elem[n1*d2 + n2]; }
  440.         const T& operator()(Index n1, Index n2) const { range_check(n1, n2); return this->elem[n1*d2 + n2]; }
  441.  
  442.         // slicing (return a row):
  443.         Row<T, 1> operator[](Index n) { return row(n); }
  444.         const Row<T, 1> operator[](Index n) const { return row(n); }
  445.  
  446.         Row<T, 1> row(Index n) { range_check(n, 0); return Row<T, 1>(d2, &this->elem[n*d2]); }
  447.         const Row<T, 1> row(Index n) const { range_check(n, 0); return Row<T, 1>(d2, &this->elem[n*d2]); }
  448.  
  449.         Row<T, 2> slice(Index n)
  450.             // rows [n:d1)
  451.         {
  452.             if (n<0) n = 0;
  453.             else if (d1<n) n = d1;    // one beyond the end
  454.             return Row<T, 2>(d1 - n, d2, this->elem + n*d2);
  455.         }
  456.  
  457.         const Row<T, 2> slice(Index n) const
  458.             // rows [n:d1)
  459.         {
  460.             if (n<0) n = 0;
  461.             else if (d1<n) n = d1;    // one beyond the end
  462.             return Row<T, 2>(d1 - n, d2, this->elem + n*d2);
  463.         }
  464.  
  465.         Row<T, 2> slice(Index n, Index m)
  466.             // the rows [n:m)
  467.         {
  468.             if (n<0) n = 0;
  469.             if (d1<m) m = d1;    // one beyond the end
  470.             return Row<T, 2>(m - n, d2, this->elem + n*d2);
  471.  
  472.         }
  473.  
  474.         const Row<T, 2> slice(Index n, Index m) const
  475.             // the rows [n:sz)
  476.         {
  477.             if (n<0) n = 0;
  478.             if (d1<m) m = d1;    // one beyond the end
  479.             return Row<T, 2>(m - n, d2, this->elem + n*d2);
  480.         }
  481.  
  482.         // Column<T,1> column(Index n); // not (yet) implemented: requies strides and operations on columns
  483.  
  484.         // element-wise operations:
  485.         template<class F> Matrix& apply(F f) { this->base_apply(f);   return *this; }
  486.         template<class F> Matrix& apply(F f, const T& c) { this->base_apply(f, c); return *this; }
  487.  
  488.         Matrix& operator=(const T& c) { this->base_apply(Assign<T>(), c);       return *this; }
  489.  
  490.         Matrix& operator*=(const T& c) { this->base_apply(Mul_assign<T>(), c);   return *this; }
  491.         Matrix& operator/=(const T& c) { this->base_apply(Div_assign<T>(), c);   return *this; }
  492.         Matrix& operator%=(const T& c) { this->base_apply(Mod_assign<T>(), c);   return *this; }
  493.         Matrix& operator+=(const T& c) { this->base_apply(Add_assign<T>(), c);   return *this; }
  494.         Matrix& operator-=(const T& c) { this->base_apply(Minus_assign<T>(), c); return *this; }
  495.  
  496.         Matrix& operator&=(const T& c) { this->base_apply(And_assign<T>(), c);   return *this; }
  497.         Matrix& operator|=(const T& c) { this->base_apply(Or_assign<T>(), c);    return *this; }
  498.         Matrix& operator^=(const T& c) { this->base_apply(Xor_assign<T>(), c);   return *this; }
  499.  
  500.         Matrix operator!() { return xfer(Matrix(*this, Not<T>())); }
  501.         Matrix operator-() { return xfer(Matrix(*this, Unary_minus<T>())); }
  502.         Matrix operator~() { return xfer(Matrix(*this, Complement<T>())); }
  503.  
  504.         template<class F> Matrix apply_new(F f) { return xfer(Matrix(*this, f)); }
  505.  
  506.         void swap_rows(Index i, Index j)
  507.             // swap_rows() uses a row's worth of memory for better run-time performance
  508.             // if you want pairwise swap, just write it yourself
  509.         {
  510.             if (i == j) return;
  511.             /*
  512.             Matrix<T,1> temp = (*this)[i];
  513.             (*this)[i] = (*this)[j];
  514.             (*this)[j] = temp;
  515.             */
  516.             Index max = (*this)[i].size();
  517.             for (Index ii = 0; ii<max; ++ii) std::swap((*this)(i, ii), (*this)(j, ii));
  518.         }
  519.     };
  520.  
  521.     //-----------------------------------------------------------------------------
  522.  
  523.     template<class T> class Matrix<T, 3> : public Matrix_base<T> {
  524.         const Index d1;
  525.         const Index d2;
  526.         const Index d3;
  527.  
  528.     protected:
  529.         // for use by Row:
  530.         Matrix(Index n1, Index n2, Index n3, T* p) : Matrix_base<T>(n1*n2*n3, p), d1(n1), d2(n2), d3(n3)
  531.         {
  532.             // std::cerr << "construct 3D Matrix from data\n";
  533.         }
  534.  
  535.     public:
  536.  
  537.         Matrix(Index n1, Index n2, Index n3) : Matrix_base<T>(n1*n2*n3), d1(n1), d2(n2), d3(n3) { }
  538.  
  539.         Matrix(Row<T, 3>& a) : Matrix_base<T>(a.dim1()*a.dim2()*a.dim3(), a.p), d1(a.dim1()), d2(a.dim2()), d3(a.dim3())
  540.         {
  541.             // std::cerr << "construct 3D Matrix from Row\n";
  542.         }
  543.  
  544.         // copy constructor: let the base do the copy:
  545.         Matrix(const Matrix& a) : Matrix_base<T>(a.size(), 0), d1(a.d1), d2(a.d2), d3(a.d3)
  546.         {
  547.             // std::cerr << "copy ctor\n";
  548.             this->base_copy(a);
  549.         }
  550.  
  551.         template<int n1, int n2, int n3>
  552.         Matrix(const T(&a)[n1][n2][n3]) : Matrix_base<T>(n1*n2), d1(n1), d2(n2), d3(n3)
  553.             // deduce "n1", "n2", "n3" (and "T"), Matrix_base allocates T[n1*n2*n3]
  554.         {
  555.             // std::cerr << "matrix ctor\n";
  556.             for (Index i = 0; i<n1; ++i)
  557.                 for (Index j = 0; j<n2; ++j)
  558.                     for (Index k = 0; k<n3; ++k)
  559.                         this->elem[i*n2*n3 + j*n3 + k] = a[i][j][k];
  560.         }
  561.  
  562.         template<class F> Matrix(const Matrix& a, F f) : Matrix_base<T>(a.size()), d1(a.d1), d2(a.d2), d3(a.d3)
  563.             // construct a new Matrix with element's that are functions of a's elements:
  564.             // does not modify a unless f has been specifically programmed to modify its argument
  565.             // T f(const T&) would be a typical type for f
  566.         {
  567.             for (Index i = 0; i<this->sz; ++i) this->elem[i] = f(a.elem[i]);
  568.         }
  569.  
  570.         template<class F, class Arg> Matrix(const Matrix& a, F f, const Arg& t1) : Matrix_base<T>(a.size()), d1(a.d1), d2(a.d2), d3(a.d3)
  571.             // construct a new Matrix with element's that are functions of a's elements:
  572.             // does not modify a unless f has been specifically programmed to modify its argument
  573.             // T f(const T&, const Arg&) would be a typical type for f
  574.         {
  575.             for (Index i = 0; i<this->sz; ++i) this->elem[i] = f(a.elem[i], t1);
  576.         }
  577.  
  578.         Matrix& operator=(const Matrix& a)
  579.             // copy assignment: let the base do the copy
  580.         {
  581.             // std::cerr << "copy assignment (" << this->size() << ',' << a.size()<< ")\n";
  582.             if (d1 != a.d1 || d2 != a.d2 || d3 != a.d3) error("length error in 2D =");
  583.             this->base_assign(a);
  584.             return *this;
  585.         }
  586.  
  587.         ~Matrix() { }
  588.  
  589.         Index dim1() const { return d1; }    // number of elements in a row
  590.         Index dim2() const { return d2; }    // number of elements in a column
  591.         Index dim3() const { return d3; }    // number of elements in a depth
  592.  
  593.         Matrix xfer()    // make an Matrix to move elements out of a scope
  594.         {
  595.             Matrix x(dim1(), dim2(), dim3(), this->data()); // make a descriptor
  596.             this->base_xfer(x);            // transfer (temporary) ownership to x
  597.             return x;
  598.         }
  599.  
  600.         void range_check(Index n1, Index n2, Index n3) const
  601.         {
  602.             // std::cerr << "range check: (" << d1 << "," << d2 << "): " << n1 << " " << n2 << "\n";
  603.             if (n1<0 || d1 <= n1) error("3D range error: dimension 1");
  604.             if (n2<0 || d2 <= n2) error("3D range error: dimension 2");
  605.             if (n3<0 || d3 <= n3) error("3D range error: dimension 3");
  606.         }
  607.  
  608.         // subscripting:
  609.         T& operator()(Index n1, Index n2, Index n3) { range_check(n1, n2, n3); return this->elem[d2*d3*n1 + d3*n2 + n3]; };
  610.         const T& operator()(Index n1, Index n2, Index n3) const { range_check(n1, n2, n3); return this->elem[d2*d3*n1 + d3*n2 + n3]; };
  611.  
  612.         // slicing (return a row):
  613.         Row<T, 2> operator[](Index n) { return row(n); }
  614.         const Row<T, 2> operator[](Index n) const { return row(n); }
  615.  
  616.         Row<T, 2> row(Index n) { range_check(n, 0, 0); return Row<T, 2>(d2, d3, &this->elem[n*d2*d3]); }
  617.         const Row<T, 2> row(Index n) const { range_check(n, 0, 0); return Row<T, 2>(d2, d3, &this->elem[n*d2*d3]); }
  618.  
  619.         Row<T, 3> slice(Index n)
  620.             // rows [n:d1)
  621.         {
  622.             if (n<0) n = 0;
  623.             else if (d1<n) n = d1;    // one beyond the end
  624.             return Row<T, 3>(d1 - n, d2, d3, this->elem + n*d2*d3);
  625.         }
  626.  
  627.         const Row<T, 3> slice(Index n) const
  628.             // rows [n:d1)
  629.         {
  630.             if (n<0) n = 0;
  631.             else if (d1<n) n = d1;    // one beyond the end
  632.             return Row<T, 3>(d1 - n, d2, d3, this->elem + n*d2*d3);
  633.         }
  634.  
  635.         Row<T, 3> slice(Index n, Index m)
  636.             // the rows [n:m)
  637.         {
  638.             if (n<0) n = 0;
  639.             if (d1<m) m = d1;    // one beyond the end
  640.             return Row<T, 3>(m - n, d2, d3, this->elem + n*d2*d3);
  641.  
  642.         }
  643.  
  644.         const Row<T, 3> slice(Index n, Index m) const
  645.             // the rows [n:sz)
  646.         {
  647.             if (n<0) n = 0;
  648.             if (d1<m) m = d1;    // one beyond the end
  649.             return Row<T, 3>(m - n, d2, d3, this->elem + n*d2*d3);
  650.         }
  651.  
  652.         // Column<T,2> column(Index n); // not (yet) implemented: requies strides and operations on columns
  653.  
  654.         // element-wise operations:
  655.         template<class F> Matrix& apply(F f) { this->base_apply(f);   return *this; }
  656.         template<class F> Matrix& apply(F f, const T& c) { this->base_apply(f, c); return *this; }
  657.  
  658.         Matrix& operator=(const T& c) { this->base_apply(Assign<T>(), c);       return *this; }
  659.  
  660.         Matrix& operator*=(const T& c) { this->base_apply(Mul_assign<T>(), c);   return *this; }
  661.         Matrix& operator/=(const T& c) { this->base_apply(Div_assign<T>(), c);   return *this; }
  662.         Matrix& operator%=(const T& c) { this->base_apply(Mod_assign<T>(), c);   return *this; }
  663.         Matrix& operator+=(const T& c) { this->base_apply(Add_assign<T>(), c);   return *this; }
  664.         Matrix& operator-=(const T& c) { this->base_apply(Minus_assign<T>(), c); return *this; }
  665.  
  666.         Matrix& operator&=(const T& c) { this->base_apply(And_assign<T>(), c);   return *this; }
  667.         Matrix& operator|=(const T& c) { this->base_apply(Or_assign<T>(), c);    return *this; }
  668.         Matrix& operator^=(const T& c) { this->base_apply(Xor_assign<T>(), c);   return *this; }
  669.  
  670.         Matrix operator!() { return xfer(Matrix(*this, Not<T>())); }
  671.         Matrix operator-() { return xfer(Matrix(*this, Unary_minus<T>())); }
  672.         Matrix operator~() { return xfer(Matrix(*this, Complement<T>())); }
  673.  
  674.         template<class F> Matrix apply_new(F f) { return xfer(Matrix(*this, f)); }
  675.  
  676.         void swap_rows(Index i, Index j)
  677.             // swap_rows() uses a row's worth of memory for better run-time performance
  678.             // if you want pairwise swap, just write it yourself
  679.         {
  680.             if (i == j) return;
  681.  
  682.             Matrix<T, 2> temp = (*this)[i];
  683.             (*this)[i] = (*this)[j];
  684.             (*this)[j] = temp;
  685.         }
  686.     };
  687.  
  688.     //-----------------------------------------------------------------------------
  689.  
  690.     template<class T> Matrix<T> scale_and_add(const Matrix<T>& a, T c, const Matrix<T>& b)
  691.         //  Fortran "saxpy()" ("fma" for "fused multiply-add").
  692.         // will the copy constructor be called twice and defeat the xfer optimization?
  693.     {
  694.         if (a.size() != b.size()) error("sizes wrong for scale_and_add()");
  695.         Matrix<T> res(a.size());
  696.         for (Index i = 0; i<a.size(); ++i) res[i] += a[i] * c + b[i];
  697.         return res.xfer();
  698.     }
  699.  
  700.     //-----------------------------------------------------------------------------
  701.  
  702.     template<class T> T dot_product(const Matrix<T>&a, const Matrix<T>& b)
  703.     {
  704.         if (a.size() != b.size()) error("sizes wrong for dot product");
  705.         T sum = 0;
  706.         for (Index i = 0; i<a.size(); ++i) sum += a[i] * b[i];
  707.         return sum;
  708.     }
  709.  
  710.     //-----------------------------------------------------------------------------
  711.  
  712.     template<class T, int N> Matrix<T, N> xfer(Matrix<T, N>& a)
  713.     {
  714.         return a.xfer();
  715.     }
  716.  
  717.     //-----------------------------------------------------------------------------
  718.  
  719.     template<class F, class A>            A apply(F f, A x) { A res(x, f);   return xfer(res); }
  720.     template<class F, class Arg, class A> A apply(F f, A x, Arg a) { A res(x, f, a); return xfer(res); }
  721.  
  722.     //-----------------------------------------------------------------------------
  723.  
  724.     // The default values for T and D have been declared before.
  725.     template<class T, int D> class Row {
  726.         // general version exists only to allow specializations
  727.     private:
  728.         Row();
  729.     };
  730.  
  731.     //-----------------------------------------------------------------------------
  732.  
  733.     template<class T> class Row<T, 1> : public Matrix<T, 1> {
  734.     public:
  735.         Row(Index n, T* p) : Matrix<T, 1>(n, p)
  736.         {
  737.         }
  738.  
  739.         Matrix<T, 1>& operator=(const T& c) { this->base_apply(Assign<T>(), c); return *this; }
  740.  
  741.         Matrix<T, 1>& operator=(const Matrix<T, 1>& a)
  742.         {
  743.             return *static_cast<Matrix<T, 1>*>(this) = a;
  744.         }
  745.     };
  746.  
  747.     //-----------------------------------------------------------------------------
  748.  
  749.     template<class T> class Row<T, 2> : public Matrix<T, 2> {
  750.     public:
  751.         Row(Index n1, Index n2, T* p) : Matrix<T, 2>(n1, n2, p)
  752.         {
  753.         }
  754.  
  755.         Matrix<T, 2>& operator=(const T& c) { this->base_apply(Assign<T>(), c); return *this; }
  756.  
  757.         Matrix<T, 2>& operator=(const Matrix<T, 2>& a)
  758.         {
  759.             return *static_cast<Matrix<T, 2>*>(this) = a;
  760.         }
  761.     };
  762.  
  763.     //-----------------------------------------------------------------------------
  764.  
  765.     template<class T> class Row<T, 3> : public Matrix<T, 3> {
  766.     public:
  767.         Row(Index n1, Index n2, Index n3, T* p) : Matrix<T, 3>(n1, n2, n3, p)
  768.         {
  769.         }
  770.  
  771.         Matrix<T, 3>& operator=(const T& c) { this->base_apply(Assign<T>(), c); return *this; }
  772.  
  773.         Matrix<T, 3>& operator=(const Matrix<T, 3>& a)
  774.         {
  775.             return *static_cast<Matrix<T, 3>*>(this) = a;
  776.         }
  777.     };
  778.  
  779.     //-----------------------------------------------------------------------------
  780.  
  781.     template<class T, int N> Matrix<T, N - 1> scale_and_add(const Matrix<T, N>& a, const Matrix<T, N - 1> c, const Matrix<T, N - 1>& b)
  782.     {
  783.         Matrix<T> res(a.size());
  784.         if (a.size() != b.size()) error("sizes wrong for scale_and_add");
  785.         for (Index i = 0; i<a.size(); ++i) res[i] += a[i] * c + b[i];
  786.         return res.xfer();
  787.     }
  788.  
  789.     //-----------------------------------------------------------------------------
  790.  
  791.     template<class T, int D> Matrix<T, D> operator*(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r *= c; }
  792.     template<class T, int D> Matrix<T, D> operator/(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r /= c; }
  793.     template<class T, int D> Matrix<T, D> operator%(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r %= c; }
  794.     template<class T, int D> Matrix<T, D> operator+(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r += c; }
  795.     template<class T, int D> Matrix<T, D> operator-(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r -= c; }
  796.  
  797.     template<class T, int D> Matrix<T, D> operator&(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r &= c; }
  798.     template<class T, int D> Matrix<T, D> operator|(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r |= c; }
  799.     template<class T, int D> Matrix<T, D> operator^(const Matrix<T, D>& m, const T& c) { Matrix<T, D> r(m); return r ^= c; }
  800.  
  801.     //-----------------------------------------------------------------------------
  802.  
  803. }
  804. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement