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