//# Matrix.h: A 2-D Specialization of the Array Class //# Copyright (C) 1993,1994,1995,1996,1999,2000,2001,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #ifndef CASA_MATRIX_2_H #define CASA_MATRIX_2_H //# Includes #include "Array.h" namespace casacore { //#Begin casa namespace // A 2-D Specialization of the Array class // // // // Matrix objects are two-dimensional specializations (e.g., more convenient // and efficient indexing) of the general Array class. You might also want // to look at the Array documentation to see inherited functionality. A // tutorial on using the array classes in general is available in the // "AIPS++ Programming Manual". // // Generally the member functions of Array are also available in // Matrix versions which take a pair of integers where the array // needs an IPosition. Since the Matrix // is two-dimensional, the IPositions are overkill, although you may // use those versions if you want to. // // Matrix mi(100,100); // Shape is 100x100 // mi.resize(50,50); // Shape now 50x50 // // // Slices may be taken with the Slice class. To take a slice, one "indexes" // with one Slice(start, length, inc) for each axis, // where end and inc are optional. // Additionally, there are row(), column() and diagonal() // member functions which return Vector's which refer to the storage back // in the Matrix: // // Matrix mf(100, 100); // mf.diagonal() = 1; // // // Correct indexing order of a matrix is: // // Matrix mi(n1,n2) // [nrow, ncolumn] // for (size_t j=0; j // // // Element-by-element arithmetic and logical operations are available (in // aips/ArrayMath.h and aips/ArrayLogical.h). Other Matrix operations (e.g. // LU decomposition) are available, and more appear periodically. // // As with the Arrays, if the preprocessor symbol AIPS_DEBUG is // defined at compile time invariants will be checked on entry to most // member functions. Additionally, if AIPS_ARRAY_INDEX_CHECK is defined // index operations will be bounds-checked. Neither of these should // be defined for production code. template class Matrix : public Array { public: // A Matrix of length zero in each dimension; zero origin. Matrix(const Alloc& allocator = Alloc()); // A Matrix with "l1" rows and "l2" columns. // Fill it with the initial value. Matrix(size_t l1, size_t l2, const T &initialValue = T(), const Alloc& allocator = Alloc()); // An uninitialized Matrix with "l1" rows and "l2" columns. Matrix(size_t l1, size_t l2, typename Array::uninitializedType, const Alloc& allocator = Alloc()); // A matrix of shape with shape "len". // Fill it with the initial value. Matrix(const IPosition &len, const T &initialValue = T(), const Alloc& allocator = Alloc()); // An uninitialized matrix of shape with shape "len". Matrix(const IPosition &len, typename Array::uninitializedType, const Alloc& allocator = Alloc()); // The copy/move constructor uses reference semantics. Matrix(const Matrix& source); Matrix(Matrix&& source); // Construct a Matrix by reference from "source". "source must have // ndim() of 2 or less. Matrix(const Array& source); Matrix(Array&& source); // Create an Matrix of a given shape from a pointer. Matrix(const IPosition &shape, T *storage, StorageInitPolicy policy = COPY, const Alloc& allocator = Alloc()); // Create an Matrix of a given shape from a pointer. Because the pointer // is const, a copy is always made. Matrix(const IPosition &shape, const T *storage); // Create an identity matrix of side length n. (Could not do this as a constructor // because of ambiguities with other constructors). static Matrix identity (size_t n); // Resize to the given shape // using Array::resize; void resize(size_t nx, size_t ny, bool copyValues=false); // Matrix& operator=(const Matrix& source) { return assign_conforming(source); } Matrix& operator=(Matrix&& source) { return assign_conforming(std::move(source)); } Matrix& operator=(const Array& source) { return assign_conforming(source); } Matrix& operator=(Array&& source) { return assign_conforming(std::move(source)); } // Copy the values from other to this Matrix. If this matrix has zero // elements then it will resize to be the same shape as other; otherwise // other must conform to this. // Note that the assign function can be used to assign a // non-conforming matrix. // Matrix& assign_conforming(const Matrix& source) { Array::assign_conforming(source); return *this; } Matrix& assign_conforming(Matrix&& source) { Array::assign_conforming(std::move(source)); return *this; } Matrix& assign_conforming(const Array& source) { // TODO Should be supported by the Array class, // see Cube::operator=(const Array&) if (source.ndim() == 2) { Array::assign_conforming(source); } else { // This might work if a.ndim == 1 or 2 (*this) = Matrix(source); } return *this; } Matrix& assign_conforming(Array&& source) { if (source.ndim() == 2) { Array::assign_conforming(std::move(source)); } else { (*this) = Matrix(std::move(source)); } return *this; } // // Copy val into every element of this Matrix; i.e. behaves as if // val were a constant conformant matrix. Array& operator=(const T &val) { return Array::operator=(val); } // Copy to this those values in marray whose corresponding elements // in marray's mask are true. Matrix& assign_conforming (const MaskedArray &marray) { Array::assign_conforming(marray); return *this; } // Single-pixel addressing. If AIPS_ARRAY_INDEX_CHECK is defined, // bounds checking is performed. // T &operator()(const IPosition &i) { return Array::operator()(i); } const T &operator()(const IPosition &i) const { return Array::operator()(i); } T &operator()(size_t i1, size_t i2) { return this->contiguous_p ? this->begin_p[i1 + i2*yinc()] : this->begin_p[i1*xinc() + i2*yinc()]; } const T &operator()(size_t i1, size_t i2) const { return this->contiguous_p ? this->begin_p[i1 + i2*yinc()] : this->begin_p[i1*xinc() + i2*yinc()]; } // // The array is masked by the input LogicalArray. // This mask must conform to the array. // // Return a MaskedArray. MaskedArray operator() (const LogicalArray &mask) const { return Array::operator() (mask); } // Return a MaskedArray. MaskedArray operator() (const LogicalArray &mask) { return Array::operator() (mask); } // // The array is masked by the input MaskedLogicalArray. // The mask is effectively the AND of the internal LogicalArray // and the internal mask of the MaskedLogicalArray. // The MaskedLogicalArray must conform to the array. // // Return a MaskedArray. MaskedArray operator() (const MaskedLogicalArray &mask) const { return Array::operator() (mask); } // Return a MaskedArray. MaskedArray operator() (const MaskedLogicalArray &mask) { return Array::operator() (mask); } // // Returns a reference to the i'th row. // Vector row(size_t i); const Vector row(size_t i) const; // // Returns a reference to the j'th column // Vector column(size_t j); const Vector column(size_t j) const; // // Returns a diagonal from the Matrix. The Matrix must be square. // n==0 is the main diagonal. n>0 is above the main diagonal, n<0 // is below it. // Vector diagonal(long long n=0); const Vector diagonal(long long n=0) const; // // Take a slice of this matrix. Slices are always indexed starting // at zero. This uses reference semantics, i.e. changing a value // in the slice changes the original. // // Matrix vd(100,100); // //... // vd(Slice(0,10),Slice(10,10)) = -1.0; // 10x10 sub-matrix set to -1.0 // // Matrix operator()(const Slice &sliceX, const Slice &sliceY); const Matrix operator()(const Slice &sliceX, const Slice &sliceY) const; // // Slice using IPositions. Required to be defined, otherwise the base // class versions are hidden. // Array operator()(const IPosition &blc, const IPosition &trc, const IPosition &incr) { return Array::operator()(blc,trc,incr); } const Array operator()(const IPosition &blc, const IPosition &trc, const IPosition &incr) const { return Array::operator()(blc,trc,incr); } Array operator()(const IPosition &blc, const IPosition &trc) { return Array::operator()(blc,trc); } const Array operator()(const IPosition &blc, const IPosition &trc) const { return Array::operator()(blc,trc); } Array operator()(const Slicer& slicer) { return Array::operator()(slicer); } const Array operator()(const Slicer& slicer) const { return Array::operator()(slicer); } // // The length of each axis of the Matrix. const IPosition &shape() const { return this->length_p; } void shape(int &s1, int &s2) const { s1 = this->length_p(0); s2=this->length_p(1); } // The number of rows in the Matrix, i.e. the length of the first axis. size_t nrow() const { return this->length_p(0); } // The number of columns in the Matrix, i.e. the length of the 2nd axis. size_t ncolumn() const { return this->length_p(1); } // Checks that the Matrix is consistent (invariants check out). virtual bool ok() const override; protected: virtual void preTakeStorage(const IPosition &shape) override; // Remove the degenerate axes from other and store result in this matrix. // An exception is thrown if removing degenerate axes does not result // in a matrix. virtual void doNonDegenerate(const Array &other, const IPosition &ignoreAxes) override; virtual size_t fixedDimensionality() const override { return 2; } private: // Cached constants to improve indexing. // size_t xinc_p, yinc_p; size_t xinc() const { return this->inc_p(0); } size_t yinc() const { return this->inc_p(1)*this->originalLength_p(0); } }; //# Declare extern templates for often used types. extern template class Matrix; extern template class Matrix; extern template class Matrix; } //#End casa namespace #include "Matrix.tcc" #endif