Simbody

MatrixHelper.h

Go to the documentation of this file.
00001 #ifndef SimTK_SIMMATRIX_MATRIX_HELPER_H_
00002 #define SimTK_SIMMATRIX_MATRIX_HELPER_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                      SimTK Core: SimTK Simmatrix(tm)                       *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK Core biosimulation toolkit originating from      *
00008  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00009  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00010  * Medical Research, grant U54 GM072970. See https://simtk.org.               *
00011  *                                                                            *
00012  * Portions copyright (c) 2005-9 Stanford University and the Authors.         *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Permission is hereby granted, free of charge, to any person obtaining a    *
00017  * copy of this software and associated documentation files (the "Software"), *
00018  * to deal in the Software without restriction, including without limitation  *
00019  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
00020  * and/or sell copies of the Software, and to permit persons to whom the      *
00021  * Software is furnished to do so, subject to the following conditions:       *
00022  *                                                                            *
00023  * The above copyright notice and this permission notice shall be included in *
00024  * all copies or substantial portions of the Software.                        *
00025  *                                                                            *
00026  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
00027  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
00028  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
00029  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
00030  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
00031  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
00032  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
00033  * -------------------------------------------------------------------------- */
00034 
00045 #include "SimTKcommon/Scalar.h"
00046 
00047 #include <iostream>
00048 #include <cassert>
00049 #include <complex>
00050 #include <cstddef>
00051 #include <utility> // for std::pair
00052 
00053 namespace SimTK {
00054 
00055 
00056 template <class S> class MatrixHelperRep;
00057 class MatrixCharacter;
00058 class MatrixCommitment;
00059 
00060 //  ------------------------------ MatrixHelper --------------------------------
00061 
00084 
00085 //  ----------------------------------------------------------------------------
00086 template <class S> 
00087 class SimTK_SimTKCOMMON_EXPORT MatrixHelper {
00088     typedef MatrixHelper<S>                         This;
00089     typedef MatrixHelper<typename CNT<S>::TNeg>     ThisNeg;
00090     typedef MatrixHelper<typename CNT<S>::THerm>    ThisHerm;
00091 public: 
00092     typedef typename CNT<S>::Number     Number;     // strips off negator from S
00093     typedef typename CNT<S>::StdNumber  StdNumber;  // turns conjugate to complex
00094     typedef typename CNT<S>::Precision  Precision;  // strips off complex from StdNumber
00095 
00096     // no default constructor
00097     // copy constructor suppressed
00098 
00099     // Destructor eliminates MatrixHelperRep object if "this" owns it.
00100     ~MatrixHelper() {deleteRepIfOwner();}
00101 
00102     // Local types for directing us to the right constructor at compile time.
00103     class ShallowCopy   { };
00104     class DeepCopy      { };
00105     class TransposeView { };
00106     class DiagonalView  { };
00107     
00109         // "Owner" constructors //
00111     
00112     // 0x0, fully resizable, fully uncommitted.
00113     MatrixHelper(int esz, int cppEsz);
00114 
00115     // Default allocation for the given commitment.
00116     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&);
00117 
00118     // Allocate a matrix that satisfies a given commitment and has a
00119     // particular initial size.
00120     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&, int m, int n);
00121 
00122     // Copy constructor that produces a new owner whose logical shape and contents are
00123     // the same as the source, but with a possibly better storage layout. Data will
00124     // be contiguous in the copy regardless of how spread out it was in the source.
00125     // The second argument is just to disambiguate this constructor from similar ones.
00126     MatrixHelper(const MatrixCommitment&, const MatrixHelper& source, const DeepCopy&);
00127 
00128     // This has the same semantics as the previous DeepCopy constructor, except that
00129     // the source has negated elements with respect to S. The resulting logical shape
00130     // and logical values are identical to the source, meaning that the negation must
00131     // actually be performed here, using one flop for every meaningful source scalar.
00132     MatrixHelper(const MatrixCommitment&, const MatrixHelper<typename CNT<S>::TNeg>& source, const DeepCopy&);
00133    
00134     
00136         // External "View" constructors //
00138 
00139     // These constructors produce a matrix which provides a view of externally-allocated
00140     // data, which is known to have the given MatrixCharacter. There is also provision
00141     // for a "spacing" parameter which defines gaps in the supplied data, although
00142     // the interpretation of that parameter depends on the MatrixCharacter (typically
00143     // it is the leading dimension for a matrix or the stride for a vector). Note
00144     // that spacing is interpreted as "number of scalars between adjacent elements"
00145     // which has the usual Lapack interpretation if the elements are scalars but
00146     // can be used for C++ vs. Simmatrix packing differences for composite elements.
00147     // The resulting handle is *not* the owner of the data, so destruction of the 
00148     // handle does not delete the data.
00149 
00150     // Create a read-only view into existing data.
00151     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&,
00152                  const MatrixCharacter&, int spacing, const S* data);
00153     // Create a writable view into existing data.
00154     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&,
00155                  const MatrixCharacter&, int spacing, S* data);
00156 
00157 
00159         // Matrix "View" constructors //
00161 
00162     // Matrix view constructors, read only and writable. Use these for submatrices,
00163     // rows, and columns. Indices are by *element* and these may consist of multiple
00164     // scalars of type template parameter S.
00165 
00166     // "Block" views
00167     MatrixHelper(const MatrixCommitment&, const MatrixHelper&, int i, int j, int nrow, int ncol);
00168     MatrixHelper(const MatrixCommitment&, MatrixHelper&,       int i, int j, int nrow, int ncol); 
00169 
00170     // "Transpose" views (note that this is Hermitian transpose; i.e., element
00171     // type is conjugated).
00172     MatrixHelper(const MatrixCommitment&, const MatrixHelper<typename CNT<S>::THerm>&, 
00173                  const TransposeView&);    // a read only transposed view
00174     MatrixHelper(const MatrixCommitment&, MatrixHelper<typename CNT<S>::THerm>&,       
00175                  const TransposeView&);    // a writable transposed view
00176 
00177     // "Diagonal" views.
00178     MatrixHelper(const MatrixCommitment&, const MatrixHelper&, const DiagonalView&); // a read only diagonal view
00179     MatrixHelper(const MatrixCommitment&, MatrixHelper&,       const DiagonalView&); // a writable diagonal view
00180 
00181     // "Indexed" view of a 1d matrix.
00182     MatrixHelper(const MatrixCommitment&, const MatrixHelper&, int n, const int* indices);
00183     MatrixHelper(const MatrixCommitment&, MatrixHelper&, int n, const int* indices);
00184 
00185     // These invoke the previous constructors but with friendlier index source.
00186     MatrixHelper(const MatrixCommitment& mc, const MatrixHelper& h, const Array_<int>& indices)
00187     {   new (this) MatrixHelper(mc, h, (int)indices.size(), &indices[0]); }
00188     MatrixHelper(const MatrixCommitment& mc, MatrixHelper& h, const Array_<int>& indices)
00189     {   new (this) MatrixHelper(mc, h, (int)indices.size(), &indices[0]); }
00190 
00191     // "Copy" an existing MatrixHelper by making a new view into the same data. 
00192     // The const form loses writability, non-const retains same writability status 
00193     // as source. If the source is already a view then the destination will have
00194     // an identical element filter so that the logical shape and values are the
00195     // same for both source and copy. (The second argument is used just to 
00196     // disambiguate this constructor from similar ones.)
00197     MatrixHelper(const MatrixCommitment&, const MatrixHelper& source, const ShallowCopy&);
00198     MatrixHelper(const MatrixCommitment&, MatrixHelper&       source, const ShallowCopy&);
00199 
00201         // Copy assignment //
00203 
00204     // Behavior of copy assignment depends on whether "this" is an owner or view. If
00205     // it's an owner it is resized and ends up a new, dense copy of "source" just as
00206     // for the DeepCopy constructor above. If "this" is a writable view, sizes must match 
00207     // and we copy elements from "source" to corresponding elements of "this". If
00208     // "this" is not writable then the operation will fail.
00209     MatrixHelper& copyAssign(const MatrixHelper& source);
00210 
00211     // Same as copyAssign() except the source has element types which are logically
00212     // negated from the element types of "this". Since the result must have the
00213     // same value as the source, this requires that all the copied elements are
00214     // actually negated at a cost of one flop per scalar.
00215     MatrixHelper& negatedCopyAssign(const MatrixHelper<typename CNT<S>::TNeg>&);
00216 
00218         // View assignment //
00220 
00221     // View assign always disconnects this helper from whatever view & data
00222     // it used to have (destructing as appropriate) and then makes it a new view
00223     // of the source. Writability is lost if the source is const, otherwise 
00224     // writability is inherited from the source.
00225     MatrixHelper& readOnlyViewAssign(const MatrixHelper& source);
00226     MatrixHelper& writableViewAssign(MatrixHelper&       source);
00227 
00228     // Restore helper to its just-constructed state. We forget everything except
00229     // the element size and handle commitment, which can never change. The
00230     // allocated helper will be the same as if we had just default-constructed
00231     // using the current commitment.
00232     void clear();
00233 
00234     // Return true if there is currently no data associated with this handle.
00235     bool isClear() const;
00236 
00237     // Using *element* indices, obtain a pointer to the beginning of a particular
00238     // element. This is always a slow operation compared to raw array access;
00239     // use sparingly. These will fail if the indices are outside the stored
00240     // portion of the matrix. Use getAnyElt() if you want something that always
00241     // works.
00242     const S* getElt(int i, int j) const;
00243     S*       updElt(int i, int j);
00244 
00245     // Faster for 1-d matrices (vectors) if you know you have one.
00246     const S* getElt(int i) const;
00247     S*       updElt(int i);
00248 
00249     // This returns the correct value for any element within the logical dimensions
00250     // of the matrix. In some cases it has to compute the value; in all cases
00251     // it has to copy it.
00252     void getAnyElt(int i, int j, S* value) const;
00253 
00254     // Faster for 1-d matrices (vectors) if you know you have one.
00255     void getAnyElt(int i, S* value) const;
00256 
00257     // Add up all the *elements*, returning the answer in the element given
00258     // by pointer to its first scalar.
00259     void sum(S* eltp) const;
00260     void colSum(int j, S* eltp) const;
00261     void rowSum(int i, S* eltp) const;
00262         
00263     // addition and subtraction (+= and -=)
00264     void addIn(const MatrixHelper&);   
00265     void addIn(const MatrixHelper<typename CNT<S>::TNeg>&);   
00266     void subIn(const MatrixHelper&); 
00267     void subIn(const MatrixHelper<typename CNT<S>::TNeg>&); 
00268 
00269     // Fill all our stored data with copies of the same supplied element.
00270     void fillWith(const S* eltp);
00271 
00272     // We're copying data from a C++ row-oriented matrix into our general
00273     // Matrix. In addition to the row ordering, C++ may use different spacing
00274     // for elements than Simmatrix does.
00275     void copyInByRowsFromCpp(const S* elts);
00276     
00277         // Scalar operations //
00278 
00279     // Fill every element with repeated copies of a single scalar value.
00280     void fillWithScalar(const StdNumber&);
00281             
00282     // Scalar multiply (and divide). This is useful no matter what the
00283     // element structure and will produce the correct result.
00284     void scaleBy(const StdNumber&);
00285 
00286     // This is only allowed for a matrix of real or complex or neg of those,
00287     // which is square, well-conditioned, and for which we have no view,
00288     // and element size 1.
00289     void invertInPlace();
00290 
00291     void dump(const char* msg=0) const; // For debugging -- comes out in a way you can feed to Matlab
00292 
00293     // See comment in MatrixBase::matmul for an explanation.
00294     template <class SA, class SB>
00295     void matmul(const StdNumber& beta,   // applied to 'this'
00296                 const StdNumber& alpha, const MatrixHelper<SA>& A, const MatrixHelper<SB>& B);    
00297     
00298         // Bookkeeping //
00299     
00300     // This is the number of logical *elements* in each column of this matrix; i.e., m.
00301     int    nrow() const;
00302     // This is the number of *elements* in each row of this matrix; i.e., n.
00303     int    ncol() const;
00304     // This is the total number of *elements* in the logical shape of this matrix, i.e. m*n.
00305     ptrdiff_t nelt() const; // nrow*ncol  
00306     // This is the number of elements if this is a 1d matrix (vector or rowvector). That is,
00307     // it is the same as one of nrow() or ncol(); the other must be 1. It is also the
00308     // same as nelt() but limited to fit in 32 bits.
00309     int length() const;
00310 
00311     // Change the logical size of the underlying memory for this Matrix to m X n, forgetting
00312     // everything that used to be there. This will fail if it would have to resize any
00313     // non-resizable dimension. However, it will succeed even on non-resizable matrices and
00314     // views provided the existing dimensions are already correct. If no size change is made,
00315     // no action is taken and the original data is still accessible.
00316     void resize(int m, int n);
00317 
00318     // Same as resize() except as much of the original data as will fit remains in place at
00319     // the same (i,j) location it had before. This may require copying the elements after
00320     // allocating new space. As for resize(), this is allowed for any Matrix whose dimensions
00321     // are already right, even if that Matrix is not resizable.
00322     void resizeKeep(int m, int n);
00323 
00324     void lockShape();
00325     void unlockShape();
00326 
00327     const MatrixCommitment& getCharacterCommitment() const;
00328     const MatrixCharacter&  getMatrixCharacter() const;
00329     void commitTo(const MatrixCommitment&);
00330 
00331     // Access to raw data. For now this is only allowed if there is no view
00332     // and the raw data is contiguous.
00333     bool      hasContiguousData() const;
00334     ptrdiff_t getContiguousDataLength() const;
00335     const S*  getContiguousData() const;
00336     S*        updContiguousData();
00337 
00338     void replaceContiguousData(S* newData, ptrdiff_t length, bool takeOwnership);
00339     void replaceContiguousData(const S* newData, ptrdiff_t length);
00340     void swapOwnedContiguousData(S* newData, ptrdiff_t length, S*& oldData);
00341 
00342     const MatrixHelperRep<S>& getRep() const {assert(rep); return *rep;}
00343     MatrixHelperRep<S>&       updRep()       {assert(rep); return *rep;}
00344     void setRep(MatrixHelperRep<S>* hrep)    {assert(!rep); rep = hrep;}
00345     MatrixHelperRep<S>* stealRep() 
00346     {   assert(rep); MatrixHelperRep<S>* stolen=rep; rep=0; return stolen; }
00347 
00348     void deleteRepIfOwner();
00349     void replaceRep(MatrixHelperRep<S>*);
00350 
00351     // Rep-stealing constructor. We're taking ownership of the supplied rep.
00352     // Internal use only!
00353     explicit MatrixHelper(MatrixHelperRep<S>*);
00354 
00355 private:
00356     // Pointer to the private implementation object. This is the only
00357     // allowable data member in this class.
00358     class MatrixHelperRep<S>* rep;
00359 
00360     // Suppress copy constructor.
00361     MatrixHelper(const MatrixHelper&);
00362 
00363 friend class MatrixHelper<typename CNT<S>::TNeg>;
00364 friend class MatrixHelper<typename CNT<S>::THerm>;
00365 };
00366      
00367 } //namespace SimTK
00368 
00369 #endif // SimTK_SIMMATRIX_MATRIX_HELPER_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines