Simbody  3.4 (development)
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  *                       Simbody(tm): SimTKcommon                             *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK 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/home/simbody.  *
00011  *                                                                            *
00012  * Portions copyright (c) 2005-12 Stanford University and the Authors.        *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
00017  * not use this file except in compliance with the License. You may obtain a  *
00018  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
00019  *                                                                            *
00020  * Unless required by applicable law or agreed to in writing, software        *
00021  * distributed under the License is distributed on an "AS IS" BASIS,          *
00022  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
00023  * See the License for the specific language governing permissions and        *
00024  * limitations under the License.                                             *
00025  * -------------------------------------------------------------------------- */
00026 
00037 #include "SimTKcommon/Scalar.h"
00038 
00039 #include <iostream>
00040 #include <cassert>
00041 #include <complex>
00042 #include <cstddef>
00043 #include <utility> // for std::pair
00044 
00045 namespace SimTK {
00046 
00047 
00048 template <class S> class MatrixHelperRep;
00049 class MatrixCharacter;
00050 class MatrixCommitment;
00051 
00052 //  ------------------------------ MatrixHelper --------------------------------
00053 
00076 
00077 //  ----------------------------------------------------------------------------
00078 template <class S> 
00079 class SimTK_SimTKCOMMON_EXPORT MatrixHelper {
00080     typedef MatrixHelper<S>                         This;
00081     typedef MatrixHelper<typename CNT<S>::TNeg>     ThisNeg;
00082     typedef MatrixHelper<typename CNT<S>::THerm>    ThisHerm;
00083 public: 
00084     typedef typename CNT<S>::Number     Number;     // strips off negator from S
00085     typedef typename CNT<S>::StdNumber  StdNumber;  // turns conjugate to complex
00086     typedef typename CNT<S>::Precision  Precision;  // strips off complex from StdNumber
00087 
00088     // no default constructor
00089     // copy constructor suppressed
00090 
00091     // Destructor eliminates MatrixHelperRep object if "this" owns it.
00092     ~MatrixHelper() {deleteRepIfOwner();}
00093 
00094     // Local types for directing us to the right constructor at compile time.
00095     class ShallowCopy   { };
00096     class DeepCopy      { };
00097     class TransposeView { };
00098     class DiagonalView  { };
00099     
00101         // "Owner" constructors //
00103     
00104     // 0x0, fully resizable, fully uncommitted.
00105     MatrixHelper(int esz, int cppEsz);
00106 
00107     // Default allocation for the given commitment.
00108     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&);
00109 
00110     // Allocate a matrix that satisfies a given commitment and has a
00111     // particular initial size.
00112     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&, int m, int n);
00113 
00114     // Copy constructor that produces a new owner whose logical shape and contents are
00115     // the same as the source, but with a possibly better storage layout. Data will
00116     // be contiguous in the copy regardless of how spread out it was in the source.
00117     // The second argument is just to disambiguate this constructor from similar ones.
00118     MatrixHelper(const MatrixCommitment&, const MatrixHelper& source, const DeepCopy&);
00119 
00120     // This has the same semantics as the previous DeepCopy constructor, except that
00121     // the source has negated elements with respect to S. The resulting logical shape
00122     // and logical values are identical to the source, meaning that the negation must
00123     // actually be performed here, using one flop for every meaningful source scalar.
00124     MatrixHelper(const MatrixCommitment&, const MatrixHelper<typename CNT<S>::TNeg>& source, const DeepCopy&);
00125    
00126     
00128         // External "View" constructors //
00130 
00131     // These constructors produce a matrix which provides a view of externally-allocated
00132     // data, which is known to have the given MatrixCharacter. There is also provision
00133     // for a "spacing" parameter which defines gaps in the supplied data, although
00134     // the interpretation of that parameter depends on the MatrixCharacter (typically
00135     // it is the leading dimension for a matrix or the stride for a vector). Note
00136     // that spacing is interpreted as "number of scalars between adjacent elements"
00137     // which has the usual Lapack interpretation if the elements are scalars but
00138     // can be used for C++ vs. Simmatrix packing differences for composite elements.
00139     // The resulting handle is *not* the owner of the data, so destruction of the 
00140     // handle does not delete the data.
00141 
00142     // Create a read-only view into existing data.
00143     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&,
00144                  const MatrixCharacter&, int spacing, const S* data);
00145     // Create a writable view into existing data.
00146     MatrixHelper(int esz, int cppEsz, const MatrixCommitment&,
00147                  const MatrixCharacter&, int spacing, S* data);
00148 
00149 
00151         // Matrix "View" constructors //
00153 
00154     // Matrix view constructors, read only and writable. Use these for submatrices,
00155     // rows, and columns. Indices are by *element* and these may consist of multiple
00156     // scalars of type template parameter S.
00157 
00158     // "Block" views
00159     MatrixHelper(const MatrixCommitment&, const MatrixHelper&, int i, int j, int nrow, int ncol);
00160     MatrixHelper(const MatrixCommitment&, MatrixHelper&,       int i, int j, int nrow, int ncol); 
00161 
00162     // "Transpose" views (note that this is Hermitian transpose; i.e., element
00163     // type is conjugated).
00164     MatrixHelper(const MatrixCommitment&, const MatrixHelper<typename CNT<S>::THerm>&, 
00165                  const TransposeView&);    // a read only transposed view
00166     MatrixHelper(const MatrixCommitment&, MatrixHelper<typename CNT<S>::THerm>&,       
00167                  const TransposeView&);    // a writable transposed view
00168 
00169     // "Diagonal" views.
00170     MatrixHelper(const MatrixCommitment&, const MatrixHelper&, const DiagonalView&); // a read only diagonal view
00171     MatrixHelper(const MatrixCommitment&, MatrixHelper&,       const DiagonalView&); // a writable diagonal view
00172 
00173     // "Indexed" view of a 1d matrix.
00174     MatrixHelper(const MatrixCommitment&, const MatrixHelper&, 
00175                  int n, const int* indices);
00176     MatrixHelper(const MatrixCommitment&, MatrixHelper&, 
00177                  int n, const int* indices);
00178 
00179     // These invoke the previous constructors but with friendlier index source.
00180     MatrixHelper(const MatrixCommitment& mc, const MatrixHelper& h, 
00181                  const Array_<int>& indices)
00182     {   new (this) MatrixHelper(mc, h, (int)indices.size(), indices.cbegin()); }
00183     MatrixHelper(const MatrixCommitment& mc, MatrixHelper& h, 
00184                  const Array_<int>& indices)
00185     {   new (this) MatrixHelper(mc, h, (int)indices.size(), indices.cbegin()); }
00186 
00187     // "Copy" an existing MatrixHelper by making a new view into the same data. 
00188     // The const form loses writability, non-const retains same writability status 
00189     // as source. If the source is already a view then the destination will have
00190     // an identical element filter so that the logical shape and values are the
00191     // same for both source and copy. (The second argument is used just to 
00192     // disambiguate this constructor from similar ones.)
00193     MatrixHelper(const MatrixCommitment&, const MatrixHelper& source, const ShallowCopy&);
00194     MatrixHelper(const MatrixCommitment&, MatrixHelper&       source, const ShallowCopy&);
00195 
00197         // Copy assignment //
00199 
00200     // Behavior of copy assignment depends on whether "this" is an owner or view. If
00201     // it's an owner it is resized and ends up a new, dense copy of "source" just as
00202     // for the DeepCopy constructor above. If "this" is a writable view, sizes must match 
00203     // and we copy elements from "source" to corresponding elements of "this". If
00204     // "this" is not writable then the operation will fail.
00205     MatrixHelper& copyAssign(const MatrixHelper& source);
00206 
00207     // Same as copyAssign() except the source has element types which are logically
00208     // negated from the element types of "this". Since the result must have the
00209     // same value as the source, this requires that all the copied elements are
00210     // actually negated at a cost of one flop per scalar.
00211     MatrixHelper& negatedCopyAssign(const MatrixHelper<typename CNT<S>::TNeg>&);
00212 
00214         // View assignment //
00216 
00217     // View assign always disconnects this helper from whatever view & data
00218     // it used to have (destructing as appropriate) and then makes it a new view
00219     // of the source. Writability is lost if the source is const, otherwise 
00220     // writability is inherited from the source.
00221     MatrixHelper& readOnlyViewAssign(const MatrixHelper& source);
00222     MatrixHelper& writableViewAssign(MatrixHelper&       source);
00223 
00224     // Restore helper to its just-constructed state. We forget everything except
00225     // the element size and handle commitment, which can never change. The
00226     // allocated helper will be the same as if we had just default-constructed
00227     // using the current commitment.
00228     void clear();
00229 
00230     // Return true if there is currently no data associated with this handle.
00231     bool isClear() const;
00232 
00233     // Using *element* indices, obtain a pointer to the beginning of a particular
00234     // element. This is always a slow operation compared to raw array access;
00235     // use sparingly. These will fail if the indices are outside the stored
00236     // portion of the matrix. Use getAnyElt() if you want something that always
00237     // works.
00238     const S* getElt(int i, int j) const;
00239     S*       updElt(int i, int j);
00240 
00241     // Faster for 1-d matrices (vectors) if you know you have one.
00242     const S* getElt(int i) const;
00243     S*       updElt(int i);
00244 
00245     // This returns the correct value for any element within the logical dimensions
00246     // of the matrix. In some cases it has to compute the value; in all cases
00247     // it has to copy it.
00248     void getAnyElt(int i, int j, S* value) const;
00249 
00250     // Faster for 1-d matrices (vectors) if you know you have one.
00251     void getAnyElt(int i, S* value) const;
00252 
00253     // Add up all the *elements*, returning the answer in the element given
00254     // by pointer to its first scalar.
00255     void sum(S* eltp) const;
00256     void colSum(int j, S* eltp) const;
00257     void rowSum(int i, S* eltp) const;
00258         
00259     // addition and subtraction (+= and -=)
00260     void addIn(const MatrixHelper&);   
00261     void addIn(const MatrixHelper<typename CNT<S>::TNeg>&);   
00262     void subIn(const MatrixHelper&); 
00263     void subIn(const MatrixHelper<typename CNT<S>::TNeg>&); 
00264 
00265     // Fill all our stored data with copies of the same supplied element.
00266     void fillWith(const S* eltp);
00267 
00268     // We're copying data from a C++ row-oriented matrix into our general
00269     // Matrix. In addition to the row ordering, C++ may use different spacing
00270     // for elements than Simmatrix does.
00271     void copyInByRowsFromCpp(const S* elts);
00272     
00273         // Scalar operations //
00274 
00275     // Fill every element with repeated copies of a single scalar value.
00276     void fillWithScalar(const StdNumber&);
00277             
00278     // Scalar multiply (and divide). This is useful no matter what the
00279     // element structure and will produce the correct result.
00280     void scaleBy(const StdNumber&);
00281 
00282     // This is only allowed for a matrix of real or complex or neg of those,
00283     // which is square, well-conditioned, and for which we have no view,
00284     // and element size 1.
00285     void invertInPlace();
00286 
00287     void dump(const char* msg=0) const; // For debugging -- comes out in a way you can feed to Matlab
00288 
00289     // See comment in MatrixBase::matmul for an explanation.
00290     template <class SA, class SB>
00291     void matmul(const StdNumber& beta,   // applied to 'this'
00292                 const StdNumber& alpha, const MatrixHelper<SA>& A, const MatrixHelper<SB>& B);    
00293     
00294         // Bookkeeping //
00295     
00296     // This is the number of logical *elements* in each column of this matrix; i.e., m.
00297     int    nrow() const;
00298     // This is the number of *elements* in each row of this matrix; i.e., n.
00299     int    ncol() const;
00300     // This is the total number of *elements* in the logical shape of this matrix, i.e. m*n.
00301     ptrdiff_t nelt() const; // nrow*ncol  
00302     // This is the number of elements if this is a 1d matrix (vector or rowvector). That is,
00303     // it is the same as one of nrow() or ncol(); the other must be 1. It is also the
00304     // same as nelt() but limited to fit in 32 bits.
00305     int length() const;
00306 
00307     // Change the logical size of the underlying memory for this Matrix to m X n, forgetting
00308     // everything that used to be there. This will fail if it would have to resize any
00309     // non-resizable dimension. However, it will succeed even on non-resizable matrices and
00310     // views provided the existing dimensions are already correct. If no size change is made,
00311     // no action is taken and the original data is still accessible.
00312     void resize(int m, int n);
00313 
00314     // Same as resize() except as much of the original data as will fit remains in place at
00315     // the same (i,j) location it had before. This may require copying the elements after
00316     // allocating new space. As for resize(), this is allowed for any Matrix whose dimensions
00317     // are already right, even if that Matrix is not resizable.
00318     void resizeKeep(int m, int n);
00319 
00320     void lockShape();
00321     void unlockShape();
00322 
00323     const MatrixCommitment& getCharacterCommitment() const;
00324     const MatrixCharacter&  getMatrixCharacter() const;
00325     void commitTo(const MatrixCommitment&);
00326 
00327     // Access to raw data. For now this is only allowed if there is no view
00328     // and the raw data is contiguous.
00329     bool      hasContiguousData() const;
00330     ptrdiff_t getContiguousDataLength() const;
00331     const S*  getContiguousData() const;
00332     S*        updContiguousData();
00333 
00334     void replaceContiguousData(S* newData, ptrdiff_t length, bool takeOwnership);
00335     void replaceContiguousData(const S* newData, ptrdiff_t length);
00336     void swapOwnedContiguousData(S* newData, ptrdiff_t length, S*& oldData);
00337 
00338     const MatrixHelperRep<S>& getRep() const {assert(rep); return *rep;}
00339     MatrixHelperRep<S>&       updRep()       {assert(rep); return *rep;}
00340     void setRep(MatrixHelperRep<S>* hrep)    {assert(!rep); rep = hrep;}
00341     MatrixHelperRep<S>* stealRep() 
00342     {   assert(rep); MatrixHelperRep<S>* stolen=rep; rep=0; return stolen; }
00343 
00344     void deleteRepIfOwner();
00345     void replaceRep(MatrixHelperRep<S>*);
00346 
00347     // Rep-stealing constructor. We're taking ownership of the supplied rep.
00348     // Internal use only!
00349     explicit MatrixHelper(MatrixHelperRep<S>*);
00350 
00351 private:
00352     // Pointer to the private implementation object. This is the only
00353     // allowable data member in this class.
00354     class MatrixHelperRep<S>* rep;
00355 
00356     // Suppress copy constructor.
00357     MatrixHelper(const MatrixHelper&);
00358 
00359 friend class MatrixHelper<typename CNT<S>::TNeg>;
00360 friend class MatrixHelper<typename CNT<S>::THerm>;
00361 };
00362      
00363 } //namespace SimTK
00364 
00365 #endif // SimTK_SIMMATRIX_MATRIX_HELPER_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines