Simbody

SymMat.h

Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines