Simbody
|
00001 #ifndef SimTK_SIMMATRIX_SMALLMATRIX_SYMMAT_H_ 00002 #define SimTK_SIMMATRIX_SMALLMATRIX_SYMMAT_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-10 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 00074 #include "SimTKcommon/internal/common.h" 00075 00076 namespace SimTK { 00077 00079 template <int M, class ELT, int RS> class SymMat { 00080 typedef ELT E; 00081 typedef typename CNT<E>::TNeg ENeg; 00082 typedef typename CNT<E>::TWithoutNegator EWithoutNegator; 00083 typedef typename CNT<E>::TReal EReal; 00084 typedef typename CNT<E>::TImag EImag; 00085 typedef typename CNT<E>::TComplex EComplex; 00086 typedef typename CNT<E>::THerm EHerm; 00087 typedef typename CNT<E>::TPosTrans EPosTrans; 00088 typedef typename CNT<E>::TSqHermT ESqHermT; 00089 typedef typename CNT<E>::TSqTHerm ESqTHerm; 00090 00091 typedef typename CNT<E>::TSqrt ESqrt; 00092 typedef typename CNT<E>::TAbs EAbs; 00093 typedef typename CNT<E>::TStandard EStandard; 00094 typedef typename CNT<E>::TInvert EInvert; 00095 typedef typename CNT<E>::TNormalize ENormalize; 00096 00097 typedef typename CNT<E>::Scalar EScalar; 00098 typedef typename CNT<E>::ULessScalar EULessScalar; 00099 typedef typename CNT<E>::Number ENumber; 00100 typedef typename CNT<E>::StdNumber EStdNumber; 00101 typedef typename CNT<E>::Precision EPrecision; 00102 typedef typename CNT<E>::ScalarNormSq EScalarNormSq; 00103 00104 public: 00105 00106 enum { 00107 NRows = M, 00108 NCols = M, 00109 NDiagElements = M, 00110 NLowerElements = (M*(M-1))/2, 00111 NPackedElements = NDiagElements+NLowerElements, 00112 NActualElements = RS * NPackedElements, 00113 NActualScalars = CNT<E>::NActualScalars * NActualElements, 00114 RowSpacing = RS, 00115 ColSpacing = NActualElements, 00116 ImagOffset = NTraits<ENumber>::ImagOffset, 00117 RealStrideFactor = 1, // composite types don't change size when 00118 // cast from complex to real or imaginary 00119 ArgDepth = ((int)CNT<E>::ArgDepth < (int)MAX_RESOLVED_DEPTH 00120 ? CNT<E>::ArgDepth + 1 00121 : MAX_RESOLVED_DEPTH), 00122 IsScalar = 0, 00123 IsULessScalar = 0, 00124 IsNumber = 0, 00125 IsStdNumber = 0, 00126 IsPrecision = 0, 00127 SignInterpretation = CNT<E>::SignInterpretation 00128 }; 00129 00130 typedef SymMat<M,E,RS> T; 00131 typedef SymMat<M,ENeg,RS> TNeg; 00132 typedef SymMat<M,EWithoutNegator,RS> TWithoutNegator; 00133 00134 typedef SymMat<M,EReal,RS*CNT<E>::RealStrideFactor> 00135 TReal; 00136 typedef SymMat<M,EImag,RS*CNT<E>::RealStrideFactor> 00137 TImag; 00138 typedef SymMat<M,EComplex,RS> TComplex; 00139 typedef T THerm; // These two are opposite of what you might expect 00140 typedef SymMat<M,EHerm,RS> TPosTrans; 00141 typedef E TElement; 00142 typedef Vec<M,E,RS> TDiag; // storage type for the diagonal elements 00143 typedef Vec<(M*(M-1))/2,E,RS> TLower; // storage type for the below-diag elements 00144 typedef Vec<(M*(M-1))/2,EHerm,RS> TUpper; // cast TLower to this for upper elements 00145 typedef Vec<(M*(M+1))/2,E,RS> TAsVec; // the whole SymMat as a single Vec 00146 00147 // These are the results of calculations, so are returned in new, packed 00148 // memory. Be sure to refer to element types here which are also packed. 00149 typedef Row<M,E,1> TRow; // packed since we have to copy 00150 typedef Vec<M,E,1> TCol; 00151 typedef SymMat<M,ESqrt,1> TSqrt; 00152 typedef SymMat<M,EAbs,1> TAbs; 00153 typedef SymMat<M,EStandard,1> TStandard; 00154 typedef SymMat<M,EInvert,1> TInvert; 00155 typedef SymMat<M,ENormalize,1> TNormalize; 00156 typedef SymMat<M,ESqHermT,1> TSqHermT; // ~Mat*Mat 00157 typedef SymMat<M,ESqTHerm,1> TSqTHerm; // Mat*~Mat 00158 typedef SymMat<M,E,1> TPacked; // no extra row spacing for new data 00159 00160 typedef EScalar Scalar; 00161 typedef EULessScalar ULessScalar; 00162 typedef ENumber Number; 00163 typedef EStdNumber StdNumber; 00164 typedef EPrecision Precision; 00165 typedef EScalarNormSq ScalarNormSq; 00166 00167 int size() const { return (M*(M+1))/2; } 00168 int nrow() const { return M; } 00169 int ncol() const { return M; } 00170 00171 // Scalar norm square is sum( squares of all scalars ). The off-diagonals 00172 // come up twice. 00173 ScalarNormSq scalarNormSqr() const { 00174 return getDiag().scalarNormSqr() + 2.*getLower().scalarNormSqr(); 00175 } 00176 00177 // sqrt() is elementwise square root; that is, the return value has the same 00178 // dimension as this SymMat but with each element replaced by whatever it thinks 00179 // its square root is. 00180 TSqrt sqrt() const { 00181 return TSqrt(getAsVec().sqrt()); 00182 } 00183 00184 // abs() is elementwise absolute value; that is, the return value has the same 00185 // dimension as this SymMat but with each element replaced by whatever it thinks 00186 // its absolute value is. 00187 TAbs abs() const { 00188 return TAbs(getAsVec().abs()); 00189 } 00190 00191 TStandard standardize() const { 00192 return TStandard(getAsVec().standardize()); 00193 } 00194 00195 EStandard trace() const {return getDiag().sum();} 00196 00197 // This gives the resulting SymMat type when (m[i] op P) is applied to each element of m. 00198 // It is a SymMat of dimension M, spacing 1, and element types which are the regular 00199 // composite result of E op P. Typically P is a scalar type but it doesn't have to be. 00200 template <class P> struct EltResult { 00201 typedef SymMat<M, typename CNT<E>::template Result<P>::Mul, 1> Mul; 00202 typedef SymMat<M, typename CNT<E>::template Result<P>::Dvd, 1> Dvd; 00203 typedef SymMat<M, typename CNT<E>::template Result<P>::Add, 1> Add; 00204 typedef SymMat<M, typename CNT<E>::template Result<P>::Sub, 1> Sub; 00205 }; 00206 00207 // This is the composite result for m op P where P is some kind of appropriately shaped 00208 // non-scalar type. 00209 template <class P> struct Result { 00210 typedef MulCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing, 00211 CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth, 00212 P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> MulOp; 00213 typedef typename MulOp::Type Mul; 00214 00215 typedef MulCNTsNonConforming<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing, 00216 CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth, 00217 P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> MulOpNonConforming; 00218 typedef typename MulOpNonConforming::Type MulNon; 00219 00220 00221 typedef DvdCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing, 00222 CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth, 00223 P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> DvdOp; 00224 typedef typename DvdOp::Type Dvd; 00225 00226 typedef AddCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing, 00227 CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth, 00228 P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> AddOp; 00229 typedef typename AddOp::Type Add; 00230 00231 typedef SubCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing, 00232 CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth, 00233 P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> SubOp; 00234 typedef typename SubOp::Type Sub; 00235 }; 00236 00237 // Shape-preserving element substitution (always packed) 00238 template <class P> struct Substitute { 00239 typedef SymMat<M,P> Type; 00240 }; 00241 00244 SymMat(){ 00245 #ifndef NDEBUG 00246 setToNaN(); 00247 #endif 00248 } 00249 00251 SymMat(const SymMat& src) { 00252 updAsVec() = src.getAsVec(); 00253 } 00254 00256 SymMat& operator=(const SymMat& src) { 00257 updAsVec() = src.getAsVec(); 00258 return *this; 00259 } 00260 00271 template <class EE, int CSS, int RSS> 00272 explicit SymMat(const Mat<M,M,EE,CSS,RSS>& m) 00273 { setFromSymmetric(m); } 00274 00278 template <class EE, int CSS, int RSS> 00279 SymMat& setFromLower(const Mat<M,M,EE,CSS,RSS>& m) { 00280 this->updDiag() = m.diag().real(); 00281 for (int j=0; j<M; ++j) 00282 for (int i=j+1; i<M; ++i) 00283 this->updEltLower(i,j) = m(i,j); 00284 return *this; 00285 } 00286 00294 template <class EE, int CSS, int RSS> 00295 SymMat& setFromUpper(const Mat<M,M,EE,CSS,RSS>& m) { 00296 this->updDiag() = m.diag().real(); 00297 for (int j=0; j<M; ++j) 00298 for (int i=j+1; i<M; ++i) 00299 this->updEltLower(i,j) = m(j,i); 00300 return *this; 00301 } 00302 00308 template <class EE, int CSS, int RSS> 00309 SymMat& setFromSymmetric(const Mat<M,M,EE,CSS,RSS>& m) { 00310 SimTK_ERRCHK1(m.isNumericallySymmetric(), "SymMat::setFromSymmetric()", 00311 "The allegedly symmetric source matrix was not symmetric to within " 00312 "a tolerance of %g.", m.getDefaultTolerance()); 00313 this->updDiag() = m.diag().real(); 00314 for (int j=0; j<M; ++j) 00315 for (int i=j+1; i<M; ++i) 00316 this->updEltLower(i,j) = 00317 (m(i,j) + CNT<EE>::transpose(m(j,i)))/2; 00318 return *this; 00319 } 00320 00323 template <int RSS> SymMat(const SymMat<M,E,RSS>& src) 00324 { updAsVec() = src.getAsVec(); } 00325 00328 template <int RSS> SymMat(const SymMat<M,ENeg,RSS>& src) 00329 { updAsVec() = src.getAsVec(); } 00330 00334 template <class EE, int RSS> explicit SymMat(const SymMat<M,EE,RSS>& src) 00335 { updAsVec() = src.getAsVec(); } 00336 00337 // Construction using an element repeats that element on the diagonal 00338 // but sets the rest of the matrix to zero. 00339 explicit SymMat(const E& e) { 00340 updDiag() = CNT<E>::real(e); 00341 for (int i=0; i < NLowerElements; ++i) updlowerE(i) = E(0); 00342 } 00343 00344 // Construction using a negated element is just like construction from 00345 // the element. 00346 explicit SymMat(const ENeg& e) { 00347 updDiag() = CNT<ENeg>::real(e); 00348 for (int i=0; i < NLowerElements; ++i) updlowerE(i) = E(0); 00349 } 00350 00351 // Given an int, turn it into a suitable floating point number 00352 // and then feed that to the above single-element constructor. 00353 explicit SymMat(int i) 00354 { new (this) SymMat(E(Precision(i))); } 00355 00369 00370 SymMat(const E& e0, 00371 const E& e1,const E& e2) 00372 { assert(M==2); TDiag& d=updDiag(); TLower& l=updLower(); 00373 d[0]=CNT<E>::real(e0); d[1]=CNT<E>::real(e2); 00374 l[0]=e1; } 00375 00376 SymMat(const E& e0, 00377 const E& e1,const E& e2, 00378 const E& e3,const E& e4, const E& e5) 00379 { assert(M==3); TDiag& d=updDiag(); TLower& l=updLower(); 00380 d[0]=CNT<E>::real(e0);d[1]=CNT<E>::real(e2);d[2]=CNT<E>::real(e5); 00381 l[0]=e1;l[1]=e3; 00382 l[2]=e4; } 00383 00384 SymMat(const E& e0, 00385 const E& e1,const E& e2, 00386 const E& e3,const E& e4, const E& e5, 00387 const E& e6,const E& e7, const E& e8, const E& e9) 00388 { assert(M==4); TDiag& d=updDiag(); TLower& l=updLower(); 00389 d[0]=CNT<E>::real(e0);d[1]=CNT<E>::real(e2);d[2]=CNT<E>::real(e5);d[3]=CNT<E>::real(e9); 00390 l[0]=e1;l[1]=e3;l[2]=e6; 00391 l[3]=e4;l[4]=e7; 00392 l[5]=e8; } 00393 00394 SymMat(const E& e0, 00395 const E& e1, const E& e2, 00396 const E& e3, const E& e4, const E& e5, 00397 const E& e6, const E& e7, const E& e8, const E& e9, 00398 const E& e10,const E& e11, const E& e12, const E& e13, const E& e14) 00399 { assert(M==5); TDiag& d=updDiag(); TLower& l=updLower(); 00400 d[0]=CNT<E>::real(e0);d[1]=CNT<E>::real(e2);d[2]=CNT<E>::real(e5);d[3]=CNT<E>::real(e9);d[4]=CNT<E>::real(e14); 00401 l[0]=e1;l[1]=e3;l[2]=e6;l[3]=e10; 00402 l[4]=e4;l[5]=e7;l[6]=e11; 00403 l[7]=e8;l[8]=e12; 00404 l[9]=e13; } 00405 00406 SymMat(const E& e0, 00407 const E& e1, const E& e2, 00408 const E& e3, const E& e4, const E& e5, 00409 const E& e6, const E& e7, const E& e8, const E& e9, 00410 const E& e10,const E& e11, const E& e12, const E& e13, const E& e14, 00411 const E& e15,const E& e16, const E& e17, const E& e18, const E& e19, const E& e20) 00412 { assert(M==6); TDiag& d=updDiag(); TLower& l=updLower(); 00413 d[0]=CNT<E>::real(e0);d[1]=CNT<E>::real(e2);d[2]=CNT<E>::real(e5); 00414 d[3]=CNT<E>::real(e9);d[4]=CNT<E>::real(e14);d[5]=CNT<E>::real(e20); 00415 l[0] =e1; l[1] =e3; l[2] =e6; l[3]=e10; l[4]=e15; 00416 l[5] =e4; l[6] =e7; l[7] =e11; l[8]=e16; 00417 l[9] =e8; l[10]=e12;l[11]=e17; 00418 l[12]=e13;l[13]=e18; 00419 l[14]=e19; } 00420 00421 // Construction from a pointer to anything assumes we're pointing 00422 // at a packed element list of the right length, providing the 00423 // lower triangle in row order, so a b c d e f means 00424 // a 00425 // b c 00426 // d e f 00427 // g h i j 00428 // This has to be mapped to our diagonal/lower layout, which in 00429 // the above example will be: 00430 // [a c f j][b d g e h i] 00431 // 00432 // In the input layout, the i'th row begins at element i(i+1)/2, 00433 // so diagonals are at i(i+1)/2 + i, while lower 00434 // elements (i,j; i>j) are at i(i+1)/2 + j. 00435 template <class EE> explicit SymMat(const EE* p) { 00436 assert(p); 00437 for (int i=0; i<M; ++i) { 00438 const int rowStart = (i*(i+1))/2; 00439 updDiag()[i] = CNT<EE>::real(p[rowStart + i]); 00440 for (int j=0; j<i; ++j) 00441 updEltLower(i,j) = p[rowStart + j]; 00442 } 00443 } 00444 00445 // This is the same thing except as an assignment to pointer rather 00446 // than a constructor from pointer. 00447 template <class EE> SymMat& operator=(const EE* p) { 00448 assert(p); 00449 for (int i=0; i<M; ++i) { 00450 const int rowStart = (i*(i+1))/2; 00451 updDiag()[i] = CNT<EE>::real(p[rowStart + i]); 00452 for (int j=0; j<i; ++j) 00453 updEltLower(i,j) = p[rowStart + j]; 00454 } 00455 return *this; 00456 } 00457 00458 // Assignment works similarly to copy -- if the lengths match, 00459 // go element-by-element. Otherwise, zero and then copy to each 00460 // diagonal element. 00461 template <class EE, int RSS> SymMat& operator=(const SymMat<M,EE,RSS>& mm) { 00462 updAsVec() = mm.getAsVec(); 00463 return *this; 00464 } 00465 00466 00467 // Conforming assignment ops 00468 template <class EE, int RSS> SymMat& 00469 operator+=(const SymMat<M,EE,RSS>& mm) { 00470 updAsVec() += mm.getAsVec(); 00471 return *this; 00472 } 00473 template <class EE, int RSS> SymMat& 00474 operator+=(const SymMat<M,negator<EE>,RSS>& mm) { 00475 updAsVec() -= -mm.getAsVec(); // negation of negator is free 00476 return *this; 00477 } 00478 00479 template <class EE, int RSS> SymMat& 00480 operator-=(const SymMat<M,EE,RSS>& mm) { 00481 updAsVec() -= mm.getAsVec(); 00482 return *this; 00483 } 00484 template <class EE, int RSS> SymMat& 00485 operator-=(const SymMat<M,negator<EE>,RSS>& mm) { 00486 updAsVec() += -mm.getAsVec(); // negation of negator is free 00487 return *this; 00488 } 00489 00490 // In place matrix multiply can only be done when the RHS matrix is the same 00491 // size and the elements are also *= compatible. 00492 template <class EE, int RSS> SymMat& 00493 operator*=(const SymMat<M,EE,RSS>& mm) { 00494 assert(false); // TODO 00495 return *this; 00496 } 00497 00498 // Conforming binary ops with 'this' on left, producing new packed result. 00499 // Cases: sy=sy+-sy, m=sy+-m, m=sy*sy, m=sy*m, v=sy*v 00500 00501 // sy= this + sy 00502 template <class E2, int RS2> 00503 typename Result<SymMat<M,E2,RS2> >::Add 00504 conformingAdd(const SymMat<M,E2,RS2>& r) const { 00505 return typename Result<SymMat<M,E2,RS2> >::Add 00506 (getAsVec().conformingAdd(r.getAsVec())); 00507 } 00508 // m= this - m 00509 template <class E2, int RS2> 00510 typename Result<SymMat<M,E2,RS2> >::Sub 00511 conformingSubtract(const SymMat<M,E2,RS2>& r) const { 00512 return typename Result<SymMat<M,E2,RS2> >::Sub 00513 (getAsVec().conformingSubtract(r.getAsVec())); 00514 } 00515 00516 // symmetric * symmetric produces a full result 00517 // m= this * s 00518 // TODO: this is not a good implementation 00519 template <class E2, int RS2> 00520 typename Result<SymMat<M,E2,RS2> >::Mul 00521 conformingMultiply(const SymMat<M,E2,RS2>& s) const { 00522 typename Result<SymMat<M,E2,RS2> >::Mul result; 00523 for (int j=0;j<M;++j) 00524 for (int i=0;i<M;++i) 00525 result(i,j) = (*this)[i] * s(j); 00526 return result; 00527 } 00528 00529 // TODO: need the rest of the SymMat operators 00530 00531 // Must be i >= j. 00532 const E& operator()(int i,int j) const 00533 { return i==j ? getDiag()[i] : getEltLower(i,j); } 00534 E& operator()(int i,int j) 00535 { return i==j ? updDiag()[i] : updEltLower(i,j); } 00536 00537 // These are slow for a symmetric matrix, requiring copying and 00538 // possibly floating point operations for conjugation. 00539 TRow operator[](int i) const {return row(i);} 00540 TCol operator()(int j) const {return col(j);} 00541 00542 00543 // This is the scalar Frobenius norm. 00544 ScalarNormSq normSqr() const { return scalarNormSqr(); } 00545 typename CNT<ScalarNormSq>::TSqrt 00546 norm() const { return CNT<ScalarNormSq>::sqrt(scalarNormSqr()); } 00547 00559 TNormalize normalize() const { 00560 if (CNT<E>::IsScalar) { 00561 return castAwayNegatorIfAny() / (SignInterpretation*norm()); 00562 } else { 00563 TNormalize elementwiseNormalized; 00564 // punt to the equivalent Vec to get the elements normalized 00565 elementwiseNormalized.updAsVec() = getAsVec().normalize(); 00566 return elementwiseNormalized; 00567 } 00568 } 00569 00570 TInvert invert() const {assert(false); return TInvert();} // TODO default inversion 00571 00572 const SymMat& operator+() const { return *this; } 00573 const TNeg& operator-() const { return negate(); } 00574 TNeg& operator-() { return updNegate(); } 00575 const THerm& operator~() const { return transpose(); } 00576 THerm& operator~() { return updTranspose(); } 00577 00578 const TNeg& negate() const { return *reinterpret_cast<const TNeg*>(this); } 00579 TNeg& updNegate() { return *reinterpret_cast<TNeg*>(this); } 00580 00581 const THerm& transpose() const { return *reinterpret_cast<const THerm*>(this); } 00582 THerm& updTranspose() { return *reinterpret_cast<THerm*>(this); } 00583 00584 const TPosTrans& positionalTranspose() const 00585 { return *reinterpret_cast<const TPosTrans*>(this); } 00586 TPosTrans& updPositionalTranspose() 00587 { return *reinterpret_cast<TPosTrans*>(this); } 00588 00589 const TReal& real() const { return *reinterpret_cast<const TReal*>(this); } 00590 TReal& real() { return *reinterpret_cast< TReal*>(this); } 00591 00592 // Had to contort these routines to get them through VC++ 7.net 00593 const TImag& imag() const { 00594 const int offs = ImagOffset; 00595 const EImag* p = reinterpret_cast<const EImag*>(this); 00596 return *reinterpret_cast<const TImag*>(p+offs); 00597 } 00598 TImag& imag() { 00599 const int offs = ImagOffset; 00600 EImag* p = reinterpret_cast<EImag*>(this); 00601 return *reinterpret_cast<TImag*>(p+offs); 00602 } 00603 00604 const TWithoutNegator& castAwayNegatorIfAny() const {return *reinterpret_cast<const TWithoutNegator*>(this);} 00605 TWithoutNegator& updCastAwayNegatorIfAny() {return *reinterpret_cast<TWithoutNegator*>(this);} 00606 00607 // These are elementwise binary operators, (this op ee) by default but (ee op this) if 00608 // 'FromLeft' appears in the name. The result is a packed SymMat<M> but the element type 00609 // may change. These are mostly used to implement global operators. 00610 // We call these "scalar" operators but actually the "scalar" can be a composite type. 00611 00612 //TODO: consider converting 'e' to Standard Numbers as precalculation and changing 00613 // return type appropriately. 00614 template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Mul> 00615 scalarMultiply(const EE& e) const { 00616 SymMat<M, typename CNT<E>::template Result<EE>::Mul> result; 00617 result.updAsVec() = getAsVec().scalarMultiply(e); 00618 return result; 00619 } 00620 template <class EE> SymMat<M, typename CNT<EE>::template Result<E>::Mul> 00621 scalarMultiplyFromLeft(const EE& e) const { 00622 SymMat<M, typename CNT<EE>::template Result<E>::Mul> result; 00623 result.updAsVec() = getAsVec().scalarMultiplyFromLeft(e); 00624 return result; 00625 } 00626 00627 // TODO: should precalculate and store 1/e, while converting to Standard Numbers. Note 00628 // that return type should change appropriately. 00629 template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Dvd> 00630 scalarDivide(const EE& e) const { 00631 SymMat<M, typename CNT<E>::template Result<EE>::Dvd> result; 00632 result.updAsVec() = getAsVec().scalarDivide(e); 00633 return result; 00634 } 00635 template <class EE> SymMat<M, typename CNT<EE>::template Result<E>::Dvd> 00636 scalarDivideFromLeft(const EE& e) const { 00637 SymMat<M, typename CNT<EE>::template Result<E>::Dvd> result; 00638 result.updAsVec() = getAsVec().scalarDivideFromLeft(e); 00639 return result; 00640 } 00641 00642 // Additive ops involving a scalar update only the diagonal 00643 template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Add> 00644 scalarAdd(const EE& e) const { 00645 SymMat<M, typename CNT<E>::template Result<EE>::Add> result(*this); 00646 result.updDiag() += e; 00647 return result; 00648 } 00649 // Add is commutative, so no 'FromLeft'. 00650 00651 template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Sub> 00652 scalarSubtract(const EE& e) const { 00653 SymMat<M, typename CNT<E>::template Result<EE>::Sub> result(*this); 00654 result.diag() -= e; 00655 return result; 00656 } 00657 // This is s-m; negate m and add s to diagonal 00658 // TODO: Should do something clever with negation here. 00659 template <class EE> SymMat<M, typename CNT<EE>::template Result<E>::Sub> 00660 scalarSubtractFromLeft(const EE& e) const { 00661 SymMat<M, typename CNT<EE>::template Result<E>::Sub> result(-(*this)); 00662 result.diag() += e; 00663 return result; 00664 } 00665 00666 // Generic assignments for any element type not listed explicitly, including scalars. 00667 // These are done repeatedly for each element and only work if the operation can 00668 // be performed leaving the original element type. 00669 template <class EE> SymMat& operator =(const EE& e) {return scalarEq(e);} 00670 template <class EE> SymMat& operator+=(const EE& e) {return scalarPlusEq(e);} 00671 template <class EE> SymMat& operator-=(const EE& e) {return scalarMinusEq(e);} 00672 template <class EE> SymMat& operator*=(const EE& e) {return scalarTimesEq(e);} 00673 template <class EE> SymMat& operator/=(const EE& e) {return scalarDivideEq(e);} 00674 00675 // Generalized scalar assignment & computed assignment methods. These will work 00676 // for any assignment-compatible element, not just scalars. 00677 template <class EE> SymMat& scalarEq(const EE& ee) 00678 { updDiag() = ee; updLower() = E(0); return *this; } 00679 template <class EE> SymMat& scalarPlusEq(const EE& ee) 00680 { updDiag() += ee; return *this; } 00681 template <class EE> SymMat& scalarMinusEq(const EE& ee) 00682 { updDiag() -= ee; return *this; } 00683 00684 // this is m = s-m; negate off diagonal, do d=s-d for each diagonal element d 00685 template <class EE> SymMat& scalarMinusEqFromLeft(const EE& ee) 00686 { updLower() *= E(-1); updDiag().scalarMinusEqFromLeft(ee); return *this; } 00687 00688 template <class EE> SymMat& scalarTimesEq(const EE& ee) 00689 { updAsVec() *= ee; return *this; } 00690 template <class EE> SymMat& scalarTimesEqFromLeft(const EE& ee) 00691 { updAsVec().scalarTimesEqFromLeft(ee); return *this; } 00692 template <class EE> SymMat& scalarDivideEq(const EE& ee) 00693 { updAsVec() /= ee; return *this; } 00694 template <class EE> SymMat& scalarDivideEqFromLeft(const EE& ee) 00695 { updAsVec().scalarDivideEqFromLeft(ee); return *this; } 00696 00697 void setToNaN() { updAsVec().setToNaN(); } 00698 void setToZero() { updAsVec().setToZero(); } 00699 00700 // These assume we are given a pointer to d[0] of a SymMat<M,E,RS> like this one. 00701 static const SymMat& getAs(const ELT* p) {return *reinterpret_cast<const SymMat*>(p);} 00702 static SymMat& updAs(ELT* p) {return *reinterpret_cast<SymMat*>(p);} 00703 00704 // Note packed spacing 00705 static TPacked getNaN() { 00706 return TPacked(CNT<typename TPacked::TDiag>::getNaN(), 00707 CNT<typename TPacked::TLower>::getNaN()); 00708 } 00709 00711 bool isNaN() const {return getAsVec().isNaN();} 00712 00715 bool isInf() const {return getAsVec().isInf();} 00716 00718 bool isFinite() const {return getAsVec().isFinite();} 00719 00722 static double getDefaultTolerance() {return M*CNT<ELT>::getDefaultTolerance();} 00723 00726 template <class E2, int RS2> 00727 bool isNumericallyEqual(const SymMat<M,E2,RS2>& m, double tol) const { 00728 return getAsVec().isNumericallyEqual(m.getAsVec(), tol); 00729 } 00730 00734 template <class E2, int RS2> 00735 bool isNumericallyEqual(const SymMat<M,E2,RS2>& m) const { 00736 const double tol = std::max(getDefaultTolerance(),m.getDefaultTolerance()); 00737 return isNumericallyEqual(m, tol); 00738 } 00739 00745 bool isNumericallyEqual 00746 (const ELT& e, 00747 double tol = getDefaultTolerance()) const 00748 { 00749 if (!diag().isNumericallyEqual(e, tol)) 00750 return false; 00751 return getLower().isNumericallyEqual(ELT(0), tol); 00752 } 00753 00754 // Rows and columns have to be copied and Hermitian elements have to 00755 // be conjugated at a floating point cost. This isn't the best way 00756 // to work with a symmetric matrix. 00757 TRow row(int i) const { 00758 SimTK_INDEXCHECK(i,M,"SymMat::row[i]"); 00759 TRow rowi; 00760 // Columns left of diagonal are lower. 00761 for (int j=0; j<i; ++j) 00762 rowi[j] = getEltLower(i,j); 00763 rowi[i] = getEltDiag(i); 00764 for (int j=i+1; j<M; ++j) 00765 rowi[j] = getEltUpper(i,j); // conversion from EHerm to E may cost flops 00766 return rowi; 00767 } 00768 00769 TCol col(int j) const { 00770 SimTK_INDEXCHECK(j,M,"SymMat::col(j)"); 00771 TCol colj; 00772 // Rows above diagonal are upper (with conjugated elements). 00773 for (int i=0; i<j; ++i) 00774 colj[i] = getEltUpper(i,j); // conversion from EHerm to E may cost flops 00775 colj[j] = getEltDiag(j); 00776 for (int i=j+1; i<M; ++i) 00777 colj[i] = getEltLower(i,j); 00778 return colj; 00779 } 00780 00786 E elt(int i, int j) const { 00787 SimTK_INDEXCHECK(i,M,"SymMat::elt(i,j)"); 00788 SimTK_INDEXCHECK(j,M,"SymMat::elt(i,j)"); 00789 if (i>j) return getEltLower(i,j); // copy element 00790 else if (i==j) return getEltDiag(i); // copy element 00791 else return getEltUpper(i,j); // conversion from EHerm to E may cost flops 00792 } 00793 00794 const TDiag& getDiag() const {return TDiag::getAs(d);} 00795 TDiag& updDiag() {return TDiag::updAs(d);} 00796 00797 // Conventional synonym 00798 const TDiag& diag() const {return getDiag();} 00799 TDiag& diag() {return updDiag();} 00800 00801 const TLower& getLower() const {return TLower::getAs(&d[M*RS]);} 00802 TLower& updLower() {return TLower::updAs(&d[M*RS]);} 00803 00804 const TUpper& getUpper() const {return reinterpret_cast<const TUpper&>(getLower());} 00805 TUpper& updUpper() {return reinterpret_cast< TUpper&>(updLower());} 00806 00807 const TAsVec& getAsVec() const {return TAsVec::getAs(d);} 00808 TAsVec& updAsVec() {return TAsVec::updAs(d);} 00809 00810 const E& getEltDiag(int i) const {return getDiag()[i];} 00811 E& updEltDiag(int i) {return updDiag()[i];} 00812 00813 // must be i > j 00814 const E& getEltLower(int i, int j) const {return getLower()[lowerIx(i,j)];} 00815 E& updEltLower(int i, int j) {return updLower()[lowerIx(i,j)];} 00816 00817 // must be i < j 00818 const EHerm& getEltUpper(int i, int j) const {return getUpper()[lowerIx(j,i)];} 00819 EHerm& updEltUpper(int i, int j) {return updUpper()[lowerIx(j,i)];} 00820 00821 TRow sum() const { 00822 TRow temp(~getDiag()); 00823 for (int i = 1; i < M; ++i) 00824 for (int j = 0; j < i; ++j) { 00825 const E& value = getEltLower(i, j);; 00826 temp[i] += value; 00827 temp[j] += E(reinterpret_cast<const EHerm&>(value)); 00828 } 00829 return temp; 00830 } 00831 00832 private: 00833 E d[NActualElements]; 00834 00835 // This utility doesn't turn lower or upper into a Vec which could turn 00836 // out to have zero length if this is a 1x1 matrix. 00837 const E& getlowerE(int i) const {return d[(M+i)*RS];} 00838 E& updlowerE(int i) {return d[(M+i)*RS];} 00839 00840 SymMat(const TDiag& di, const TLower& low) { 00841 updDiag() = di; updLower() = low; 00842 } 00843 00844 explicit SymMat(const TAsVec& v) { 00845 TAsVec::updAs(d) = v; 00846 } 00847 00848 // Convert i,j with i>j to an index in "lower". This also gives the 00849 // right index for "upper" with i and j reversed. 00850 static int lowerIx(int i, int j) { 00851 assert(0 <= j && j < i && i < M); 00852 return (i-j-1) + j*(M-1) - (j*(j-1))/2; 00853 } 00854 00855 template <int MM, class EE, int RSS> friend class SymMat; 00856 }; 00857 00859 // Global operators involving two symmetric matrices. // 00860 // sy=sy+sy, sy=sy-sy, m=sy*sy, sy==sy, sy!=sy // 00862 00863 // m3 = m1 + m2 where all m's have the same dimension M. 00864 template <int M, class E1, int S1, class E2, int S2> inline 00865 typename SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >::Add 00866 operator+(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) { 00867 return SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> > 00868 ::AddOp::perform(l,r); 00869 } 00870 00871 // m3 = m1 - m2 where all m's have the same dimension M. 00872 template <int M, class E1, int S1, class E2, int S2> inline 00873 typename SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >::Sub 00874 operator-(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) { 00875 return SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> > 00876 ::SubOp::perform(l,r); 00877 } 00878 00879 // m3 = m1 * m2 where all m's have the same dimension M. 00880 // The result will not be symmetric. 00881 template <int M, class E1, int S1, class E2, int S2> inline 00882 typename SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >::Mul 00883 operator*(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) { 00884 return SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> > 00885 ::MulOp::perform(l,r); 00886 } 00887 00888 // bool = m1 == m2, m1 and m2 have the same dimension M 00889 template <int M, class E1, int S1, class E2, int S2> inline bool 00890 operator==(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) { 00891 return l.getAsVec() == r.getAsVec(); 00892 } 00893 00894 // bool = m1 == m2, m1 and m2 have the same dimension M 00895 template <int M, class E1, int S1, class E2, int S2> inline bool 00896 operator!=(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) {return !(l==r);} 00897 00899 // Global operators involving a SymMat and a scalar. // 00901 00902 // SCALAR MULTIPLY 00903 00904 // m = m*real, real*m 00905 template <int M, class E, int S> inline 00906 typename SymMat<M,E,S>::template Result<float>::Mul 00907 operator*(const SymMat<M,E,S>& l, const float& r) 00908 { return SymMat<M,E,S>::template Result<float>::MulOp::perform(l,r); } 00909 template <int M, class E, int S> inline 00910 typename SymMat<M,E,S>::template Result<float>::Mul 00911 operator*(const float& l, const SymMat<M,E,S>& r) {return r*l;} 00912 00913 template <int M, class E, int S> inline 00914 typename SymMat<M,E,S>::template Result<double>::Mul 00915 operator*(const SymMat<M,E,S>& l, const double& r) 00916 { return SymMat<M,E,S>::template Result<double>::MulOp::perform(l,r); } 00917 template <int M, class E, int S> inline 00918 typename SymMat<M,E,S>::template Result<double>::Mul 00919 operator*(const double& l, const SymMat<M,E,S>& r) {return r*l;} 00920 00921 template <int M, class E, int S> inline 00922 typename SymMat<M,E,S>::template Result<long double>::Mul 00923 operator*(const SymMat<M,E,S>& l, const long double& r) 00924 { return SymMat<M,E,S>::template Result<long double>::MulOp::perform(l,r); } 00925 template <int M, class E, int S> inline 00926 typename SymMat<M,E,S>::template Result<long double>::Mul 00927 operator*(const long double& l, const SymMat<M,E,S>& r) {return r*l;} 00928 00929 // m = m*int, int*m -- just convert int to m's precision float 00930 template <int M, class E, int S> inline 00931 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Mul 00932 operator*(const SymMat<M,E,S>& l, int r) {return l * (typename CNT<E>::Precision)r;} 00933 template <int M, class E, int S> inline 00934 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Mul 00935 operator*(int l, const SymMat<M,E,S>& r) {return r * (typename CNT<E>::Precision)l;} 00936 00937 // Complex, conjugate, and negator are all easy to templatize. 00938 00939 // m = m*complex, complex*m 00940 template <int M, class E, int S, class R> inline 00941 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul 00942 operator*(const SymMat<M,E,S>& l, const std::complex<R>& r) 00943 { return SymMat<M,E,S>::template Result<std::complex<R> >::MulOp::perform(l,r); } 00944 template <int M, class E, int S, class R> inline 00945 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul 00946 operator*(const std::complex<R>& l, const SymMat<M,E,S>& r) {return r*l;} 00947 00948 // m = m*conjugate, conjugate*m (convert conjugate->complex) 00949 template <int M, class E, int S, class R> inline 00950 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul 00951 operator*(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l*(std::complex<R>)r;} 00952 template <int M, class E, int S, class R> inline 00953 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul 00954 operator*(const conjugate<R>& l, const SymMat<M,E,S>& r) {return r*(std::complex<R>)l;} 00955 00956 // m = m*negator, negator*m: convert negator to standard number 00957 template <int M, class E, int S, class R> inline 00958 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Mul 00959 operator*(const SymMat<M,E,S>& l, const negator<R>& r) {return l * (typename negator<R>::StdNumber)(R)r;} 00960 template <int M, class E, int S, class R> inline 00961 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Mul 00962 operator*(const negator<R>& l, const SymMat<M,E,S>& r) {return r * (typename negator<R>::StdNumber)(R)l;} 00963 00964 00965 // SCALAR DIVIDE. This is a scalar operation when the scalar is on the right, 00966 // but when it is on the left it means scalar * pseudoInverse(mat), which is 00967 // a similar symmetric matrix. 00968 00969 // m = m/real, real/m 00970 template <int M, class E, int S> inline 00971 typename SymMat<M,E,S>::template Result<float>::Dvd 00972 operator/(const SymMat<M,E,S>& l, const float& r) 00973 { return SymMat<M,E,S>::template Result<float>::DvdOp::perform(l,r); } 00974 template <int M, class E, int S> inline 00975 typename CNT<float>::template Result<SymMat<M,E,S> >::Dvd 00976 operator/(const float& l, const SymMat<M,E,S>& r) 00977 { return CNT<float>::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); } 00978 00979 template <int M, class E, int S> inline 00980 typename SymMat<M,E,S>::template Result<double>::Dvd 00981 operator/(const SymMat<M,E,S>& l, const double& r) 00982 { return SymMat<M,E,S>::template Result<double>::DvdOp::perform(l,r); } 00983 template <int M, class E, int S> inline 00984 typename CNT<double>::template Result<SymMat<M,E,S> >::Dvd 00985 operator/(const double& l, const SymMat<M,E,S>& r) 00986 { return CNT<double>::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); } 00987 00988 template <int M, class E, int S> inline 00989 typename SymMat<M,E,S>::template Result<long double>::Dvd 00990 operator/(const SymMat<M,E,S>& l, const long double& r) 00991 { return SymMat<M,E,S>::template Result<long double>::DvdOp::perform(l,r); } 00992 template <int M, class E, int S> inline 00993 typename CNT<long double>::template Result<SymMat<M,E,S> >::Dvd 00994 operator/(const long double& l, const SymMat<M,E,S>& r) 00995 { return CNT<long double>::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); } 00996 00997 // m = m/int, int/m -- just convert int to m's precision float 00998 template <int M, class E, int S> inline 00999 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Dvd 01000 operator/(const SymMat<M,E,S>& l, int r) {return l / (typename CNT<E>::Precision)r;} 01001 template <int M, class E, int S> inline 01002 typename CNT<typename CNT<E>::Precision>::template Result<SymMat<M,E,S> >::Dvd 01003 operator/(int l, const SymMat<M,E,S>& r) {return (typename CNT<E>::Precision)l / r;} 01004 01005 01006 // Complex, conjugate, and negator are all easy to templatize. 01007 01008 // m = m/complex, complex/m 01009 template <int M, class E, int S, class R> inline 01010 typename SymMat<M,E,S>::template Result<std::complex<R> >::Dvd 01011 operator/(const SymMat<M,E,S>& l, const std::complex<R>& r) 01012 { return SymMat<M,E,S>::template Result<std::complex<R> >::DvdOp::perform(l,r); } 01013 template <int M, class E, int S, class R> inline 01014 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Dvd 01015 operator/(const std::complex<R>& l, const SymMat<M,E,S>& r) 01016 { return CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); } 01017 01018 // m = m/conjugate, conjugate/m (convert conjugate->complex) 01019 template <int M, class E, int S, class R> inline 01020 typename SymMat<M,E,S>::template Result<std::complex<R> >::Dvd 01021 operator/(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l/(std::complex<R>)r;} 01022 template <int M, class E, int S, class R> inline 01023 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Dvd 01024 operator/(const conjugate<R>& l, const SymMat<M,E,S>& r) {return (std::complex<R>)l/r;} 01025 01026 // m = m/negator, negator/m: convert negator to number 01027 template <int M, class E, int S, class R> inline 01028 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Dvd 01029 operator/(const SymMat<M,E,S>& l, const negator<R>& r) {return l/(typename negator<R>::StdNumber)(R)r;} 01030 template <int M, class E, int S, class R> inline 01031 typename CNT<R>::template Result<SymMat<M,E,S> >::Dvd 01032 operator/(const negator<R>& l, const SymMat<M,E,S>& r) {return (typename negator<R>::StdNumber)(R)l/r;} 01033 01034 01035 // Add and subtract are odd as scalar ops. They behave as though the 01036 // scalar stands for a conforming matrix whose diagonal elements are that, 01037 // scalar and then a normal matrix add or subtract is done. 01038 01039 // SCALAR ADD 01040 01041 // m = m+real, real+m 01042 template <int M, class E, int S> inline 01043 typename SymMat<M,E,S>::template Result<float>::Add 01044 operator+(const SymMat<M,E,S>& l, const float& r) 01045 { return SymMat<M,E,S>::template Result<float>::AddOp::perform(l,r); } 01046 template <int M, class E, int S> inline 01047 typename SymMat<M,E,S>::template Result<float>::Add 01048 operator+(const float& l, const SymMat<M,E,S>& r) {return r+l;} 01049 01050 template <int M, class E, int S> inline 01051 typename SymMat<M,E,S>::template Result<double>::Add 01052 operator+(const SymMat<M,E,S>& l, const double& r) 01053 { return SymMat<M,E,S>::template Result<double>::AddOp::perform(l,r); } 01054 template <int M, class E, int S> inline 01055 typename SymMat<M,E,S>::template Result<double>::Add 01056 operator+(const double& l, const SymMat<M,E,S>& r) {return r+l;} 01057 01058 template <int M, class E, int S> inline 01059 typename SymMat<M,E,S>::template Result<long double>::Add 01060 operator+(const SymMat<M,E,S>& l, const long double& r) 01061 { return SymMat<M,E,S>::template Result<long double>::AddOp::perform(l,r); } 01062 template <int M, class E, int S> inline 01063 typename SymMat<M,E,S>::template Result<long double>::Add 01064 operator+(const long double& l, const SymMat<M,E,S>& r) {return r+l;} 01065 01066 // m = m+int, int+m -- just convert int to m's precision float 01067 template <int M, class E, int S> inline 01068 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Add 01069 operator+(const SymMat<M,E,S>& l, int r) {return l + (typename CNT<E>::Precision)r;} 01070 template <int M, class E, int S> inline 01071 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Add 01072 operator+(int l, const SymMat<M,E,S>& r) {return r + (typename CNT<E>::Precision)l;} 01073 01074 // Complex, conjugate, and negator are all easy to templatize. 01075 01076 // m = m+complex, complex+m 01077 template <int M, class E, int S, class R> inline 01078 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add 01079 operator+(const SymMat<M,E,S>& l, const std::complex<R>& r) 01080 { return SymMat<M,E,S>::template Result<std::complex<R> >::AddOp::perform(l,r); } 01081 template <int M, class E, int S, class R> inline 01082 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add 01083 operator+(const std::complex<R>& l, const SymMat<M,E,S>& r) {return r+l;} 01084 01085 // m = m+conjugate, conjugate+m (convert conjugate->complex) 01086 template <int M, class E, int S, class R> inline 01087 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add 01088 operator+(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l+(std::complex<R>)r;} 01089 template <int M, class E, int S, class R> inline 01090 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add 01091 operator+(const conjugate<R>& l, const SymMat<M,E,S>& r) {return r+(std::complex<R>)l;} 01092 01093 // m = m+negator, negator+m: convert negator to standard number 01094 template <int M, class E, int S, class R> inline 01095 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Add 01096 operator+(const SymMat<M,E,S>& l, const negator<R>& r) {return l + (typename negator<R>::StdNumber)(R)r;} 01097 template <int M, class E, int S, class R> inline 01098 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Add 01099 operator+(const negator<R>& l, const SymMat<M,E,S>& r) {return r + (typename negator<R>::StdNumber)(R)l;} 01100 01101 // SCALAR SUBTRACT -- careful, not commutative. 01102 01103 // m = m-real, real-m 01104 template <int M, class E, int S> inline 01105 typename SymMat<M,E,S>::template Result<float>::Sub 01106 operator-(const SymMat<M,E,S>& l, const float& r) 01107 { return SymMat<M,E,S>::template Result<float>::SubOp::perform(l,r); } 01108 template <int M, class E, int S> inline 01109 typename CNT<float>::template Result<SymMat<M,E,S> >::Sub 01110 operator-(const float& l, const SymMat<M,E,S>& r) 01111 { return CNT<float>::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); } 01112 01113 template <int M, class E, int S> inline 01114 typename SymMat<M,E,S>::template Result<double>::Sub 01115 operator-(const SymMat<M,E,S>& l, const double& r) 01116 { return SymMat<M,E,S>::template Result<double>::SubOp::perform(l,r); } 01117 template <int M, class E, int S> inline 01118 typename CNT<double>::template Result<SymMat<M,E,S> >::Sub 01119 operator-(const double& l, const SymMat<M,E,S>& r) 01120 { return CNT<double>::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); } 01121 01122 template <int M, class E, int S> inline 01123 typename SymMat<M,E,S>::template Result<long double>::Sub 01124 operator-(const SymMat<M,E,S>& l, const long double& r) 01125 { return SymMat<M,E,S>::template Result<long double>::SubOp::perform(l,r); } 01126 template <int M, class E, int S> inline 01127 typename CNT<long double>::template Result<SymMat<M,E,S> >::Sub 01128 operator-(const long double& l, const SymMat<M,E,S>& r) 01129 { return CNT<long double>::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); } 01130 01131 // m = m-int, int-m // just convert int to m's precision float 01132 template <int M, class E, int S> inline 01133 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Sub 01134 operator-(const SymMat<M,E,S>& l, int r) {return l - (typename CNT<E>::Precision)r;} 01135 template <int M, class E, int S> inline 01136 typename CNT<typename CNT<E>::Precision>::template Result<SymMat<M,E,S> >::Sub 01137 operator-(int l, const SymMat<M,E,S>& r) {return (typename CNT<E>::Precision)l - r;} 01138 01139 01140 // Complex, conjugate, and negator are all easy to templatize. 01141 01142 // m = m-complex, complex-m 01143 template <int M, class E, int S, class R> inline 01144 typename SymMat<M,E,S>::template Result<std::complex<R> >::Sub 01145 operator-(const SymMat<M,E,S>& l, const std::complex<R>& r) 01146 { return SymMat<M,E,S>::template Result<std::complex<R> >::SubOp::perform(l,r); } 01147 template <int M, class E, int S, class R> inline 01148 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Sub 01149 operator-(const std::complex<R>& l, const SymMat<M,E,S>& r) 01150 { return CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); } 01151 01152 // m = m-conjugate, conjugate-m (convert conjugate->complex) 01153 template <int M, class E, int S, class R> inline 01154 typename SymMat<M,E,S>::template Result<std::complex<R> >::Sub 01155 operator-(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l-(std::complex<R>)r;} 01156 template <int M, class E, int S, class R> inline 01157 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Sub 01158 operator-(const conjugate<R>& l, const SymMat<M,E,S>& r) {return (std::complex<R>)l-r;} 01159 01160 // m = m-negator, negator-m: convert negator to standard number 01161 template <int M, class E, int S, class R> inline 01162 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Sub 01163 operator-(const SymMat<M,E,S>& l, const negator<R>& r) {return l-(typename negator<R>::StdNumber)(R)r;} 01164 template <int M, class E, int S, class R> inline 01165 typename CNT<R>::template Result<SymMat<M,E,S> >::Sub 01166 operator-(const negator<R>& l, const SymMat<M,E,S>& r) {return (typename negator<R>::StdNumber)(R)l-r;} 01167 01168 01169 // SymMat I/O 01170 template <int M, class E, int RS, class CHAR, class TRAITS> inline 01171 std::basic_ostream<CHAR,TRAITS>& 01172 operator<<(std::basic_ostream<CHAR,TRAITS>& o, const SymMat<M,E,RS>& m) { 01173 for (int i=0;i<M;++i) { 01174 o << std::endl << "["; 01175 for (int j=0; j<=i; ++j) 01176 o << (j>0?" ":"") << m(i,j); 01177 for (int j=i+1; j<M; ++j) 01178 o << " *"; 01179 o << "]"; 01180 } 01181 if (M) o << std::endl; 01182 return o; 01183 } 01184 01185 template <int M, class E, int RS, class CHAR, class TRAITS> inline 01186 std::basic_istream<CHAR,TRAITS>& 01187 operator>>(std::basic_istream<CHAR,TRAITS>& is, SymMat<M,E,RS>& m) { 01188 // TODO: not sure how to do input yet 01189 assert(false); 01190 return is; 01191 } 01192 01193 } //namespace SimTK 01194 01195 01196 #endif //SimTK_SIMMATRIX_SMALLMATRIX_SYMMAT_H_