1 #ifndef SimTK_SimTKCOMMON_MATRIX_HELPER_REP_FULL_H_
2 #define SimTK_SimTKCOMMON_MATRIX_HELPER_REP_FULL_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) 2008-12 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 #include "SimTKcommon/Scalar.h"
28 #include "SimTKcommon/SmallMatrix.h"
29 
30 #include "MatrixHelperRep.h"
31 
32 #include <cstddef>
33 #include <cstring>
34 
35 namespace SimTK {
36 
37 
38 //------------------------------- FullHelper -----------------------------------
39 //
40 // This abstract class represents a matrix for which every one
41 // of the mXn elements is stored explicitly in data.
42 // Derived classes provide fast scalar elements, column- or row-order storage,
43 // or fancier indexing schemes.
44 //------------------------------------------------------------------------------
45 template <class S>
46 class FullHelper : public MatrixHelperRep<S> {
47     typedef FullHelper<S>           This;
48     typedef MatrixHelperRep<S>      Base;
49     typedef typename CNT<S>::TNeg   SNeg;
50     typedef typename CNT<S>::THerm  SHerm;
51     typedef FullHelper<SNeg>        ThisNeg;
52     typedef FullHelper<SHerm>       ThisHerm;
53 public:
54     // Allocate new memory for a full, contiguous storage, owner matrix. The
55     // leading dimension will be either nr or nc depending on whether
56     // this is column- or row-order storage. Note that nr and nc are
57     // in elements while leadingDim is in scalars.
FullHelper(int esz,int cppesz,int nr,int nc,int ldim)58     FullHelper(int esz, int cppesz, int nr, int nc, int ldim)
59     :   Base(esz,cppesz), m_leadingDim(ldim)
60     {
61         assert(   m_leadingDim==nr*this->m_eltSize
62                || m_leadingDim==nc*this->m_eltSize);
63         // The "this->" (or Base::) is required here (by gcc and the standard,
64         // though not VC++ 9) to delay lookup of these non-tempatized members
65         // until instantiation. (Google "two-stage name lookup".)
66         this->m_owner     = true;
67         this->m_writable  = true;
68         this->allocateData(nr,nc);
69         this->m_actual.setStructure(MatrixStructure::Full);
70         this->m_actual.setActualSize(nr,nc);
71     }
72 
73     // Use someone else's memory, which we assume to be the right size.
FullHelper(int esz,int cppesz,int nr,int nc,int ldim,const S * shared,bool canWrite)74     FullHelper(int esz, int cppesz, int nr, int nc, int ldim,
75                const S* shared, bool canWrite)
76     :   Base(esz,cppesz), m_leadingDim(ldim)
77     {
78         this->m_owner     = false;
79         this->m_writable  = canWrite;
80         this->setData(const_cast<S*>(shared));
81         this->m_actual.setStructure(MatrixStructure::Full);
82         this->m_actual.setActualSize(nr,nc);
83     }
84 
getLeadingDim()85     int getLeadingDim() const {return m_leadingDim;}
86 
getAnyElt_(int i,int j,S * value)87     void getAnyElt_(int i, int j, S* value) const
88     {   this->copyElt(value, this->getElt_(i,j)); }
89 
90     // The meaning of "Full" is that every element is stored in memory somewhere.
eltIsStored_(int,int)91     bool eltIsStored_(int, int) const {return true;}
92 
93     // Just changing the return type here.
94     virtual FullHelper* cloneHelper_() const = 0;
95 
96     // A deep copy of a full matrix always results in contiguous storage, in
97     // row or column order depending on what is cheaper.
98     virtual FullHelper* createDeepCopy_() const = 0;
99 
100     // This serves for all block views of Full matrices because selecting
101     // a block doesn't change the type of handle we need.
createBlockView_(const EltBlock & block)102     FullHelper* createBlockView_(const EltBlock& block) {
103         FullHelper* p = cloneHelper_();
104         p->m_data = this->updElt_(block.row0(), block.col0());
105         return p;
106     }
107 
108 protected:
109     int m_leadingDim; // in scalars
110 
111     // Note that these indexers can take signed indices and produce signed
112     // data offsets. Here we don't know whether the data is stored in row
113     // or column order, so the indices are in terms of "fast" and "slow"
114     // where "fast" is the one that moves consecutively through memory.
115 
116     // First is for use with composite elements, second is for scalar elements.
eltIx(int fast,int slow)117     ptrdiff_t eltIx   (int fast, int slow) const
118     {   return (ptrdiff_t)slow*m_leadingDim + fast*this->m_eltSize; }
scalarIx(int fast,int slow)119     ptrdiff_t scalarIx(int fast, int slow) const
120     {   return (ptrdiff_t)slow*m_leadingDim + fast; }
121 
isContiguousElt(int nFast)122     bool isContiguousElt   (int nFast) const
123     {   return m_leadingDim == nFast*this->m_eltSize; }
isContiguousScalar(int nFast)124     bool isContiguousScalar(int nFast) const
125     {   return m_leadingDim == nFast; }
126 
scalarColSum(int j)127     S scalarColSum(int j) const {
128         S csum = S(0);
129         for (int i=0; i<this->nrow(); ++i) csum += *this->getElt_(i,j);
130         return csum;
131     }
132 
scalarRowSum(int i)133     S scalarRowSum(int i) const {
134         S rsum = S(0);
135         for (int j=0; j<this->ncol(); ++j) rsum += *this->getElt_(i,j);
136         return rsum;
137     }
138 };
139 
140 //----------------------------- RegularFullHelper ------------------------------
141 //
142 // This is a Full matrix whose elements are regularly spaced in memory, meaning
143 // that a change in row index i creates a predictable memory offset independent
144 // of j, and similarly a change in column index j creates a predictable offset
145 // independent of i.
146 //------------------------------------------------------------------------------
147 template <class S>
148 class RegularFullHelper : public FullHelper<S> {
149     typedef RegularFullHelper<S>    This;
150     typedef FullHelper<S>           Base;
151 public:
RegularFullHelper(int esz,int cppesz,int nr,int nc,int ldim)152     RegularFullHelper(int esz, int cppesz, int nr, int nc, int ldim)
153     :   Base(esz,cppesz,nr,nc,ldim) {}
RegularFullHelper(int esz,int cppesz,int nr,int nc,int ldim,const S * shared,bool canWrite)154     RegularFullHelper(int esz, int cppesz, int nr, int nc, int ldim,
155                       const S* shared, bool canWrite)
156     :   Base(esz,cppesz,nr,nc,ldim,shared,canWrite) {}
157 
hasRegularData_()158     bool hasRegularData_() const {return true;}
159 
160     // These implementations work for any RegularFullHelper.
161     This*            createRegularView_(const EltBlock&, const EltIndexer&);
162     VectorHelper<S>* createDiagonalView_();
163     VectorHelper<S>* createColumnView_(int j, int i, int m);
164     VectorHelper<S>* createRowView_(int i, int j, int n);
165 
166     // This is a new pure virtual that all RegularFullHelpers must provide.
167     // Some will return their actual indexers, others will calculate one,
168     // which is why we don't return a reference here.
169     virtual EltIndexer getEltIndexer() const = 0;
170 
171 protected:
172     typedef typename CNT<S>::StdNumber StdNumber;
173     // This is for use by scalar col- and row- ordered matrices only. The same
174     // code works because transpose(inv(m))==inv(transpose(m)).
lapackInvertInPlace()175     void lapackInvertInPlace() {
176         // should have been checked already
177         assert(this->m_eltSize==1 && this->nrow()==this->ncol());
178         const int m = this->nrow();
179         StdNumber* rawMem = reinterpret_cast<StdNumber*>(this->m_data);
180         Array_<int> ipiv(m);
181         int info;
182         Lapack::getrf<StdNumber>(m,m,rawMem,this->m_leadingDim,&ipiv[0],info);
183         assert(info==0);
184 
185         // Calculate optimal size for work
186         StdNumber workSz;
187         Lapack::getri<StdNumber>(m,rawMem,this->m_leadingDim,&ipiv[0],
188                                  &workSz,-1,info);
189         const int wsz = (int)CNT<StdNumber>::real(workSz);
190 
191         Array_<StdNumber> work(wsz);
192         Lapack::getri<StdNumber>(m,rawMem,this->m_leadingDim,&ipiv[0],
193                                  &work[0],wsz,info);
194         assert(info==0);
195     }
196 };
197 
198 // Full, column order, composite. Row i is the fast dimension here.
199 template <class S>
200 class FullColOrderEltHelper : public RegularFullHelper<S> {
201     typedef FullColOrderEltHelper<S>    This;
202     typedef RegularFullHelper<S>        Base;
203 public:
204     // Leading dimension is # rows for contiguous column-ordered memory.
FullColOrderEltHelper(int esz,int cppesz,int nr,int nc)205     FullColOrderEltHelper(int esz, int cppesz, int nr, int nc)
206     :   Base(esz, cppesz, nr, nc, nr*esz) {
207         this->m_actual.setStorage
208            (MatrixStorage(MatrixStorage::Full, MatrixStorage::NoPlacement,
209                           MatrixStorage::ColumnOrder, MatrixStorage::NoDiag));
210     }
211 
FullColOrderEltHelper(int esz,int cppesz,int nr,int nc,int ldim,S * shared,bool canWrite)212     FullColOrderEltHelper(int esz, int cppesz, int nr, int nc, int ldim,
213                           S* shared, bool canWrite)
214     :   Base(esz, cppesz, nr, nc, ldim, shared, canWrite) {
215         assert(ldim>=nr*esz);
216         this->m_actual.setStorage
217            (MatrixStorage(MatrixStorage::Full, MatrixStorage::NoPlacement,
218                           MatrixStorage::ColumnOrder, MatrixStorage::NoDiag));
219     }
220 
221     // This should be processed a column at a time if possible.
preferRowOrder_()222     bool preferRowOrder_() const {return false;}
223 
224     // These virtual methods should be overridden in the derived scalar class.
getElt_(int i,int j)225     virtual const S*    getElt_(int i, int j) const
226     {   return this->m_data + this->eltIx(i,j); }
updElt_(int i,int j)227     virtual S*          updElt_(int i, int j)
228     {   return this->m_data + this->eltIx(i,j); }
hasContiguousData_()229     virtual bool        hasContiguousData_()  const
230     {   return this->isContiguousElt(this->nrow()); }
cloneHelper_()231     virtual This*       cloneHelper_()        const
232     {   return new This(*this); }
233 
234     // This implementation will return a FullRowOrderEltHelper. Override for
235     // scalars.
236     virtual RegularFullHelper<S>* createTransposeView_();
237 
238     // These implementations are fine for both composite and scalar class.
239 
240     // Regular spacing as (dfast/di, dfast/dj) and (dslow/di, dslow/dj),
241     // with i,j in elements.
getEltIndexer()242     EltIndexer getEltIndexer() const {return EltIndexer(1,0,0,1);}
243 
createDeepCopy_()244     This* createDeepCopy_() const {
245         This* p = cloneHelper_();
246         p->m_leadingDim = this->nrow()*this->m_eltSize; // packed now
247         p->m_writable = true;
248         p->m_owner = true;
249         p->allocateData(this->nelt());
250         if (hasContiguousData_())
251             std::copy(this->m_data, this->m_data +
252                       Base::nelt()*this->m_eltSize, p->m_data);
253         else for (int j=0; j < this->ncol(); ++j)
254             std::copy(getElt_(0,j), getElt_(0,j) +
255                       this->nrow()*this->m_eltSize, p->updElt_(0,j));
256         return p;
257     }
258 
259 
260     // OK for any size elements.
resize_(int m,int n)261     void resize_(int m, int n) {
262         this->clearData();
263         this->allocateData(m,n);
264         this->m_leadingDim = m * this->m_eltSize; // # scalars in a column
265     }
266 
267     // OK for any size elements.
resizeKeep_(int m,int n)268     void resizeKeep_(int m, int n) {
269         const int newLeadingDim = m * this->m_eltSize; // # scalars in a column
270         S* const newData = this->allocateMemory(m,n);
271         const int colsToCopy = std::min(n, this->ncol());
272         const int rowsToCopy = std::min(m, this->nrow()); // in elements
273         for (int j=0; j < colsToCopy; ++j) {
274             S*       const dest = newData + (ptrdiff_t)j*newLeadingDim;
275             const S* const src  = this->m_data + (ptrdiff_t)j*this->m_leadingDim;
276             std::copy(src, src+rowsToCopy*this->m_eltSize, dest);
277         }
278         this->clearData();
279         this->setData(newData);
280         this->m_leadingDim = newLeadingDim;
281     }
282 };
283 
284 // Full, column order, scalar, final.
285 template <class S>
286 class FullColOrderScalarHelper : public FullColOrderEltHelper<S> {
287     typedef FullColOrderScalarHelper<S> This;
288     typedef FullColOrderEltHelper<S>    Base;
289 public:
290     // Leading dimension is # rows for contiguous column-ordered memory.
FullColOrderScalarHelper(int nr,int nc)291     FullColOrderScalarHelper(int nr, int nc)
292     :   Base(1, 1, nr, nc) {}
FullColOrderScalarHelper(int nr,int nc,int ldim,S * shared,bool canWrite)293     FullColOrderScalarHelper(int nr, int nc, int ldim, S* shared, bool canWrite)
294     :   Base(1, 1, nr, nc, ldim, shared, canWrite) {}
295 
296     // For speed, these override the Base implementations for composite elements.
getElt_(int i,int j)297     const S*    getElt_(int i, int j) const
298     {   return this->m_data + this->scalarIx(i,j); }
updElt_(int i,int j)299     S*          updElt_(int i, int j)
300     {   return this->m_data + this->scalarIx(i,j); }
hasContiguousData_()301     bool        hasContiguousData_()  const
302     {   return this->isContiguousScalar(this->nrow()); }
cloneHelper_()303     This*       cloneHelper_()        const
304     {   return new This(*this); }
305 
306     // This implementation will return a FullRowOrderScalarHelper.
307     RegularFullHelper<S>* createTransposeView_();
308 
colSum_(int j,S * csum)309     void colSum_(int j, S* csum) const {*csum = this->scalarColSum(j);}
rowSum_(int i,S * rsum)310     void rowSum_(int i, S* rsum) const {*rsum = this->scalarRowSum(i);}
311     // Sum element column by column to avoid cache faults.
sum_(S * esum)312     void sum_(S* esum) const {
313         *esum = S(0);
314         for (int j=0; j<this->ncol(); ++j) *esum += this->scalarColSum(j);
315     }
316 
invertInPlace_()317     void invertInPlace_() {this->lapackInvertInPlace();}
318 };
319 
320 // Full, row order, composite. Column j is the fast dimension here.
321 template <class S>
322 class FullRowOrderEltHelper : public RegularFullHelper<S> {
323     typedef FullRowOrderEltHelper<S>    This;
324     typedef RegularFullHelper<S>        Base;
325 public:
326     // Leading dimension is # cols for contiguous row-ordered memory.
FullRowOrderEltHelper(int esz,int cppesz,int nr,int nc)327     FullRowOrderEltHelper(int esz, int cppesz, int nr, int nc)
328     :   Base(esz, cppesz, nr, nc, nc*esz) {
329         this->m_actual.setStorage
330            (MatrixStorage(MatrixStorage::Full, MatrixStorage::NoPlacement,
331                           MatrixStorage::RowOrder, MatrixStorage::NoDiag));
332     }
333 
FullRowOrderEltHelper(int esz,int cppesz,int nr,int nc,int ldim,S * shared,bool canWrite)334     FullRowOrderEltHelper(int esz, int cppesz, int nr, int nc, int ldim,
335                           S* shared, bool canWrite)
336     :   Base(esz, cppesz, nr, nc, ldim, shared, canWrite) {
337         assert(ldim>=nc*esz);
338         this->m_actual.setStorage
339            (MatrixStorage(MatrixStorage::Full, MatrixStorage::NoPlacement,
340                           MatrixStorage::RowOrder, MatrixStorage::NoDiag));
341     }
342 
343     // This should be processed a row at a time if possible.
preferRowOrder_()344     bool preferRowOrder_() const {return true;}
345 
346     // These virtual methods should be overridden in the derived scalar class.
getElt_(int i,int j)347     virtual const S*    getElt_(int i, int j) const
348     {   return this->m_data + this->eltIx(j,i); }
updElt_(int i,int j)349     virtual S*          updElt_(int i, int j)
350     {   return this->m_data + this->eltIx(j,i); }
hasContiguousData_()351     virtual bool        hasContiguousData_()  const
352     {   return this->isContiguousElt(this->ncol()); }
cloneHelper_()353     virtual This*       cloneHelper_()        const
354     {   return new This(*this); }
355 
356     // This implementation will return a FullColOrderEltHelper. Override for
357     // scalars.
358     virtual RegularFullHelper<S>* createTransposeView_();
359 
360     // These implementations are fine for both composite and scalar class.
getEltIndexer()361     EltIndexer getEltIndexer() const {return EltIndexer(0,1,1,0);}
362 
createDeepCopy_()363     This* createDeepCopy_() const {
364         This* p = cloneHelper_();
365         p->m_leadingDim = this->ncol()*this->m_eltSize; // packed now
366         p->m_writable = true;
367         p->m_owner = true;
368         p->allocateData(this->nelt());
369         if (hasContiguousData_())
370             std::copy(this->m_data, this->m_data +
371                       this->nelt()*this->m_eltSize, p->m_data);
372         else for (int i=0; i < this->nrow(); ++i)
373             std::copy(this->getElt_(i,0), this->getElt_(i,0) +
374                       this->ncol()*this->m_eltSize, p->updElt_(i,0));
375         return p;
376     }
377 
resize_(int m,int n)378     void resize_(int m, int n) {
379         this->clearData();
380         this->allocateData(m,n);
381         this->m_leadingDim = n * this->m_eltSize;   // # scalars in a row
382     }
383 
384     // OK for any size elements.
resizeKeep_(int m,int n)385     void resizeKeep_(int m, int n) {
386         const int newLeadingDim = n * this->m_eltSize; // # scalars in a row
387         S* const newData = this->allocateMemory(m,n);
388         const int colsToCopy = std::min(n, this->ncol()); // in elements
389         const int rowsToCopy = std::min(m, this->nrow());
390         for (int i=0; i < rowsToCopy; ++i) {
391             S*       const dest = newData + (ptrdiff_t)i*newLeadingDim;
392             const S* const src  = this->m_data + (ptrdiff_t)i*this->m_leadingDim;
393             std::copy(src, src+colsToCopy*this->m_eltSize, dest);
394         }
395         this->clearData();
396         this->setData(newData);
397         this->m_leadingDim = newLeadingDim;
398     }
399 };
400 
401 // Full, row order, scalar, final.
402 template <class S>
403 class FullRowOrderScalarHelper : public FullRowOrderEltHelper<S> {
404     typedef FullRowOrderScalarHelper<S> This;
405     typedef FullRowOrderEltHelper<S>    Base;
406 public:
407     // Leading dimension is # cols for contiguous row-ordered memory.
FullRowOrderScalarHelper(int nr,int nc)408     FullRowOrderScalarHelper(int nr, int nc)
409     :   Base(1, 1, nr, nc) {}
FullRowOrderScalarHelper(int nr,int nc,int ldim,S * shared,bool canWrite)410     FullRowOrderScalarHelper(int nr, int nc, int ldim, S* shared, bool canWrite)
411     :   Base(1, 1, nr, nc, ldim, shared, canWrite) {}
412 
413     // For speed, these override the Base implementations for composite elements.
getElt_(int i,int j)414     const S*    getElt_(int i, int j) const
415     {   return this->m_data + this->scalarIx(j,i); }
updElt_(int i,int j)416     S*          updElt_(int i, int j)
417     {   return this->m_data + this->scalarIx(j,i); }
hasContiguousData_()418     bool        hasContiguousData_()  const
419     {   return this->isContiguousScalar(this->ncol()); }
cloneHelper_()420     This*       cloneHelper_()        const
421     {   return new This(*this); }
422 
423     // This implementation will return a FullColOrderScalarHelper.
424     RegularFullHelper<S>* createTransposeView_();
425 
colSum_(int j,S * csum)426     void colSum_(int j, S* csum) const {*csum = this->scalarColSum(j);}
rowSum_(int i,S * rsum)427     void rowSum_(int i, S* rsum) const {*rsum = this->scalarRowSum(i);}
428     // Sum element row by row to avoid cache faults.
sum_(S * esum)429     void sum_(S* esum) const {
430         *esum = S(0);
431         for (int i=0; i<this->nrow(); ++i) *esum += this->scalarRowSum(i);
432     }
433 
invertInPlace_()434     void invertInPlace_() {this->lapackInvertInPlace();}
435 };
436 
437 
438 // These definitions for inline methods had to wait until other classes
439 // were defined.
440 
441 template <class S> inline RegularFullHelper<S>*
createTransposeView_()442 FullColOrderEltHelper<S>::createTransposeView_() {
443     FullRowOrderEltHelper<S>* p =
444         new FullRowOrderEltHelper<S>(this->m_eltSize, this->m_cppEltSize,
445                                      this->ncol(), this->nrow(),
446                                      this->m_leadingDim, this->m_data, this->m_writable);
447     return p;
448 }
449 
450 template <class S> inline RegularFullHelper<S>*
createTransposeView_()451 FullColOrderScalarHelper<S>::createTransposeView_() {
452     FullRowOrderScalarHelper<S>* p =
453         new FullRowOrderScalarHelper<S>(this->ncol(), this->nrow(),
454                                         this->m_leadingDim, this->m_data, this->m_writable);
455     return p;
456 }
457 
458 template <class S> inline RegularFullHelper<S>*
createTransposeView_()459 FullRowOrderEltHelper<S>::createTransposeView_() {
460     FullColOrderEltHelper<S>* p =
461         new FullColOrderEltHelper<S>(this->m_eltSize, this->m_cppEltSize,
462                                      this->ncol(), this->nrow(),
463                                      this->m_leadingDim, this->m_data, this->m_writable);
464     return p;
465 }
466 
467 template <class S> inline RegularFullHelper<S>*
createTransposeView_()468 FullRowOrderScalarHelper<S>::createTransposeView_() {
469     FullColOrderScalarHelper<S>* p =
470         new FullColOrderScalarHelper<S>(this->ncol(), this->nrow(),
471                                         this->m_leadingDim, this->m_data, this->m_writable);
472     return p;
473 }
474 
475 // Full, indexed, composite.
476 template <class S>
477 class FullIndexedEltHelper : public RegularFullHelper<S> {
478     typedef FullIndexedEltHelper<S>     This;
479     typedef RegularFullHelper<S>        Base;
480 public:
481     // Construct a new view of any regularly-spaced full matrix, allowing
482     // composite elements. Source is taken non-const but writability is only
483     // granted if the source had it.
484     // Note that the (r0,c0) element may be one element off the end of the
485     // matrix as long as the corresponding dimension is 0.
FullIndexedEltHelper(RegularFullHelper<S> & src,const EltBlock & block,const EltIndexer & ix)486     FullIndexedEltHelper(RegularFullHelper<S>& src, const EltBlock& block, const EltIndexer& ix)
487     :   Base(src.getEltSize(), src.getCppEltSize(),
488              block.nrow(), block.ncol(), src.getLeadingDim(),
489              src.getElt(block.row0(), block.col0()), src.isWritable()),
490         m_indexer(src.getEltIndexer().postIndexBy(ix))
491     {
492         SimTK_SIZECHECK(block.row0(), src.nrow()-block.nrow(), "FullIndexedEltHelper ctor");
493         SimTK_SIZECHECK(block.col0(), src.ncol()-block.ncol(), "FullIndexedEltHelper ctor");
494     }
495 
496         // Implementations good for both composite and scalar elements. //
497 
hasContiguousData_()498     bool        hasContiguousData_()  const {return false;}
getEltIndexer()499     EltIndexer  getEltIndexer()       const {return m_indexer;}
500 
501     // Prefer to go through the data a row at a time if adjacent column
502     // elements in the same row are closer together than adjacent row
503     // elements in the same column.
preferRowOrder_()504     bool preferRowOrder_() const {return ixEltIx(0,1) < ixEltIx(1,0);}
505 
506         // Implementations that should be overridden for scalar elements. //
507 
getElt_(int i,int j)508     virtual const S*    getElt_(int i, int j) const {return this->m_data + ixEltIx(i,j);}
updElt_(int i,int j)509     virtual S*          updElt_(int i, int j)       {return this->m_data + ixEltIx(i,j);}
cloneHelper_()510     virtual This*       cloneHelper_()        const {return new This(*this);}
511 
512     // This implementation works for this class and the scalar derived class.
createTransposeView_()513     This* createTransposeView_() {
514         This* p = cloneHelper_();
515         p->m_indexer = m_indexer.transpose();
516         p->m_actual.setActualSize(this->ncol(), this->nrow());
517         return p;
518     }
519 
520     // A deep copy of an indexed matrix eliminates the index, producing a
521     // full, column- or row-ordered matrix with contiguous storage.
522     // We choose the destination storage order to match whichever way is
523     // fastest to travel through the indexed matrix, since then we can
524     // traverse both matrices in their fastest order.
createDeepCopy_()525     virtual RegularFullHelper<S>* createDeepCopy_() const {
526         if (preferRowOrder_()) {
527             FullRowOrderEltHelper<S>* p =
528                 new FullRowOrderEltHelper<S>(this->m_eltSize,this->m_cppEltSize,
529                                              this->nrow(),this->ncol());
530             for (int i=0; i < this->nrow(); ++i) {
531                 S* dest = p->updElt_(i,0);   // start of a dense row
532                 for (int j=0; j < this->ncol(); ++j, dest += this->m_eltSize)
533                     this->copyElt(dest, this->getElt_(i,j));
534             }
535             return p;
536         } else {
537             FullColOrderEltHelper<S>* p =
538                 new FullColOrderEltHelper<S>(this->m_eltSize,this->m_cppEltSize,
539                                              this->nrow(), this->ncol());
540             for (int j=0; j < this->ncol(); ++j) {
541                 S* dest = p->updElt_(0,j);   // start of a dense column
542                 for (int i=0; i < this->nrow(); ++i, dest += this->m_eltSize)
543                     this->copyElt(dest, this->getElt_(i,j));
544             }
545             return p;
546         }
547     }
548 
549 protected:
550     EltIndexer m_indexer;
551 
row(int i,int j)552     int row(int i, int j) const {return m_indexer.row(i,j);}
col(int i,int j)553     int col(int i, int j) const {return m_indexer.col(i,j);}
554 
ixEltIx(int i,int j)555     ptrdiff_t ixEltIx(int i, int j) const {return this->eltIx(row(i,j),col(i,j));}
556 };
557 
558 // Full, indexed, scalar, final.
559 template <class S>
560 class FullIndexedScalarHelper : public FullIndexedEltHelper<S> {
561     typedef FullIndexedScalarHelper<S>  This;
562     typedef FullIndexedEltHelper<S>     Base;
563 public:
564     // Construct a new view of any regularly-spaced full matrix, as long as that
565     // matrix has scalar elements.
FullIndexedScalarHelper(RegularFullHelper<S> & src,const EltBlock & block,const EltIndexer & ix)566     FullIndexedScalarHelper(RegularFullHelper<S>& src, const EltBlock& block,
567                             const EltIndexer& ix)
568     :   Base(src, block, ix)
569     {
570         SimTK_ASSERT_ALWAYS(src.getEltSize()==1,
571             "FullIndexedScalarHelper ctor: source must have scalar elements");
572     }
573 
574     // For speed, these override the composite-element implementatiosn.
getElt_(int i,int j)575     const S* getElt_(int i, int j) const
576     {   return this->m_data + ixScalarIx(i,j); }
updElt_(int i,int j)577     S*       updElt_(int i, int j)
578     {   return this->m_data + ixScalarIx(i,j); }
579 
cloneHelper_()580     This* cloneHelper_() const {return new This(*this);}
581 
createDeepCopy_()582     RegularFullHelper<S>* createDeepCopy_() const {
583         if (this->preferRowOrder_()) {
584             FullRowOrderScalarHelper<S>* p =
585                 new FullRowOrderScalarHelper<S>(this->nrow(),this->ncol());
586             for (int i=0; i < this->nrow(); ++i) {
587                 S* dest = p->updElt_(i,0);   // start of a dense row
588                 for (int j=0; j < this->ncol(); ++j, ++dest)
589                     *dest = *this->getElt_(i,j);
590             }
591             return p;
592         } else {
593             FullColOrderScalarHelper<S>* p =
594                 new FullColOrderScalarHelper<S>(this->nrow(),this->ncol());
595             for (int j=0; j < this->ncol(); ++j) {
596                 S* dest = p->updElt_(0,j);   // start of a dense column
597                 for (int i=0; i < this->nrow(); ++i, ++dest)
598                     *dest = *this->getElt_(i,j);
599             }
600             return p;
601         }
602     }
603 
604 private:
ixScalarIx(int i,int j)605     ptrdiff_t ixScalarIx(int i, int j) const
606     {   return this->scalarIx(this->row(i,j),this->col(i,j)); }
607 };
608 
609 template <class S> inline RegularFullHelper<S>*
createRegularView_(const EltBlock & block,const EltIndexer & ix)610 RegularFullHelper<S>::createRegularView_(const EltBlock& block,
611                                          const EltIndexer& ix) {
612     RegularFullHelper<S>* p;
613     if (this->m_eltSize==1) p = new FullIndexedScalarHelper<S>(*this, block, ix);
614     else                    p = new FullIndexedEltHelper<S>(*this, block, ix);
615     return p;
616 }
617 
618 
619 
620 
621 } // namespace SimTK
622 
623 
624 #endif // SimTK_SimTKCOMMON_MATRIX_HELPER_REP_FULL_H_
625