Simbody
|
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_