Simbody
3.4 (development)
|
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_