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-7 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>::TAbs               EAbs;
00092     typedef typename CNT<E>::TStandard          EStandard;
00093     typedef typename CNT<E>::TInvert            EInvert;
00094     typedef typename CNT<E>::TNormalize         ENormalize;
00095 
00096     typedef typename CNT<E>::Scalar             EScalar;
00097     typedef typename CNT<E>::Number             ENumber;
00098     typedef typename CNT<E>::StdNumber          EStdNumber;
00099     typedef typename CNT<E>::Precision          EPrecision;
00100     typedef typename CNT<E>::ScalarSq           EScalarSq;
00101 
00102 public:
00103 
00104     enum {
00105         NRows               = M,
00106         NCols               = M,
00107         NPackedElements     = (M*(M+1))/2,
00108         NActualElements     = RS * NPackedElements,
00109         NActualScalars      = CNT<E>::NActualScalars * NActualElements,
00110         RowSpacing          = RS,
00111         ColSpacing          = NActualElements,
00112         ImagOffset          = NTraits<ENumber>::ImagOffset,
00113         RealStrideFactor    = 1, // composite types don't change size when
00114                                  // cast from complex to real or imaginary
00115         ArgDepth            = ((int)CNT<E>::ArgDepth < (int)MAX_RESOLVED_DEPTH 
00116                                 ? CNT<E>::ArgDepth + 1 
00117                                 : MAX_RESOLVED_DEPTH),
00118         IsScalar            = 0,
00119         IsNumber            = 0,
00120         IsStdNumber         = 0,
00121         IsPrecision         = 0,
00122         SignInterpretation  = CNT<E>::SignInterpretation
00123     };
00124 
00125     typedef SymMat<M,E,RS>                  T;
00126     typedef SymMat<M,ENeg,RS>               TNeg;
00127     typedef SymMat<M,EWithoutNegator,RS>    TWithoutNegator;
00128 
00129     typedef SymMat<M,EReal,RS*CNT<E>::RealStrideFactor>          
00130                                             TReal;
00131     typedef SymMat<M,EImag,RS*CNT<E>::RealStrideFactor>          
00132                                             TImag;
00133     typedef SymMat<M,EComplex,RS>           TComplex;
00134     typedef T                               THerm;   // These two are opposite of what you might expect
00135     typedef SymMat<M,EHerm,RS>              TPosTrans;
00136     typedef E                               TElement;
00137     typedef Vec<M,E,RS>                     TDiag;   // storage type for the diagonal elements
00138     typedef Vec<(M*(M-1))/2,E,RS>           TLower;  // storage type for the below-diag elements
00139     typedef Vec<(M*(M-1))/2,EHerm,RS>       TUpper;  // cast TLower to this for upper elements
00140     typedef Vec<(M*(M+1))/2,E,RS>           TAsVec;  // the whole SymMat as a single Vec
00141 
00142     // These are the results of calculations, so are returned in new, packed
00143     // memory. Be sure to refer to element types here which are also packed.
00144     typedef Row<M,E,1>                  TRow; // packed since we have to copy
00145     typedef Vec<M,E,1>                  TCol;
00146     typedef SymMat<M,EAbs,1>            TAbs;
00147     typedef SymMat<M,EStandard,1>       TStandard;
00148     typedef SymMat<M,EInvert,1>         TInvert;
00149     typedef SymMat<M,ENormalize,1>      TNormalize;
00150     typedef SymMat<M,ESqHermT,1>        TSqHermT; // ~Mat*Mat
00151     typedef SymMat<M,ESqTHerm,1>        TSqTHerm; // Mat*~Mat
00152     typedef SymMat<M,E,1>               TPacked;  // no extra row spacing for new data
00153     
00154     typedef EScalar                     Scalar;
00155     typedef ENumber                     Number;
00156     typedef EStdNumber                  StdNumber;
00157     typedef EPrecision                  Precision;
00158     typedef EScalarSq                   ScalarSq;
00159 
00160     int size() const { return (M*(M+1))/2; }
00161     int nrow() const { return M; }
00162     int ncol() const { return M; }
00163 
00164     // Scalar norm square is sum( squares of all scalars ). The off-diagonals
00165     // come up twice.
00166     ScalarSq scalarNormSqr() const { 
00167         return getDiag().scalarNormSqr() + 2.*getLower().scalarNormSqr();
00168     }
00169 
00170     // abs() is elementwise absolute value; that is, the return value has the same
00171     // dimension as this Mat but with each element replaced by whatever it thinks
00172     // its absolute value is.
00173     TAbs abs() const { 
00174         return TAbs(getAsVec().abs());
00175     }
00176 
00177     TStandard standardize() const {
00178         return TStandard(getAsVec().standardize());
00179     }
00180 
00181     StdNumber trace() const {return getDiag().sum();}
00182 
00183     // This gives the resulting SymMat type when (m[i] op P) is applied to each element of m.
00184     // It is a SymMat of dimension M, spacing 1, and element types which are the regular
00185     // composite result of E op P. Typically P is a scalar type but it doesn't have to be.
00186     template <class P> struct EltResult { 
00187         typedef SymMat<M, typename CNT<E>::template Result<P>::Mul, 1> Mul;
00188         typedef SymMat<M, typename CNT<E>::template Result<P>::Dvd, 1> Dvd;
00189         typedef SymMat<M, typename CNT<E>::template Result<P>::Add, 1> Add;
00190         typedef SymMat<M, typename CNT<E>::template Result<P>::Sub, 1> Sub;
00191     };
00192 
00193     // This is the composite result for m op P where P is some kind of appropriately shaped
00194     // non-scalar type.
00195     template <class P> struct Result { 
00196         typedef MulCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing,
00197             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00198             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> MulOp;
00199         typedef typename MulOp::Type Mul;
00200 
00201         typedef MulCNTsNonConforming<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing,
00202             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00203             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> MulOpNonConforming;
00204         typedef typename MulOpNonConforming::Type MulNon;
00205 
00206 
00207         typedef DvdCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing,
00208             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00209             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> DvdOp;
00210         typedef typename DvdOp::Type Dvd;
00211 
00212         typedef AddCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing,
00213             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00214             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> AddOp;
00215         typedef typename AddOp::Type Add;
00216 
00217         typedef SubCNTs<M,M,ArgDepth,SymMat,ColSpacing,RowSpacing,
00218             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00219             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> SubOp;
00220         typedef typename SubOp::Type Sub;
00221     };
00222 
00223     // Shape-preserving element substitution (always packed)
00224     template <class P> struct Substitute {
00225         typedef SymMat<M,P> Type;
00226     };
00227 
00228     // Default construction initializes to NaN when debugging but
00229     // is left uninitialized otherwise.
00230     SymMat(){ 
00231     #ifndef NDEBUG
00232         setToNaN();
00233     #endif
00234     }
00235 
00236     SymMat(const SymMat& src) {
00237         updAsVec() = src.getAsVec();
00238     }
00239 
00240     SymMat& operator=(const SymMat& src) {    // no harm if src and 'this' are the same
00241         updAsVec() = src.getAsVec();
00242         return *this;
00243     }
00244 
00245     // Allow an explicit conversion from square Mat of right size, looking only at lower
00246     // elements and real part of diagonal elements.
00247     template <class EE, int CSS, int RSS>
00248     explicit SymMat(const Mat<M,M,EE,CSS,RSS>& m) {
00249         updDiag() = m.diag().real();
00250         for (int j=0; j<M; ++j)
00251             for (int i=j+1; i<M; ++i)
00252                 updEltLower(i,j) = m(i,j);
00253     }
00254 
00255     // We want an implicit conversion from a SymMat of the same length
00256     // and element type but with different spacings.
00257     template <int RSS> SymMat(const SymMat<M,E,RSS>& src) 
00258       { updAsVec() = src.getAsVec(); }
00259 
00260     // We want an implicit conversion from a SymMat of the same length
00261     // and *negated* element type, possibly with different spacings.
00262     template <int RSS> SymMat(const SymMat<M,ENeg,RSS>& src)
00263       { updAsVec() = src.getAsVec(); }
00264 
00265     // Construct a SymMat from a SymMat of the same dimensions, with any
00266     // spacings. Works as long as the element types are assignment compatible.
00267     template <class EE, int RSS> explicit SymMat(const SymMat<M,EE,RSS>& src)
00268       { updAsVec() = src.getAsVec(); }
00269 
00270     // Construction using an element repeats that element on the diagonal
00271     // but sets the rest of the matrix to zero.
00272     // TODO: diag should just use real part
00273     explicit SymMat(const E& e)
00274       { updDiag() = e; updLower() = E(0); }
00275 
00276 
00277     // Construction from a pointer to anything assumes we're pointing
00278     // at a packed element list of the right length, providing the
00279     // lower triangle in row order, so a b c d e f means
00280     //      a
00281     //      b c
00282     //      d e f
00283     //      g h i j
00284     // This has to be mapped to our diagonal/lower layout, which in
00285     // the above example will be:
00286     //      [a c f j][b d g e h i]
00287     //
00288     // In the input layout, the i'th row begins at element i(i+1)/2,
00289     // so diagonals are at i(i+1)/2 + i, while lower
00290     // elements (i,j; i>j) are at i(i+1)/2 + j.
00291     template <class EE> explicit SymMat(const EE* p) {
00292         assert(p);
00293         for (int i=0; i<M; ++i) {
00294             const int rowStart = (i*(i+1))/2;
00295             updDiag()[i] = p[rowStart + i];
00296             for (int j=0; j<i; ++j)
00297                 updEltLower(i,j) = p[rowStart + j];
00298         }
00299     }
00300 
00301     // This is the same thing except as an assignment to pointer rather
00302     // than a constructor from pointer.
00303     template <class EE> SymMat& operator=(const EE* p) {
00304         assert(p);
00305         for (int i=0; i<M; ++i) {
00306             const int rowStart = (i*(i+1))/2;
00307             updDiag()[i] = p[rowStart + i];
00308             for (int j=0; j<i; ++j)
00309                 updEltLower(i,j) = p[rowStart + j];
00310         }
00311         return *this;
00312     }
00313 
00314     // Assignment works similarly to copy -- if the lengths match,
00315     // go element-by-element. Otherwise, zero and then copy to each 
00316     // diagonal element.
00317     template <class EE, int RSS> SymMat& operator=(const SymMat<M,EE,RSS>& mm) {
00318         updAsVec() = mm.getAsVec();
00319         return *this;
00320     }
00321 
00322 
00323     // Conforming assignment ops
00324     template <class EE, int RSS> SymMat& 
00325     operator+=(const SymMat<M,EE,RSS>& mm) {
00326         updAsVec() += mm.getAsVec();
00327         return *this;
00328     }
00329     template <class EE, int RSS> SymMat&
00330     operator+=(const SymMat<M,negator<EE>,RSS>& mm) {
00331         updAsVec() -= -mm.getAsVec();   // negation of negator is free
00332         return *this;
00333     }
00334 
00335     template <class EE, int RSS> SymMat&
00336     operator-=(const SymMat<M,EE,RSS>& mm) {
00337         updAsVec() -= mm.getAsVec();
00338         return *this;
00339     }
00340     template <class EE, int RSS> SymMat&
00341     operator-=(const SymMat<M,negator<EE>,RSS>& mm) {
00342         updAsVec() += -mm.getAsVec();   // negation of negator is free
00343         return *this;
00344     }
00345 
00346     // In place matrix multiply can only be done when the RHS matrix is the same
00347     // size and the elements are also *= compatible.
00348     template <class EE, int RSS> SymMat&
00349     operator*=(const SymMat<M,EE,RSS>& mm) {
00350         assert(false); // TODO
00351         return *this;
00352     }
00353 
00354     // Conforming binary ops with 'this' on left, producing new packed result.
00355     // Cases: sy=sy+-sy, m=sy+-m, m=sy*sy, m=sy*m, v=sy*v
00356 
00357     // sy= this + sy
00358     template <class E2, int RS2> 
00359     typename Result<SymMat<M,E2,RS2> >::Add
00360     conformingAdd(const SymMat<M,E2,RS2>& r) const {
00361         return typename Result<SymMat<M,E2,RS2> >::Add
00362             (getAsVec().conformingAdd(r.getAsVec()));
00363     }
00364     // m= this - m
00365     template <class E2, int RS2> 
00366     typename Result<SymMat<M,E2,RS2> >::Sub
00367     conformingSubtract(const SymMat<M,E2,RS2>& r) const {
00368         return typename Result<SymMat<M,E2,RS2> >::Sub
00369             (getAsVec().conformingSubtract(r.getAsVec()));
00370     }
00371 
00372     // TODO: need the rest of the SymMat operators
00373     
00374     // Must be i >= j.
00375     const E& operator()(int i,int j) const 
00376       { return i==j ? getDiag()[i] : getEltLower(i,j); }
00377     E& operator()(int i,int j)
00378       { return i==j ? updDiag()[i] : updEltLower(i,j); }
00379 
00380     // This is the scalar Frobenius norm.
00381     ScalarSq normSqr() const { return scalarNormSqr(); }
00382     ScalarSq norm()    const { return std::sqrt(scalarNormSqr()); }
00383 
00384     // There is no conventional meaning for normalize() applied to a matrix. We
00385     // choose to define it as follows:
00386     // If the elements of this SymMat are scalars, the result is what you get by
00387     // dividing each element by the Frobenius norm() calculated above. If the elements are
00388     // *not* scalars, then the elements are *separately* normalized.
00389     //
00390     // Normalize returns a matrix of the same dimension but in new, packed storage
00391     // and with a return type that does not include negator<> even if the original
00392     // SymMat<> does, because we can eliminate the negation here almost for free.
00393     // But we can't standardize (change conjugate to complex) for free, so we'll retain
00394     // conjugates if there are any.
00395     TNormalize normalize() const {
00396         if (CNT<E>::IsScalar) {
00397             return castAwayNegatorIfAny() / (SignInterpretation*norm());
00398         } else {
00399             TNormalize elementwiseNormalized;
00400             // punt to the equivalent Vec to get the elements normalized
00401             elementwiseNormalized.updAsVec() = getAsVec().normalize();
00402             return elementwiseNormalized;
00403         }
00404     }
00405 
00406     TInvert invert() const {assert(false); return TInvert();} // TODO default inversion
00407 
00408     const SymMat& operator+() const { return *this; }
00409     const TNeg&   operator-() const { return negate(); }
00410     TNeg&         operator-()       { return updNegate(); }
00411     const THerm&  operator~() const { return transpose(); }
00412     THerm&        operator~()       { return updTranspose(); }
00413 
00414     const TNeg&  negate() const { return *reinterpret_cast<const TNeg*>(this); }
00415     TNeg&        updNegate()    { return *reinterpret_cast<TNeg*>(this); }
00416 
00417     const THerm& transpose()    const { return *reinterpret_cast<const THerm*>(this); }
00418     THerm&       updTranspose()       { return *reinterpret_cast<THerm*>(this); }
00419 
00420     const TPosTrans& positionalTranspose() const
00421         { return *reinterpret_cast<const TPosTrans*>(this); }
00422     TPosTrans&       updPositionalTranspose()
00423         { return *reinterpret_cast<TPosTrans*>(this); }
00424 
00425     const TReal& real() const { return *reinterpret_cast<const TReal*>(this); }
00426     TReal&       real()       { return *reinterpret_cast<      TReal*>(this); }
00427 
00428     // Had to contort these routines to get them through VC++ 7.net
00429     const TImag& imag()    const { 
00430         const int offs = ImagOffset;
00431         const EImag* p = reinterpret_cast<const EImag*>(this);
00432         return *reinterpret_cast<const TImag*>(p+offs);
00433     }
00434     TImag& imag() { 
00435         const int offs = ImagOffset;
00436         EImag* p = reinterpret_cast<EImag*>(this);
00437         return *reinterpret_cast<TImag*>(p+offs);
00438     }
00439 
00440     const TWithoutNegator& castAwayNegatorIfAny() const {return *reinterpret_cast<const TWithoutNegator*>(this);}
00441     TWithoutNegator&       updCastAwayNegatorIfAny()    {return *reinterpret_cast<TWithoutNegator*>(this);}
00442 
00443     // These are elementwise binary operators, (this op ee) by default but (ee op this) if
00444     // 'FromLeft' appears in the name. The result is a packed SymMat<M> but the element type
00445     // may change. These are mostly used to implement global operators.
00446     // We call these "scalar" operators but actually the "scalar" can be a composite type.
00447 
00448     //TODO: consider converting 'e' to Standard Numbers as precalculation and changing
00449     // return type appropriately.
00450     template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Mul>
00451     scalarMultiply(const EE& e) const {
00452         SymMat<M, typename CNT<E>::template Result<EE>::Mul> result;
00453         result.updAsVec() = getAsVec().scalarMultiply(e);
00454         return result;
00455     }
00456     template <class EE> SymMat<M, typename CNT<EE>::template Result<E>::Mul>
00457     scalarMultiplyFromLeft(const EE& e) const {
00458         SymMat<M, typename CNT<EE>::template Result<E>::Mul> result;
00459         result.updAsVec() = getAsVec().scalarMultiplyFromLeft(e);
00460         return result;
00461     }
00462 
00463     // TODO: should precalculate and store 1/e, while converting to Standard Numbers. Note
00464     // that return type should change appropriately.
00465     template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Dvd>
00466     scalarDivide(const EE& e) const {
00467         SymMat<M, typename CNT<E>::template Result<EE>::Dvd> result;
00468         result.updAsVec() = getAsVec().scalarDivide(e);
00469         return result;
00470     }
00471     template <class EE> SymMat<M, typename CNT<EE>::template Result<E>::Dvd>
00472     scalarDivideFromLeft(const EE& e) const {
00473         SymMat<M, typename CNT<EE>::template Result<E>::Dvd> result;
00474         result.updAsVec() = getAsVec().scalarDivideFromLeft(e);
00475         return result;
00476     }
00477 
00478     // Additive ops involving a scalar update only the diagonal
00479     template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Add>
00480     scalarAdd(const EE& e) const {
00481         SymMat<M, typename CNT<E>::template Result<EE>::Add> result(*this);
00482         result.updDiag() += e;
00483         return result;
00484     }
00485     // Add is commutative, so no 'FromLeft'.
00486 
00487     template <class EE> SymMat<M, typename CNT<E>::template Result<EE>::Sub>
00488     scalarSubtract(const EE& e) const {
00489         SymMat<M, typename CNT<E>::template Result<EE>::Sub> result(*this);
00490         result.diag() -= e;
00491         return result;
00492     }
00493     // This is s-m; negate m and add s to diagonal
00494     // TODO: Should do something clever with negation here.
00495     template <class EE> SymMat<M, typename CNT<EE>::template Result<E>::Sub>
00496     scalarSubtractFromLeft(const EE& e) const {
00497         SymMat<M, typename CNT<EE>::template Result<E>::Sub> result(-(*this));
00498         result.diag() += e;
00499         return result;
00500     }
00501 
00502     // Generic assignments for any element type not listed explicitly, including scalars.
00503     // These are done repeatedly for each element and only work if the operation can
00504     // be performed leaving the original element type.
00505     template <class EE> SymMat& operator =(const EE& e) {return scalarEq(e);}
00506     template <class EE> SymMat& operator+=(const EE& e) {return scalarPlusEq(e);}
00507     template <class EE> SymMat& operator-=(const EE& e) {return scalarMinusEq(e);}
00508     template <class EE> SymMat& operator*=(const EE& e) {return scalarTimesEq(e);}
00509     template <class EE> SymMat& operator/=(const EE& e) {return scalarDivideEq(e);}
00510 
00511     // Generalized scalar assignment & computed assignment methods. These will work
00512     // for any assignment-compatible element, not just scalars.
00513     template <class EE> SymMat& scalarEq(const EE& ee)
00514       { updDiag() = ee; updLower() = E(0); return *this; }
00515     template <class EE> SymMat& scalarPlusEq(const EE& ee)
00516       { updDiag() += ee; return *this; }
00517     template <class EE> SymMat& scalarMinusEq(const EE& ee)
00518       { updDiag() -= ee; return *this; }
00519 
00520     // this is m = s-m; negate off diagonal, do d=s-d for each diagonal element d
00521     template <class EE> SymMat& scalarMinusEqFromLeft(const EE& ee)
00522       { updLower() *= E(-1); updDiag().scalarMinusEqFromLeft(ee); return *this; }
00523 
00524     template <class EE> SymMat& scalarTimesEq(const EE& ee)
00525       { updAsVec() *= ee; return *this; }
00526     template <class EE> SymMat& scalarTimesEqFromLeft(const EE& ee)
00527       { updAsVec().scalarTimesEqFromLeft(ee); return *this; }
00528     template <class EE> SymMat& scalarDivideEq(const EE& ee)
00529       { updAsVec() /= ee; return *this; }
00530     template <class EE> SymMat& scalarDivideEqFromLeft(const EE& ee)
00531       { updAsVec().scalarDivideEqFromLeft(ee); return *this; } 
00532 
00533     void setToNaN() { updAsVec().setToNaN(); }
00534 
00535     // These assume we are given a pointer to d[0] of a SymMat<M,E,RS> like this one.
00536     static const SymMat& getAs(const ELT* p)  {return *reinterpret_cast<const SymMat*>(p);}
00537     static SymMat&       updAs(ELT* p)        {return *reinterpret_cast<SymMat*>(p);}
00538 
00539     // Note packed spacing
00540     static TPacked getNaN() {
00541         return TPacked(CNT<typename TPacked::TDiag>::getNaN(),
00542                        CNT<typename TPacked::TLower>::getNaN());
00543     }
00544 
00545     const TDiag&  getDiag()  const {return TDiag::getAs(d);}
00546     TDiag&        updDiag()        {return TDiag::updAs(d);}
00547 
00548     // Conventional synonym
00549     const TDiag& diag() const {return getDiag();}
00550     TDiag&       diag()       {return updDiag();}
00551 
00552     const TLower& getLower() const {return TLower::getAs(&d[M*RS]);}
00553     TLower&       updLower()       {return TLower::updAs(&d[M*RS]);}
00554 
00555     const TUpper& getUpper() const {return reinterpret_cast<const TUpper&>(getLower());}
00556     TUpper&       updUpper()       {return reinterpret_cast<      TUpper&>(updLower());}
00557 
00558     const TAsVec& getAsVec() const {return TAsVec::getAs(d);}
00559     TAsVec&       updAsVec()       {return TAsVec::updAs(d);}
00560 
00561     // must be i > j
00562     const E& getEltLower(int i, int j) const {return getLower()[lowerIx(i,j)];}
00563     E&       updEltLower(int i, int j)       {return updLower()[lowerIx(i,j)];}
00564 
00565     // must be i < j
00566     const EHerm& getEltUpper(int i, int j) const {return getUpper()[lowerIx(j,i)];}
00567     EHerm&       updEltUpper(int i, int j)       {return updUpper()[lowerIx(j,i)];}
00568     
00569     TRow sum() const {
00570         TRow temp(~getDiag());
00571         for (int i = 1; i < M; ++i)
00572             for (int j = 0; j < i; ++j) {
00573                 E value = getEltLower(i, j);;
00574                 temp[i] += value;
00575                 temp[j] += value;
00576             }
00577         return temp;
00578     }
00579 
00580 private:
00581     E d[NActualElements];
00582 
00583     SymMat(const TDiag& di, const TLower& low) {
00584         updDiag() = di; updLower() = low;
00585     }
00586 
00587     explicit SymMat(const TAsVec& v) {
00588         TAsVec::updAs(d) = v;
00589     }
00590     
00591     // Convert i,j with i>j to an index in "lower". This also gives the
00592     // right index for "upper" with i and j reversed.
00593     static int lowerIx(int i, int j) {
00594         assert(0 <= j && j < i && i < M);
00595         return (i-j-1) + j*(M-1) - (j*(j-1))/2;
00596     }
00597 
00598     template <int MM, class EE, int RSS> friend class SymMat;
00599 };
00600 
00602 // Global operators involving two symmetric matrices. //
00603 //   sy=sy+sy, sy=sy-sy, m=sy*sy, sy==sy, sy!=sy      //
00605 
00606 // m3 = m1 + m2 where all m's have the same dimension M. 
00607 template <int M, class E1, int S1, class E2, int S2> inline
00608 typename SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >::Add
00609 operator+(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) {
00610     return SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >
00611         ::AddOp::perform(l,r);
00612 }
00613 
00614 // m3 = m1 - m2 where all m's have the same dimension M. 
00615 template <int M, class E1, int S1, class E2, int S2> inline
00616 typename SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >::Sub
00617 operator-(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) {
00618     return SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >
00619         ::SubOp::perform(l,r);
00620 }
00621 
00622 // m3 = m1 * m2 where all m's have the same dimension M. 
00623 // The result will not be symmetric.
00624 template <int M, class E1, int S1, class E2, int S2> inline
00625 typename SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >::Mul
00626 operator-(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) {
00627     return SymMat<M,E1,S1>::template Result< SymMat<M,E2,S2> >
00628         ::MulOp::perform(l,r);
00629 }
00630 
00631 // bool = m1 == m2, m1 and m2 have the same dimension M
00632 template <int M, class E1, int S1, class E2, int S2> inline bool
00633 operator==(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) {
00634     return l.getAsVec() == r.getAsVec();
00635 }
00636 
00637 // bool = m1 == m2, m1 and m2 have the same dimension M
00638 template <int M, class E1, int S1, class E2, int S2> inline bool
00639 operator!=(const SymMat<M,E1,S1>& l, const SymMat<M,E2,S2>& r) {return !(l==r);} 
00640 
00642 // Global operators involving a SymMat and a scalar. //
00644 
00645 // SCALAR MULTIPLY
00646 
00647 // m = m*real, real*m 
00648 template <int M, class E, int S> inline
00649 typename SymMat<M,E,S>::template Result<float>::Mul
00650 operator*(const SymMat<M,E,S>& l, const float& r)
00651   { return SymMat<M,E,S>::template Result<float>::MulOp::perform(l,r); }
00652 template <int M, class E, int S> inline
00653 typename SymMat<M,E,S>::template Result<float>::Mul
00654 operator*(const float& l, const SymMat<M,E,S>& r) {return r*l;}
00655 
00656 template <int M, class E, int S> inline
00657 typename SymMat<M,E,S>::template Result<double>::Mul
00658 operator*(const SymMat<M,E,S>& l, const double& r)
00659   { return SymMat<M,E,S>::template Result<double>::MulOp::perform(l,r); }
00660 template <int M, class E, int S> inline
00661 typename SymMat<M,E,S>::template Result<double>::Mul
00662 operator*(const double& l, const SymMat<M,E,S>& r) {return r*l;}
00663 
00664 template <int M, class E, int S> inline
00665 typename SymMat<M,E,S>::template Result<long double>::Mul
00666 operator*(const SymMat<M,E,S>& l, const long double& r)
00667   { return SymMat<M,E,S>::template Result<long double>::MulOp::perform(l,r); }
00668 template <int M, class E, int S> inline
00669 typename SymMat<M,E,S>::template Result<long double>::Mul
00670 operator*(const long double& l, const SymMat<M,E,S>& r) {return r*l;}
00671 
00672 // m = m*int, int*m -- just convert int to m's precision float
00673 template <int M, class E, int S> inline
00674 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Mul
00675 operator*(const SymMat<M,E,S>& l, int r) {return l * (typename CNT<E>::Precision)r;}
00676 template <int M, class E, int S> inline
00677 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Mul
00678 operator*(int l, const SymMat<M,E,S>& r) {return r * (typename CNT<E>::Precision)l;}
00679 
00680 // Complex, conjugate, and negator are all easy to templatize.
00681 
00682 // m = m*complex, complex*m
00683 template <int M, class E, int S, class R> inline
00684 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul
00685 operator*(const SymMat<M,E,S>& l, const std::complex<R>& r)
00686   { return SymMat<M,E,S>::template Result<std::complex<R> >::MulOp::perform(l,r); }
00687 template <int M, class E, int S, class R> inline
00688 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul
00689 operator*(const std::complex<R>& l, const SymMat<M,E,S>& r) {return r*l;}
00690 
00691 // m = m*conjugate, conjugate*m (convert conjugate->complex)
00692 template <int M, class E, int S, class R> inline
00693 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul
00694 operator*(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l*(std::complex<R>)r;}
00695 template <int M, class E, int S, class R> inline
00696 typename SymMat<M,E,S>::template Result<std::complex<R> >::Mul
00697 operator*(const conjugate<R>& l, const SymMat<M,E,S>& r) {return r*(std::complex<R>)l;}
00698 
00699 // m = m*negator, negator*m: convert negator to standard number
00700 template <int M, class E, int S, class R> inline
00701 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Mul
00702 operator*(const SymMat<M,E,S>& l, const negator<R>& r) {return l * (typename negator<R>::StdNumber)(R)r;}
00703 template <int M, class E, int S, class R> inline
00704 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Mul
00705 operator*(const negator<R>& l, const SymMat<M,E,S>& r) {return r * (typename negator<R>::StdNumber)(R)l;}
00706 
00707 
00708 // SCALAR DIVIDE. This is a scalar operation when the scalar is on the right,
00709 // but when it is on the left it means scalar * pseudoInverse(mat), which is 
00710 // a similar symmetric matrix.
00711 
00712 // m = m/real, real/m 
00713 template <int M, class E, int S> inline
00714 typename SymMat<M,E,S>::template Result<float>::Dvd
00715 operator/(const SymMat<M,E,S>& l, const float& r)
00716   { return SymMat<M,E,S>::template Result<float>::DvdOp::perform(l,r); }
00717 template <int M, class E, int S> inline
00718 typename CNT<float>::template Result<SymMat<M,E,S> >::Dvd
00719 operator/(const float& l, const SymMat<M,E,S>& r)
00720   { return CNT<float>::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); }
00721 
00722 template <int M, class E, int S> inline
00723 typename SymMat<M,E,S>::template Result<double>::Dvd
00724 operator/(const SymMat<M,E,S>& l, const double& r)
00725   { return SymMat<M,E,S>::template Result<double>::DvdOp::perform(l,r); }
00726 template <int M, class E, int S> inline
00727 typename CNT<double>::template Result<SymMat<M,E,S> >::Dvd
00728 operator/(const double& l, const SymMat<M,E,S>& r)
00729   { return CNT<double>::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); }
00730 
00731 template <int M, class E, int S> inline
00732 typename SymMat<M,E,S>::template Result<long double>::Dvd
00733 operator/(const SymMat<M,E,S>& l, const long double& r)
00734   { return SymMat<M,E,S>::template Result<long double>::DvdOp::perform(l,r); }
00735 template <int M, class E, int S> inline
00736 typename CNT<long double>::template Result<SymMat<M,E,S> >::Dvd
00737 operator/(const long double& l, const SymMat<M,E,S>& r)
00738   { return CNT<long double>::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); }
00739 
00740 // m = m/int, int/m -- just convert int to m's precision float
00741 template <int M, class E, int S> inline
00742 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Dvd
00743 operator/(const SymMat<M,E,S>& l, int r) {return l / (typename CNT<E>::Precision)r;}
00744 template <int M, class E, int S> inline
00745 typename CNT<typename CNT<E>::Precision>::template Result<SymMat<M,E,S> >::Dvd
00746 operator/(int l, const SymMat<M,E,S>& r) {return (typename CNT<E>::Precision)l / r;}
00747 
00748 
00749 // Complex, conjugate, and negator are all easy to templatize.
00750 
00751 // m = m/complex, complex/m
00752 template <int M, class E, int S, class R> inline
00753 typename SymMat<M,E,S>::template Result<std::complex<R> >::Dvd
00754 operator/(const SymMat<M,E,S>& l, const std::complex<R>& r)
00755   { return SymMat<M,E,S>::template Result<std::complex<R> >::DvdOp::perform(l,r); }
00756 template <int M, class E, int S, class R> inline
00757 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Dvd
00758 operator/(const std::complex<R>& l, const SymMat<M,E,S>& r)
00759   { return CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::DvdOp::perform(l,r); }
00760 
00761 // m = m/conjugate, conjugate/m (convert conjugate->complex)
00762 template <int M, class E, int S, class R> inline
00763 typename SymMat<M,E,S>::template Result<std::complex<R> >::Dvd
00764 operator/(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l/(std::complex<R>)r;}
00765 template <int M, class E, int S, class R> inline
00766 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Dvd
00767 operator/(const conjugate<R>& l, const SymMat<M,E,S>& r) {return (std::complex<R>)l/r;}
00768 
00769 // m = m/negator, negator/m: convert negator to number
00770 template <int M, class E, int S, class R> inline
00771 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Dvd
00772 operator/(const SymMat<M,E,S>& l, const negator<R>& r) {return l/(typename negator<R>::StdNumber)(R)r;}
00773 template <int M, class E, int S, class R> inline
00774 typename CNT<R>::template Result<SymMat<M,E,S> >::Dvd
00775 operator/(const negator<R>& l, const SymMat<M,E,S>& r) {return (typename negator<R>::StdNumber)(R)l/r;}
00776 
00777 
00778 // Add and subtract are odd as scalar ops. They behave as though the
00779 // scalar stands for a conforming matrix whose diagonal elements are that,
00780 // scalar and then a normal matrix add or subtract is done.
00781 
00782 // SCALAR ADD
00783 
00784 // m = m+real, real+m 
00785 template <int M, class E, int S> inline
00786 typename SymMat<M,E,S>::template Result<float>::Add
00787 operator+(const SymMat<M,E,S>& l, const float& r)
00788   { return SymMat<M,E,S>::template Result<float>::AddOp::perform(l,r); }
00789 template <int M, class E, int S> inline
00790 typename SymMat<M,E,S>::template Result<float>::Add
00791 operator+(const float& l, const SymMat<M,E,S>& r) {return r+l;}
00792 
00793 template <int M, class E, int S> inline
00794 typename SymMat<M,E,S>::template Result<double>::Add
00795 operator+(const SymMat<M,E,S>& l, const double& r)
00796   { return SymMat<M,E,S>::template Result<double>::AddOp::perform(l,r); }
00797 template <int M, class E, int S> inline
00798 typename SymMat<M,E,S>::template Result<double>::Add
00799 operator+(const double& l, const SymMat<M,E,S>& r) {return r+l;}
00800 
00801 template <int M, class E, int S> inline
00802 typename SymMat<M,E,S>::template Result<long double>::Add
00803 operator+(const SymMat<M,E,S>& l, const long double& r)
00804   { return SymMat<M,E,S>::template Result<long double>::AddOp::perform(l,r); }
00805 template <int M, class E, int S> inline
00806 typename SymMat<M,E,S>::template Result<long double>::Add
00807 operator+(const long double& l, const SymMat<M,E,S>& r) {return r+l;}
00808 
00809 // m = m+int, int+m -- just convert int to m's precision float
00810 template <int M, class E, int S> inline
00811 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Add
00812 operator+(const SymMat<M,E,S>& l, int r) {return l + (typename CNT<E>::Precision)r;}
00813 template <int M, class E, int S> inline
00814 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Add
00815 operator+(int l, const SymMat<M,E,S>& r) {return r + (typename CNT<E>::Precision)l;}
00816 
00817 // Complex, conjugate, and negator are all easy to templatize.
00818 
00819 // m = m+complex, complex+m
00820 template <int M, class E, int S, class R> inline
00821 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add
00822 operator+(const SymMat<M,E,S>& l, const std::complex<R>& r)
00823   { return SymMat<M,E,S>::template Result<std::complex<R> >::AddOp::perform(l,r); }
00824 template <int M, class E, int S, class R> inline
00825 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add
00826 operator+(const std::complex<R>& l, const SymMat<M,E,S>& r) {return r+l;}
00827 
00828 // m = m+conjugate, conjugate+m (convert conjugate->complex)
00829 template <int M, class E, int S, class R> inline
00830 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add
00831 operator+(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l+(std::complex<R>)r;}
00832 template <int M, class E, int S, class R> inline
00833 typename SymMat<M,E,S>::template Result<std::complex<R> >::Add
00834 operator+(const conjugate<R>& l, const SymMat<M,E,S>& r) {return r+(std::complex<R>)l;}
00835 
00836 // m = m+negator, negator+m: convert negator to standard number
00837 template <int M, class E, int S, class R> inline
00838 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Add
00839 operator+(const SymMat<M,E,S>& l, const negator<R>& r) {return l + (typename negator<R>::StdNumber)(R)r;}
00840 template <int M, class E, int S, class R> inline
00841 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Add
00842 operator+(const negator<R>& l, const SymMat<M,E,S>& r) {return r + (typename negator<R>::StdNumber)(R)l;}
00843 
00844 // SCALAR SUBTRACT -- careful, not commutative.
00845 
00846 // m = m-real, real-m 
00847 template <int M, class E, int S> inline
00848 typename SymMat<M,E,S>::template Result<float>::Sub
00849 operator-(const SymMat<M,E,S>& l, const float& r)
00850   { return SymMat<M,E,S>::template Result<float>::SubOp::perform(l,r); }
00851 template <int M, class E, int S> inline
00852 typename CNT<float>::template Result<SymMat<M,E,S> >::Sub
00853 operator-(const float& l, const SymMat<M,E,S>& r)
00854   { return CNT<float>::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); }
00855 
00856 template <int M, class E, int S> inline
00857 typename SymMat<M,E,S>::template Result<double>::Sub
00858 operator-(const SymMat<M,E,S>& l, const double& r)
00859   { return SymMat<M,E,S>::template Result<double>::SubOp::perform(l,r); }
00860 template <int M, class E, int S> inline
00861 typename CNT<double>::template Result<SymMat<M,E,S> >::Sub
00862 operator-(const double& l, const SymMat<M,E,S>& r)
00863   { return CNT<double>::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); }
00864 
00865 template <int M, class E, int S> inline
00866 typename SymMat<M,E,S>::template Result<long double>::Sub
00867 operator-(const SymMat<M,E,S>& l, const long double& r)
00868   { return SymMat<M,E,S>::template Result<long double>::SubOp::perform(l,r); }
00869 template <int M, class E, int S> inline
00870 typename CNT<long double>::template Result<SymMat<M,E,S> >::Sub
00871 operator-(const long double& l, const SymMat<M,E,S>& r)
00872   { return CNT<long double>::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); }
00873 
00874 // m = m-int, int-m // just convert int to m's precision float
00875 template <int M, class E, int S> inline
00876 typename SymMat<M,E,S>::template Result<typename CNT<E>::Precision>::Sub
00877 operator-(const SymMat<M,E,S>& l, int r) {return l - (typename CNT<E>::Precision)r;}
00878 template <int M, class E, int S> inline
00879 typename CNT<typename CNT<E>::Precision>::template Result<SymMat<M,E,S> >::Sub
00880 operator-(int l, const SymMat<M,E,S>& r) {return (typename CNT<E>::Precision)l - r;}
00881 
00882 
00883 // Complex, conjugate, and negator are all easy to templatize.
00884 
00885 // m = m-complex, complex-m
00886 template <int M, class E, int S, class R> inline
00887 typename SymMat<M,E,S>::template Result<std::complex<R> >::Sub
00888 operator-(const SymMat<M,E,S>& l, const std::complex<R>& r)
00889   { return SymMat<M,E,S>::template Result<std::complex<R> >::SubOp::perform(l,r); }
00890 template <int M, class E, int S, class R> inline
00891 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Sub
00892 operator-(const std::complex<R>& l, const SymMat<M,E,S>& r)
00893   { return CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::SubOp::perform(l,r); }
00894 
00895 // m = m-conjugate, conjugate-m (convert conjugate->complex)
00896 template <int M, class E, int S, class R> inline
00897 typename SymMat<M,E,S>::template Result<std::complex<R> >::Sub
00898 operator-(const SymMat<M,E,S>& l, const conjugate<R>& r) {return l-(std::complex<R>)r;}
00899 template <int M, class E, int S, class R> inline
00900 typename CNT<std::complex<R> >::template Result<SymMat<M,E,S> >::Sub
00901 operator-(const conjugate<R>& l, const SymMat<M,E,S>& r) {return (std::complex<R>)l-r;}
00902 
00903 // m = m-negator, negator-m: convert negator to standard number
00904 template <int M, class E, int S, class R> inline
00905 typename SymMat<M,E,S>::template Result<typename negator<R>::StdNumber>::Sub
00906 operator-(const SymMat<M,E,S>& l, const negator<R>& r) {return l-(typename negator<R>::StdNumber)(R)r;}
00907 template <int M, class E, int S, class R> inline
00908 typename CNT<R>::template Result<SymMat<M,E,S> >::Sub
00909 operator-(const negator<R>& l, const SymMat<M,E,S>& r) {return (typename negator<R>::StdNumber)(R)l-r;}
00910 
00911 
00912 // SymMat I/O
00913 template <int M, class E, int RS, class CHAR, class TRAITS> inline
00914 std::basic_ostream<CHAR,TRAITS>&
00915 operator<<(std::basic_ostream<CHAR,TRAITS>& o, const SymMat<M,E,RS>& m) {
00916     for (int i=0;i<M;++i) {
00917         o << std::endl << "[";
00918         for (int j=0; j<=i; ++j)         
00919             o << (j>0?" ":"") << m(i,j);
00920         for (int j=i+1; j<M; ++j)
00921             o << " *";
00922         o << "]";
00923     }
00924     if (M) o << std::endl;
00925     return o; 
00926 }
00927 
00928 template <int M, class E, int RS, class CHAR, class TRAITS> inline
00929 std::basic_istream<CHAR,TRAITS>&
00930 operator>>(std::basic_istream<CHAR,TRAITS>& is, SymMat<M,E,RS>& m) {
00931     // TODO: not sure how to do input yet
00932     assert(false);
00933     return is;
00934 }
00935 
00936 } //namespace SimTK
00937 
00938 
00939 #endif //SimTK_SIMMATRIX_SMALLMATRIX_SYMMAT_H_

Generated on Thu Feb 28 01:34:33 2008 for SimTKcommon by  doxygen 1.4.7