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