Simbody  3.4 (development)
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  *                       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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines