// -*-C++-*-
// Copyright (C) 2004
// Christian Stimming <stimming@tuhh.de>
//
// Row-order modifications by Jacob (Jack) Gryn <jgryn at cs dot yorku dot ca>
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2, 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 Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
/** @file
* @brief General Dense Rectangular Matrix Class
*/
// LAPACK++ (V. 1.0a Beta)
// (C) 1992-1996 All Rights Reserved.
//
// Lapack++ Rectangular Matrix Class
//
// Dense (nonsingular) matrix, assumes no special structure or properties.
//
// ) allows 2-d indexing
// ) non-unit strides
// ) inject assignment
// ) std::cout << A.info() prints out internal states of A
// ) indexing via A(i,j) where i,j are either integers or
// LaIndex
#ifndef _LA_GEN_MAT_DOUBLE_H_
#define _LA_GEN_MAT_DOUBLE_H_
#include "arch.h"
#include "lafnames.h"
#include VECTOR_DOUBLE_H
#include LA_INDEX_H
#include LA_GEN_MAT_FLOAT_H
class LaGenMatComplex;
class LaGenMatDouble;
class LaGenMatFloat;
class LaGenMatInt;
class LaGenMatLongInt;
/** \brief General Dense Rectangular Matrix Class
*
* This is the basic LAPACK++ matrix. It is a dense (nonsingular)
* matrix, assumes no special structure or properties.
*
* - allows 2-d indexing
* - non-unit strides
* - inject assignment
* - std::cout << A.info() prints out internal states of A
* - indexing via A(i,j) where i,j are either integers or LaIndex
*
* Multiplication of this matrix should be done by the functions in
* blas1pp.h, blas2pp.h and blas3pp.h,
* e.g. Blas_Mat_Mat_Mult(). (There are also some operators in
* blaspp.h, but we advice against them because they will always
* allocate a new matrix for the result even though you usually
* already have a matrix at hand for writing the result into.)
* Transpositions of matrices usually do not have to be calculated
* explicitly, but you can directly use the different multiplication
* functions that will use a matrix as a transposed one,
* e.g. Blas_Mat_Trans_Mat_Mult().
*/
class DLLIMPORT LaGenMatDouble
{
public:
/** The type of the value elements. */
typedef double value_type;
/** Convenience typedef of this class to itself to make
* common function definitions easier. (New in
* lapackpp-2.4.5) */
typedef LaGenMatDouble matrix_type;
/** Internal wrapper type; don't use that in an
* application. */
typedef VectorDouble vec_type;
private:
vec_type v;
LaIndex ii[2];
int dim[2]; // size of original matrix, not submatrix
int sz[2]; // size of this submatrix
void init(int m, int n);
static int debug_; // trace all entry and exits into methods and
// operators of this class. This variable is
// explicitly initalized in gmd.cc
static int *info_; // print matrix info only, not values
// originally 0, set to 1, and then
// reset to 0 after use.
// use as in
//
// std::cout << B.info() << std::endl;
//
// this *info_ member is unique in that it really isn't
// part of the matrix info, just a flag as to how
// to print it. We've included in this beta release
// as part of our testing, but we do not expect it
// to be user accessable.
// It has to be declared as global static
// so that we may monitor expresssions like
// X::(const &X) and still utilize without violating
// the "const" condition.
// Because this *info_ is used at most one at a time,
// there is no harm in keeping only one copy of it,
// also, we do not need to malloc free space every time
// we call a matrix constructor.
int shallow_; // set flag to '0' in order to return matrices
// by value from functions without unecessary
// copying.
// users shouldn't be able to modify assignment semantics..
//
//LaGenMatDouble& shallow_assign();
public:
/** @name Declaration */
//@{
/*::::::::::::::::::::::::::*/
/* Constructors/Destructors */
/*::::::::::::::::::::::::::*/
/** Constructs a null 0x0 matrix. */
LaGenMatDouble();
/** Constructs a column-major matrix of size \f$m\times
* n\f$. Matrix elements are NOT initialized! */
LaGenMatDouble(int m, int n);
/** Constructs an \f$m\times n\f$ matrix by using the values
* from the one-dimensional C array \c v of length \c m*n.
*
* \note If \c row_ordering is \c false, then the data will \e
* not be copied but instead the C array will be shared
* (shallow copy). In that case, you must not delete the C
* array as long as you use this newly created matrix. Also,
* if you need a copy (deep copy), construct one matrix \c A
* by this constructor, and then copy this content into a
* second matrix by \c B.copy(A). On the other hand, if \c
* row_ordering is \c true, then the data will be copied
* immediately (deep copy).
*
* \param v The one-dimensional C array of size \c m*n whose
* data should be used. If \c row_ordering is \c false, then
* the data will \e not be copied but shared (shallow
* copy). If \c row_ordering is \c true, then the data will be
* copied (deep copy).
*
* \param m The number of rows in the new matrix.
*
* \param n The number of columns in the new matrix.
*
* \param row_ordering If \c false, then the C array is used
* in column-order, i.e. the first \c m elements of \c v are
* used as the first column of the matrix, the next \c m
* elements are the second column and so on. (This is the
* default and this is also the internal storage format in
* order to be compatible with the underlying Fortran
* subroutines.) If this is \c true, then the C array is used
* in row-order, i.e. the first \c n elements of \c v are used
* as the first row of the matrix, the next \c n elements are
* the second row and so on. (Internally, this is achieved by
* allocating a new copy of the array and copying the array
* into the internal ordering.)
*/
LaGenMatDouble(double*v, int m, int n, bool row_ordering=false);
/** Create a new matrix from an existing one by copying.
*
* Watch out! Due to the C++ "named return value optimization"
* you cannot use this as an alias for copy() when declaring a
* variable if the right-side is a return value of
* operator(). More precisely, you cannot write the following:
* \verbatim
LaGenMatDouble x( y(LaIndex(),LaIndex()) ); // erroneous reference copy!
\endverbatim
*
* Instead, if the initialization should create a new copy of
* the right-side matrix, you have to write it this way:
* \verbatim
LaGenMatDouble x( y(LaIndex(),LaIndex()).copy() ); // correct deep-copy
\endverbatim
*
* Or this way:
* \verbatim
LaGenMatDouble x;
x = y(LaIndex(),LaIndex()); // correct deep-copy
\endverbatim
*/
LaGenMatDouble(const LaGenMatDouble&);
/** Create a new matrix from an existing one by copying and
* converting each element from a float to a double. */
explicit LaGenMatDouble(const LaGenMatFloat&);
/** Resize to a \e new matrix of size m x n. The element
* values of the new matrix are \e uninitialized, even if
* resizing to a smaller matrix. */
LaGenMatDouble& resize(int m, int n);
/** Resize to a \e new matrix of the same size as the given
* matrix s. The element values of the new matrix are \e
* uninitialized, even if resizing to a smaller matrix. */
LaGenMatDouble& resize(const LaGenMatDouble& s);
/** Destroy matrix and reclaim vector memory space if this is
* the only structure using it. */
virtual ~LaGenMatDouble();
//@}
/** @name Information Predicates */
//@{
/** Returns true if this is an all-zero matrix. (New in
* lapackpp-2.4.5) */
bool is_zero() const;
/** Returns true if this matrix is only a submatrix view of
* another (larger) matrix. (New in lapackpp-2.4.4) */
bool is_submatrixview() const
{ return size(0) != gdim(0) || size(1) != gdim(1); };
/** Returns true if this matrix has unit stride.
*
* This is a necessary condition for not being a submatrix
* view, but it's not sufficient. (New in lapackpp-2.4.4) */
bool has_unitstride() const
{ return inc(0) == 1 && inc(1) == 1; };
/** Returns true if the given matrix \c mat is exactly equal
* to this object. (New in lapackpp-2.4.5) */
bool equal_to(const LaGenMatDouble& mat) const;
//@}
/** @name Information */
//@{
/*::::::::::::::::::::::::::::::::*/
/* Indices and access operations */
/*::::::::::::::::::::::::::::::::*/
/** Returns the length n of the dth dimension, i.e. for a M x
* N matrix, \c size(0) returns M and \c size(1) returns N. */
inline int size(int d) const; // submatrix size
/** Returns the number of columns, i.e. for a M x N matrix
* this returns N. New in lapackpp-2.4.4. */
inline int cols() const { return size(1); }
/** Returns the number of rows, i.e. for a M x N matrix this
* returns M. New in lapackpp-2.4.4. */
inline int rows() const { return size(0); }
/** Returns the distance between memory locations (in terms of
* number of elements) between consecutive elements along
* dimension d. For example, if \c inc(d) returns 1, then
* elements along the dth dimension are contiguous in
* memory. */
inline int inc(int d) const; // explicit increment
/** Returns the global dimensions of the (possibly larger)
* matrix owning this space. This will only differ from \c
* size(d) if the current matrix is actually a submatrix view
* of some larger matrix. */
inline int gdim(int d) const; // global dimensions
/** If the memory space used by this matrix is viewed as a
* linear array, \c start(d) returns the starting offset of
* the first element in dimension \c d. (See \ref LaIndex
* class.) */
inline int start(int d) const; // return ii[d].start()
/** If the memory space used by this matrix is viewed as a
* linear array, \c end(d) returns the starting offset of the
* last element in dimension \c d. (See \ref LaIndex
* class.) */
inline int end(int d) const; // return ii[d].end()
/** Returns the index specifying this submatrix view in
* dimension \c d. (See \ref LaIndex class.) This will only
* differ from a unit-stride index if the current matrix is
* actually a submatrix view of some larger matrix. */
inline LaIndex index(int d) const;// index
/** Returns the number of data objects which utilize the same
* (or portions of the same) memory space used by this
* matrix. */
inline int ref_count() const;
/** Returns the memory address of the first element of the
* matrix. \c G.addr() is equivalent to \c &G(0,0) . */
inline double* addr() const; // begining addr of data space
//@}
/** @name Access functions */
//@{
/** Returns the \f$(i,j)\f$th element of this matrix, with the
* indices i and j starting at zero (zero-based offset). This
* means you have
*
* \f[ A_{n\times m} = \left(\begin{array}{ccc} a_{11} & &
* a_{1m} \\ & \ddots & \\ a_{n1} & & a_{nm}
* \end{array}\right)
* \f]
*
* but for accessing the element \f$a_{11}\f$ you have to
* write @c A(0,0).
*
* Optional runtime bounds checking (0<=i<m, 0<=j<n) is set
* by the compile time macro LA_BOUNDS_CHECK. */
inline double& operator()(int i, int j);
/** Returns the \f$(i,j)\f$th element of this matrix, with the
* indices i and j starting at zero (zero-based offset). This
* means you have
*
* \f[ A_{n\times m} = \left(\begin{array}{ccc} a_{11} & &
* a_{1m} \\ & \ddots & \\ a_{n1} & & a_{nm}
* \end{array}\right) \f]
*
* but for accessing the element \f$a_{11}\f$ you have to
* write @c A(0,0).
*
* Optional runtime bounds checking (0<=i<m, 0<=j<n) is set
* by the compile time macro LA_BOUNDS_CHECK. */
inline double& operator()(int i, int j) const;
/** Return a submatrix view specified by the indices I and
* J. (See \ref LaIndex class.) These indices specify start,
* increment, and ending offsets, similar to triplet notation
* of Matlab or Fortran 90. For example, if B is a 10 x 10
* matrix, I is \c (0:2:2) and J is \c (3:1:4), then \c B(I,J)
* denotes the 2 x 2 matrix
*
* \f[ \left(\begin{array}{cc} b_{0,3} & b_{2,3} \\
* b_{0,4} & b_{4,4}
* \end{array}\right) \f]
*/
LaGenMatDouble operator()(const LaIndex& I, const LaIndex& J) ;
/** Return a submatrix view specified by the indices I and
* J. (See \ref LaIndex class.) These indices specify start,
* increment, and ending offsets, similar to triplet notation
* of Matlab or Fortran 90. For example, if B is a 10 x 10
* matrix, I is \c (0:2:2) and J is \c (3:1:4), then \c B(I,J)
* denotes the 2 x 2 matrix
*
* \f[ \left(\begin{array}{cc} b_{0,3} & b_{2,3} \\
* b_{0,4} & b_{4,4}
* \end{array}\right) \f]
*/
LaGenMatDouble operator()(const LaIndex& I, const LaIndex& J) const;
/** Returns a submatrix view for the specified row \c k of
* this matrix.
*
* The returned object references still the same memory as
* this object, so if you modify elements, they will appear
* modified in both objects. (New in lapackpp-2.4.6) */
LaGenMatDouble row(int k);
/** Returns a submatrix view for the specified row \c k of
* this matrix.
*
* The returned object references still the same memory as
* this object, so if you modify elements, they will appear
* modified in both objects. (New in lapackpp-2.4.6) */
LaGenMatDouble row(int k) const;
/** Returns a submatrix view for the specified column \c k
* of this matrix.
*
* The returned object references still the same memory as
* this object, so if you modify elements, they will appear
* modified in both objects. (New in lapackpp-2.4.6) */
LaGenMatDouble col(int k);
/** Returns a submatrix view for the specified column \c k
* of this matrix.
*
* The returned object references still the same memory as
* this object, so if you modify elements, they will appear
* modified in both objects. (New in lapackpp-2.4.6) */
LaGenMatDouble col(int k) const;
//@}
/** @name Assignments */
//@{
/** Set elements of left-hand side to the scalar value s. No
* new matrix is created, so that if there are other matrices
* that reference this memory space, they will also be
* affected. */
LaGenMatDouble& operator=(double s);
/** Release left-hand side (reclaiming memory space if
* possible) and copy elements of elements of \c s. Unline \c
* inject(), it does not require conformity, and previous
* references of left-hand side are unaffected.
*
* This is an alias for copy().
*
* Watch out! Due to the C++ "named return value optimization"
* you cannot use this as an alias for copy() when declaring a
* variable if the right-side is a return value of
* operator(). More precisely, you cannot write the following:
* \verbatim
LaGenMatDouble x = y(LaIndex(),LaIndex()); // erroneous reference copy!
\endverbatim
*
* Instead, if the initialization should create a new copy of
* the right-side matrix, you have to write it this way:
* \verbatim
LaGenMatDouble x = y(LaIndex(),LaIndex()).copy(); // correct deep-copy
\endverbatim
*
* Or this way:
* \verbatim
LaGenMatDouble x;
x = y(LaIndex(),LaIndex()); // correct deep-copy
\endverbatim
*
* Note: The manual for lapack++-1.1 claimed that this
* operator would be an alias for ref(), not for copy(),
* i.e. this operator creates a reference instead of a deep
* copy. However, since that confused many people, the
* behaviour was changed so that B=A will now create B as a
* deep copy instead of a reference. If you want a
* reference, please write B.ref(A) explicitly.
*/
LaGenMatDouble& operator=(const LaGenMatDouble& s);
/** Add the scalar value s to elements of left-hand side. No
* new matrix is created, so that if there are other matrices
* that reference this memory space, they will also be
* affected.
*
* @note This method is rather slow. In many cases, it can
* be much faster to use Blas_Mat_Mult() with a Ones-Matrix
* instead. */
LaGenMatDouble& operator+=(double s);
/** Add the scalar value s to elements of left-hand side. No
* new matrix is created, so that if there are other matrices
* that reference this memory space, they will also be
* affected. (New in lapackpp-2.4.7.) */
LaGenMatDouble& add(double s);
/** Scale the left-hand side matrix by the given scalar
* value. No new matrix is created, so that if there are
* other matrices that reference this memory space, they
* will also be affected. (New in lapackpp-2.4.7.) */
LaGenMatDouble& operator*=(double s);
/** Scale the left-hand side matrix by the given scalar
* value. No new matrix is created, so that if there are
* other matrices that reference this memory space, they
* will also be affected. (New in lapackpp-2.4.7.) */
LaGenMatDouble& scale(double s);
/** Copy elements of s into the memory space referenced by the
* left-hand side, without first releasing it. The effect is
* that if other matrices share memory with left-hand side,
* they too will be affected. Note that the size of s must be
* the same as that of the left-hand side matrix.
*
* @note If you rather wanted to create a new copy of \c s,
* you should use \c copy() instead. */
LaGenMatDouble& inject(const LaGenMatDouble& s);
/** Release left-hand side (reclaiming memory space if
* possible) and copy elements of elements of \c s. Unline \c
* inject(), it does not require conformity, and previous
* references of left-hand side are unaffected. */
LaGenMatDouble& copy(const LaGenMatDouble& s);
/** Returns a newly allocated matrix that is an
* element-by-element copy of this matrix.
*
* New in lapackpp-2.5.2 */
LaGenMatDouble copy() const;
/** This is an optimization for returning temporary matrices
* from functions, without copying. The shallow_assign()
* function essentially sets an internal flag which instructs
* the \c X::X(&X) copy constructor to avoid the copying. */
inline LaGenMatDouble& shallow_assign();
/** Let this matrix reference the given matrix s, so that the
* given matrix memory s is now referenced by multiple objects
* (by the given object s and now also by this object). Handle
* this with care!
*
* This function releases any previously referenced memory of
* this object. */
LaGenMatDouble& ref(const LaGenMatDouble& s);
//@}
/** @name Expensive access functions */
//@{
/** Returns a newly allocated large matrix that consists of
* \c M-by-N copies of the given matrix. (New in
* lapackpp-2.4.5.) */
LaGenMatDouble repmat (int M, int N) const;
/** Returns the trace, i.e. the sum of all diagonal elements
* of the matrix. (New in lapackpp-2.4.5) */
value_type trace () const;
/** Returns a newly allocated column vector of dimension \c
* Nx1 that contains the diagonal of the given matrix. (New
* in lapackpp-2.4.5) */
LaGenMatDouble diag () const;
//@}
/** @name Debugging information */
//@{
/** Returns global shallow flag */
inline int shallow() const // read global shallow flag
{ return shallow_;}
/** Returns global debug flag */
inline int debug() const; // read global debug flag
/** Set global debug flag */
inline int debug(int d); // set global debug flag
/**
// use as in
//
// std::cout << B.info() << std::endl;
//
// this *info_ member is unique in that it really isn't
// part of the matrix info, just a flag as to how
// to print it. We've included in this beta release
// as part of our testing, but we do not expect it
// to be user accessable.
*/
inline const LaGenMatDouble& info() const {
*(const_cast<LaGenMatDouble*>(this)->info_) = 1;
return *this;
};
/** Print the matrix info (not the actual elements) to the
* given ostream. */
inline std::ostream& Info(std::ostream& s) const
{
s << "Size: (" << size(0) << "x" << size(1) << ") " ;
s << "Indeces: " << ii[0] << " " << ii[1];
s << "#ref: " << ref_count()
<< "addr: " << addr() << " shallow:" << shallow_ << std::endl;
return s;
};
//@}
/** Print the matrix to the given output stream. If the matrix
* info flag is set, then this prints only the matrix info,
* see LaGenMatDouble::info(). Otherwise all matrix elements
* are printed.
*
* @see LaPreferences::setPrintFormat()
*/
friend DLLIMPORT std::ostream& operator<<(std::ostream&, const LaGenMatDouble&);
/** @name Matrix type conversions */
//@{
/** Convert this matrix to a complex matrix with imaginary part zero. */
LaGenMatComplex to_LaGenMatComplex() const;
/** Convert this matrix to a float (floating-point single precision) matrix. */
LaGenMatFloat to_LaGenMatFloat() const;
/** Convert this matrix to an int matrix. */
LaGenMatInt to_LaGenMatInt() const;
/** Convert this matrix to a long int matrix. */
LaGenMatLongInt to_LaGenMatLongInt() const;
//@}
/** @name Constructors for elementary matrices */
//@{
/** Returns a newly allocated all-zero matrix of dimension
* \c NxN, if \c M is not given, or \c NxM if \c M is given.
* (New in lapackpp-2.4.5) */
static LaGenMatDouble zeros (int N, int M=0);
/** Returns a newly allocated all-one matrix of dimension \c
* NxN, if \c M is not given, or \c NxM if \c M is given.
* (New in lapackpp-2.4.5) */
static LaGenMatDouble ones (int N, int M=0);
/** Returns a newly allocated identity matrix of dimension
* \c NxN, if \c M is not given, or a rectangular matrix \c
* NxM if \c M is given. (New in lapackpp-2.4.5) */
static LaGenMatDouble eye (int N, int M=0);
/** Returns a newly allocated matrix of dimension \c NxM
* with pseudo-random values. The values are uniformly
* distributed in the interval \c (0,1) or, if specified, \c
* (low,high). (New in lapackpp-2.4.5)
*
* Note: Since this uses the system's \c rand() call, the
* randomness of the values might be questionable -- don't
* use this if you need really strong random numbers. */
static LaGenMatDouble rand (int N, int M,
value_type low=0, value_type high=1);
/** Returns a newly allocated diagonal matrix of dimension
* \c NxN that has the vector \c vect of length \c N on the
* diagonal. (New in lapackpp-2.4.5) */
static LaGenMatDouble from_diag (const LaGenMatDouble &vect);
/** Returns a newly allocated linarly spaced column vector
* with \c nr_points elements, between and including \c
* start and \c end. (New in lapackpp-2.4.5.) */
static LaGenMatDouble linspace (value_type start, value_type end,
int nr_points);
//@}
}; //* End of LaGenMatDouble Class *//
namespace la {
/** The basic matrix data type containing double values. */
typedef LaGenMatDouble mat;
} // namespace
/** Print the matrix to the given output stream. If the matrix
* info flag is set, then this prints only the matrix info,
* see LaGenMatDouble::info(). Otherwise all matrix elements
* are printed.
*
* @see LaPreferences::setPrintFormat()
*/
DLLIMPORT
std::ostream& operator<<(std::ostream&, const LaGenMatDouble&);
//* Member Functions *//
inline int LaGenMatDouble::size(int d) const
{
return sz[d];
}
inline int LaGenMatDouble::inc(int d) const
{
return ii[d].inc();
}
inline int LaGenMatDouble::gdim(int d) const
{
return dim[d];
}
inline int LaGenMatDouble::start(int d) const
{
return ii[d].start();
}
inline int LaGenMatDouble::end(int d) const
{
return ii[d].end();
}
inline int LaGenMatDouble::ref_count() const
{
return v.ref_count();
}
inline LaIndex LaGenMatDouble::index(int d) const
{
return ii[d];
}
inline double* LaGenMatDouble::addr() const
{
return v.addr();
}
inline int LaGenMatDouble::debug() const
{
return debug_;
}
inline int LaGenMatDouble::debug(int d)
{
return debug_ = d;
}
inline double& LaGenMatDouble::operator()(int i, int j)
{
#ifdef LA_BOUNDS_CHECK
assert(i>=0);
assert(i<size(0));
assert(j>=0);
assert(j<size(1));
#endif
return v( dim[0]*(ii[1].start() + j*ii[1].inc()) +
ii[0].start() + i*ii[0].inc());
}
inline double& LaGenMatDouble::operator()(int i, int j) const
{
#ifdef LA_BOUNDS_CHECK
assert(i>=0);
assert(i<size(0));
assert(j>=0);
assert(j<size(1));
#endif
return v( dim[0]*(ii[1].start() + j*ii[1].inc()) +
ii[0].start() + i*ii[0].inc());
}
inline LaGenMatDouble& LaGenMatDouble::shallow_assign()
{
shallow_ = 1;
return *this;
}
#endif
// _LA_GEN_MAT_H_
syntax highlighted by Code2HTML, v. 0.9.1