1 #ifndef SimTK_SIMMATRIX_MATRIXBASE_H_ 2 #define SimTK_SIMMATRIX_MATRIXBASE_H_ 3 4 /* -------------------------------------------------------------------------- * 5 * Simbody(tm): SimTKcommon * 6 * -------------------------------------------------------------------------- * 7 * This is part of the SimTK biosimulation toolkit originating from * 8 * Simbios, the NIH National Center for Physics-Based Simulation of * 9 * Biological Structures at Stanford, funded under the NIH Roadmap for * 10 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 11 * * 12 * Portions copyright (c) 2005-13 Stanford University and the Authors. * 13 * Authors: Michael Sherman * 14 * Contributors: * 15 * * 16 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 17 * not use this file except in compliance with the License. You may obtain a * 18 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 19 * * 20 * Unless required by applicable law or agreed to in writing, software * 21 * distributed under the License is distributed on an "AS IS" BASIS, * 22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 23 * See the License for the specific language governing permissions and * 24 * limitations under the License. * 25 * -------------------------------------------------------------------------- */ 26 27 /** @file 28 Define the SimTK::MatrixBase class that is part of Simbody's BigMatrix 29 toolset. **/ 30 31 namespace SimTK { 32 33 //============================================================================== 34 // MATRIX BASE 35 //============================================================================== 36 /** @brief This is the common base class for Simbody's Vector_ and Matrix_ 37 classes for handling large, variable-sized vectors and matrices. 38 39 %MatrixBase does not normally appear in user programs. Instead classes 40 Vector_ and Matrix_ are used, or more commonly the typedefs Vector and Matrix 41 which are abbreviations for Vector_<Real> and Matrix_<Real>. 42 43 %Matrix base is a variable-size 2d matrix of Composite Numerical Type (CNT) 44 elements. This is a container of such elements, it is NOT a Composite Numerical 45 Type itself. 46 47 <h2>Implementation</h2> 48 MatrixBase<ELT> uses MatrixHelper<S> for implementation, where S 49 is ELT::Scalar, that is, the underlying float, double, 50 complex<float>, negator<conjugate<double>>, 51 etc. from which ELT is constructed. This is a finite set of which all 52 members are explicitly instantiated in the implementation code, so 53 clients don't have to know how anything is implemented. 54 55 MatrixBase is the only class in the Matrix/Vector family which has any 56 data members (it has exactly one MatrixHelper, which itself consists only 57 of a single pointer to an opaque class). Thus all other objects 58 in this family (that is, derived from MatrixBase) are exactly the same 59 size in memory and may be "reinterpreted" as appropriate. For example, 60 a Vector may be reinterpreted as a Matrix or vice versa, provided runtime 61 requirements are met (e.g., exactly 1 column). 62 63 Unlike the small matrix classes, very little is encoded in the type. 64 Only the element type, and matrix vs. vector vs. row are in the type; 65 everything else like shape, storage layout, and writability are handled 66 at run time. **/ 67 // ---------------------------------------------------------------------------- 68 template <class ELT> class MatrixBase { 69 public: 70 // These typedefs are handy, but despite appearances you cannot 71 // treat a MatrixBase as a composite numerical type. That is, 72 // CNT<MatrixBase> will not compile, or if it does it won't be 73 // meaningful. 74 75 typedef ELT E; 76 typedef typename CNT<E>::TNeg ENeg; 77 typedef typename CNT<E>::TWithoutNegator EWithoutNegator; 78 typedef typename CNT<E>::TReal EReal; 79 typedef typename CNT<E>::TImag EImag; 80 typedef typename CNT<E>::TComplex EComplex; 81 typedef typename CNT<E>::THerm EHerm; 82 typedef typename CNT<E>::TPosTrans EPosTrans; 83 84 typedef typename CNT<E>::TAbs EAbs; 85 typedef typename CNT<E>::TStandard EStandard; 86 typedef typename CNT<E>::TInvert EInvert; 87 typedef typename CNT<E>::TNormalize ENormalize; 88 typedef typename CNT<E>::TSqHermT ESqHermT; 89 typedef typename CNT<E>::TSqTHerm ESqTHerm; 90 91 typedef typename CNT<E>::Scalar EScalar; 92 typedef typename CNT<E>::Number ENumber; 93 typedef typename CNT<E>::StdNumber EStdNumber; 94 typedef typename CNT<E>::Precision EPrecision; 95 typedef typename CNT<E>::ScalarNormSq EScalarNormSq; 96 97 typedef EScalar Scalar; // the underlying Scalar type 98 typedef ENumber Number; // negator removed from Scalar 99 typedef EStdNumber StdNumber; // conjugate goes to complex 100 typedef EPrecision Precision; // complex removed from StdNumber 101 typedef EScalarNormSq ScalarNormSq; // type of scalar^2 102 103 typedef MatrixBase<ENeg> TNeg; 104 typedef MatrixBase<EWithoutNegator> TWithoutNegator; 105 typedef MatrixBase<EReal> TReal; 106 typedef MatrixBase<EImag> TImag; 107 typedef MatrixBase<EComplex> TComplex; 108 typedef MatrixBase<EHerm> THerm; 109 typedef MatrixBase<E> TPosTrans; 110 111 typedef MatrixBase<EAbs> TAbs; 112 typedef MatrixBase<EStandard> TStandard; 113 typedef MatrixBase<EInvert> TInvert; 114 typedef MatrixBase<ENormalize> TNormalize; 115 typedef MatrixBase<ESqHermT> TSqHermT; // ~Mat*Mat 116 typedef MatrixBase<ESqTHerm> TSqTHerm; // Mat*~Mat 117 getCharacterCommitment()118 const MatrixCommitment& getCharacterCommitment() const {return helper.getCharacterCommitment();} getMatrixCharacter()119 const MatrixCharacter& getMatrixCharacter() const {return helper.getMatrixCharacter();} 120 121 /// Change the handle commitment for this matrix handle; only allowed if the 122 /// handle is currently clear. commitTo(const MatrixCommitment & mc)123 void commitTo(const MatrixCommitment& mc) 124 { helper.commitTo(mc); } 125 126 // This gives the resulting matrix type when (m(i,j) op P) is applied to each element. 127 // It will have element types which are the regular composite result of E op P. 128 template <class P> struct EltResult { 129 typedef MatrixBase<typename CNT<E>::template Result<P>::Mul> Mul; 130 typedef MatrixBase<typename CNT<E>::template Result<P>::Dvd> Dvd; 131 typedef MatrixBase<typename CNT<E>::template Result<P>::Add> Add; 132 typedef MatrixBase<typename CNT<E>::template Result<P>::Sub> Sub; 133 }; 134 135 /// Return the number of rows m in the logical shape of this matrix. nrow()136 int nrow() const {return helper.nrow();} 137 /// Return the number of columns n in the logical shape of this matrix. ncol()138 int ncol() const {return helper.ncol();} 139 140 /// Return the number of elements in the \e logical shape of this matrix. 141 /// This has nothing to do with how many elements are actually stored; 142 /// it is simply the product of the logical number of rows and columns, 143 /// that is, nrow()*ncol(). Note that although each dimension is limited 144 /// to a 32 bit size, the product of those dimensions may be > 32 bits 145 /// on a 64 bit machine so the return type may be larger than that of 146 /// nrow() and ncol(). nelt()147 ptrdiff_t nelt() const {return helper.nelt();} 148 149 /// Return true if either dimension of this Matrix is resizable. isResizeable()150 bool isResizeable() const {return getCharacterCommitment().isResizeable();} 151 152 enum { 153 NScalarsPerElement = CNT<E>::NActualScalars, 154 CppNScalarsPerElement = sizeof(E) / sizeof(Scalar) 155 }; 156 157 /// The default constructor builds a 0x0 matrix managed by a helper that 158 /// understands how many scalars there are in one of our elements but is 159 /// otherwise uncommitted. MatrixBase()160 MatrixBase() : helper(NScalarsPerElement,CppNScalarsPerElement) {} 161 162 /// This constructor allocates the default matrix a completely uncommitted 163 /// matrix commitment, given particular initial dimensions. MatrixBase(int m,int n)164 MatrixBase(int m, int n) 165 : helper(NScalarsPerElement,CppNScalarsPerElement,MatrixCommitment(),m,n) {} 166 167 /// This constructor takes a handle commitment and allocates the default 168 /// matrix for that kind of commitment. If a dimension is set to a 169 /// particular (unchangeable) value in the commitment then the initial 170 /// allocation will use that value. Unlocked dimensions are given the 171 /// smallest value consistent with other committed attributes, typically 0. MatrixBase(const MatrixCommitment & commitment)172 explicit MatrixBase(const MatrixCommitment& commitment) 173 : helper(NScalarsPerElement,CppNScalarsPerElement,commitment) {} 174 175 176 /// This constructor takes a handle commitment and allocates the default 177 /// matrix for that kind of commitment given particular initial minimum 178 /// dimensions, which cannot be larger than those permitted by the 179 /// commitment. MatrixBase(const MatrixCommitment & commitment,int m,int n)180 MatrixBase(const MatrixCommitment& commitment, int m, int n) 181 : helper(NScalarsPerElement,CppNScalarsPerElement,commitment,m,n) {} 182 183 /// Copy constructor is a deep copy (not appropriate for views!). MatrixBase(const MatrixBase & b)184 MatrixBase(const MatrixBase& b) 185 : helper(b.helper.getCharacterCommitment(), 186 b.helper, typename MatrixHelper<Scalar>::DeepCopy()) { } 187 188 /// Implicit conversion from matrix with negated elements (otherwise this 189 /// is just like the copy constructor. MatrixBase(const TNeg & b)190 MatrixBase(const TNeg& b) 191 : helper(b.helper.getCharacterCommitment(), 192 b.helper, typename MatrixHelper<Scalar>::DeepCopy()) { } 193 194 /// Copy assignment is a deep copy but behavior depends on type of lhs: if 195 /// view, rhs must match. If owner, we reallocate and copy rhs. copyAssign(const MatrixBase & b)196 MatrixBase& copyAssign(const MatrixBase& b) { 197 helper.copyAssign(b.helper); 198 return *this; 199 } 200 MatrixBase& operator=(const MatrixBase& b) { return copyAssign(b); } 201 202 203 /// View assignment is a shallow copy, meaning that we disconnect the MatrixBase 204 /// from whatever it used to refer to (destructing as necessary), then make it a new view 205 /// for the data descriptor referenced by the source. 206 /// CAUTION: we always take the source as const, but that is ignored in 207 /// determining whether the resulting view is writable. Instead, that is 208 /// inherited from the writability status of the source. We have to do this 209 /// in order to allow temporary view objects to be writable -- the compiler 210 /// creates temporaries like m(i,j,m,n) as const. viewAssign(const MatrixBase & src)211 MatrixBase& viewAssign(const MatrixBase& src) { 212 helper.writableViewAssign(const_cast<MatrixHelper<Scalar>&>(src.helper)); 213 return *this; 214 } 215 216 // default destructor 217 218 /// Initializing constructor with all of the initially-allocated elements 219 /// initialized to the same value. The given dimensions are treated as 220 /// minimum dimensions in case the commitment requires more. So it is 221 /// always permissible to set them both to 0 in which case you'll get 222 /// the smallest matrix that satisfies the commitment, with each of its 223 /// elements (if any) set to the given initial value. MatrixBase(const MatrixCommitment & commitment,int m,int n,const ELT & initialValue)224 MatrixBase(const MatrixCommitment& commitment, int m, int n, const ELT& initialValue) 225 : helper(NScalarsPerElement, CppNScalarsPerElement, commitment, m, n) 226 { helper.fillWith(reinterpret_cast<const Scalar*>(&initialValue)); } 227 228 /// Initializing constructor with the initially-allocated elements 229 /// initialized from a C++ array of elements, which is provided in 230 /// <i>row major</i> order. The given dimensions are treated as 231 /// minimum dimensions in case the commitment requires more. The 232 /// array is presumed to be long enough to supply a value for each 233 /// element. Note that C++ packing for elements may be different than 234 /// Simmatrix packing of the same elements (Simmatrix packs them 235 /// more tightly in some cases). So you should not use this constructor 236 /// to copy elements from one Simmatrix matrix to another; this is 237 /// exclusively for initializing a Simmatrix from a C++ array. MatrixBase(const MatrixCommitment & commitment,int m,int n,const ELT * cppInitialValuesByRow)238 MatrixBase(const MatrixCommitment& commitment, int m, int n, 239 const ELT* cppInitialValuesByRow) 240 : helper(NScalarsPerElement, CppNScalarsPerElement, commitment, m, n) 241 { helper.copyInByRowsFromCpp(reinterpret_cast<const Scalar*>(cppInitialValuesByRow)); } 242 243 /// @name Matrix view of pre-exising data 244 /// 245 /// Non-resizeable view of someone else's already-allocated 246 /// memory of a size and storage type indicated by the supplied 247 /// MatrixCharacter. The \a spacing argument has different interpretations 248 /// depending on the storage format. Typically it is the leading 249 /// dimension for Lapack-style full storage or stride for a vector. 250 /// Spacing is in units like "number of scalars between elements" or 251 /// "number of scalars between columns" so it can be used to deal 252 /// with C++ packing vs. Simmatrix packing if necessary. 253 /// @{ 254 255 /// Construct a read-only view of pre-existing data. MatrixBase(const MatrixCommitment & commitment,const MatrixCharacter & character,int spacing,const Scalar * data)256 MatrixBase(const MatrixCommitment& commitment, 257 const MatrixCharacter& character, 258 int spacing, const Scalar* data) // read only data 259 : helper(NScalarsPerElement, CppNScalarsPerElement, 260 commitment, character, spacing, data) {} 261 262 /// Construct a writable view of pre-existing data. MatrixBase(const MatrixCommitment & commitment,const MatrixCharacter & character,int spacing,Scalar * data)263 MatrixBase(const MatrixCommitment& commitment, 264 const MatrixCharacter& character, 265 int spacing, Scalar* data) // writable data 266 : helper(NScalarsPerElement, CppNScalarsPerElement, 267 commitment, character, spacing, data) {} 268 /// @} 269 270 // Create a new MatrixBase from an existing helper. Both shallow and deep copies are possible. MatrixBase(const MatrixCommitment & commitment,MatrixHelper<Scalar> & source,const typename MatrixHelper<Scalar>::ShallowCopy & shallow)271 MatrixBase(const MatrixCommitment& commitment, 272 MatrixHelper<Scalar>& source, 273 const typename MatrixHelper<Scalar>::ShallowCopy& shallow) 274 : helper(commitment, source, shallow) {} MatrixBase(const MatrixCommitment & commitment,const MatrixHelper<Scalar> & source,const typename MatrixHelper<Scalar>::ShallowCopy & shallow)275 MatrixBase(const MatrixCommitment& commitment, 276 const MatrixHelper<Scalar>& source, 277 const typename MatrixHelper<Scalar>::ShallowCopy& shallow) 278 : helper(commitment, source, shallow) {} MatrixBase(const MatrixCommitment & commitment,const MatrixHelper<Scalar> & source,const typename MatrixHelper<Scalar>::DeepCopy & deep)279 MatrixBase(const MatrixCommitment& commitment, 280 const MatrixHelper<Scalar>& source, 281 const typename MatrixHelper<Scalar>::DeepCopy& deep) 282 : helper(commitment, source, deep) {} 283 284 /// This restores the MatrixBase to the state it would be in had it 285 /// been constructed specifying only its handle commitment. The size will 286 /// have been reduced to the smallest size consistent with the commitment. clear()287 void clear() {helper.clear();} 288 289 MatrixBase& operator*=(const StdNumber& t) { helper.scaleBy(t); return *this; } 290 MatrixBase& operator/=(const StdNumber& t) { helper.scaleBy(StdNumber(1)/t); return *this; } 291 MatrixBase& operator+=(const MatrixBase& r) { helper.addIn(r.helper); return *this; } 292 MatrixBase& operator-=(const MatrixBase& r) { helper.subIn(r.helper); return *this; } 293 MatrixBase(const MatrixBase<EE> & b)294 template <class EE> MatrixBase(const MatrixBase<EE>& b) 295 : helper(MatrixCommitment(),b.helper, typename MatrixHelper<Scalar>::DeepCopy()) { } 296 297 template <class EE> MatrixBase& operator=(const MatrixBase<EE>& b) 298 { helper = b.helper; return *this; } 299 template <class EE> MatrixBase& operator+=(const MatrixBase<EE>& b) 300 { helper.addIn(b.helper); return *this; } 301 template <class EE> MatrixBase& operator-=(const MatrixBase<EE>& b) 302 { helper.subIn(b.helper); return *this; } 303 304 /// Matrix assignment to an element sets only the *diagonal* elements to 305 /// the indicated value; everything else is set to zero. This is particularly 306 /// useful for setting a Matrix to zero or to the identity; for other values 307 /// it creates a Matrix which acts like the scalar. That is, if the scalar 308 /// is s and we do M=s, then multiplying another Matrix B by the resulting 309 /// diagonal matrix M gives the same result as multiplying B by s. That is 310 /// (M=s)*B == s*B. 311 /// 312 /// NOTE: this must be overridden for Vector and RowVector since then scalar 313 /// assignment is defined to copy the scalar to every element. 314 MatrixBase& operator=(const ELT& t) { 315 setToZero(); updDiag().setTo(t); 316 return *this; 317 } 318 319 /// Set M's diagonal elements to a "scalar" value S, and all off-diagonal 320 /// elements to zero. S can be any type which is assignable to an element 321 /// of type E. This is the same as the Matrix assignment operator M=S for 322 /// a scalar type S. It is overriden for Vector and Row types to behave 323 /// as elementwiseScalarAssign. 324 template <class S> inline MatrixBase& scalarAssign(const S & s)325 scalarAssign(const S& s) { 326 setToZero(); updDiag().setTo(s); 327 return *this; 328 } 329 330 /// Add a scalar to M's diagonal. This is the same as the Matrix += 331 /// operator. This is overridden for Vector and Row types to behave 332 /// as elementwiseAddScalarInPlace. 333 template <class S> inline MatrixBase& scalarAddInPlace(const S & s)334 scalarAddInPlace(const S& s) { 335 updDiag().elementwiseAddScalarInPlace(s); 336 } 337 338 339 /// Subtract a scalar from M's diagonal. This is the same as the Matrix -= 340 /// operator. This is overridden for Vector and Row types to behave 341 /// as elementwiseSubtractScalarInPlace. 342 template <class S> inline MatrixBase& scalarSubtractInPlace(const S & s)343 scalarSubtractInPlace(const S& s) { 344 updDiag().elementwiseSubtractScalarInPlace(s); 345 } 346 347 /// Set M(i,i) = S - M(i,i), M(i,j) = -M(i,j) for i!=j. This is overridden 348 /// for Vector and Row types to behave as elementwiseSubtractFromScalarInPlace. 349 template <class S> inline MatrixBase& scalarSubtractFromLeftInPlace(const S & s)350 scalarSubtractFromLeftInPlace(const S& s) { 351 negateInPlace(); 352 updDiag().elementwiseAddScalarInPlace(s); // yes, add 353 } 354 355 /// Set M(i,j) = M(i,j)*S for some "scalar" S. Actually S can be any 356 /// type for which E = E*S makes sense. That is, S must be conformant 357 /// with E and it must be possible to store the result back in an E. 358 /// This is the *= operator for M *= S and behaves the same way for 359 /// Matrix, Vector, and RowVector: every element gets multiplied in 360 /// place on the right by S. 361 template <class S> inline MatrixBase& 362 scalarMultiplyInPlace(const S&); 363 364 /// Set M(i,j) = S * M(i,j) for some "scalar" S. This is the same 365 /// as the above routine if S really is a scalar, but for S a more 366 /// complicated CNT it will be different. 367 template <class S> inline MatrixBase& 368 scalarMultiplyFromLeftInPlace(const S&); 369 370 /// Set M(i,j) = M(i,j)/S for some "scalar" S. Actually S can be any 371 /// type for which E = E/S makes sense. That is, S^-1 must be conformant 372 /// with E and it must be possible to store the result back in an E. 373 /// This is the /= operator for M /= S and behaves the same way for 374 /// Matrix, Vector, and RowVector: every element gets divided in 375 /// place on the right by S. 376 template <class S> inline MatrixBase& 377 scalarDivideInPlace(const S&); 378 379 /// Set M(i,j) = S/M(i,j) for some "scalar" S. Actually S can be any 380 /// type for which E = S/E makes sense. That is, S must be conformant 381 /// with E^-1 and it must be possible to store the result back in an E. 382 template <class S> inline MatrixBase& 383 scalarDivideFromLeftInPlace(const S&); 384 385 386 /// M = diag(r) * M; r must have nrow() elements. 387 /// That is, M[i] *= r[i]. 388 template <class EE> inline MatrixBase& 389 rowScaleInPlace(const VectorBase<EE>&); 390 391 /// Return type is a new matrix which will have the same dimensions as 'this' but 392 /// will have element types appropriate for the elementwise multiply being performed. 393 template <class EE> inline void 394 rowScale(const VectorBase<EE>& r, typename EltResult<EE>::Mul& out) const; 395 396 template <class EE> inline typename EltResult<EE>::Mul rowScale(const VectorBase<EE> & r)397 rowScale(const VectorBase<EE>& r) const { 398 typename EltResult<EE>::Mul out(nrow(), ncol()); rowScale(r,out); return out; 399 } 400 401 /// M = M * diag(c); c must have ncol() elements. 402 /// That is, M(j) *= c[j]. 403 template <class EE> inline MatrixBase& 404 colScaleInPlace(const VectorBase<EE>&); 405 406 template <class EE> inline void 407 colScale(const VectorBase<EE>& c, typename EltResult<EE>::Mul& out) const; 408 409 template <class EE> inline typename EltResult<EE>::Mul colScale(const VectorBase<EE> & c)410 colScale(const VectorBase<EE>& c) const { 411 typename EltResult<EE>::Mul out(nrow(), ncol()); colScale(c,out); return out; 412 } 413 414 415 /// M = diag(r) * M * diag(c); r must have nrow() elements; must have ncol() elements. 416 /// That is, M(i,j) *= r[i]*c[j]. 417 /// Having a combined row & column scaling operator means we can go through the matrix 418 /// memory once instead of twice. 419 template <class ER, class EC> inline MatrixBase& 420 rowAndColScaleInPlace(const VectorBase<ER>& r, const VectorBase<EC>& c); 421 422 template <class ER, class EC> inline void 423 rowAndColScale(const VectorBase<ER>& r, const VectorBase<EC>& c, 424 typename EltResult<typename VectorBase<ER>::template EltResult<EC>::Mul>::Mul& out) const; 425 426 template <class ER, class EC> inline typename EltResult<typename VectorBase<ER>::template EltResult<EC>::Mul>::Mul rowAndColScale(const VectorBase<ER> & r,const VectorBase<EC> & c)427 rowAndColScale(const VectorBase<ER>& r, const VectorBase<EC>& c) const { 428 typename EltResult<typename VectorBase<ER>::template EltResult<EC>::Mul>::Mul 429 out(nrow(), ncol()); 430 rowAndColScale(r,c,out); return out; 431 } 432 433 /// Set M(i,j)=s for every element of M and some value s. This requires only 434 /// that s be assignment compatible with M's elements; s doesn't 435 /// actually have to be a scalar. Note that for Matrix types this behavior 436 /// is different than scalar assignment, which puts the scalar only on M's 437 /// diagonal and sets the rest of M to zero. For Vector and RowVector types, 438 /// this operator is identical to the normal assignment operator and 439 /// scalarAssignInPlace() method which also assign the scalar to every element. 440 template <class S> inline MatrixBase& 441 elementwiseAssign(const S& s); 442 443 /// Overloaded to allow an integer argument, which is converted to Real. elementwiseAssign(int s)444 MatrixBase& elementwiseAssign(int s) 445 { return elementwiseAssign<Real>(Real(s)); } 446 447 /// Set M(i,j) = M(i,j)^-1. 448 MatrixBase& elementwiseInvertInPlace(); 449 450 void elementwiseInvert(MatrixBase<typename CNT<E>::TInvert>& out) const; 451 elementwiseInvert()452 MatrixBase<typename CNT<E>::TInvert> elementwiseInvert() const { 453 MatrixBase<typename CNT<E>::TInvert> out(nrow(), ncol()); 454 elementwiseInvert(out); 455 return out; 456 } 457 458 /// Set M(i,j)+=s for every element of M and some value s. This requires that s be 459 /// conformant with M's elements (of type E) and that the result can 460 /// be stored in an E. For Matrix types this behavior is different than 461 /// the normal += or scalarAddInPlace() operators, which add the scalar 462 /// only to the Matrix diagonal. For Vector and RowVector, this operator 463 /// is identical to += and scalarAddInPlace() which also add the scalar 464 /// to every element. 465 template <class S> inline MatrixBase& 466 elementwiseAddScalarInPlace(const S& s); 467 468 template <class S> inline void 469 elementwiseAddScalar(const S& s, typename EltResult<S>::Add&) const; 470 471 template <class S> inline typename EltResult<S>::Add elementwiseAddScalar(const S & s)472 elementwiseAddScalar(const S& s) const { 473 typename EltResult<S>::Add out(nrow(), ncol()); 474 elementwiseAddScalar(s,out); 475 return out; 476 } 477 478 /// Set M(i,j)-=s for every element of M and some value s. This requires that s be 479 /// conformant with M's elements (of type E) and that the result can 480 /// be stored in an E. For Matrix types this behavior is different than 481 /// the normal -= or scalarSubtractInPlace() operators, which subtract the scalar 482 /// only from the Matrix diagonal. For Vector and RowVector, this operator 483 /// is identical to -= and scalarSubtractInPlace() which also subtract the scalar 484 /// from every element. 485 template <class S> inline MatrixBase& 486 elementwiseSubtractScalarInPlace(const S& s); 487 488 template <class S> inline void 489 elementwiseSubtractScalar(const S& s, typename EltResult<S>::Sub&) const; 490 491 template <class S> inline typename EltResult<S>::Sub elementwiseSubtractScalar(const S & s)492 elementwiseSubtractScalar(const S& s) const { 493 typename EltResult<S>::Sub out(nrow(), ncol()); 494 elementwiseSubtractScalar(s,out); 495 return out; 496 } 497 498 /// Set M(i,j) = s - M(i,j) for every element of M and some value s. This requires that s be 499 /// conformant with M's elements (of type E) and that the result can 500 /// be stored in an E. For Matrix types this behavior is different than 501 /// the scalarSubtractFromLeftInPlace() operator, which subtracts only the diagonal 502 /// elements of M from s, while simply negating the off diagonal elements. 503 /// For Vector and RowVector, this operator 504 /// is identical to scalarSubtractFromLeftInPlace() which also subtracts every 505 /// element of M from the scalar. 506 template <class S> inline MatrixBase& 507 elementwiseSubtractFromScalarInPlace(const S& s); 508 509 template <class S> inline void 510 elementwiseSubtractFromScalar( 511 const S&, 512 typename MatrixBase<S>::template EltResult<E>::Sub&) const; 513 514 template <class S> inline typename MatrixBase<S>::template EltResult<E>::Sub elementwiseSubtractFromScalar(const S & s)515 elementwiseSubtractFromScalar(const S& s) const { 516 typename MatrixBase<S>::template EltResult<E>::Sub out(nrow(), ncol()); 517 elementwiseSubtractFromScalar<S>(s,out); 518 return out; 519 } 520 521 /// M(i,j) *= R(i,j); R must have same dimensions as this. 522 template <class EE> inline MatrixBase& 523 elementwiseMultiplyInPlace(const MatrixBase<EE>&); 524 525 template <class EE> inline void 526 elementwiseMultiply(const MatrixBase<EE>&, typename EltResult<EE>::Mul&) const; 527 528 template <class EE> inline typename EltResult<EE>::Mul elementwiseMultiply(const MatrixBase<EE> & m)529 elementwiseMultiply(const MatrixBase<EE>& m) const { 530 typename EltResult<EE>::Mul out(nrow(), ncol()); 531 elementwiseMultiply<EE>(m,out); 532 return out; 533 } 534 535 /// M(i,j) = R(i,j) * M(i,j); R must have same dimensions as this. 536 template <class EE> inline MatrixBase& 537 elementwiseMultiplyFromLeftInPlace(const MatrixBase<EE>&); 538 539 template <class EE> inline void 540 elementwiseMultiplyFromLeft( 541 const MatrixBase<EE>&, 542 typename MatrixBase<EE>::template EltResult<E>::Mul&) const; 543 544 template <class EE> inline typename MatrixBase<EE>::template EltResult<E>::Mul elementwiseMultiplyFromLeft(const MatrixBase<EE> & m)545 elementwiseMultiplyFromLeft(const MatrixBase<EE>& m) const { 546 typename EltResult<EE>::Mul out(nrow(), ncol()); 547 elementwiseMultiplyFromLeft<EE>(m,out); 548 return out; 549 } 550 551 /// M(i,j) /= R(i,j); R must have same dimensions as this. 552 template <class EE> inline MatrixBase& 553 elementwiseDivideInPlace(const MatrixBase<EE>&); 554 555 template <class EE> inline void 556 elementwiseDivide(const MatrixBase<EE>&, typename EltResult<EE>::Dvd&) const; 557 558 template <class EE> inline typename EltResult<EE>::Dvd elementwiseDivide(const MatrixBase<EE> & m)559 elementwiseDivide(const MatrixBase<EE>& m) const { 560 typename EltResult<EE>::Dvd out(nrow(), ncol()); 561 elementwiseDivide<EE>(m,out); 562 return out; 563 } 564 565 /// M(i,j) = R(i,j) / M(i,j); R must have same dimensions as this. 566 template <class EE> inline MatrixBase& 567 elementwiseDivideFromLeftInPlace(const MatrixBase<EE>&); 568 569 template <class EE> inline void 570 elementwiseDivideFromLeft( 571 const MatrixBase<EE>&, 572 typename MatrixBase<EE>::template EltResult<E>::Dvd&) const; 573 574 template <class EE> inline typename MatrixBase<EE>::template EltResult<EE>::Dvd elementwiseDivideFromLeft(const MatrixBase<EE> & m)575 elementwiseDivideFromLeft(const MatrixBase<EE>& m) const { 576 typename MatrixBase<EE>::template EltResult<E>::Dvd out(nrow(), ncol()); 577 elementwiseDivideFromLeft<EE>(m,out); 578 return out; 579 } 580 581 /// Fill every element in current allocation with given element (or NaN or 0). setTo(const ELT & t)582 MatrixBase& setTo(const ELT& t) {helper.fillWith(reinterpret_cast<const Scalar*>(&t)); return *this;} setToNaN()583 MatrixBase& setToNaN() {helper.fillWithScalar(CNT<StdNumber>::getNaN()); return *this;} setToZero()584 MatrixBase& setToZero() {helper.fillWithScalar(StdNumber(0)); return *this;} 585 586 // View creating operators. 587 inline RowVectorView_<ELT> row(int i) const; // select a row 588 inline RowVectorView_<ELT> updRow(int i); 589 inline VectorView_<ELT> col(int j) const; // select a column 590 inline VectorView_<ELT> updCol(int j); 591 592 RowVectorView_<ELT> operator[](int i) const {return row(i);} 593 RowVectorView_<ELT> operator[](int i) {return updRow(i);} operator()594 VectorView_<ELT> operator()(int j) const {return col(j);} operator()595 VectorView_<ELT> operator()(int j) {return updCol(j);} 596 597 // Select a block. 598 inline MatrixView_<ELT> block(int i, int j, int m, int n) const; 599 inline MatrixView_<ELT> updBlock(int i, int j, int m, int n); 600 operator()601 MatrixView_<ELT> operator()(int i, int j, int m, int n) const 602 { return block(i,j,m,n); } operator()603 MatrixView_<ELT> operator()(int i, int j, int m, int n) 604 { return updBlock(i,j,m,n); } 605 606 // Hermitian transpose. 607 inline MatrixView_<EHerm> transpose() const; 608 inline MatrixView_<EHerm> updTranspose(); 609 610 MatrixView_<EHerm> operator~() const {return transpose();} 611 MatrixView_<EHerm> operator~() {return updTranspose();} 612 613 /// Select main diagonal (of largest leading square if rectangular) and 614 /// return it as a read-only view of the diagonal elements of this Matrix. 615 inline VectorView_<ELT> diag() const; 616 /// Select main diagonal (of largest leading square if rectangular) and 617 /// return it as a writable view of the diagonal elements of this Matrix. 618 inline VectorView_<ELT> updDiag(); 619 /// This non-const version of diag() is an alternate name for updDiag() 620 /// available for historical reasons. diag()621 VectorView_<ELT> diag() {return updDiag();} 622 623 // Create a view of the real or imaginary elements. TODO 624 //inline MatrixView_<EReal> real() const; 625 //inline MatrixView_<EReal> updReal(); 626 //inline MatrixView_<EImag> imag() const; 627 //inline MatrixView_<EImag> updImag(); 628 629 // Overload "real" and "imag" for both read and write as a nod to convention. TODO 630 //MatrixView_<EReal> real() {return updReal();} 631 //MatrixView_<EReal> imag() {return updImag();} 632 633 // TODO: this routine seems ill-advised but I need it for the IVM port at the moment invert()634 TInvert invert() const { // return a newly-allocated inverse; dump negator 635 TInvert m(*this); 636 m.helper.invertInPlace(); 637 return m; // TODO - bad: makes an extra copy 638 } 639 invertInPlace()640 void invertInPlace() {helper.invertInPlace();} 641 642 /// Matlab-compatible debug output. 643 void dump(const char* msg=0) const { 644 helper.dump(msg); 645 } 646 647 /// Element selection for stored elements. These are the fastest element access 648 /// methods but may not be able to access all elements of the logical matrix when 649 /// some of its elements are not stored in memory. For example, a Hermitian matrix 650 /// stores only half its elements and other ones have to be calculated by conjugation 651 /// if they are to be returned as type ELT. (You can get them for free by recasting 652 /// the matrix so that the elements are reinterpreted as conjugates.) If you want 653 /// to guarantee that you can access the value of every element of a matrix, stored or not, 654 /// use getAnyElt() instead. getElt(int i,int j)655 const ELT& getElt(int i, int j) const { return *reinterpret_cast<const ELT*>(helper.getElt(i,j)); } updElt(int i,int j)656 ELT& updElt(int i, int j) { return *reinterpret_cast< ELT*>(helper.updElt(i,j)); } 657 operator()658 const ELT& operator()(int i, int j) const {return getElt(i,j);} operator()659 ELT& operator()(int i, int j) {return updElt(i,j);} 660 661 /// This returns a copy of the element value for any position in the logical matrix, 662 /// regardless of whether it is stored in memory. If necessary the element's value 663 /// is calculated. This is much slower than getElt() but less restrictive. 664 /// @see getElt() getAnyElt(int i,int j,ELT & value)665 void getAnyElt(int i, int j, ELT& value) const 666 { helper.getAnyElt(i,j,reinterpret_cast<Scalar*>(&value)); } getAnyElt(int i,int j)667 ELT getAnyElt(int i, int j) const {ELT e; getAnyElt(i,j,e); return e;} 668 669 /// Scalar norm square is sum( squares of all scalars ). Note that this 670 /// is not very useful unless the elements are themselves scalars. 671 // TODO: very slow! Should be optimized at least for the case 672 // where ELT is a Scalar. scalarNormSqr()673 ScalarNormSq scalarNormSqr() const { 674 const int nr=nrow(), nc=ncol(); 675 ScalarNormSq sum(0); 676 for(int j=0;j<nc;++j) 677 for (int i=0; i<nr; ++i) 678 sum += CNT<E>::scalarNormSqr((*this)(i,j)); 679 return sum; 680 } 681 682 /// abs() is elementwise absolute value; that is, the return value has the same 683 /// dimension as this Matrix but with each element replaced by whatever it thinks 684 /// its absolute value is. 685 // TODO: very slow! Should be optimized at least for the case 686 // where ELT is a Scalar. abs(TAbs & mabs)687 void abs(TAbs& mabs) const { 688 const int nr=nrow(), nc=ncol(); 689 mabs.resize(nr,nc); 690 for(int j=0;j<nc;++j) 691 for (int i=0; i<nr; ++i) 692 mabs(i,j) = CNT<E>::abs((*this)(i,j)); 693 } 694 695 /// abs() with the result as a function return. More convenient than the 696 /// other abs() member function, but may involve an additional copy of the 697 /// matrix. abs()698 TAbs abs() const { TAbs mabs; abs(mabs); return mabs; } 699 700 /// Return a Matrix of the same shape and contents as this one but 701 /// with the element type converted to one based on the standard 702 /// C++ scalar types: float, double, complex<float>, 703 /// complex<double>. That is, negator<> 704 /// and conjugate<> are eliminated from the element type by 705 /// performing any needed negations computationally. 706 /// Note that this is actually producing a new matrix with new data; 707 /// you can also do this for free by reinterpreting the current 708 /// matrix as a different type, if you don't mind looking at 709 /// shared data. standardize()710 TStandard standardize() const { 711 const int nr=nrow(), nc=ncol(); 712 TStandard mstd(nr, nc); 713 for(int j=0;j<nc;++j) 714 for (int i=0; i<nr; ++i) 715 mstd(i,j) = CNT<E>::standardize((*this)(i,j)); 716 return mstd; 717 } 718 719 /// This is the scalar Frobenius norm, and its square. Note: if this is a 720 /// Matrix then the Frobenius norm is NOT the same as the 2-norm, although 721 /// they are equivalent for Vectors. normSqr()722 ScalarNormSq normSqr() const { return scalarNormSqr(); } 723 // TODO -- not good; unnecessary overflow 724 typename CNT<ScalarNormSq>::TSqrt norm()725 norm() const { return CNT<ScalarNormSq>::sqrt(scalarNormSqr()); } 726 727 /// We only allow RMS norm if the elements are scalars. If there are no 728 /// elements in this Matrix, we'll define its RMS norm to be 0, although 729 /// NaN might be a better choice. 730 typename CNT<ScalarNormSq>::TSqrt normRMS()731 normRMS() const { 732 if (!CNT<ELT>::IsScalar) 733 SimTK_THROW1(Exception::Cant, "normRMS() only defined for scalar elements"); 734 if (nelt() == 0) 735 return typename CNT<ScalarNormSq>::TSqrt(0); 736 return CNT<ScalarNormSq>::sqrt(scalarNormSqr()/nelt()); 737 } 738 739 /// Form the column sums of this matrix, returned as a RowVector. colSum()740 RowVector_<ELT> colSum() const { 741 const int cols = ncol(); 742 RowVector_<ELT> row(cols); 743 for (int j = 0; j < cols; ++j) 744 helper.colSum(j, reinterpret_cast<Scalar*>(&row[j])); 745 return row; 746 } 747 /// Alternate name for colSum(); behaves like the Matlab function sum(). sum()748 RowVector_<ELT> sum() const {return colSum();} 749 750 /// Form the row sums of this matrix, returned as a Vector. rowSum()751 Vector_<ELT> rowSum() const { 752 const int rows = nrow(); 753 Vector_<ELT> col(rows); 754 for (int i = 0; i < rows; ++i) 755 helper.rowSum(i, reinterpret_cast<Scalar*>(&col[i])); 756 return col; 757 } 758 759 //TODO: make unary +/- return a self-view so they won't reallocate? 760 const MatrixBase& operator+() const {return *this; } negate()761 const TNeg& negate() const {return *reinterpret_cast<const TNeg*>(this); } updNegate()762 TNeg& updNegate() {return *reinterpret_cast<TNeg*>(this); } 763 764 const TNeg& operator-() const {return negate();} 765 TNeg& operator-() {return updNegate();} 766 negateInPlace()767 MatrixBase& negateInPlace() {(*this) *= EPrecision(-1); return *this;} 768 769 /// Change the size of this matrix. This is only allowed for owner matrices. The 770 /// current storage format is retained, but all the data is lost. If you want 771 /// to keep the old data, use resizeKeep(). 772 /// @see resizeKeep() resize(int m,int n)773 MatrixBase& resize(int m, int n) { helper.resize(m,n); return *this; } 774 /// Change the size of this matrix, retaining as much of the old data as will 775 /// fit. This is only allowed for owner matrices. The 776 /// current storage format is retained, and the existing data is copied 777 /// into the new memory to the extent that it will fit. 778 /// @see resize() resizeKeep(int m,int n)779 MatrixBase& resizeKeep(int m, int n) { helper.resizeKeep(m,n); return *this; } 780 781 // This prevents shape changes in a Matrix that would otherwise allow it. No harm if is 782 // are called on a Matrix that is locked already; it always succeeds. lockShape()783 void lockShape() {helper.lockShape();} 784 785 // This allows shape changes again for a Matrix which was constructed to allow them 786 // but had them locked with the above routine. No harm if this is called on a Matrix 787 // that is already unlocked, but it is not allowed to call this on a Matrix which 788 // *never* allowed resizing. An exception will be thrown in that case. unlockShape()789 void unlockShape() {helper.unlockShape();} 790 791 // An assortment of handy conversions getAsMatrixView()792 const MatrixView_<ELT>& getAsMatrixView() const { return *reinterpret_cast<const MatrixView_<ELT>*>(this); } updAsMatrixView()793 MatrixView_<ELT>& updAsMatrixView() { return *reinterpret_cast< MatrixView_<ELT>*>(this); } getAsMatrix()794 const Matrix_<ELT>& getAsMatrix() const { return *reinterpret_cast<const Matrix_<ELT>*>(this); } updAsMatrix()795 Matrix_<ELT>& updAsMatrix() { return *reinterpret_cast< Matrix_<ELT>*>(this); } 796 getAsVectorView()797 const VectorView_<ELT>& getAsVectorView() const 798 { assert(ncol()==1); return *reinterpret_cast<const VectorView_<ELT>*>(this); } updAsVectorView()799 VectorView_<ELT>& updAsVectorView() 800 { assert(ncol()==1); return *reinterpret_cast< VectorView_<ELT>*>(this); } getAsVector()801 const Vector_<ELT>& getAsVector() const 802 { assert(ncol()==1); return *reinterpret_cast<const Vector_<ELT>*>(this); } updAsVector()803 Vector_<ELT>& updAsVector() 804 { assert(ncol()==1); return *reinterpret_cast< Vector_<ELT>*>(this); } getAsVectorBase()805 const VectorBase<ELT>& getAsVectorBase() const 806 { assert(ncol()==1); return *reinterpret_cast<const VectorBase<ELT>*>(this); } updAsVectorBase()807 VectorBase<ELT>& updAsVectorBase() 808 { assert(ncol()==1); return *reinterpret_cast< VectorBase<ELT>*>(this); } 809 getAsRowVectorView()810 const RowVectorView_<ELT>& getAsRowVectorView() const 811 { assert(nrow()==1); return *reinterpret_cast<const RowVectorView_<ELT>*>(this); } updAsRowVectorView()812 RowVectorView_<ELT>& updAsRowVectorView() 813 { assert(nrow()==1); return *reinterpret_cast< RowVectorView_<ELT>*>(this); } getAsRowVector()814 const RowVector_<ELT>& getAsRowVector() const 815 { assert(nrow()==1); return *reinterpret_cast<const RowVector_<ELT>*>(this); } updAsRowVector()816 RowVector_<ELT>& updAsRowVector() 817 { assert(nrow()==1); return *reinterpret_cast< RowVector_<ELT>*>(this); } getAsRowVectorBase()818 const RowVectorBase<ELT>& getAsRowVectorBase() const 819 { assert(nrow()==1); return *reinterpret_cast<const RowVectorBase<ELT>*>(this); } updAsRowVectorBase()820 RowVectorBase<ELT>& updAsRowVectorBase() 821 { assert(nrow()==1); return *reinterpret_cast< RowVectorBase<ELT>*>(this); } 822 823 // Access to raw data. We have to return the raw data 824 // pointer as pointer-to-scalar because we may pack the elements tighter 825 // than a C++ array would. 826 827 /// This is the number of consecutive scalars used to represent one 828 /// element of type ELT. This may be fewer than C++ would use for the 829 /// element, since it may introduce some padding. getNScalarsPerElement()830 int getNScalarsPerElement() const {return NScalarsPerElement;} 831 832 /// This is like sizeof(ELT), but returning the number of bytes \e we use 833 /// to store the element which may be fewer than what C++ would use. We store 834 /// these packed elements adjacent to one another in memory. getPackedSizeofElement()835 int getPackedSizeofElement() const {return NScalarsPerElement*sizeof(Scalar);} 836 hasContiguousData()837 bool hasContiguousData() const {return helper.hasContiguousData();} getContiguousScalarDataLength()838 ptrdiff_t getContiguousScalarDataLength() const { 839 return helper.getContiguousDataLength(); 840 } getContiguousScalarData()841 const Scalar* getContiguousScalarData() const { 842 return helper.getContiguousData(); 843 } updContiguousScalarData()844 Scalar* updContiguousScalarData() { 845 return helper.updContiguousData(); 846 } replaceContiguousScalarData(Scalar * newData,ptrdiff_t length,bool takeOwnership)847 void replaceContiguousScalarData(Scalar* newData, ptrdiff_t length, bool takeOwnership) { 848 helper.replaceContiguousData(newData,length,takeOwnership); 849 } replaceContiguousScalarData(const Scalar * newData,ptrdiff_t length)850 void replaceContiguousScalarData(const Scalar* newData, ptrdiff_t length) { 851 helper.replaceContiguousData(newData,length); 852 } swapOwnedContiguousScalarData(Scalar * newData,ptrdiff_t length,Scalar * & oldData)853 void swapOwnedContiguousScalarData(Scalar* newData, ptrdiff_t length, Scalar*& oldData) { 854 helper.swapOwnedContiguousData(newData,length,oldData); 855 } 856 857 /// Helper rep-stealing constructor. We take over ownership of this rep here. Note 858 /// that this \e defines the handle commitment for this handle. This is intended 859 /// for internal use only -- don't call this constructor unless you really 860 /// know what you're doing. MatrixBase(MatrixHelperRep<Scalar> * hrep)861 explicit MatrixBase(MatrixHelperRep<Scalar>* hrep) : helper(hrep) {} 862 863 protected: getHelper()864 const MatrixHelper<Scalar>& getHelper() const {return helper;} updHelper()865 MatrixHelper<Scalar>& updHelper() {return helper;} 866 867 private: 868 MatrixHelper<Scalar> helper; // this is just one pointer 869 870 template <class EE> friend class MatrixBase; 871 872 // ============================= Unimplemented ============================= 873 // This routine is useful for implementing friendlier Matrix expressions and operators. 874 // It maps closely to the Level-3 BLAS family of pxxmm() routines like sgemm(). The 875 // operation performed assumes that "this" is the result, and that "this" has 876 // already been sized correctly to receive the result. We'll compute 877 // this = beta*this + alpha*A*B 878 // If beta is 0 then "this" can be uninitialized. If alpha is 0 we promise not 879 // to look at A or B. The routine can work efficiently even if A and/or B are transposed 880 // by their views, so an expression like 881 // C += s * ~A * ~B 882 // can be performed with the single equivalent call 883 // C.matmul(1., s, Tr(A), Tr(B)) 884 // where Tr(A) indicates a transposed view of the original A. 885 // The ultimate efficiency of this call depends on the data layout and views which 886 // are used for the three matrices. 887 // NOTE: neither A nor B can be the same matrix as 'this', nor views of the same data 888 // which would expose elements of 'this' that will be modified by this operation. 889 template <class ELT_A, class ELT_B> matmul(const StdNumber & beta,const StdNumber & alpha,const MatrixBase<ELT_A> & A,const MatrixBase<ELT_B> & B)890 MatrixBase& matmul(const StdNumber& beta, // applied to 'this' 891 const StdNumber& alpha, const MatrixBase<ELT_A>& A, const MatrixBase<ELT_B>& B) 892 { 893 helper.matmul(beta,alpha,A.helper,B.helper); 894 return *this; 895 } 896 897 }; 898 899 } //namespace SimTK 900 901 #endif // SimTK_SIMMATRIX_MATRIXBASE_H_ 902