1 #ifndef SimTK_SIMMATRIX_MATRIXBASE_H_
2 #define SimTK_SIMMATRIX_MATRIXBASE_H_
3 
4 /* -------------------------------------------------------------------------- *
5  *                       Simbody(tm): SimTKcommon                             *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from           *
8  * Simbios, the NIH National Center for Physics-Based Simulation of           *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
11  *                                                                            *
12  * Portions copyright (c) 2005-13 Stanford University and the Authors.        *
13  * Authors: Michael Sherman                                                   *
14  * Contributors:                                                              *
15  *                                                                            *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
17  * not use this file except in compliance with the License. You may obtain a  *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
19  *                                                                            *
20  * Unless required by applicable law or agreed to in writing, software        *
21  * distributed under the License is distributed on an "AS IS" BASIS,          *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
23  * See the License for the specific language governing permissions and        *
24  * limitations under the License.                                             *
25  * -------------------------------------------------------------------------- */
26 
27 /** @file
28 Define the SimTK::MatrixBase class that is part of Simbody's BigMatrix
29 toolset. **/
30 
31 namespace SimTK {
32 
33 //==============================================================================
34 //                               MATRIX BASE
35 //==============================================================================
36 /** @brief This is the common base class for Simbody's Vector_ and Matrix_
37 classes for handling large, variable-sized vectors and matrices.
38 
39 %MatrixBase does not normally appear in user programs. Instead classes
40 Vector_ and Matrix_ are used, or more commonly the typedefs Vector and Matrix
41 which are abbreviations for Vector_<Real> and Matrix_<Real>.
42 
43 %Matrix base is a variable-size 2d matrix of Composite Numerical Type (CNT)
44 elements. This is a container of such elements, it is NOT a Composite Numerical
45 Type itself.
46 
47 <h2>Implementation</h2>
48 MatrixBase<ELT> uses MatrixHelper<S> for implementation, where S
49 is ELT::Scalar, that is, the underlying float, double,
50 complex<float>, negator<conjugate<double>>,
51 etc. from which ELT is constructed. This is a finite set of which all
52 members are explicitly instantiated in the implementation code, so
53 clients don't have to know how anything is implemented.
54 
55 MatrixBase is the only class in the Matrix/Vector family which has any
56 data members (it has exactly one MatrixHelper, which itself consists only
57 of a single pointer to an opaque class). Thus all other objects
58 in this family (that is, derived from MatrixBase) are exactly the same
59 size in memory and may be "reinterpreted" as appropriate. For example,
60 a Vector may be reinterpreted as a Matrix or vice versa, provided runtime
61 requirements are met (e.g., exactly 1 column).
62 
63 Unlike the small matrix classes, very little is encoded in the type.
64 Only the element type, and matrix vs. vector vs. row are in the type;
65 everything else like shape, storage layout, and writability are handled
66 at run time. **/
67 //  ----------------------------------------------------------------------------
68 template <class ELT> class MatrixBase {
69 public:
70     // These typedefs are handy, but despite appearances you cannot
71     // treat a MatrixBase as a composite numerical type. That is,
72     // CNT<MatrixBase> will not compile, or if it does it won't be
73     // meaningful.
74 
75     typedef ELT                                 E;
76     typedef typename CNT<E>::TNeg               ENeg;
77     typedef typename CNT<E>::TWithoutNegator    EWithoutNegator;
78     typedef typename CNT<E>::TReal              EReal;
79     typedef typename CNT<E>::TImag              EImag;
80     typedef typename CNT<E>::TComplex           EComplex;
81     typedef typename CNT<E>::THerm              EHerm;
82     typedef typename CNT<E>::TPosTrans          EPosTrans;
83 
84     typedef typename CNT<E>::TAbs               EAbs;
85     typedef typename CNT<E>::TStandard          EStandard;
86     typedef typename CNT<E>::TInvert            EInvert;
87     typedef typename CNT<E>::TNormalize         ENormalize;
88     typedef typename CNT<E>::TSqHermT           ESqHermT;
89     typedef typename CNT<E>::TSqTHerm           ESqTHerm;
90 
91     typedef typename CNT<E>::Scalar             EScalar;
92     typedef typename CNT<E>::Number             ENumber;
93     typedef typename CNT<E>::StdNumber          EStdNumber;
94     typedef typename CNT<E>::Precision          EPrecision;
95     typedef typename CNT<E>::ScalarNormSq       EScalarNormSq;
96 
97     typedef EScalar    Scalar;        // the underlying Scalar type
98     typedef ENumber    Number;        // negator removed from Scalar
99     typedef EStdNumber StdNumber;     // conjugate goes to complex
100     typedef EPrecision Precision;     // complex removed from StdNumber
101     typedef EScalarNormSq  ScalarNormSq;      // type of scalar^2
102 
103     typedef MatrixBase<ENeg>             TNeg;
104     typedef MatrixBase<EWithoutNegator>  TWithoutNegator;
105     typedef MatrixBase<EReal>            TReal;
106     typedef MatrixBase<EImag>            TImag;
107     typedef MatrixBase<EComplex>         TComplex;
108     typedef MatrixBase<EHerm>            THerm;
109     typedef MatrixBase<E>                TPosTrans;
110 
111     typedef MatrixBase<EAbs>             TAbs;
112     typedef MatrixBase<EStandard>        TStandard;
113     typedef MatrixBase<EInvert>          TInvert;
114     typedef MatrixBase<ENormalize>       TNormalize;
115     typedef MatrixBase<ESqHermT>         TSqHermT;  // ~Mat*Mat
116     typedef MatrixBase<ESqTHerm>         TSqTHerm;  // Mat*~Mat
117 
getCharacterCommitment()118     const MatrixCommitment& getCharacterCommitment() const {return helper.getCharacterCommitment();}
getMatrixCharacter()119     const MatrixCharacter& getMatrixCharacter()     const {return helper.getMatrixCharacter();}
120 
121     /// Change the handle commitment for this matrix handle; only allowed if the
122     /// handle is currently clear.
commitTo(const MatrixCommitment & mc)123     void commitTo(const MatrixCommitment& mc)
124     {   helper.commitTo(mc); }
125 
126     // This gives the resulting matrix type when (m(i,j) op P) is applied to each element.
127     // It will have element types which are the regular composite result of E op P.
128     template <class P> struct EltResult {
129         typedef MatrixBase<typename CNT<E>::template Result<P>::Mul> Mul;
130         typedef MatrixBase<typename CNT<E>::template Result<P>::Dvd> Dvd;
131         typedef MatrixBase<typename CNT<E>::template Result<P>::Add> Add;
132         typedef MatrixBase<typename CNT<E>::template Result<P>::Sub> Sub;
133     };
134 
135     /// Return the number of rows m in the logical shape of this matrix.
nrow()136     int  nrow() const {return helper.nrow();}
137     /// Return the number of columns n in the logical shape of this matrix.
ncol()138     int  ncol() const {return helper.ncol();}
139 
140     /// Return the number of elements in the \e logical shape of this matrix.
141     /// This has nothing to do with how many elements are actually stored;
142     /// it is simply the product of the logical number of rows and columns,
143     /// that is, nrow()*ncol(). Note that although each dimension is limited
144     /// to a 32 bit size, the product of those dimensions may be > 32 bits
145     /// on a 64 bit machine so the return type may be larger than that of
146     /// nrow() and ncol().
nelt()147     ptrdiff_t nelt() const {return helper.nelt();}
148 
149     /// Return true if either dimension of this Matrix is resizable.
isResizeable()150     bool isResizeable() const {return getCharacterCommitment().isResizeable();}
151 
152     enum {
153         NScalarsPerElement    = CNT<E>::NActualScalars,
154         CppNScalarsPerElement = sizeof(E) / sizeof(Scalar)
155     };
156 
157     /// The default constructor builds a 0x0 matrix managed by a helper that
158     /// understands how many scalars there are in one of our elements but is
159     /// otherwise uncommitted.
MatrixBase()160     MatrixBase() : helper(NScalarsPerElement,CppNScalarsPerElement) {}
161 
162     /// This constructor allocates the default matrix a completely uncommitted
163     /// matrix commitment, given particular initial dimensions.
MatrixBase(int m,int n)164     MatrixBase(int m, int n)
165     :   helper(NScalarsPerElement,CppNScalarsPerElement,MatrixCommitment(),m,n) {}
166 
167     /// This constructor takes a handle commitment and allocates the default
168     /// matrix for that kind of commitment. If a dimension is set to a
169     /// particular (unchangeable) value in the commitment then the initial
170     /// allocation will use that value. Unlocked dimensions are given the
171     /// smallest value consistent with other committed attributes, typically 0.
MatrixBase(const MatrixCommitment & commitment)172     explicit MatrixBase(const MatrixCommitment& commitment)
173     :   helper(NScalarsPerElement,CppNScalarsPerElement,commitment) {}
174 
175 
176     /// This constructor takes a handle commitment and allocates the default
177     /// matrix for that kind of commitment given particular initial minimum
178     /// dimensions, which cannot be larger than those permitted by the
179     /// commitment.
MatrixBase(const MatrixCommitment & commitment,int m,int n)180     MatrixBase(const MatrixCommitment& commitment, int m, int n)
181     :   helper(NScalarsPerElement,CppNScalarsPerElement,commitment,m,n) {}
182 
183     /// Copy constructor is a deep copy (not appropriate for views!).
MatrixBase(const MatrixBase & b)184     MatrixBase(const MatrixBase& b)
185       : helper(b.helper.getCharacterCommitment(),
186                b.helper, typename MatrixHelper<Scalar>::DeepCopy()) { }
187 
188     /// Implicit conversion from matrix with negated elements (otherwise this
189     /// is just like the copy constructor.
MatrixBase(const TNeg & b)190     MatrixBase(const TNeg& b)
191       : helper(b.helper.getCharacterCommitment(),
192                b.helper, typename MatrixHelper<Scalar>::DeepCopy()) { }
193 
194     /// Copy assignment is a deep copy but behavior depends on type of lhs: if
195     /// view, rhs must match. If owner, we reallocate and copy rhs.
copyAssign(const MatrixBase & b)196     MatrixBase& copyAssign(const MatrixBase& b) {
197         helper.copyAssign(b.helper);
198         return *this;
199     }
200     MatrixBase& operator=(const MatrixBase& b) { return copyAssign(b); }
201 
202 
203     /// View assignment is a shallow copy, meaning that we disconnect the MatrixBase
204     /// from whatever it used to refer to (destructing as necessary), then make it a new view
205     /// for the data descriptor referenced by the source.
206     /// CAUTION: we always take the source as const, but that is ignored in
207     /// determining whether the resulting view is writable. Instead, that is
208     /// inherited from the writability status of the source. We have to do this
209     /// in order to allow temporary view objects to be writable -- the compiler
210     /// creates temporaries like m(i,j,m,n) as const.
viewAssign(const MatrixBase & src)211     MatrixBase& viewAssign(const MatrixBase& src) {
212         helper.writableViewAssign(const_cast<MatrixHelper<Scalar>&>(src.helper));
213         return *this;
214     }
215 
216     // default destructor
217 
218     /// Initializing constructor with all of the initially-allocated elements
219     /// initialized to the same value. The given dimensions are treated as
220     /// minimum dimensions in case the commitment requires more. So it is
221     /// always permissible to set them both to 0 in which case you'll get
222     /// the smallest matrix that satisfies the commitment, with each of its
223     /// elements (if any) set to the given initial value.
MatrixBase(const MatrixCommitment & commitment,int m,int n,const ELT & initialValue)224     MatrixBase(const MatrixCommitment& commitment, int m, int n, const ELT& initialValue)
225     :   helper(NScalarsPerElement, CppNScalarsPerElement, commitment, m, n)
226     {   helper.fillWith(reinterpret_cast<const Scalar*>(&initialValue)); }
227 
228     /// Initializing constructor with the initially-allocated elements
229     /// initialized from a C++ array of elements, which is provided in
230     /// <i>row major</i> order. The given dimensions are treated as
231     /// minimum dimensions in case the commitment requires more. The
232     /// array is presumed to be long enough to supply a value for each
233     /// element. Note that C++ packing for elements may be different than
234     /// Simmatrix packing of the same elements (Simmatrix packs them
235     /// more tightly in some cases). So you should not use this constructor
236     /// to copy elements from one Simmatrix matrix to another; this is
237     /// exclusively for initializing a Simmatrix from a C++ array.
MatrixBase(const MatrixCommitment & commitment,int m,int n,const ELT * cppInitialValuesByRow)238     MatrixBase(const MatrixCommitment& commitment, int m, int n,
239                const ELT* cppInitialValuesByRow)
240     :   helper(NScalarsPerElement, CppNScalarsPerElement, commitment, m, n)
241     {   helper.copyInByRowsFromCpp(reinterpret_cast<const Scalar*>(cppInitialValuesByRow)); }
242 
243     /// @name           Matrix view of pre-exising data
244     ///
245     /// Non-resizeable view of someone else's already-allocated
246     /// memory of a size and storage type indicated by the supplied
247     /// MatrixCharacter. The \a spacing argument has different interpretations
248     /// depending on the storage format. Typically it is the leading
249     /// dimension for Lapack-style full storage or stride for a vector.
250     /// Spacing is in units like "number of scalars between elements" or
251     /// "number of scalars between columns" so it can be used to deal
252     /// with C++ packing vs. Simmatrix packing if necessary.
253     /// @{
254 
255     /// Construct a read-only view of pre-existing data.
MatrixBase(const MatrixCommitment & commitment,const MatrixCharacter & character,int spacing,const Scalar * data)256     MatrixBase(const MatrixCommitment& commitment,
257                const MatrixCharacter&  character,
258                int spacing, const Scalar* data) // read only data
259     :   helper(NScalarsPerElement, CppNScalarsPerElement,
260                commitment, character, spacing, data) {}
261 
262     /// Construct a writable view of pre-existing data.
MatrixBase(const MatrixCommitment & commitment,const MatrixCharacter & character,int spacing,Scalar * data)263     MatrixBase(const MatrixCommitment& commitment,
264                const MatrixCharacter&  character,
265                int spacing, Scalar* data) // writable data
266     :   helper(NScalarsPerElement, CppNScalarsPerElement,
267                commitment, character, spacing, data) {}
268     /// @}
269 
270     // Create a new MatrixBase from an existing helper. Both shallow and deep copies are possible.
MatrixBase(const MatrixCommitment & commitment,MatrixHelper<Scalar> & source,const typename MatrixHelper<Scalar>::ShallowCopy & shallow)271     MatrixBase(const MatrixCommitment& commitment,
272                MatrixHelper<Scalar>&   source,
273                const typename MatrixHelper<Scalar>::ShallowCopy& shallow)
274     :   helper(commitment, source, shallow) {}
MatrixBase(const MatrixCommitment & commitment,const MatrixHelper<Scalar> & source,const typename MatrixHelper<Scalar>::ShallowCopy & shallow)275     MatrixBase(const MatrixCommitment&      commitment,
276                const MatrixHelper<Scalar>&  source,
277                const typename MatrixHelper<Scalar>::ShallowCopy& shallow)
278     :   helper(commitment, source, shallow) {}
MatrixBase(const MatrixCommitment & commitment,const MatrixHelper<Scalar> & source,const typename MatrixHelper<Scalar>::DeepCopy & deep)279     MatrixBase(const MatrixCommitment&      commitment,
280                const MatrixHelper<Scalar>&  source,
281                const typename MatrixHelper<Scalar>::DeepCopy& deep)
282     :   helper(commitment, source, deep) {}
283 
284     /// This restores the MatrixBase to the state it would be in had it
285     /// been constructed specifying only its handle commitment. The size will
286     /// have been reduced to the smallest size consistent with the commitment.
clear()287     void clear() {helper.clear();}
288 
289     MatrixBase& operator*=(const StdNumber& t)  { helper.scaleBy(t);              return *this; }
290     MatrixBase& operator/=(const StdNumber& t)  { helper.scaleBy(StdNumber(1)/t); return *this; }
291     MatrixBase& operator+=(const MatrixBase& r) { helper.addIn(r.helper);         return *this; }
292     MatrixBase& operator-=(const MatrixBase& r) { helper.subIn(r.helper);         return *this; }
293 
MatrixBase(const MatrixBase<EE> & b)294     template <class EE> MatrixBase(const MatrixBase<EE>& b)
295       : helper(MatrixCommitment(),b.helper, typename MatrixHelper<Scalar>::DeepCopy()) { }
296 
297     template <class EE> MatrixBase& operator=(const MatrixBase<EE>& b)
298       { helper = b.helper; return *this; }
299     template <class EE> MatrixBase& operator+=(const MatrixBase<EE>& b)
300       { helper.addIn(b.helper); return *this; }
301     template <class EE> MatrixBase& operator-=(const MatrixBase<EE>& b)
302       { helper.subIn(b.helper); return *this; }
303 
304     /// Matrix assignment to an element sets only the *diagonal* elements to
305     /// the indicated value; everything else is set to zero. This is particularly
306     /// useful for setting a Matrix to zero or to the identity; for other values
307     /// it creates a Matrix which acts like the scalar. That is, if the scalar
308     /// is s and we do M=s, then multiplying another Matrix B by the resulting
309     /// diagonal matrix M gives the same result as multiplying B by s. That is
310     /// (M=s)*B == s*B.
311     ///
312     /// NOTE: this must be overridden for Vector and RowVector since then scalar
313     /// assignment is defined to copy the scalar to every element.
314     MatrixBase& operator=(const ELT& t) {
315         setToZero(); updDiag().setTo(t);
316         return *this;
317     }
318 
319     /// Set M's diagonal elements to a "scalar" value S, and all off-diagonal
320     /// elements to zero. S can be any type which is assignable to an element
321     /// of type E. This is the same as the Matrix assignment operator M=S for
322     /// a scalar type S. It is overriden for Vector and Row types to behave
323     /// as elementwiseScalarAssign.
324     template <class S> inline MatrixBase&
scalarAssign(const S & s)325     scalarAssign(const S& s) {
326         setToZero(); updDiag().setTo(s);
327         return *this;
328     }
329 
330     /// Add a scalar to M's diagonal. This is the same as the Matrix +=
331     /// operator. This is overridden for Vector and Row types to behave
332     /// as elementwiseAddScalarInPlace.
333     template <class S> inline MatrixBase&
scalarAddInPlace(const S & s)334     scalarAddInPlace(const S& s) {
335         updDiag().elementwiseAddScalarInPlace(s);
336     }
337 
338 
339     /// Subtract a scalar from M's diagonal. This is the same as the Matrix -=
340     /// operator. This is overridden for Vector and Row types to behave
341     /// as elementwiseSubtractScalarInPlace.
342     template <class S> inline MatrixBase&
scalarSubtractInPlace(const S & s)343     scalarSubtractInPlace(const S& s) {
344         updDiag().elementwiseSubtractScalarInPlace(s);
345     }
346 
347     /// Set M(i,i) = S - M(i,i), M(i,j) = -M(i,j) for i!=j. This is overridden
348     /// for Vector and Row types to behave as elementwiseSubtractFromScalarInPlace.
349     template <class S> inline MatrixBase&
scalarSubtractFromLeftInPlace(const S & s)350     scalarSubtractFromLeftInPlace(const S& s) {
351         negateInPlace();
352         updDiag().elementwiseAddScalarInPlace(s); // yes, add
353     }
354 
355     /// Set M(i,j) = M(i,j)*S for some "scalar" S. Actually S can be any
356     /// type for which E = E*S makes sense. That is, S must be conformant
357     /// with E and it must be possible to store the result back in an E.
358     /// This is the *= operator for M *= S and behaves the same way for
359     /// Matrix, Vector, and RowVector: every element gets multiplied in
360     /// place on the right by S.
361     template <class S> inline MatrixBase&
362     scalarMultiplyInPlace(const S&);
363 
364     /// Set M(i,j) = S * M(i,j) for some "scalar" S. This is the same
365     /// as the above routine if S really is a scalar, but for S a more
366     /// complicated CNT it will be different.
367     template <class S> inline MatrixBase&
368     scalarMultiplyFromLeftInPlace(const S&);
369 
370     /// Set M(i,j) = M(i,j)/S for some "scalar" S. Actually S can be any
371     /// type for which E = E/S makes sense. That is, S^-1 must be conformant
372     /// with E and it must be possible to store the result back in an E.
373     /// This is the /= operator for M /= S and behaves the same way for
374     /// Matrix, Vector, and RowVector: every element gets divided in
375     /// place on the right by S.
376     template <class S> inline MatrixBase&
377     scalarDivideInPlace(const S&);
378 
379     /// Set M(i,j) = S/M(i,j) for some "scalar" S. Actually S can be any
380     /// type for which E = S/E makes sense. That is, S must be conformant
381     /// with E^-1 and it must be possible to store the result back in an E.
382     template <class S> inline MatrixBase&
383     scalarDivideFromLeftInPlace(const S&);
384 
385 
386     /// M = diag(r) * M; r must have nrow() elements.
387     /// That is, M[i] *= r[i].
388     template <class EE> inline MatrixBase&
389     rowScaleInPlace(const VectorBase<EE>&);
390 
391     /// Return type is a new matrix which will have the same dimensions as 'this' but
392     /// will have element types appropriate for the elementwise multiply being performed.
393     template <class EE> inline void
394     rowScale(const VectorBase<EE>& r, typename EltResult<EE>::Mul& out) const;
395 
396     template <class EE> inline typename EltResult<EE>::Mul
rowScale(const VectorBase<EE> & r)397     rowScale(const VectorBase<EE>& r) const {
398         typename EltResult<EE>::Mul out(nrow(), ncol()); rowScale(r,out); return out;
399     }
400 
401     /// M = M * diag(c); c must have ncol() elements.
402     /// That is, M(j) *= c[j].
403     template <class EE> inline MatrixBase&
404     colScaleInPlace(const VectorBase<EE>&);
405 
406     template <class EE> inline void
407     colScale(const VectorBase<EE>& c, typename EltResult<EE>::Mul& out) const;
408 
409     template <class EE> inline typename EltResult<EE>::Mul
colScale(const VectorBase<EE> & c)410     colScale(const VectorBase<EE>& c) const {
411         typename EltResult<EE>::Mul out(nrow(), ncol()); colScale(c,out); return out;
412     }
413 
414 
415     /// M = diag(r) * M * diag(c); r must have nrow() elements;  must have ncol() elements.
416     /// That is, M(i,j) *= r[i]*c[j].
417     /// Having a combined row & column scaling operator means we can go through the matrix
418     /// memory once instead of twice.
419     template <class ER, class EC> inline MatrixBase&
420     rowAndColScaleInPlace(const VectorBase<ER>& r, const VectorBase<EC>& c);
421 
422     template <class ER, class EC> inline void
423     rowAndColScale(const VectorBase<ER>& r, const VectorBase<EC>& c,
424                    typename EltResult<typename VectorBase<ER>::template EltResult<EC>::Mul>::Mul& out) const;
425 
426     template <class ER, class EC> inline typename EltResult<typename VectorBase<ER>::template EltResult<EC>::Mul>::Mul
rowAndColScale(const VectorBase<ER> & r,const VectorBase<EC> & c)427     rowAndColScale(const VectorBase<ER>& r, const VectorBase<EC>& c) const {
428         typename EltResult<typename VectorBase<ER>::template EltResult<EC>::Mul>::Mul
429             out(nrow(), ncol());
430         rowAndColScale(r,c,out); return out;
431     }
432 
433     /// Set M(i,j)=s for every element of M and some value s. This requires only
434     /// that s be assignment compatible with M's elements; s doesn't
435     /// actually have to be a scalar. Note that for Matrix types this behavior
436     /// is different than scalar assignment, which puts the scalar only on M's
437     /// diagonal and sets the rest of M to zero. For Vector and RowVector types,
438     /// this operator is identical to the normal assignment operator and
439     /// scalarAssignInPlace() method which also assign the scalar to every element.
440     template <class S> inline MatrixBase&
441     elementwiseAssign(const S& s);
442 
443     /// Overloaded to allow an integer argument, which is converted to Real.
elementwiseAssign(int s)444     MatrixBase& elementwiseAssign(int s)
445     {   return elementwiseAssign<Real>(Real(s)); }
446 
447     /// Set M(i,j) = M(i,j)^-1.
448     MatrixBase& elementwiseInvertInPlace();
449 
450     void elementwiseInvert(MatrixBase<typename CNT<E>::TInvert>& out) const;
451 
elementwiseInvert()452     MatrixBase<typename CNT<E>::TInvert> elementwiseInvert() const {
453         MatrixBase<typename CNT<E>::TInvert> out(nrow(), ncol());
454         elementwiseInvert(out);
455         return out;
456     }
457 
458     /// Set M(i,j)+=s for every element of M and some value s. This requires that s be
459     /// conformant with M's elements (of type E) and that the result can
460     /// be stored in an E. For Matrix types this behavior is different than
461     /// the normal += or scalarAddInPlace() operators, which add the scalar
462     /// only to the Matrix diagonal. For Vector and RowVector, this operator
463     /// is identical to += and scalarAddInPlace() which also add the scalar
464     /// to every element.
465     template <class S> inline MatrixBase&
466     elementwiseAddScalarInPlace(const S& s);
467 
468     template <class S> inline void
469     elementwiseAddScalar(const S& s, typename EltResult<S>::Add&) const;
470 
471     template <class S> inline typename EltResult<S>::Add
elementwiseAddScalar(const S & s)472     elementwiseAddScalar(const S& s) const {
473         typename EltResult<S>::Add out(nrow(), ncol());
474         elementwiseAddScalar(s,out);
475         return out;
476     }
477 
478     /// Set M(i,j)-=s for every element of M and some value s. This requires that s be
479     /// conformant with M's elements (of type E) and that the result can
480     /// be stored in an E. For Matrix types this behavior is different than
481     /// the normal -= or scalarSubtractInPlace() operators, which subtract the scalar
482     /// only from the Matrix diagonal. For Vector and RowVector, this operator
483     /// is identical to -= and scalarSubtractInPlace() which also subtract the scalar
484     /// from every element.
485     template <class S> inline MatrixBase&
486     elementwiseSubtractScalarInPlace(const S& s);
487 
488     template <class S> inline void
489     elementwiseSubtractScalar(const S& s, typename EltResult<S>::Sub&) const;
490 
491     template <class S> inline typename EltResult<S>::Sub
elementwiseSubtractScalar(const S & s)492     elementwiseSubtractScalar(const S& s) const {
493         typename EltResult<S>::Sub out(nrow(), ncol());
494         elementwiseSubtractScalar(s,out);
495         return out;
496     }
497 
498     /// Set M(i,j) = s - M(i,j) for every element of M and some value s. This requires that s be
499     /// conformant with M's elements (of type E) and that the result can
500     /// be stored in an E. For Matrix types this behavior is different than
501     /// the scalarSubtractFromLeftInPlace() operator, which subtracts only the diagonal
502     /// elements of M from s, while simply negating the off diagonal elements.
503     /// For Vector and RowVector, this operator
504     /// is identical to scalarSubtractFromLeftInPlace() which also subtracts every
505     /// element of M from the scalar.
506     template <class S> inline MatrixBase&
507     elementwiseSubtractFromScalarInPlace(const S& s);
508 
509     template <class S> inline void
510     elementwiseSubtractFromScalar(
511         const S&,
512         typename MatrixBase<S>::template EltResult<E>::Sub&) const;
513 
514     template <class S> inline typename MatrixBase<S>::template EltResult<E>::Sub
elementwiseSubtractFromScalar(const S & s)515     elementwiseSubtractFromScalar(const S& s) const {
516         typename MatrixBase<S>::template EltResult<E>::Sub out(nrow(), ncol());
517         elementwiseSubtractFromScalar<S>(s,out);
518         return out;
519     }
520 
521     /// M(i,j) *= R(i,j); R must have same dimensions as this.
522     template <class EE> inline MatrixBase&
523     elementwiseMultiplyInPlace(const MatrixBase<EE>&);
524 
525     template <class EE> inline void
526     elementwiseMultiply(const MatrixBase<EE>&, typename EltResult<EE>::Mul&) const;
527 
528     template <class EE> inline typename EltResult<EE>::Mul
elementwiseMultiply(const MatrixBase<EE> & m)529     elementwiseMultiply(const MatrixBase<EE>& m) const {
530         typename EltResult<EE>::Mul out(nrow(), ncol());
531         elementwiseMultiply<EE>(m,out);
532         return out;
533     }
534 
535     /// M(i,j) = R(i,j) * M(i,j); R must have same dimensions as this.
536     template <class EE> inline MatrixBase&
537     elementwiseMultiplyFromLeftInPlace(const MatrixBase<EE>&);
538 
539     template <class EE> inline void
540     elementwiseMultiplyFromLeft(
541         const MatrixBase<EE>&,
542         typename MatrixBase<EE>::template EltResult<E>::Mul&) const;
543 
544     template <class EE> inline typename MatrixBase<EE>::template EltResult<E>::Mul
elementwiseMultiplyFromLeft(const MatrixBase<EE> & m)545     elementwiseMultiplyFromLeft(const MatrixBase<EE>& m) const {
546         typename EltResult<EE>::Mul out(nrow(), ncol());
547         elementwiseMultiplyFromLeft<EE>(m,out);
548         return out;
549     }
550 
551     /// M(i,j) /= R(i,j); R must have same dimensions as this.
552     template <class EE> inline MatrixBase&
553     elementwiseDivideInPlace(const MatrixBase<EE>&);
554 
555     template <class EE> inline void
556     elementwiseDivide(const MatrixBase<EE>&, typename EltResult<EE>::Dvd&) const;
557 
558     template <class EE> inline typename EltResult<EE>::Dvd
elementwiseDivide(const MatrixBase<EE> & m)559     elementwiseDivide(const MatrixBase<EE>& m) const {
560         typename EltResult<EE>::Dvd out(nrow(), ncol());
561         elementwiseDivide<EE>(m,out);
562         return out;
563     }
564 
565     /// M(i,j) = R(i,j) / M(i,j); R must have same dimensions as this.
566     template <class EE> inline MatrixBase&
567     elementwiseDivideFromLeftInPlace(const MatrixBase<EE>&);
568 
569     template <class EE> inline void
570     elementwiseDivideFromLeft(
571         const MatrixBase<EE>&,
572         typename MatrixBase<EE>::template EltResult<E>::Dvd&) const;
573 
574     template <class EE> inline typename MatrixBase<EE>::template EltResult<EE>::Dvd
elementwiseDivideFromLeft(const MatrixBase<EE> & m)575     elementwiseDivideFromLeft(const MatrixBase<EE>& m) const {
576         typename MatrixBase<EE>::template EltResult<E>::Dvd out(nrow(), ncol());
577         elementwiseDivideFromLeft<EE>(m,out);
578         return out;
579     }
580 
581     /// Fill every element in current allocation with given element (or NaN or 0).
setTo(const ELT & t)582     MatrixBase& setTo(const ELT& t) {helper.fillWith(reinterpret_cast<const Scalar*>(&t)); return *this;}
setToNaN()583     MatrixBase& setToNaN() {helper.fillWithScalar(CNT<StdNumber>::getNaN()); return *this;}
setToZero()584     MatrixBase& setToZero() {helper.fillWithScalar(StdNumber(0)); return *this;}
585 
586     // View creating operators.
587     inline RowVectorView_<ELT> row(int i) const;   // select a row
588     inline RowVectorView_<ELT> updRow(int i);
589     inline VectorView_<ELT>    col(int j) const;   // select a column
590     inline VectorView_<ELT>    updCol(int j);
591 
592     RowVectorView_<ELT> operator[](int i) const {return row(i);}
593     RowVectorView_<ELT> operator[](int i)       {return updRow(i);}
operator()594     VectorView_<ELT>    operator()(int j) const {return col(j);}
operator()595     VectorView_<ELT>    operator()(int j)       {return updCol(j);}
596 
597     // Select a block.
598     inline MatrixView_<ELT> block(int i, int j, int m, int n) const;
599     inline MatrixView_<ELT> updBlock(int i, int j, int m, int n);
600 
operator()601     MatrixView_<ELT> operator()(int i, int j, int m, int n) const
602       { return block(i,j,m,n); }
operator()603     MatrixView_<ELT> operator()(int i, int j, int m, int n)
604       { return updBlock(i,j,m,n); }
605 
606     // Hermitian transpose.
607     inline MatrixView_<EHerm> transpose() const;
608     inline MatrixView_<EHerm> updTranspose();
609 
610     MatrixView_<EHerm> operator~() const {return transpose();}
611     MatrixView_<EHerm> operator~()       {return updTranspose();}
612 
613     /// Select main diagonal (of largest leading square if rectangular) and
614     /// return it as a read-only view of the diagonal elements of this Matrix.
615     inline VectorView_<ELT> diag() const;
616     /// Select main diagonal (of largest leading square if rectangular) and
617     /// return it as a writable view of the diagonal elements of this Matrix.
618     inline VectorView_<ELT> updDiag();
619     /// This non-const version of diag() is an alternate name for updDiag()
620     /// available for historical reasons.
diag()621     VectorView_<ELT> diag() {return updDiag();}
622 
623     // Create a view of the real or imaginary elements. TODO
624     //inline MatrixView_<EReal> real() const;
625     //inline MatrixView_<EReal> updReal();
626     //inline MatrixView_<EImag> imag() const;
627     //inline MatrixView_<EImag> updImag();
628 
629     // Overload "real" and "imag" for both read and write as a nod to convention. TODO
630     //MatrixView_<EReal> real() {return updReal();}
631     //MatrixView_<EReal> imag() {return updImag();}
632 
633     // TODO: this routine seems ill-advised but I need it for the IVM port at the moment
invert()634     TInvert invert() const {  // return a newly-allocated inverse; dump negator
635         TInvert m(*this);
636         m.helper.invertInPlace();
637         return m;   // TODO - bad: makes an extra copy
638     }
639 
invertInPlace()640     void invertInPlace() {helper.invertInPlace();}
641 
642     /// Matlab-compatible debug output.
643     void dump(const char* msg=0) const {
644         helper.dump(msg);
645     }
646 
647     /// Element selection for stored elements. These are the fastest element access
648     /// methods but may not be able to access all elements of the logical matrix when
649     /// some of its elements are not stored in memory. For example, a Hermitian matrix
650     /// stores only half its elements and other ones have to be calculated by conjugation
651     /// if they are to be returned as type ELT. (You can get them for free by recasting
652     /// the matrix so that the elements are reinterpreted as conjugates.) If you want
653     /// to guarantee that you can access the value of every element of a matrix, stored or not,
654     /// use getAnyElt() instead.
getElt(int i,int j)655     const ELT& getElt(int i, int j) const { return *reinterpret_cast<const ELT*>(helper.getElt(i,j)); }
updElt(int i,int j)656     ELT&       updElt(int i, int j)       { return *reinterpret_cast<      ELT*>(helper.updElt(i,j)); }
657 
operator()658     const ELT& operator()(int i, int j) const {return getElt(i,j);}
operator()659     ELT&       operator()(int i, int j)       {return updElt(i,j);}
660 
661     /// This returns a copy of the element value for any position in the logical matrix,
662     /// regardless of whether it is stored in memory. If necessary the element's value
663     /// is calculated. This is much slower than getElt() but less restrictive.
664     /// @see getElt()
getAnyElt(int i,int j,ELT & value)665     void getAnyElt(int i, int j, ELT& value) const
666     {   helper.getAnyElt(i,j,reinterpret_cast<Scalar*>(&value)); }
getAnyElt(int i,int j)667     ELT getAnyElt(int i, int j) const {ELT e; getAnyElt(i,j,e); return e;}
668 
669     /// Scalar norm square is sum( squares of all scalars ). Note that this
670     /// is not very useful unless the elements are themselves scalars.
671     // TODO: very slow! Should be optimized at least for the case
672     //       where ELT is a Scalar.
scalarNormSqr()673     ScalarNormSq scalarNormSqr() const {
674         const int nr=nrow(), nc=ncol();
675         ScalarNormSq sum(0);
676         for(int j=0;j<nc;++j)
677             for (int i=0; i<nr; ++i)
678                 sum += CNT<E>::scalarNormSqr((*this)(i,j));
679         return sum;
680     }
681 
682     /// abs() is elementwise absolute value; that is, the return value has the same
683     /// dimension as this Matrix but with each element replaced by whatever it thinks
684     /// its absolute value is.
685     // TODO: very slow! Should be optimized at least for the case
686     //       where ELT is a Scalar.
abs(TAbs & mabs)687     void abs(TAbs& mabs) const {
688         const int nr=nrow(), nc=ncol();
689         mabs.resize(nr,nc);
690         for(int j=0;j<nc;++j)
691             for (int i=0; i<nr; ++i)
692                 mabs(i,j) = CNT<E>::abs((*this)(i,j));
693     }
694 
695     /// abs() with the result as a function return. More convenient than the
696     /// other abs() member function, but may involve an additional copy of the
697     /// matrix.
abs()698     TAbs abs() const { TAbs mabs; abs(mabs); return mabs; }
699 
700     /// Return a Matrix of the same shape and contents as this one but
701     /// with the element type converted to one based on the standard
702     /// C++ scalar types: float, double, complex<float>,
703     /// complex<double>. That is, negator<>
704     /// and conjugate<> are eliminated from the element type by
705     /// performing any needed negations computationally.
706     /// Note that this is actually producing a new matrix with new data;
707     /// you can also do this for free by reinterpreting the current
708     /// matrix as a different type, if you don't mind looking at
709     /// shared data.
standardize()710     TStandard standardize() const {
711         const int nr=nrow(), nc=ncol();
712         TStandard mstd(nr, nc);
713         for(int j=0;j<nc;++j)
714             for (int i=0; i<nr; ++i)
715                 mstd(i,j) = CNT<E>::standardize((*this)(i,j));
716         return mstd;
717     }
718 
719     /// This is the scalar Frobenius norm, and its square. Note: if this is a
720     /// Matrix then the Frobenius norm is NOT the same as the 2-norm, although
721     /// they are equivalent for Vectors.
normSqr()722     ScalarNormSq normSqr() const { return scalarNormSqr(); }
723     // TODO -- not good; unnecessary overflow
724     typename CNT<ScalarNormSq>::TSqrt
norm()725         norm() const { return CNT<ScalarNormSq>::sqrt(scalarNormSqr()); }
726 
727     /// We only allow RMS norm if the elements are scalars. If there are no
728     /// elements in this Matrix, we'll define its RMS norm to be 0, although
729     /// NaN might be a better choice.
730     typename CNT<ScalarNormSq>::TSqrt
normRMS()731     normRMS() const {
732         if (!CNT<ELT>::IsScalar)
733             SimTK_THROW1(Exception::Cant, "normRMS() only defined for scalar elements");
734         if (nelt() == 0)
735             return typename CNT<ScalarNormSq>::TSqrt(0);
736         return CNT<ScalarNormSq>::sqrt(scalarNormSqr()/nelt());
737     }
738 
739     /// Form the column sums of this matrix, returned as a RowVector.
colSum()740     RowVector_<ELT> colSum() const {
741         const int cols = ncol();
742         RowVector_<ELT> row(cols);
743         for (int j = 0; j < cols; ++j)
744             helper.colSum(j, reinterpret_cast<Scalar*>(&row[j]));
745         return row;
746     }
747     /// Alternate name for colSum(); behaves like the Matlab function sum().
sum()748     RowVector_<ELT> sum() const {return colSum();}
749 
750     /// Form the row sums of this matrix, returned as a Vector.
rowSum()751     Vector_<ELT> rowSum() const {
752         const int rows = nrow();
753         Vector_<ELT> col(rows);
754         for (int i = 0; i < rows; ++i)
755             helper.rowSum(i, reinterpret_cast<Scalar*>(&col[i]));
756         return col;
757     }
758 
759     //TODO: make unary +/- return a self-view so they won't reallocate?
760     const MatrixBase& operator+() const {return *this; }
negate()761     const TNeg&       negate()    const {return *reinterpret_cast<const TNeg*>(this); }
updNegate()762     TNeg&             updNegate()       {return *reinterpret_cast<TNeg*>(this); }
763 
764     const TNeg&       operator-() const {return negate();}
765     TNeg&             operator-()       {return updNegate();}
766 
negateInPlace()767     MatrixBase& negateInPlace() {(*this) *= EPrecision(-1); return *this;}
768 
769     /// Change the size of this matrix. This is only allowed for owner matrices. The
770     /// current storage format is retained, but all the data is lost. If you want
771     /// to keep the old data, use resizeKeep().
772     /// @see resizeKeep()
resize(int m,int n)773     MatrixBase& resize(int m, int n)     { helper.resize(m,n); return *this; }
774     /// Change the size of this matrix, retaining as much of the old data as will
775     /// fit. This is only allowed for owner matrices. The
776     /// current storage format is retained, and the existing data is copied
777     /// into the new memory to the extent that it will fit.
778     /// @see resize()
resizeKeep(int m,int n)779     MatrixBase& resizeKeep(int m, int n) { helper.resizeKeep(m,n); return *this; }
780 
781     // This prevents shape changes in a Matrix that would otherwise allow it. No harm if is
782     // are called on a Matrix that is locked already; it always succeeds.
lockShape()783     void lockShape() {helper.lockShape();}
784 
785     // This allows shape changes again for a Matrix which was constructed to allow them
786     // but had them locked with the above routine. No harm if this is called on a Matrix
787     // that is already unlocked, but it is not allowed to call this on a Matrix which
788     // *never* allowed resizing. An exception will be thrown in that case.
unlockShape()789     void unlockShape() {helper.unlockShape();}
790 
791     // An assortment of handy conversions
getAsMatrixView()792     const MatrixView_<ELT>& getAsMatrixView() const { return *reinterpret_cast<const MatrixView_<ELT>*>(this); }
updAsMatrixView()793     MatrixView_<ELT>&       updAsMatrixView()       { return *reinterpret_cast<      MatrixView_<ELT>*>(this); }
getAsMatrix()794     const Matrix_<ELT>&     getAsMatrix()     const { return *reinterpret_cast<const Matrix_<ELT>*>(this); }
updAsMatrix()795     Matrix_<ELT>&           updAsMatrix()           { return *reinterpret_cast<      Matrix_<ELT>*>(this); }
796 
getAsVectorView()797     const VectorView_<ELT>& getAsVectorView() const
798       { assert(ncol()==1); return *reinterpret_cast<const VectorView_<ELT>*>(this); }
updAsVectorView()799     VectorView_<ELT>&       updAsVectorView()
800       { assert(ncol()==1); return *reinterpret_cast<      VectorView_<ELT>*>(this); }
getAsVector()801     const Vector_<ELT>&     getAsVector()     const
802       { assert(ncol()==1); return *reinterpret_cast<const Vector_<ELT>*>(this); }
updAsVector()803     Vector_<ELT>&           updAsVector()
804       { assert(ncol()==1); return *reinterpret_cast<      Vector_<ELT>*>(this); }
getAsVectorBase()805     const VectorBase<ELT>& getAsVectorBase() const
806       { assert(ncol()==1); return *reinterpret_cast<const VectorBase<ELT>*>(this); }
updAsVectorBase()807     VectorBase<ELT>&       updAsVectorBase()
808       { assert(ncol()==1); return *reinterpret_cast<      VectorBase<ELT>*>(this); }
809 
getAsRowVectorView()810     const RowVectorView_<ELT>& getAsRowVectorView() const
811       { assert(nrow()==1); return *reinterpret_cast<const RowVectorView_<ELT>*>(this); }
updAsRowVectorView()812     RowVectorView_<ELT>&       updAsRowVectorView()
813       { assert(nrow()==1); return *reinterpret_cast<      RowVectorView_<ELT>*>(this); }
getAsRowVector()814     const RowVector_<ELT>&     getAsRowVector()     const
815       { assert(nrow()==1); return *reinterpret_cast<const RowVector_<ELT>*>(this); }
updAsRowVector()816     RowVector_<ELT>&           updAsRowVector()
817       { assert(nrow()==1); return *reinterpret_cast<      RowVector_<ELT>*>(this); }
getAsRowVectorBase()818     const RowVectorBase<ELT>& getAsRowVectorBase() const
819       { assert(nrow()==1); return *reinterpret_cast<const RowVectorBase<ELT>*>(this); }
updAsRowVectorBase()820     RowVectorBase<ELT>&       updAsRowVectorBase()
821       { assert(nrow()==1); return *reinterpret_cast<      RowVectorBase<ELT>*>(this); }
822 
823     // Access to raw data. We have to return the raw data
824     // pointer as pointer-to-scalar because we may pack the elements tighter
825     // than a C++ array would.
826 
827     /// This is the number of consecutive scalars used to represent one
828     /// element of type ELT. This may be fewer than C++ would use for the
829     /// element, since it may introduce some padding.
getNScalarsPerElement()830     int getNScalarsPerElement()  const {return NScalarsPerElement;}
831 
832     /// This is like sizeof(ELT), but returning the number of bytes \e we use
833     /// to store the element which may be fewer than what C++ would use. We store
834     /// these packed elements adjacent to one another in memory.
getPackedSizeofElement()835     int getPackedSizeofElement() const {return NScalarsPerElement*sizeof(Scalar);}
836 
hasContiguousData()837     bool hasContiguousData() const {return helper.hasContiguousData();}
getContiguousScalarDataLength()838     ptrdiff_t getContiguousScalarDataLength() const {
839         return helper.getContiguousDataLength();
840     }
getContiguousScalarData()841     const Scalar* getContiguousScalarData() const {
842         return helper.getContiguousData();
843     }
updContiguousScalarData()844     Scalar* updContiguousScalarData() {
845         return helper.updContiguousData();
846     }
replaceContiguousScalarData(Scalar * newData,ptrdiff_t length,bool takeOwnership)847     void replaceContiguousScalarData(Scalar* newData, ptrdiff_t length, bool takeOwnership) {
848         helper.replaceContiguousData(newData,length,takeOwnership);
849     }
replaceContiguousScalarData(const Scalar * newData,ptrdiff_t length)850     void replaceContiguousScalarData(const Scalar* newData, ptrdiff_t length) {
851         helper.replaceContiguousData(newData,length);
852     }
swapOwnedContiguousScalarData(Scalar * newData,ptrdiff_t length,Scalar * & oldData)853     void swapOwnedContiguousScalarData(Scalar* newData, ptrdiff_t length, Scalar*& oldData) {
854         helper.swapOwnedContiguousData(newData,length,oldData);
855     }
856 
857     /// Helper rep-stealing constructor. We take over ownership of this rep here. Note
858     /// that this \e defines the handle commitment for this handle. This is intended
859     /// for internal use only -- don't call this constructor unless you really
860     /// know what you're doing.
MatrixBase(MatrixHelperRep<Scalar> * hrep)861     explicit MatrixBase(MatrixHelperRep<Scalar>* hrep) : helper(hrep) {}
862 
863 protected:
getHelper()864     const MatrixHelper<Scalar>& getHelper() const {return helper;}
updHelper()865     MatrixHelper<Scalar>&       updHelper()       {return helper;}
866 
867 private:
868     MatrixHelper<Scalar> helper; // this is just one pointer
869 
870     template <class EE> friend class MatrixBase;
871 
872     // ============================= Unimplemented =============================
873     // This routine is useful for implementing friendlier Matrix expressions and operators.
874     // It maps closely to the Level-3 BLAS family of pxxmm() routines like sgemm(). The
875     // operation performed assumes that "this" is the result, and that "this" has
876     // already been sized correctly to receive the result. We'll compute
877     //     this = beta*this + alpha*A*B
878     // If beta is 0 then "this" can be uninitialized. If alpha is 0 we promise not
879     // to look at A or B. The routine can work efficiently even if A and/or B are transposed
880     // by their views, so an expression like
881     //        C += s * ~A * ~B
882     // can be performed with the single equivalent call
883     //        C.matmul(1., s, Tr(A), Tr(B))
884     // where Tr(A) indicates a transposed view of the original A.
885     // The ultimate efficiency of this call depends on the data layout and views which
886     // are used for the three matrices.
887     // NOTE: neither A nor B can be the same matrix as 'this', nor views of the same data
888     // which would expose elements of 'this' that will be modified by this operation.
889     template <class ELT_A, class ELT_B>
matmul(const StdNumber & beta,const StdNumber & alpha,const MatrixBase<ELT_A> & A,const MatrixBase<ELT_B> & B)890     MatrixBase& matmul(const StdNumber& beta,   // applied to 'this'
891                        const StdNumber& alpha, const MatrixBase<ELT_A>& A, const MatrixBase<ELT_B>& B)
892     {
893         helper.matmul(beta,alpha,A.helper,B.helper);
894         return *this;
895     }
896 
897 };
898 
899 } //namespace SimTK
900 
901 #endif // SimTK_SIMMATRIX_MATRIXBASE_H_
902