Row.h

Go to the documentation of this file.
00001 #ifndef SimTK_SIMMATRIX_SMALLMATRIX_ROW_H_
00002 #define SimTK_SIMMATRIX_SMALLMATRIX_ROW_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-8 Stanford University and the Authors.         *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors: Peter Eastman                                                *
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 
00039 #include "SimTKcommon/internal/common.h"
00040 
00041 
00042 namespace SimTK {
00043 
00044 // The following functions are used internally by Row.
00045 
00046 namespace Impl {
00047 
00048 // For those wimpy compilers that don't unroll short, constant-limit loops, Peter Eastman added these
00049 // recursive template implementations of add and subtract.
00050 
00051 template <class E1, int S1, class E2, int S2> void
00052 conformingAdd(const Row<1,E1,S1>& r1, const Row<1,E2,S2>& r2, Row<1,typename CNT<E1>::template Result<E2>::Add>& result) {
00053     result[0] = r1[0] + r2[0];
00054 }
00055 template <int N, class E1, int S1, class E2, int S2> void
00056 conformingAdd(const Row<N,E1,S1>& r1, const Row<N,E2,S2>& r2, Row<N,typename CNT<E1>::template Result<E2>::Add>& result) {
00057     conformingAdd(reinterpret_cast<const Row<N-1,E1,S1>&>(r1), reinterpret_cast<const Row<N-1,E2,S2>&>(r2), reinterpret_cast<Row<N-1,typename CNT<E1>::template Result<E2>::Add>&>(result));
00058     result[N-1] = r1[N-1] + r2[N-1];
00059 }
00060 template <class E1, int S1, class E2, int S2> void
00061 conformingSubtract(const Row<1,E1,S1>& r1, const Row<1,E2,S2>& r2, Row<1,typename CNT<E1>::template Result<E2>::Add>& result) {
00062     result[0] = r1[0] - r2[0];
00063 }
00064 template <int N, class E1, int S1, class E2, int S2> void
00065 conformingSubtract(const Row<N,E1,S1>& r1, const Row<N,E2,S2>& r2, Row<N,typename CNT<E1>::template Result<E2>::Add>& result) {
00066     conformingSubtract(reinterpret_cast<const Row<N-1,E1,S1>&>(r1), reinterpret_cast<const Row<N-1,E2,S2>&>(r2), reinterpret_cast<Row<N-1,typename CNT<E1>::template Result<E2>::Add>&>(result));
00067     result[N-1] = r1[N-1] - r2[N-1];
00068 }
00069 template <class E1, int S1, class E2, int S2> void
00070 copy(Row<1,E1,S1>& r1, const Row<1,E2,S2>& r2) {
00071     r1[0] = r2[0];
00072 }
00073 template <int N, class E1, int S1, class E2, int S2> void
00074 copy(Row<N,E1,S1>& r1, const Row<N,E2,S2>& r2) {
00075     copy(reinterpret_cast<Row<N-1,E1,S1>&>(r1), reinterpret_cast<const Row<N-1,E2,S2>&>(r2));
00076     r1[N-1] = r2[N-1];
00077 }
00078 
00079 }
00080 
00082 template <int N, class ELT, int STRIDE> class Row {
00083     typedef ELT                                 E;
00084     typedef typename CNT<E>::TNeg               ENeg;
00085     typedef typename CNT<E>::TWithoutNegator    EWithoutNegator;
00086     typedef typename CNT<E>::TReal              EReal;
00087     typedef typename CNT<E>::TImag              EImag;
00088     typedef typename CNT<E>::TComplex           EComplex;
00089     typedef typename CNT<E>::THerm              EHerm;
00090     typedef typename CNT<E>::TPosTrans          EPosTrans;
00091     typedef typename CNT<E>::TSqHermT           ESqHermT;
00092     typedef typename CNT<E>::TSqTHerm           ESqTHerm;
00093 
00094     typedef typename CNT<E>::TAbs               EAbs;
00095     typedef typename CNT<E>::TStandard          EStandard;
00096     typedef typename CNT<E>::TInvert            EInvert;
00097     typedef typename CNT<E>::TNormalize         ENormalize;
00098 
00099     typedef typename CNT<E>::Scalar             EScalar;
00100     typedef typename CNT<E>::Number             ENumber;
00101     typedef typename CNT<E>::StdNumber          EStdNumber;
00102     typedef typename CNT<E>::Precision          EPrecision;
00103     typedef typename CNT<E>::ScalarSq           EScalarSq;
00104 
00105 public:
00106 
00107     enum {
00108         NRows               = 1,
00109         NCols               = N,
00110         RowSpacing          = 1,
00111         ColSpacing          = STRIDE,
00112         NPackedElements     = N,
00113         NActualElements     = N * STRIDE,   // includes trailing gap
00114         NActualScalars      = CNT<E>::NActualScalars * NActualElements,
00115         ImagOffset          = NTraits<ENumber>::ImagOffset,
00116         RealStrideFactor    = 1, // composite types don't change size when
00117                                  // cast from complex to real or imaginary
00118         ArgDepth            = ((int)CNT<E>::ArgDepth < (int)MAX_RESOLVED_DEPTH 
00119                                 ? CNT<E>::ArgDepth + 1 
00120                                 : MAX_RESOLVED_DEPTH),
00121         IsScalar            = 0,
00122         IsNumber            = 0,
00123         IsStdNumber         = 0,
00124         IsPrecision         = 0,
00125         SignInterpretation  = CNT<E>::SignInterpretation
00126     };
00127 
00128     typedef Row<N,E,STRIDE>                 T;
00129     typedef Row<N,ENeg,STRIDE>              TNeg;
00130     typedef Row<N,EWithoutNegator,STRIDE>   TWithoutNegator;
00131 
00132     typedef Row<N,EReal,STRIDE*CNT<E>::RealStrideFactor>         
00133                                             TReal;
00134     typedef Row<N,EImag,STRIDE*CNT<E>::RealStrideFactor>         
00135                                             TImag;
00136     typedef Row<N,EComplex,STRIDE>          TComplex;
00137     typedef Vec<N,EHerm,STRIDE>             THerm;
00138     typedef Vec<N,E,STRIDE>                 TPosTrans;
00139     typedef E                               TElement;
00140     typedef Row                             TRow;
00141     typedef E                               TCol;
00142 
00143     // These are the results of calculations, so are returned in new, packed
00144     // memory. Be sure to refer to element types here which are also packed.
00145     typedef Row<N,EAbs,1>                   TAbs;       // Note stride
00146     typedef Row<N,EStandard,1>              TStandard;
00147     typedef Vec<N,EInvert,1>                TInvert;    // packed
00148     typedef Row<N,ENormalize,1>             TNormalize;
00149 
00150     typedef SymMat<N,ESqHermT>              TSqHermT;   // result of self outer product
00151     typedef EScalarSq                       TSqTHerm;   // result of self dot product
00152 
00153     // These recurse right down to the underlying scalar type no matter how
00154     // deep the elements are.
00155     typedef EScalar                         Scalar;
00156     typedef ENumber                         Number;
00157     typedef EStdNumber                      StdNumber;
00158     typedef EPrecision                      Precision;
00159     typedef EScalarSq                       ScalarSq;
00160 
00161     int size()   const  { return N; }
00162     int nrow()   const  { return 1; }
00163     int ncol()   const  { return N; }
00164 
00165 
00166     // Scalar norm square is sum( squares of all scalars )
00167     ScalarSq scalarNormSqr() const { 
00168         ScalarSq sum(0);
00169         for(int i=0;i<N;++i) sum += CNT<E>::scalarNormSqr(d[i*STRIDE]);
00170         return sum;
00171     }
00172 
00173     // abs() is elementwise absolute value; that is, the return value has the same
00174     // dimension as this Row but with each element replaced by whatever it thinks
00175     // its absolute value is.
00176     TAbs abs() const {
00177         TAbs rabs;
00178         for(int i=0;i<N;++i) rabs[i] = CNT<E>::abs(d[i*STRIDE]);
00179         return rabs;
00180     }
00181 
00182     TStandard standardize() const {
00183         TStandard rstd;
00184         for(int i=0;i<N;++i) rstd[i] = CNT<E>::standardize(d[i*STRIDE]);
00185         return rstd;
00186     }
00187 
00188     // Sum just adds up all the elements, getting rid of negators and
00189     // conjugates in the process.
00190     EStandard sum() const {
00191         E sum(0);
00192         for (int i=0;i<N;++i) sum += d[i*STRIDE];
00193         return CNT<E>::standardize(sum);
00194     }
00195 
00196     // This gives the resulting rowvector type when (v[i] op P) is applied to each element of v.
00197     // It is a row of length N, stride 1, and element types which are the regular
00198     // composite result of E op P. Typically P is a scalar type but it doesn't have to be.
00199     template <class P> struct EltResult { 
00200         typedef Row<N, typename CNT<E>::template Result<P>::Mul, 1> Mul;
00201         typedef Row<N, typename CNT<E>::template Result<P>::Dvd, 1> Dvd;
00202         typedef Row<N, typename CNT<E>::template Result<P>::Add, 1> Add;
00203         typedef Row<N, typename CNT<E>::template Result<P>::Sub, 1> Sub;
00204     };
00205 
00206     // This is the composite result for v op P where P is some kind of appropriately shaped
00207     // non-scalar type.
00208     template <class P> struct Result { 
00209         typedef MulCNTs<1,N,ArgDepth,Row,ColSpacing,RowSpacing,
00210             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00211             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> MulOp;
00212         typedef typename MulOp::Type Mul;
00213 
00214         typedef MulCNTsNonConforming<1,N,ArgDepth,Row,ColSpacing,RowSpacing,
00215             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00216             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> MulOpNonConforming;
00217         typedef typename MulOpNonConforming::Type MulNon;
00218 
00219 
00220         typedef DvdCNTs<1,N,ArgDepth,Row,ColSpacing,RowSpacing,
00221             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00222             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> DvdOp;
00223         typedef typename DvdOp::Type Dvd;
00224 
00225         typedef AddCNTs<1,N,ArgDepth,Row,ColSpacing,RowSpacing,
00226             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00227             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> AddOp;
00228         typedef typename AddOp::Type Add;
00229 
00230         typedef SubCNTs<1,N,ArgDepth,Row,ColSpacing,RowSpacing,
00231             CNT<P>::NRows, CNT<P>::NCols, CNT<P>::ArgDepth,
00232             P, CNT<P>::ColSpacing, CNT<P>::RowSpacing> SubOp;
00233         typedef typename SubOp::Type Sub;
00234     };
00235 
00236     // Shape-preserving element substitution (always packed)
00237     template <class P> struct Substitute {
00238         typedef Row<N,P> Type;
00239     };
00240 
00241     // Default construction initializes to NaN when debugging but
00242     // is left uninitialized otherwise.
00243     Row(){ 
00244     #ifndef NDEBUG
00245         setToNaN();
00246     #endif
00247     }
00248 
00249     // It's important not to use the default copy constructor or copy
00250     // assignment because the compiler doesn't understand that we may
00251     // have noncontiguous storage and will try to copy the whole array.
00252     Row(const Row& src) {
00253         Impl::copy(*this, src);
00254     }
00255     Row& operator=(const Row& src) {    // no harm if src and 'this' are the same
00256         Impl::copy(*this, src);
00257         return *this;
00258     }
00259 
00260     // We want an implicit conversion from a Row of the same length
00261     // and element type but with a different stride.
00262     template <int SS> Row(const Row<N,E,SS>& src) {
00263         Impl::copy(*this, src);
00264     }
00265 
00266     // We want an implicit conversion from a Row of the same length
00267     // and *negated* element type, possibly with a different stride.
00268     template <int SS> Row(const Row<N,ENeg,SS>& src) {
00269         Impl::copy(*this, src);
00270     }
00271 
00272     // Construct a Row from a Row of the same length, with any
00273     // stride. Works as long as the element types are compatible.
00274     template <class EE, int SS> explicit Row(const Row<N,EE,SS>& vv) {
00275         Impl::copy(*this, vv);
00276     }
00277 
00278     // Construction using an element assigns to each element.
00279     explicit Row(const ELT& e)
00280       { for (int i=0;i<N;++i) d[i*STRIDE]=e; }
00281 
00282     // A bevy of constructors for Rows up to length 6.
00283     Row(const E& e0,const E& e1)
00284       { assert(N==2);(*this)[0]=e0;(*this)[1]=e1; }
00285     Row(const E& e0,const E& e1,const E& e2)
00286       { assert(N==3);(*this)[0]=e0;(*this)[1]=e1;(*this)[2]=e2; }
00287     Row(const E& e0,const E& e1,const E& e2,const E& e3)
00288       { assert(N==4);(*this)[0]=e0;(*this)[1]=e1;(*this)[2]=e2;(*this)[3]=e3; }
00289     Row(const E& e0,const E& e1,const E& e2,const E& e3,const E& e4)
00290       { assert(N==5);(*this)[0]=e0;(*this)[1]=e1;(*this)[2]=e2;
00291         (*this)[3]=e3;(*this)[4]=e4; }
00292     Row(const E& e0,const E& e1,const E& e2,const E& e3,const E& e4,const E& e5)
00293       { assert(N==6);(*this)[0]=e0;(*this)[1]=e1;(*this)[2]=e2;
00294         (*this)[3]=e3;(*this)[4]=e4;(*this)[5]=e5; }
00295 
00296     // Construction from a pointer to anything assumes we're pointing
00297     // at an element list of the right length.
00298     template <class EE> explicit Row(const EE* p)
00299       { assert(p); for(int i=0;i<N;++i) d[i*STRIDE]=p[i]; }
00300     template <class EE> Row& operator=(const EE* p)
00301       { assert(p); for(int i=0;i<N;++i) d[i*STRIDE]=p[i]; return *this; }
00302 
00303     // Conforming assignment ops.
00304     template <class EE, int SS> Row& operator=(const Row<N,EE,SS>& vv) {
00305         Impl::copy(*this, vv);
00306         return *this;
00307     }
00308     template <class EE, int SS> Row& operator+=(const Row<N,EE,SS>& r)
00309       { for(int i=0;i<N;++i) d[i*STRIDE] += r[i]; return *this; }
00310     template <class EE, int SS> Row& operator+=(const Row<N,negator<EE>,SS>& r)
00311       { for(int i=0;i<N;++i) d[i*STRIDE] -= -(r[i]); return *this; }
00312     template <class EE, int SS> Row& operator-=(const Row<N,EE,SS>& r)
00313       { for(int i=0;i<N;++i) d[i*STRIDE] -= r[i]; return *this; }
00314     template <class EE, int SS> Row& operator-=(const Row<N,negator<EE>,SS>& r)
00315       { for(int i=0;i<N;++i) d[i*STRIDE] += -(r[i]); return *this; }
00316 
00317     // Conforming binary ops with 'this' on left, producing new packed result.
00318     // Cases: r=r+r, r=r-r, s=r*v r=r*m
00319     template <class EE, int SS> Row<N,typename CNT<E>::template Result<EE>::Add>
00320     conformingAdd(const Row<N,EE,SS>& r) const {
00321         Row<N,typename CNT<E>::template Result<EE>::Add> result;
00322         Impl::conformingAdd(*this, r, result);
00323         return result;
00324     }
00325     template <class EE, int SS> Row<N,typename CNT<E>::template Result<EE>::Sub>
00326     conformingSubtract(const Row<N,EE,SS>& r) const {
00327         Row<N,typename CNT<E>::template Result<EE>::Sub> result;
00328         Impl::conformingSubtract(*this, r, result);
00329         return result;
00330     }
00331 
00332     // dot product
00333     template <class EE, int SS> typename CNT<E>::template Result<EE>::Mul
00334     conformingMultiply(const Vec<N,EE,SS>& r) const {
00335         return (*this)*r;
00336     }
00337 
00338     // row=row*mat
00339     template <int MatNCol, class EE, int CS, int RS> 
00340     Row<MatNCol,typename CNT<E>::template Result<EE>::Mul>
00341     conformingMultiply(const Mat<N,MatNCol,EE,CS,RS>& m) const {
00342         Row<MatNCol,typename CNT<E>::template Result<EE>::Mul> result;
00343         for (int j=0;j<N;++j) result[j] = conformingMultiply(m(j));
00344         return result;
00345     }
00346 
00347     const E& operator[](int i) const { assert(0 <= i && i < N); return d[i*STRIDE]; }
00348     E&       operator[](int i)       { assert(0 <= i && i < N); return d[i*STRIDE]; }
00349     const E& operator()(int i) const { return (*this)[i]; }
00350     E&       operator()(int i)       { return (*this)[i]; }
00351 
00352     ScalarSq normSqr() const { return scalarNormSqr(); }
00353     ScalarSq norm()    const { return std::sqrt(scalarNormSqr()); }
00354 
00355     // If the elements of this Row are scalars, the result is what you get by
00356     // dividing each element by the norm() calculated above. If the elements are
00357     // *not* scalars, then the elements are *separately* normalized. That means
00358     // you will get a different answer from Row<2,Row3>::normalize() than you
00359     // would from a Row<6>::normalize() containing the same scalars.
00360     //
00361     // Normalize returns a row of the same dimension but in new, packed storage
00362     // and with a return type that does not include negator<> even if the original
00363     // Row<> does, because we can eliminate the negation here almost for free.
00364     // But we can't standardize (change conjugate to complex) for free, so we'll retain
00365     // conjugates if there are any.
00366     TNormalize normalize() const {
00367         if (CNT<E>::IsScalar) {
00368             return castAwayNegatorIfAny() / (SignInterpretation*norm());
00369         } else {
00370             TNormalize elementwiseNormalized;
00371             for (int j=0; j<N; ++j) 
00372                 elementwiseNormalized[j] = CNT<E>::normalize((*this)[j]);
00373             return elementwiseNormalized;
00374         }
00375     }
00376 
00377     TInvert invert() const {assert(false); return TInvert();} // TODO default inversion
00378 
00379     const Row&   operator+() const { return *this; }
00380     const TNeg&  operator-() const { return negate(); }
00381     TNeg&        operator-()       { return updNegate(); }
00382     const THerm& operator~() const { return transpose(); }
00383     THerm&       operator~()       { return updTranspose(); }
00384 
00385     const TNeg&  negate() const { return *reinterpret_cast<const TNeg*>(this); }
00386     TNeg&        updNegate()    { return *reinterpret_cast<TNeg*>(this); }
00387 
00388     const THerm& transpose()    const { return *reinterpret_cast<const THerm*>(this); }
00389     THerm&       updTranspose()       { return *reinterpret_cast<THerm*>(this); }
00390 
00391     const TPosTrans& positionalTranspose() const
00392         { return *reinterpret_cast<const TPosTrans*>(this); }
00393     TPosTrans&       updPositionalTranspose()
00394         { return *reinterpret_cast<TPosTrans*>(this); }
00395 
00396     const TReal& real() const { return *reinterpret_cast<const TReal*>(this); }
00397     TReal&       real()       { return *reinterpret_cast<      TReal*>(this); }
00398 
00399     // Had to contort these routines to get them through VC++ 7.net
00400     const TImag& imag()    const { 
00401         const int offs = ImagOffset;
00402         const EImag* p = reinterpret_cast<const EImag*>(this);
00403         return *reinterpret_cast<const TImag*>(p+offs);
00404     }
00405     TImag& imag() { 
00406         const int offs = ImagOffset;
00407         EImag* p = reinterpret_cast<EImag*>(this);
00408         return *reinterpret_cast<TImag*>(p+offs);
00409     }
00410 
00411     const TWithoutNegator& castAwayNegatorIfAny() const {return *reinterpret_cast<const TWithoutNegator*>(this);}
00412     TWithoutNegator&       updCastAwayNegatorIfAny()    {return *reinterpret_cast<TWithoutNegator*>(this);}
00413 
00414 
00415     // These are elementwise binary operators, (this op ee) by default but (ee op this) if
00416     // 'FromLeft' appears in the name. The result is a packed Row<N> but the element type
00417     // may change. These are mostly used to implement global operators.
00418 
00419     //TODO: consider converting 'e' to Standard Numbers as precalculation and changing
00420     // return type appropriately.
00421     template <class EE> Row<N, typename CNT<E>::template Result<EE>::Mul>
00422     scalarMultiply(const EE& e) const {
00423         Row<N, typename CNT<E>::template Result<EE>::Mul> result;
00424         for (int j=0; j<N; ++j) result[j] = (*this)[j] * e;
00425         return result;
00426     }
00427     template <class EE> Row<N, typename CNT<EE>::template Result<E>::Mul>
00428     scalarMultiplyFromLeft(const EE& e) const {
00429         Row<N, typename CNT<EE>::template Result<E>::Mul> result;
00430         for (int j=0; j<N; ++j) result[j] = e * (*this)[j];
00431         return result;
00432     }
00433 
00434     // TODO: should precalculate and store 1/e, while converting to Standard Numbers. Note
00435     // that return type should change appropriately.
00436     template <class EE> Row<N, typename CNT<E>::template Result<EE>::Dvd>
00437     scalarDivide(const EE& e) const {
00438         Row<N, typename CNT<E>::template Result<EE>::Dvd> result;
00439         for (int j=0; j<N; ++j) result[j] = (*this)[j] / e;
00440         return result;
00441     }
00442     template <class EE> Row<N, typename CNT<EE>::template Result<E>::Dvd>
00443     scalarDivideFromLeft(const EE& e) const {
00444         Row<N, typename CNT<EE>::template Result<E>::Dvd> result;
00445         for (int j=0; j<N; ++j) result[j] = e / (*this)[j];
00446         return result;
00447     }
00448 
00449     template <class EE> Row<N, typename CNT<E>::template Result<EE>::Add>
00450     scalarAdd(const EE& e) const {
00451         Row<N, typename CNT<E>::template Result<EE>::Add> result;
00452         for (int j=0; j<N; ++j) result[j] = (*this)[j] + e;
00453         return result;
00454     }
00455     // Add is commutative, so no 'FromLeft'.
00456 
00457     template <class EE> Row<N, typename CNT<E>::template Result<EE>::Sub>
00458     scalarSubtract(const EE& e) const {
00459         Row<N, typename CNT<E>::template Result<EE>::Sub> result;
00460         for (int j=0; j<N; ++j) result[j] = (*this)[j] - e;
00461         return result;
00462     }
00463     template <class EE> Row<N, typename CNT<EE>::template Result<E>::Sub>
00464     scalarSubtractFromLeft(const EE& e) const {
00465         Row<N, typename CNT<EE>::template Result<E>::Sub> result;
00466         for (int j=0; j<N; ++j) result[j] = e - (*this)[j];
00467         return result;
00468     }
00469 
00470     // Generic assignments for any element type not listed explicitly, including scalars.
00471     // These are done repeatedly for each element and only work if the operation can
00472     // be performed leaving the original element type.
00473     template <class EE> Row& operator =(const EE& e) {return scalarEq(e);}
00474     template <class EE> Row& operator+=(const EE& e) {return scalarPlusEq(e);}
00475     template <class EE> Row& operator-=(const EE& e) {return scalarMinusEq(e);}
00476     template <class EE> Row& operator*=(const EE& e) {return scalarTimesEq(e);}
00477     template <class EE> Row& operator/=(const EE& e) {return scalarDivideEq(e);}
00478 
00479     // Generalized scalar assignment & computed assignment methods. These will work
00480     // for any assignment-compatible element, not just scalars.
00481     template <class EE> Row& scalarEq(const EE& ee)
00482       { for(int i=0;i<N;++i) d[i*STRIDE] = ee; return *this; }
00483     template <class EE> Row& scalarPlusEq(const EE& ee)
00484       { for(int i=0;i<N;++i) d[i*STRIDE] += ee; return *this; }
00485     template <class EE> Row& scalarMinusEq(const EE& ee)
00486       { for(int i=0;i<N;++i) d[i*STRIDE] -= ee; return *this; }
00487     template <class EE> Row& scalarInverseMinusEq(const EE& ee)
00488       { for(int i=0;i<N;++i) d[i*STRIDE] = ee - d[i*STRIDE]; return *this; }
00489     template <class EE> Row& scalarTimesEq(const EE& ee)
00490       { for(int i=0;i<N;++i) d[i*STRIDE] *= ee; return *this; }
00491     template <class EE> Row& scalarDivideEq(const EE& ee)
00492       { for(int i=0;i<N;++i) d[i*STRIDE] /= ee; return *this; }
00493     template <class EE> Row& scalarInverseDivideEq(const EE& ee)
00494       { for(int i=0;i<N;++i) d[i*STRIDE] = ee / d[i*STRIDE]; return *this; }
00495 
00496     void setToNaN() {
00497         (*this) = CNT<ELT>::getNaN();
00498     }
00499 
00500     // Extract a sub-Row with size known at compile time. These have to be
00501     // called with explicit template arguments, e.g. getSubRow<3>(j).
00502     template <int NN>
00503     const Row<NN,ELT,STRIDE>& getSubRow(int j) const {
00504         assert(0 <= j && j + NN <= N);
00505         return Row<NN,ELT,STRIDE>::getAs(&(*this)[j]);
00506     }
00507     template <int NN>
00508     Row<NN,ELT,STRIDE>& updSubRow(int j) {
00509         assert(0 <= j && j + NN <= N);
00510         return Row<NN,ELT,STRIDE>::updAs(&(*this)[j]);
00511     }
00512 
00513     // Return a row one smaller than this one by dropping the element
00514     // at the indicated position p. The result is packed but has same
00515     // element type as this one.
00516     Row<N-1,ELT,1> drop1(int p) const {
00517         assert(0 <= p && p < N);
00518         Row<N-1,ELT,1> out;
00519         int nxt=0;
00520         for (int i=0; i<N-1; ++i, ++nxt) {
00521             if (nxt==p) ++nxt;  // skip the loser
00522             out[i] = (*this)[nxt];
00523         }
00524         return out;
00525     }
00526 
00527     // Return a vector one larger than this one by adding an element
00528     // to the end. The result is packed but has same element type as
00529     // this one. Works for any assignment compatible element.
00530     template <class EE> Row<N+1,ELT,1> append1(const EE& v) const {
00531         Row<N+1,ELT,1> out;
00532         Row<N,ELT,1>::updAs(&out[0]) = (*this);
00533         out[N] = v;
00534         return out;
00535     }
00536 
00537 
00538     // Return a vector one larger than this one by inserting an element
00539     // *before* the indicated one. The result is packed but has same element type as
00540     // this one. Works for any assignment compatible element. The index
00541     // can be one greater than normally allowed in which case the element
00542     // is appended.
00543     template <class EE> Row<N+1,ELT,1> insert1(int p, const EE& v) const {
00544         assert(0 <= p && p <= N);
00545         if (p==N) return append1(v);
00546         Row<N+1,ELT,1> out;
00547         int nxt=0;
00548         for (int i=0; i<N; ++i, ++nxt) {
00549             if (i==p) out[nxt++] = v;
00550             out[nxt] = (*this)[i];
00551         }
00552         return out;
00553     }
00554 
00555     // These assume we are given a pointer to d[0] of a Row<N,E,S> like this one.
00556     static const Row& getAs(const ELT* p)  {return *reinterpret_cast<const Row*>(p);}
00557     static Row&       updAs(ELT* p)        {return *reinterpret_cast<Row*>(p);}
00558 
00559     // Extract a subrow from a longer one. Element type and stride must match.
00560     template <int NN>
00561     static const Row& getSubRow(const Row<NN,ELT,STRIDE>& r, int j) {
00562         assert(0 <= j && j + N <= NN);
00563         return getAs(&r[j]);
00564     }
00565     template <int NN>
00566     static Row& updSubRow(Row<NN,ELT,STRIDE>& r, int j) {
00567         assert(0 <= j && j + N <= NN);
00568         return updAs(&r[j]);
00569     }
00570 
00571     static Row<N,ELT,1> getNaN() { return Row<N,ELT,1>(CNT<ELT>::getNaN()); }
00572 private:
00573     ELT d[NActualElements];    // data
00574 };
00575 
00577 // Global operators involving two rows.    //
00578 //   v+v, v-v, v==v, v!=v                  //
00580 
00581 // v3 = v1 + v2 where all v's have the same length N. 
00582 template <int N, class E1, int S1, class E2, int S2> inline
00583 typename Row<N,E1,S1>::template Result< Row<N,E2,S2> >::Add
00584 operator+(const Row<N,E1,S1>& l, const Row<N,E2,S2>& r) { 
00585     return Row<N,E1,S1>::template Result< Row<N,E2,S2> >
00586         ::AddOp::perform(l,r);
00587 }
00588 
00589 // v3 = v1 - v2, similar to +
00590 template <int N, class E1, int S1, class E2, int S2> inline
00591 typename Row<N,E1,S1>::template Result< Row<N,E2,S2> >::Sub
00592 operator-(const Row<N,E1,S1>& l, const Row<N,E2,S2>& r) { 
00593     return Row<N,E1,S1>::template Result< Row<N,E2,S2> >
00594         ::SubOp::perform(l,r);
00595 }
00596 
00597 // bool = v1 == v2, v1 and v2 have the same length M
00598 template <int N, class E1, int S1, class E2, int S2> inline bool
00599 operator==(const Row<N,E1,S1>& l, const Row<N,E2,S2>& r) { 
00600     for (int i=0; i < N; ++i)
00601         if (l[i] != r[i]) return false;
00602     return true;
00603 }
00604 
00605 // bool = v1 != v2, v1 and v2 have the same length M
00606 template <int N, class E1, int S1, class E2, int S2> inline bool
00607 operator!=(const Row<N,E1,S1>& l, const Row<N,E2,S2>& r) {return !(l==r);} 
00608 
00609 
00611 // Global operators involving a row and a scalar. //
00613 
00614 // I haven't been able to figure out a nice way to templatize for the
00615 // built-in reals without introducing a lot of unwanted type matches
00616 // as well. So we'll just grind them out explicitly here.
00617 
00618 // SCALAR MULTIPLY
00619 
00620 // v = v*real, real*v 
00621 template <int N, class E, int S> inline
00622 typename Row<N,E,S>::template Result<float>::Mul
00623 operator*(const Row<N,E,S>& l, const float& r)
00624   { return Row<N,E,S>::template Result<float>::MulOp::perform(l,r); }
00625 template <int N, class E, int S> inline
00626 typename Row<N,E,S>::template Result<float>::Mul
00627 operator*(const float& l, const Row<N,E,S>& r) {return r*l;}
00628 
00629 template <int N, class E, int S> inline
00630 typename Row<N,E,S>::template Result<double>::Mul
00631 operator*(const Row<N,E,S>& l, const double& r)
00632   { return Row<N,E,S>::template Result<double>::MulOp::perform(l,r); }
00633 template <int N, class E, int S> inline
00634 typename Row<N,E,S>::template Result<double>::Mul
00635 operator*(const double& l, const Row<N,E,S>& r) {return r*l;}
00636 
00637 template <int N, class E, int S> inline
00638 typename Row<N,E,S>::template Result<long double>::Mul
00639 operator*(const Row<N,E,S>& l, const long double& r)
00640   { return Row<N,E,S>::template Result<long double>::MulOp::perform(l,r); }
00641 template <int N, class E, int S> inline
00642 typename Row<N,E,S>::template Result<long double>::Mul
00643 operator*(const long double& l, const Row<N,E,S>& r) {return r*l;}
00644 
00645 // v = v*int, int*v -- just convert int to v's precision float
00646 template <int N, class E, int S> inline
00647 typename Row<N,E,S>::template Result<typename CNT<E>::Precision>::Mul
00648 operator*(const Row<N,E,S>& l, int r) {return l * (typename CNT<E>::Precision)r;}
00649 template <int N, class E, int S> inline
00650 typename Row<N,E,S>::template Result<typename CNT<E>::Precision>::Mul
00651 operator*(int l, const Row<N,E,S>& r) {return r * (typename CNT<E>::Precision)l;}
00652 
00653 // Complex, conjugate, and negator are all easy to templatize.
00654 
00655 // v = v*complex, complex*v
00656 template <int N, class E, int S, class R> inline
00657 typename Row<N,E,S>::template Result<std::complex<R> >::Mul
00658 operator*(const Row<N,E,S>& l, const std::complex<R>& r)
00659   { return Row<N,E,S>::template Result<std::complex<R> >::MulOp::perform(l,r); }
00660 template <int N, class E, int S, class R> inline
00661 typename Row<N,E,S>::template Result<std::complex<R> >::Mul
00662 operator*(const std::complex<R>& l, const Row<N,E,S>& r) {return r*l;}
00663 
00664 // v = v*conjugate, conjugate*v (convert conjugate->complex)
00665 template <int N, class E, int S, class R> inline
00666 typename Row<N,E,S>::template Result<std::complex<R> >::Mul
00667 operator*(const Row<N,E,S>& l, const conjugate<R>& r) {return l*(std::complex<R>)r;}
00668 template <int N, class E, int S, class R> inline
00669 typename Row<N,E,S>::template Result<std::complex<R> >::Mul
00670 operator*(const conjugate<R>& l, const Row<N,E,S>& r) {return r*(std::complex<R>)l;}
00671 
00672 // v = v*negator, negator*v: convert negator to standard number
00673 template <int N, class E, int S, class R> inline
00674 typename Row<N,E,S>::template Result<typename negator<R>::StdNumber>::Mul
00675 operator*(const Row<N,E,S>& l, const negator<R>& r) {return l * (typename negator<R>::StdNumber)(R)r;}
00676 template <int N, class E, int S, class R> inline
00677 typename Row<N,E,S>::template Result<typename negator<R>::StdNumber>::Mul
00678 operator*(const negator<R>& l, const Row<N,E,S>& r) {return r * (typename negator<R>::StdNumber)(R)l;}
00679 
00680 
00681 // SCALAR DIVIDE. This is a scalar operation when the scalar is on the right,
00682 // but when it is on the left it means scalar * pseudoInverse(row), which is a vec.
00683 
00684 // v = v/real, real/v 
00685 template <int N, class E, int S> inline
00686 typename Row<N,E,S>::template Result<float>::Dvd
00687 operator/(const Row<N,E,S>& l, const float& r)
00688   { return Row<N,E,S>::template Result<float>::DvdOp::perform(l,r); }
00689 template <int N, class E, int S> inline
00690 typename CNT<float>::template Result<Row<N,E,S> >::Dvd
00691 operator/(const float& l, const Row<N,E,S>& r)
00692   { return CNT<float>::template Result<Row<N,E,S> >::DvdOp::perform(l,r); }
00693 
00694 template <int N, class E, int S> inline
00695 typename Row<N,E,S>::template Result<double>::Dvd
00696 operator/(const Row<N,E,S>& l, const double& r)
00697   { return Row<N,E,S>::template Result<double>::DvdOp::perform(l,r); }
00698 template <int N, class E, int S> inline
00699 typename CNT<double>::template Result<Row<N,E,S> >::Dvd
00700 operator/(const double& l, const Row<N,E,S>& r)
00701   { return CNT<double>::template Result<Row<N,E,S> >::DvdOp::perform(l,r); }
00702 
00703 template <int N, class E, int S> inline
00704 typename Row<N,E,S>::template Result<long double>::Dvd
00705 operator/(const Row<N,E,S>& l, const long double& r)
00706   { return Row<N,E,S>::template Result<long double>::DvdOp::perform(l,r); }
00707 template <int N, class E, int S> inline
00708 typename CNT<long double>::template Result<Row<N,E,S> >::Dvd
00709 operator/(const long double& l, const Row<N,E,S>& r)
00710   { return CNT<long double>::template Result<Row<N,E,S> >::DvdOp::perform(l,r); }
00711 
00712 // v = v/int, int/v -- just convert int to v's precision float
00713 template <int N, class E, int S> inline
00714 typename Row<N,E,S>::template Result<typename CNT<E>::Precision>::Dvd
00715 operator/(const Row<N,E,S>& l, int r) {return l / (typename CNT<E>::Precision)r;}
00716 template <int N, class E, int S> inline
00717 typename CNT<typename CNT<E>::Precision>::template Result<Row<N,E,S> >::Dvd
00718 operator/(int l, const Row<N,E,S>& r) {return (typename CNT<E>::Precision)l / r;}
00719 
00720 
00721 // Complex, conjugate, and negator are all easy to templatize.
00722 
00723 // v = v/complex, complex/v
00724 template <int N, class E, int S, class R> inline
00725 typename Row<N,E,S>::template Result<std::complex<R> >::Dvd
00726 operator/(const Row<N,E,S>& l, const std::complex<R>& r)
00727   { return Row<N,E,S>::template Result<std::complex<R> >::DvdOp::perform(l,r); }
00728 template <int N, class E, int S, class R> inline
00729 typename CNT<std::complex<R> >::template Result<Row<N,E,S> >::Dvd
00730 operator/(const std::complex<R>& l, const Row<N,E,S>& r)
00731   { return CNT<std::complex<R> >::template Result<Row<N,E,S> >::DvdOp::perform(l,r); }
00732 
00733 // v = v/conjugate, conjugate/v (convert conjugate->complex)
00734 template <int N, class E, int S, class R> inline
00735 typename Row<N,E,S>::template Result<std::complex<R> >::Dvd
00736 operator/(const Row<N,E,S>& l, const conjugate<R>& r) {return l/(std::complex<R>)r;}
00737 template <int N, class E, int S, class R> inline
00738 typename CNT<std::complex<R> >::template Result<Row<N,E,S> >::Dvd
00739 operator/(const conjugate<R>& l, const Row<N,E,S>& r) {return (std::complex<R>)l/r;}
00740 
00741 // v = v/negator, negator/v: convert negator to number
00742 template <int N, class E, int S, class R> inline
00743 typename Row<N,E,S>::template Result<typename negator<R>::StdNumber>::Dvd
00744 operator/(const Row<N,E,S>& l, const negator<R>& r) {return l/(typename negator<R>::StdNumber)(R)r;}
00745 template <int N, class E, int S, class R> inline
00746 typename CNT<R>::template Result<Row<N,E,S> >::Dvd
00747 operator/(const negator<R>& l, const Row<N,E,S>& r) {return (typename negator<R>::StdNumber)(R)l/r;}
00748 
00749 
00750 // Add and subtract are odd as scalar ops. They behave as though the
00751 // scalar stands for a vector each of whose elements is that scalar,
00752 // and then a normal vector add or subtract is done.
00753 
00754 // SCALAR ADD
00755 
00756 // v = v+real, real+v 
00757 template <int N, class E, int S> inline
00758 typename Row<N,E,S>::template Result<float>::Add
00759 operator+(const Row<N,E,S>& l, const float& r)
00760   { return Row<N,E,S>::template Result<float>::AddOp::perform(l,r); }
00761 template <int N, class E, int S> inline
00762 typename Row<N,E,S>::template Result<float>::Add
00763 operator+(const float& l, const Row<N,E,S>& r) {return r+l;}
00764 
00765 template <int N, class E, int S> inline
00766 typename Row<N,E,S>::template Result<double>::Add
00767 operator+(const Row<N,E,S>& l, const double& r)
00768   { return Row<N,E,S>::template Result<double>::AddOp::perform(l,r); }
00769 template <int N, class E, int S> inline
00770 typename Row<N,E,S>::template Result<double>::Add
00771 operator+(const double& l, const Row<N,E,S>& r) {return r+l;}
00772 
00773 template <int N, class E, int S> inline
00774 typename Row<N,E,S>::template Result<long double>::Add
00775 operator+(const Row<N,E,S>& l, const long double& r)
00776   { return Row<N,E,S>::template Result<long double>::AddOp::perform(l,r); }
00777 template <int N, class E, int S> inline
00778 typename Row<N,E,S>::template Result<long double>::Add
00779 operator+(const long double& l, const Row<N,E,S>& r) {return r+l;}
00780 
00781 // v = v+int, int+v -- just convert int to v's precision float
00782 template <int N, class E, int S> inline
00783 typename Row<N,E,S>::template Result<typename CNT<E>::Precision>::Add
00784 operator+(const Row<N,E,S>& l, int r) {return l + (typename CNT<E>::Precision)r;}
00785 template <int N, class E, int S> inline
00786 typename Row<N,E,S>::template Result<typename CNT<E>::Precision>::Add
00787 operator+(int l, const Row<N,E,S>& r) {return r + (typename CNT<E>::Precision)l;}
00788 
00789 // Complex, conjugate, and negator are all easy to templatize.
00790 
00791 // v = v+complex, complex+v
00792 template <int N, class E, int S, class R> inline
00793 typename Row<N,E,S>::template Result<std::complex<R> >::Add
00794 operator+(const Row<N,E,S>& l, const std::complex<R>& r)
00795   { return Row<N,E,S>::template Result<std::complex<R> >::AddOp::perform(l,r); }
00796 template <int N, class E, int S, class R> inline
00797 typename Row<N,E,S>::template Result<std::complex<R> >::Add
00798 operator+(const std::complex<R>& l, const Row<N,E,S>& r) {return r+l;}
00799 
00800 // v = v+conjugate, conjugate+v (convert conjugate->complex)
00801 template <int N, class E, int S, class R> inline
00802 typename Row<N,E,S>::template Result<std::complex<R> >::Add
00803 operator+(const Row<N,E,S>& l, const conjugate<R>& r) {return l+(std::complex<R>)r;}
00804 template <int N, class E, int S, class R> inline
00805 typename Row<N,E,S>::template Result<std::complex<R> >::Add
00806 operator+(const conjugate<R>& l, const Row<N,E,S>& r) {return r+(std::complex<R>)l;}
00807 
00808 // v = v+negator, negator+v: convert negator to standard number
00809 template <int N, class E, int S, class R> inline
00810 typename Row<N,E,S>::template Result<typename negator<R>::StdNumber>::Add
00811 operator+(const Row<N,E,S>& l, const negator<R>& r) {return l + (typename negator<R>::StdNumber)(R)r;}
00812 template <int N, class E, int S, class R> inline
00813 typename Row<N,E,S>::template Result<typename negator<R>::StdNumber>::Add
00814 operator+(const negator<R>& l, const Row<N,E,S>& r) {return r + (typename negator<R>::StdNumber)(R)l;}
00815 
00816 // SCALAR SUBTRACT -- careful, not commutative.
00817 
00818 // v = v-real, real-v 
00819 template <int N, class E, int S> inline
00820 typename Row<N,E,S>::template Result<float>::Sub
00821 operator-(const Row<N,E,S>& l, const float& r)
00822   { return Row<N,E,S>::template Result<float>::SubOp::perform(l,r); }
00823 template <int N, class E, int S> inline
00824 typename CNT<float>::template Result<Row<N,E,S> >::Sub
00825 operator-(const float& l, const Row<N,E,S>& r)
00826   { return CNT<float>::template Result<Row<N,E,S> >::SubOp::perform(l,r); }
00827 
00828 template <int N, class E, int S> inline
00829 typename Row<N,E,S>::template Result<double>::Sub
00830 operator-(const Row<N,E,S>& l, const double& r)
00831   { return Row<N,E,S>::template Result<double>::SubOp::perform(l,r); }
00832 template <int N, class E, int S> inline
00833 typename CNT<double>::template Result<Row<N,E,S> >::Sub
00834 operator-(const double& l, const Row<N,E,S>& r)
00835   { return CNT<double>::template Result<Row<N,E,S> >::SubOp::perform(l,r); }
00836 
00837 template <int N, class E, int S> inline
00838 typename Row<N,E,S>::template Result<long double>::Sub
00839 operator-(const Row<N,E,S>& l, const long double& r)
00840   { return Row<N,E,S>::template Result<long double>::SubOp::perform(l,r); }
00841 template <int N, class E, int S> inline
00842 typename CNT<long double>::template Result<Row<N,E,S> >::Sub
00843 operator-(const long double& l, const Row<N,E,S>& r)
00844   { return CNT<long double>::template Result<Row<N,E,S> >::SubOp::perform(l,r); }
00845 
00846 // v = v-int, int-v // just convert int to v's precision float
00847 template <int N, class E, int S> inline
00848 typename Row<N,E,S>::template Result<typename CNT<E>::Precision>::Sub
00849 operator-(const Row<N,E,S>& l, int r) {return l - (typename CNT<E>::Precision)r;}
00850 template <int N, class E, int S> inline
00851 typename CNT<typename CNT<E>::Precision>::template Result<Row<N,E,S> >::Sub
00852 operator-(int l, const Row<N,E,S>& r) {return (typename CNT<E>::Precision)l - r;}
00853 
00854 
00855 // Complex, conjugate, and negator are all easy to templatize.
00856 
00857 // v = v-complex, complex-v
00858 template <int N, class E, int S, class R> inline
00859 typename Row<N,E,S>::template Result<std::complex<R> >::Sub
00860 operator-(const Row<N,E,S>& l, const std::complex<R>& r)
00861   { return Row<N,E,S>::template Result<std::complex<R> >::SubOp::perform(l,r); }
00862 template <int N, class E, int S, class R> inline
00863 typename CNT<std::complex<R> >::template Result<Row<N,E,S> >::Sub
00864 operator-(const std::complex<R>& l, const Row<N,E,S>& r)
00865   { return CNT<std::complex<R> >::template Result<Row<N,E,S> >::SubOp::perform(l,r); }
00866 
00867 // v = v-conjugate, conjugate-v (convert conjugate->complex)
00868 template <int N, class E, int S, class R> inline
00869 typename Row<N,E,S>::template Result<std::complex<R> >::Sub
00870 operator-(const Row<N,E,S>& l, const conjugate<R>& r) {return l-(std::complex<R>)r;}
00871 template <int N, class E, int S, class R> inline
00872 typename CNT<std::complex<R> >::template Result<Row<N,E,S> >::Sub
00873 operator-(const conjugate<R>& l, const Row<N,E,S>& r) {return (std::complex<R>)l-r;}
00874 
00875 // v = v-negator, negator-v: convert negator to standard number
00876 template <int N, class E, int S, class R> inline
00877 typename Row<N,E,S>::template Result<typename negator<R>::StdNumber>::Sub
00878 operator-(const Row<N,E,S>& l, const negator<R>& r) {return l-(typename negator<R>::StdNumber)(R)r;}
00879 template <int N, class E, int S, class R> inline
00880 typename CNT<R>::template Result<Row<N,E,S> >::Sub
00881 operator-(const negator<R>& l, const Row<N,E,S>& r) {return (typename negator<R>::StdNumber)(R)l-r;}
00882 
00883 
00884 // Row I/O
00885 template <int N, class E, int S, class CHAR, class TRAITS> inline
00886 std::basic_ostream<CHAR,TRAITS>&
00887 operator<<(std::basic_ostream<CHAR,TRAITS>& o, const Row<N,E,S>& v) {
00888     o << "[" << v[0]; for(int i=1;i<N;++i) o<<','<<v[i]; o<<']'; return o;
00889 }
00890 
00891 template <int N, class E, int S, class CHAR, class TRAITS> inline
00892 std::basic_istream<CHAR,TRAITS>&
00893 operator>>(std::basic_istream<CHAR,TRAITS>& is, Row<N,E,S>& v) {
00894     // TODO: not sure how to do Row input yet
00895     assert(false);
00896     return is;
00897 }
00898 
00899 } //namespace SimTK
00900 
00901 
00902 #endif //SimTK_SIMMATRIX_SMALLMATRIX_ROW_H_

Generated on Fri Sep 26 07:44:16 2008 for SimTKcore by  doxygen 1.5.6