1 /* -------------------------------------------------------------------------- *
2 * Simbody(tm): SimTKcommon *
3 * -------------------------------------------------------------------------- *
4 * This is part of the SimTK biosimulation toolkit originating from *
5 * Simbios, the NIH National Center for Physics-Based Simulation of *
6 * Biological Structures at Stanford, funded under the NIH Roadmap for *
7 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
8 * *
9 * Portions copyright (c) 2005-15 Stanford University and the Authors. *
10 * Authors: Michael Sherman *
11 * Contributors: *
12 * *
13 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
14 * not use this file except in compliance with the License. You may obtain a *
15 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
16 * *
17 * Unless required by applicable law or agreed to in writing, software *
18 * distributed under the License is distributed on an "AS IS" BASIS, *
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
20 * See the License for the specific language governing permissions and *
21 * limitations under the License. *
22 * -------------------------------------------------------------------------- */
23
24 // Avoid annoying deprecated warnings regarding std::copy during instantiations.
25 #ifdef _MSC_VER
26 #pragma warning(disable:4996)
27 #endif
28
29 #include "SimTKcommon/Scalar.h"
30 #include "SimTKcommon/SmallMatrix.h"
31 #include "SimTKcommon/TemplatizedLapack.h"
32
33 #include "SimTKcommon/internal/MatrixHelper.h"
34 #include "SimTKcommon/internal/MatrixCharacteristics.h"
35
36 #include "MatrixHelperRep.h"
37 #include "MatrixHelperRep_Full.h"
38 #include "MatrixHelperRep_Tri.h"
39 #include "MatrixHelperRep_Vector.h"
40
41 #include <iostream>
42 #include <cstdio>
43
44 namespace SimTK {
45
46
47 //----------------------------- MATRIX HELPER ----------------------------------
48 //
49 // Implementations of MatrixHelper methods. Most are just pass throughs to
50 // MatrixHelperRep, but some may involve replacing the current MatrixHelperRep
51 // with a different one.
52 //------------------------------------------------------------------------------
53
54 template <class S> void
deleteRepIfOwner()55 MatrixHelper<S>::deleteRepIfOwner() {
56 if (rep && &rep->getMyHandle() == this)
57 delete rep;
58 rep=0;
59 }
60
61 // Rep replacement. Delete the existing rep if we're the owner of it.
62 // We are going to be the owner of the new rep regardless.
63 template <class S> void
replaceRep(MatrixHelperRep<S> * hrep)64 MatrixHelper<S>::replaceRep(MatrixHelperRep<S>* hrep) {
65 deleteRepIfOwner();
66 rep=hrep;
67 rep->setMyHandle(*this);
68 }
69
70 // Space-stealing constructor. We're going to take over ownership
71 // of this rep.
72 template <class S>
MatrixHelper(MatrixHelperRep<S> * hrep)73 MatrixHelper<S>::MatrixHelper(MatrixHelperRep<S>* hrep) : rep(hrep)
74 { if (rep) rep->setMyHandle(*this); }
75
76 template <class S> const MatrixCommitment&
getCharacterCommitment() const77 MatrixHelper<S>::getCharacterCommitment() const
78 { return getRep().getCharacterCommitment(); }
79
80 template <class S> const MatrixCharacter&
getMatrixCharacter() const81 MatrixHelper<S>::getMatrixCharacter() const
82 { return getRep().getMatrixCharacter(); }
83
84
85
86 // This is the constructor for a Matrix in which only the handle commitment has been
87 // supplied. The allocated matrix will have the smallest size that satisfies the
88 // commitment, typically 0x0 or 0x1.
89 template <class S>
MatrixHelper(int esz,int cppEsz,const MatrixCommitment & mc)90 MatrixHelper<S>::MatrixHelper(int esz, int cppEsz, const MatrixCommitment& mc) : rep(0) {
91 // Determine the best actual matrix to allocate to satisfy this commitment.
92 const MatrixCharacter actual = mc.calcDefaultCharacter(0,0);
93
94 rep = MatrixHelperRep<S>::createOwnerMatrixHelperRep(esz, cppEsz, actual);
95 assert(rep);
96 rep->setMyHandle(*this);
97
98 rep->m_commitment = mc;
99 }
100
101 // This is effectively the default constructor. It creates a writable, fully resizable 0x0
102 // matrix, with the handle committed only to the given element size.
103 // Just calls the above constructor with a default commitment.
104 template <class S>
MatrixHelper(int esz,int cppEsz)105 MatrixHelper<S>::MatrixHelper(int esz, int cppEsz) : rep(0) {
106 new (this) MatrixHelper(esz, cppEsz, MatrixCommitment());
107 }
108
109 // This is the constructor for a Matrix in which the handle commitment has been
110 // supplied, along with an initial allocation size. Provided the size satisfies the
111 // commitment, the resulting matrix will have that size.
112 template <class S>
MatrixHelper(int esz,int cppEsz,const MatrixCommitment & commitment,int m,int n)113 MatrixHelper<S>::MatrixHelper
114 (int esz, int cppEsz, const MatrixCommitment& commitment,
115 int m, int n) : rep(0)
116 {
117 SimTK_ERRCHK2(commitment.isSizeOK(m,n), "MatrixHelper::ctor()",
118 "The initial size allocation %s x %s didn't satisfy the supplied commitment.",
119 m, n);
120
121 // Determine the best actual matrix to allocate to satisfy this commitment.
122 const MatrixCharacter actual = commitment.calcDefaultCharacter(m,n);
123
124 rep = MatrixHelperRep<S>::createOwnerMatrixHelperRep(esz, cppEsz, actual);
125 assert(rep);
126 rep->setMyHandle(*this);
127
128 rep->m_commitment = commitment;
129 }
130
131 // Create a read-only view into existing data.
132 template <class S>
MatrixHelper(int esz,int cppEsz,const MatrixCommitment & commitment,const MatrixCharacter & actual,int spacing,const S * data)133 MatrixHelper<S>::MatrixHelper
134 (int esz, int cppEsz, const MatrixCommitment& commitment,
135 const MatrixCharacter& actual, int spacing, const S* data) : rep(0)
136 {
137 SimTK_ERRCHK(commitment.isSatisfiedBy(actual), "MatrixHelper::ctor(external data)",
138 "The supplied actual matrix character for the external data did not "
139 "satisfy the specified handle character commitment.");
140
141 rep = MatrixHelperRep<S>::createExternalMatrixHelperRep
142 (esz, cppEsz, actual, spacing, const_cast<S*>(data), false);
143 assert(rep);
144 rep->setMyHandle(*this);
145
146 rep->m_commitment = commitment;
147 }
148
149 // Create a writable view into existing data.
150 template <class S>
MatrixHelper(int esz,int cppEsz,const MatrixCommitment & commitment,const MatrixCharacter & actual,int spacing,S * data)151 MatrixHelper<S>::MatrixHelper
152 (int esz, int cppEsz, const MatrixCommitment& commitment,
153 const MatrixCharacter& actual, int spacing, S* data) : rep(0)
154 {
155 SimTK_ERRCHK(commitment.isSatisfiedBy(actual), "MatrixHelper::ctor(external data)",
156 "The supplied actual matrix character for the external data did not "
157 "satisfy the specified handle character commitment.");
158
159 rep = MatrixHelperRep<S>::createExternalMatrixHelperRep
160 (esz, cppEsz, actual, spacing, data, true);
161 assert(rep);
162 rep->setMyHandle(*this);
163
164 rep->m_commitment = commitment;
165 }
166
167 // clear() restores this matrix to the state it would be in if it were constructed
168 // using its current character commitment. We'll replace the current HelperRep with
169 // a fresh one. Note that this is more expensive than resize(0,0) which doesn't
170 // require replacement of the HelperRep.
171 template <class S> void
clear()172 MatrixHelper<S>::clear() {
173 // Determine the best actual matrix to allocate to satisfy this commitment.
174 const MatrixCharacter actual = getCharacterCommitment().calcDefaultCharacter(0,0);
175 const int esz = getRep().getEltSize();
176 const int cppEsz = getRep().getCppEltSize();
177
178 MatrixHelperRep<S>* newRep =
179 MatrixHelperRep<S>::createOwnerMatrixHelperRep(esz, cppEsz, actual);
180 assert(newRep);
181
182 newRep->m_commitment = getRep().m_commitment;
183 if (!getRep().m_canBeOwner) {
184 newRep->m_canBeOwner = false;
185 newRep->m_owner = false;
186 }
187
188 replaceRep(newRep);
189 }
190
191 template <class S> bool
isClear() const192 MatrixHelper<S>::isClear() const {return getRep().isClear();}
193
194
195 template <class S> void
commitTo(const MatrixCommitment & mc)196 MatrixHelper<S>::commitTo(const MatrixCommitment& mc) {
197 SimTK_ERRCHK_ALWAYS(isClear(), "MatrixHelper::commitTo()",
198 "You can only replace the character commitment in an empty Matrix handle."
199 " Call clear() first to empty the handle.");
200 updRep().m_commitment = mc;
201 clear(); // reallocate to satisfy the new commitment
202 }
203
204 // Copy constructor is suppressed; these are closest things but require
205 // specification of deep or shallow copy.
206
207 // Create a read-only view of existing data.
208 template <class S>
MatrixHelper(const MatrixCommitment & mc,const MatrixHelper & h,const ShallowCopy &)209 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, const MatrixHelper& h, const ShallowCopy&) : rep(0) {
210 SimTK_ERRCHK(mc.isSatisfiedBy(h.getMatrixCharacter()), "MatrixHelper::ctor(const,shallow)",
211 "The actual matrix character of the source did not "
212 "satisfy the specified handle character commitment.");
213 rep = h.rep->createWholeView(false);
214 rep->setMyHandle(*this);
215 rep->m_commitment = mc;
216 }
217
218 // Create a (possibly) writable view of existing data.
219 template <class S>
MatrixHelper(const MatrixCommitment & mc,MatrixHelper & h,const ShallowCopy &)220 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, MatrixHelper& h, const ShallowCopy&) : rep(0) {
221 SimTK_ERRCHK(mc.isSatisfiedBy(h.getMatrixCharacter()), "MatrixHelper::ctor(writable,shallow)",
222 "The actual matrix character of the source did not "
223 "satisfy the specified handle character commitment.");
224 rep = h.rep->createWholeView(true);
225 rep->setMyHandle(*this);
226 rep->m_commitment = mc;
227 }
228
229 // Deep copy. "This" be always writable and in densely packed storage.
230 template <class S>
MatrixHelper(const MatrixCommitment & mc,const MatrixHelper & h,const DeepCopy &)231 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, const MatrixHelper& h, const DeepCopy&) : rep(0) {
232 SimTK_ERRCHK(mc.isSatisfiedBy(h.getMatrixCharacter()), "MatrixHelper::ctor(deep)",
233 "The actual matrix character of the source did not "
234 "satisfy the specified handle character commitment.");
235 rep = h.rep->createDeepCopy();
236 rep->setMyHandle(*this);
237 rep->m_commitment = mc;
238 }
239
240 // Negated deep copy. We'll get a brand new, filterless, writable, packed copy with
241 // the same values as the original (duh, that's what "copy" means) -- BUT, the
242 // physical floating point representations will all have been negated since we're
243 // copying a Matrix whose elements are of type negator<S> while ours are type S (or
244 // vice versa).
245 template <class S>
MatrixHelper(const MatrixCommitment & mc,const MatrixHelper<typename CNT<S>::TNeg> & h,const DeepCopy &)246 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, const MatrixHelper<typename CNT<S>::TNeg>& h, const DeepCopy&) : rep(0) {
247 SimTK_ERRCHK(mc.isSatisfiedBy(h.getMatrixCharacter()), "MatrixHelper::ctor(negated,deep)",
248 "The actual matrix character of the source did not "
249 "satisfy the specified handle character commitment.");
250 rep = h.rep->createNegatedDeepCopy();
251 rep->setMyHandle(*this);
252 rep->m_commitment = mc;
253 }
254
255 // construct read-only block view
256 template <class S>
MatrixHelper(const MatrixCommitment & mc,const MatrixHelper & h,int i,int j,int m,int n)257 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, const MatrixHelper& h, int i, int j, int m, int n) : rep(0) {
258 if (n==1)
259 rep = h.rep->createColumnView(j,i,m,false); // column j, from i to i+m-1
260 else if (m==1)
261 rep = h.rep->createRowView(i,j,n,false); // row i, from j to j+n-1
262 else
263 rep = h.rep->createBlockView(EltBlock(i,j,m,n), false);
264
265 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()), "MatrixHelper::ctor(const,block)",
266 "The actual matrix character of the source block did not "
267 "satisfy the specified handle character commitment.");
268
269 rep->setMyHandle(*this);
270 rep->m_commitment = mc;
271 }
272
273 // construct (possibly) writable block view
274 template <class S>
MatrixHelper(const MatrixCommitment & mc,MatrixHelper & h,int i,int j,int m,int n)275 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, MatrixHelper& h, int i, int j, int m, int n) : rep(0) {
276 if (n==1)
277 rep = h.rep->createColumnView(j,i,m,true); // column j, from i to i+m-1
278 else if (m==1)
279 rep = h.rep->createRowView(i,j,n,true); // row i, from j to j+n-1
280 else
281 rep = h.rep->createBlockView(EltBlock(i,j,m,n),true);
282
283 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()), "MatrixHelper::ctor(writable,block)",
284 "The actual matrix character of the source block did not "
285 "satisfy the specified handle character commitment.");
286
287 rep->setMyHandle(*this);
288 rep->m_commitment = mc;
289 }
290
291 // Construct read only transposed view of passed-in helper.
292 template <class S>
MatrixHelper(const MatrixCommitment & mc,const MatrixHelper<typename CNT<S>::THerm> & h,const TransposeView &)293 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, const MatrixHelper<typename CNT<S>::THerm>& h,
294 const TransposeView&) : rep(0) {
295 rep = h.rep->createHermitianView(false);
296
297 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()), "MatrixHelper::ctor(const,transpose)",
298 "The actual matrix character of the transposed source did not "
299 "satisfy the specified handle character commitment.");
300
301 rep->setMyHandle(*this);
302 rep->m_commitment = mc;
303 }
304
305 // Construct (possibly) writable transposed view of passed-in helper.
306 template <class S>
MatrixHelper(const MatrixCommitment & mc,MatrixHelper<typename CNT<S>::THerm> & h,const TransposeView &)307 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, MatrixHelper<typename CNT<S>::THerm>& h,
308 const TransposeView&) : rep(0) {
309 rep = h.rep->createHermitianView(true);
310
311 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()), "MatrixHelper::ctor(writable,transpose)",
312 "The actual matrix character of the transposed source did not "
313 "satisfy the specified handle character commitment.");
314
315 rep->setMyHandle(*this);
316 rep->m_commitment = mc;
317 }
318
319 // Construct read only diagonal view of passed-in helper.
320 template <class S>
MatrixHelper(const MatrixCommitment & mc,const MatrixHelper & h,const DiagonalView &)321 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, const MatrixHelper& h,
322 const DiagonalView&) : rep(0) {
323 rep = h.rep->createDiagonalView(false);
324
325 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()), "MatrixHelper::ctor(const,diagonal)",
326 "The actual matrix character of the diagonal of the source did not "
327 "satisfy the specified handle character commitment.");
328
329 rep->setMyHandle(*this);
330 rep->m_commitment = mc;
331 }
332
333 // Construct (possibly) writable diagonal view of passed-in helper.
334 template <class S>
MatrixHelper(const MatrixCommitment & mc,MatrixHelper & h,const DiagonalView &)335 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, MatrixHelper& h,
336 const DiagonalView&) : rep(0) {
337 rep = h.rep->createDiagonalView(true);
338
339 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()),
340 "MatrixHelper::ctor(writable,diagonal)",
341 "The actual matrix character of the diagonal of the source did not "
342 "satisfy the specified handle character commitment.");
343
344 rep->setMyHandle(*this);
345 rep->m_commitment = mc;
346 }
347
348 // Construct a read-only indexed view of a Vector.
349 template <class S>
MatrixHelper(const MatrixCommitment & mc,const MatrixHelper & h,int n,const int * ix)350 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, const MatrixHelper& h,
351 int n, const int* ix) : rep(0) {
352 const VectorHelper<S>& vh =
353 SimTK_DYNAMIC_CAST_DEBUG<const VectorHelper<S>&>(*h.rep);
354 rep = new IndexedVectorHelper<S>(vh.getEltSize(), vh.getCppEltSize(), n,
355 vh.preferRowOrder_(), ix, n ? vh.getElt_(0) : 0, false);
356
357 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()),
358 "MatrixHelper::ctor(const,indexed)",
359 "The actual matrix character of the indexed source did not "
360 "satisfy the specified handle character commitment.");
361
362 rep->setMyHandle(*this);
363 rep->m_commitment = mc;
364 }
365
366 // Construct a writable indexed view of a Vector.
367 template <class S>
MatrixHelper(const MatrixCommitment & mc,MatrixHelper & h,int n,const int * ix)368 MatrixHelper<S>::MatrixHelper(const MatrixCommitment& mc, MatrixHelper& h,
369 int n, const int* ix) : rep(0) {
370 VectorHelper<S>& vh = SimTK_DYNAMIC_CAST_DEBUG<VectorHelper<S>&>(*h.rep);
371 rep = new IndexedVectorHelper<S>(vh.getEltSize(), vh.getCppEltSize(), n,
372 vh.preferRowOrder_(), ix, n ? vh.updElt_(0) : 0, true);
373
374 SimTK_ERRCHK(mc.isSatisfiedBy(rep->getMatrixCharacter()),
375 "MatrixHelper::ctor(writable,indexed)",
376 "The actual matrix character of the indexed source did not "
377 "satisfy the specified handle character commitment.");
378
379 rep->setMyHandle(*this);
380 rep->m_commitment = mc;
381 }
382
383 // Perform deep assignment. "This" gets reallocated if necessary if it's an
384 // owner, but if this is a view the source and destination sizes must match.
385 template <class S> MatrixHelper<S>&
copyAssign(const MatrixHelper & h)386 MatrixHelper<S>::copyAssign(const MatrixHelper& h) {
387 if (rep->isOwner())
388 rep->resize(h.nrow(), h.ncol(), false);
389 else {
390 // OK if the sizes match.
391 assert(nrow()==h.nrow() && ncol()==h.ncol());
392 }
393
394 rep->copyInFromCompatibleSource(*h.rep);
395 return *this;
396 }
397 // Like copy assign but the source has elements with the opposite interpretation
398 // of sign. Note that the result still has the original value, but the in-memory
399 // representation will be different, meaning flops will be burned here.
400 template <class S> MatrixHelper<S>&
negatedCopyAssign(const MatrixHelper<typename CNT<S>::TNeg> & h)401 MatrixHelper<S>::negatedCopyAssign(const MatrixHelper<typename CNT<S>::TNeg>& h) {
402 if (rep->isOwner())
403 rep->resize(h.nrow(), h.ncol(), false);
404 else {
405 // OK if the sizes match.
406 assert(nrow()==h.nrow() && ncol()==h.ncol());
407 }
408
409 rep->negatedCopyInFromCompatibleSource(*h.rep);
410 return *this;
411 }
412
413 // Create a read-only view of existing data. Element size of source and destination
414 // must match. The result will have no element filter unless the source already does.
415 template <class S> MatrixHelper<S>&
readOnlyViewAssign(const MatrixHelper & h)416 MatrixHelper<S>::readOnlyViewAssign(const MatrixHelper& h) {
417 SimTK_ERRCHK(getCharacterCommitment().isSatisfiedBy(h.getMatrixCharacter()),
418 "MatrixHelper<S>::readOnlyViewAssign()",
419 "The source matrix does not satisfy this handle's character commitment.");
420
421 MatrixHelperRep<S>* newRep = h.getRep().createWholeView(false);
422 newRep->m_commitment = getRep().m_commitment; // preserve commitment
423 newRep->m_canBeOwner = getRep().m_canBeOwner;
424 replaceRep(newRep);
425 return *this;
426 }
427 // Create a (possibly) writable view of existing data.
428 template <class S> MatrixHelper<S>&
writableViewAssign(MatrixHelper & h)429 MatrixHelper<S>::writableViewAssign(MatrixHelper& h) {
430 SimTK_ERRCHK(getCharacterCommitment().isSatisfiedBy(h.getMatrixCharacter()),
431 "MatrixHelper<S>::writableViewAssign()",
432 "The source matrix does not satisfy this handle's character commitment.");
433
434 MatrixHelperRep<S>* newRep = h.getRep().createWholeView(true);
435 newRep->m_commitment = getRep().m_commitment; // preserve commitment
436 newRep->m_canBeOwner = getRep().m_canBeOwner;
437 replaceRep(newRep);
438 return *this;
439 }
440
441 template <class S> void
scaleBy(const typename CNT<S>::StdNumber & s)442 MatrixHelper<S>::scaleBy(const typename CNT<S>::StdNumber& s) {
443 rep->scaleBy(s);
444 }
445 template <class S> void
addIn(const MatrixHelper & h)446 MatrixHelper<S>::addIn(const MatrixHelper& h) {
447 rep->addIn(h);
448 }
449 template <class S> void
addIn(const MatrixHelper<typename CNT<S>::TNeg> & h)450 MatrixHelper<S>::addIn(const MatrixHelper<typename CNT<S>::TNeg>& h) {
451 subIn(reinterpret_cast<const MatrixHelper<S>&>(h));
452 }
453 template <class S> void
subIn(const MatrixHelper & h)454 MatrixHelper<S>::subIn(const MatrixHelper& h) {
455 rep->subIn(h);
456 }
457 template <class S> void
subIn(const MatrixHelper<typename CNT<S>::TNeg> & h)458 MatrixHelper<S>::subIn(const MatrixHelper<typename CNT<S>::TNeg>& h) {
459 addIn(reinterpret_cast<const MatrixHelper<S>&>(h));
460 }
461 template <class S> void
fillWith(const S * eltp)462 MatrixHelper<S>::fillWith(const S* eltp) {
463 rep->fillWith(eltp);
464 }
465 template <class S> void
copyInByRowsFromCpp(const S * elts)466 MatrixHelper<S>::copyInByRowsFromCpp(const S* elts) {
467 rep->copyInByRowsFromCpp(elts);
468 }
469
470 template <class S> void
invertInPlace()471 MatrixHelper<S>::invertInPlace() {
472 rep->invertInPlace();
473 }
474
475 template <class S> void
dump(const char * msg) const476 MatrixHelper<S>::dump(const char* msg) const {
477 rep->dump(msg);
478 }
479
480 template <class S> const S*
getElt(int i,int j) const481 MatrixHelper<S>::getElt(int i, int j) const {return rep->getElt(i,j);}
482 template <class S> S*
updElt(int i,int j)483 MatrixHelper<S>::updElt(int i, int j) {return rep->updElt(i,j);}
484 template <class S> void
getAnyElt(int i,int j,S * value) const485 MatrixHelper<S>::getAnyElt(int i, int j, S* value) const
486 { return rep->getAnyElt(i,j,value); }
487
488 template <class S> const S*
getElt(int i) const489 MatrixHelper<S>::getElt(int i) const {return rep->getElt(i);}
490 template <class S> S*
updElt(int i)491 MatrixHelper<S>::updElt(int i) {return rep->updElt(i);}
492 template <class S> void
getAnyElt(int i,S * value) const493 MatrixHelper<S>::getAnyElt(int i, S* value) const
494 { return rep->getAnyElt(i,value); }
495
496 template <class S> int
nrow() const497 MatrixHelper<S>::nrow() const {
498 return rep->nrow();
499 }
500 template <class S> int
ncol() const501 MatrixHelper<S>::ncol() const {
502 return rep->ncol();
503 }
504 template <class S> ptrdiff_t
nelt() const505 MatrixHelper<S>::nelt() const {
506 return rep->nelt();
507 }
508 template <class S> int
length() const509 MatrixHelper<S>::length() const {
510 return rep->length();
511 }
512
513 template <class S> void
resize(int m,int n)514 MatrixHelper<S>::resize (int m, int n) {rep->resize(m,n,false);}
515 template <class S> void
resizeKeep(int m,int n)516 MatrixHelper<S>::resizeKeep(int m, int n) {rep->resize(m,n,true);}
517
lockShape()518 template <class S> void MatrixHelper<S>::lockShape() {rep->lockHandle();}
unlockShape()519 template <class S> void MatrixHelper<S>::unlockShape() {rep->unlockHandle();}
520
521 template <class S> void
sum(S * const answer) const522 MatrixHelper<S>::sum(S* const answer) const {
523 rep->sum(answer);
524 }
525 template <class S> void
colSum(int j,S * const answer) const526 MatrixHelper<S>::colSum(int j, S* const answer) const {
527 rep->colSum(j,answer);
528 }
529 template <class S> void
rowSum(int i,S * const answer) const530 MatrixHelper<S>::rowSum(int i, S* const answer) const {
531 rep->rowSum(i,answer);
532 }
533 template <class S> void
fillWithScalar(const typename CNT<S>::StdNumber & s)534 MatrixHelper<S>::fillWithScalar(const typename CNT<S>::StdNumber& s) {
535 rep->fillWithScalar(s);
536 }
537
538 template <class S> bool
hasContiguousData() const539 MatrixHelper<S>::hasContiguousData() const {
540 return rep->hasContiguousData();
541 }
542 template <class S> ptrdiff_t
getContiguousDataLength() const543 MatrixHelper<S>::getContiguousDataLength() const {
544 assert(hasContiguousData());
545 return rep->nScalars();
546 }
547 template <class S> const S*
getContiguousData() const548 MatrixHelper<S>::getContiguousData() const {
549 assert(hasContiguousData());
550 return rep->m_data;
551 }
552 template <class S> S*
updContiguousData()553 MatrixHelper<S>::updContiguousData() {
554 assert(hasContiguousData());
555 return rep->m_data;
556 }
557 template <class S> void
replaceContiguousData(S * newData,ptrdiff_t length,bool takeOwnership)558 MatrixHelper<S>::replaceContiguousData(S* newData, ptrdiff_t length, bool takeOwnership) {
559 assert(length == getContiguousDataLength());
560 if (rep->m_owner) {
561 MatrixHelperRep<S>::deleteAllocatedMemory(rep->m_data);
562 rep->m_data=0;
563 }
564 rep->m_data = newData;
565 rep->m_owner = takeOwnership;
566 }
567 template <class S> void
replaceContiguousData(const S * newData,ptrdiff_t length)568 MatrixHelper<S>::replaceContiguousData(const S* newData, ptrdiff_t length) {
569 replaceContiguousData(const_cast<S*>(newData), length, false);
570 rep->m_writable = false;
571 }
572 template <class S> void
swapOwnedContiguousData(S * newData,ptrdiff_t length,S * & oldData)573 MatrixHelper<S>::swapOwnedContiguousData(S* newData, ptrdiff_t length, S*& oldData) {
574 assert(length == getContiguousDataLength());
575 assert(rep->m_owner);
576 oldData = rep->m_data;
577 rep->m_data = newData;
578 }
579
580
581
582
583 //----------------------------- MATRIX HELPER REP ------------------------------
584 //
585 //------------------------------------------------------------------------------
586
587 template <class S> MatrixHelperRep<S>*
createOwnerMatrixHelperRep(int esz,int cppEsz,const MatrixCharacter & want)588 MatrixHelperRep<S>::createOwnerMatrixHelperRep(int esz, int cppEsz, const MatrixCharacter& want) {
589 SimTK_ASSERT2((esz==1&&cppEsz==1) || (esz>1&&cppEsz>=esz),
590 "MatrixHelperRep::createOwnerMatrixHelperRep(): bad element size esz=%d, cppEsz=%d", esz, cppEsz);
591
592 MatrixHelperRep<S>* rep = 0;
593
594 const int nr = want.nrow();
595 const int nc = want.ncol();
596 const MatrixStructure& structure = want.getStructure();
597 const MatrixStorage& storage = want.getStorage();
598 const bool rowOrder = (storage.getOrder() == MatrixStorage::RowOrder);
599
600 switch (structure.getStructure()) {
601
602 case MatrixStructure::Full:
603 if (rowOrder)
604 rep = (esz == 1 ? (RegularFullHelper<S>*)new FullRowOrderScalarHelper<S>(nr,nc)
605 : (RegularFullHelper<S>*)new FullRowOrderEltHelper<S>(esz, cppEsz,nr,nc));
606 else
607 rep = (esz == 1 ? (RegularFullHelper<S>*)new FullColOrderScalarHelper<S>(nr,nc)
608 : (RegularFullHelper<S>*)new FullColOrderEltHelper<S>(esz, cppEsz,nr,nc));
609 break;
610
611 case MatrixStructure::Triangular:
612 case MatrixStructure::Symmetric:
613 case MatrixStructure::Hermitian:
614 case MatrixStructure::SkewSymmetric:
615 case MatrixStructure::SkewHermitian: {
616 const bool triangular = structure.getStructure() == MatrixStructure::Triangular;
617 const bool hermitian = structure.getStructure() == MatrixStructure::Hermitian
618 || structure.getStructure() == MatrixStructure::SkewHermitian;
619 const bool skew = structure.getStructure() == MatrixStructure::SkewSymmetric
620 || structure.getStructure() == MatrixStructure::SkewHermitian;
621
622 if (/*storage.getPlacement() == MatrixStorage::Upper*/true)
623 rep = (esz == 1 ? (TriInFullHelper<S>*)new TriInFullUpperHelper<S>(1,1,nr,nc,
624 triangular,hermitian,skew,rowOrder)
625 : (TriInFullHelper<S>*)new TriInFullUpperHelper<S>(esz,cppEsz,nr,nc,
626 triangular,hermitian,skew,rowOrder));
627 //else
628 // rep = (esz == 1 ? (TriInFullHelper<S>*)new TriInFullLowerHelper<S>(1,1,nr,nc,
629 // false,true,false,rowOrder)
630 // : (TriInFullHelper<S>*)new TriInFullLowerHelper<S>(esz,cppEsz,nr,nc,
631 // false,true,false,rowOrder));
632 break;
633 }
634
635 case MatrixStructure::Matrix1d: {
636 assert(nr==1 || nc==1);
637 const int length = nr*nc;
638 rep = (esz==1 ? (FullVectorHelper<S>*)new ContiguousVectorScalarHelper<S>(length,rowOrder)
639 : (FullVectorHelper<S>*)new ContiguousVectorHelper<S>(esz,cppEsz,length,rowOrder));
640 break;
641 }
642
643 default:
644 SimTK_ERRCHK1(!"not implemented", "MatrixHelperRep::createOwnerMatrixHelperRep()",
645 "Matrix structure commitment %s not implemented yet.",
646 MatrixStructure::name(structure.getStructure()));
647 }
648
649 return rep;
650 }
651
652
653 template <class S> MatrixHelperRep<S>*
createExternalMatrixHelperRep(int esz,int cppEsz,const MatrixCharacter & actual,int spacing,S * data,bool canWrite)654 MatrixHelperRep<S>::createExternalMatrixHelperRep
655 (int esz, int cppEsz, const MatrixCharacter& actual,
656 int spacing, S* data, bool canWrite)
657 {
658 SimTK_ASSERT2((esz==1&&cppEsz==1) || (esz>1&&cppEsz>=esz),
659 "MatrixHelperRep::createExternalMatrixHelperRep(): bad element size esz=%d, cppEsz=%d", esz, cppEsz);
660
661 MatrixHelperRep<S>* rep = 0;
662
663 const int nr = actual.nrow();
664 const int nc = actual.ncol();
665 const MatrixStructure& structure = actual.getStructure();
666 const MatrixStorage& storage = actual.getStorage();
667 const bool rowOrder = (storage.getOrder() == MatrixStorage::RowOrder);
668
669 switch (structure.getStructure()) {
670
671 case MatrixStructure::Full:
672 if (rowOrder)
673 rep = (esz == 1 ? (RegularFullHelper<S>*)new FullRowOrderScalarHelper<S>(nr,nc,
674 spacing,data,canWrite)
675 : (RegularFullHelper<S>*)new FullRowOrderEltHelper<S>(esz, cppEsz,nr,nc,
676 spacing,data,canWrite));
677 else
678 rep = (esz == 1 ? (RegularFullHelper<S>*)new FullColOrderScalarHelper<S>(nr,nc,
679 spacing,data,canWrite)
680 : (RegularFullHelper<S>*)new FullColOrderEltHelper<S>(esz, cppEsz,nr,nc,
681 spacing,data,canWrite));
682 break;
683
684 case MatrixStructure::Triangular:
685 case MatrixStructure::Symmetric:
686 case MatrixStructure::Hermitian:
687 case MatrixStructure::SkewSymmetric:
688 case MatrixStructure::SkewHermitian: {
689 const bool triangular = structure.getStructure() == MatrixStructure::Triangular;
690 const bool hermitian = structure.getStructure() == MatrixStructure::Hermitian
691 || structure.getStructure() == MatrixStructure::SkewHermitian;
692 const bool skew = structure.getStructure() == MatrixStructure::SkewSymmetric
693 || structure.getStructure() == MatrixStructure::SkewHermitian;
694
695 if (/*storage.getPlacement() == MatrixStorage::Upper*/true)
696 rep = (esz == 1 ? (TriInFullHelper<S>*)new TriInFullUpperHelper<S>(1,1,nr,nc,
697 triangular,hermitian,skew,rowOrder,
698 spacing,data,canWrite)
699 : (TriInFullHelper<S>*)new TriInFullUpperHelper<S>(esz,cppEsz,nr,nc,
700 triangular,hermitian,skew,rowOrder,
701 spacing,data,canWrite));
702 //else
703 // rep = (esz == 1 ? (TriInFullHelper<S>*)new TriInFullLowerHelper<S>(1,1,nr,nc,
704 // false,true,false,rowOrder)
705 // : (TriInFullHelper<S>*)new TriInFullLowerHelper<S>(esz,cppEsz,nr,nc,
706 // false,true,false,rowOrder));
707 break;
708 }
709
710 case MatrixStructure::Matrix1d: {
711 assert(nr==1 || nc==1);
712 const int length = nr*nc;
713 const int strideInElements = spacing/esz;
714 if (strideInElements > 1)
715 rep = (esz==1 ? (FullVectorHelper<S>*)new StridedVectorScalarHelper<S>(length,rowOrder,
716 strideInElements,data,canWrite)
717 : (FullVectorHelper<S>*)new StridedVectorHelper<S>(esz,cppEsz,length,rowOrder,
718 strideInElements,data,canWrite));
719 else
720 rep = (esz==1 ? (FullVectorHelper<S>*)new ContiguousVectorScalarHelper<S>(length,rowOrder,
721 data,canWrite)
722 : (FullVectorHelper<S>*)new ContiguousVectorHelper<S>(esz,cppEsz,length,rowOrder,
723 data,canWrite));
724 break;
725 }
726
727 default:
728 SimTK_ERRCHK1(!"not implemented", "MatrixHelperRep::createOwnerMatrixHelperRep()",
729 "Matrix structure commitment %s not implemented yet.",
730 MatrixStructure::name(structure.getStructure()));
731 }
732
733 return rep;
734 }
735
736 template <class S> void
scaleBy(const typename CNT<S>::StdNumber & s)737 MatrixHelperRep<S>::scaleBy(const typename CNT<S>::StdNumber& s) {
738 // XXX -- really, really bad! Optimize for contiguous data!
739 for (int j=0; j<ncol(); ++j)
740 for (int i=0; i<nrow(); ++i)
741 scaleElt(updElt(i,j),s);
742 }
743
744 template <class S> void
addIn(const MatrixHelper<S> & h)745 MatrixHelperRep<S>::addIn(const MatrixHelper<S>& h) {
746 const MatrixHelperRep& hrep = h.getRep();
747
748 assert(nrow()==hrep.nrow() && ncol()==hrep.ncol());
749 assert(getEltSize()==hrep.getEltSize());
750 // XXX -- really, really bad! Optimize for contiguous data, missing views, etc.!
751 for (int j=0; j<ncol(); ++j)
752 for (int i=0; i<nrow(); ++i)
753 addToElt(updElt(i,j),hrep.getElt(i,j));
754 }
755 template <class S> void
addIn(const MatrixHelper<typename CNT<S>::TNeg> & nh)756 MatrixHelperRep<S>::addIn(const MatrixHelper<typename CNT<S>::TNeg>& nh) {
757 subIn(reinterpret_cast<const MatrixHelper<S>&>(nh));
758 }
759
760 template <class S> void
subIn(const MatrixHelper<S> & h)761 MatrixHelperRep<S>::subIn(const MatrixHelper<S>& h) {
762 const MatrixHelperRep& hrep = h.getRep();
763
764 assert(nrow()==hrep.nrow() && ncol()==hrep.ncol());
765 assert(getEltSize()==hrep.getEltSize());
766 // XXX -- really, really bad! Optimize for contiguous data, missing views, etc.!
767 for (int j=0; j<ncol(); ++j)
768 for (int i=0; i<nrow(); ++i)
769 subFromElt(updElt(i,j),hrep.getElt(i,j));
770 }
771 template <class S> void
subIn(const MatrixHelper<typename CNT<S>::TNeg> & nh)772 MatrixHelperRep<S>::subIn(const MatrixHelper<typename CNT<S>::TNeg>& nh) {
773 addIn(reinterpret_cast<const MatrixHelper<S>&>(nh));
774 }
775
776 template <class S> void
fillWith(const S * eltp)777 MatrixHelperRep<S>::fillWith(const S* eltp) {
778 if (hasContiguousData()) {
779 const ptrdiff_t len = nelt();
780 if (getEltSize() == 1)
781 for (ptrdiff_t i = 0; i < len; i++)
782 m_data[i] = *eltp;
783 else
784 for (ptrdiff_t i = 0; i < len; i++)
785 for (int j = 0; j < getEltSize(); j++)
786 m_data[i*getEltSize()+j] = eltp[j];
787 }
788 else {
789 for (int j=0; j<ncol(); ++j)
790 for (int i=0; i<nrow(); ++i)
791 copyElt(updElt(i,j),eltp);
792 }
793 }
794
795 // We're copying data from a C++ row-oriented matrix into our general
796 // Matrix. In addition to the row ordering, C++ may use different spacing
797 // for elements than Simmatrix does. Lucky we know that value!
798 template <class S> void
copyInByRowsFromCpp(const S * elts)799 MatrixHelperRep<S>::copyInByRowsFromCpp(const S* elts) {
800 const int cppRowSz = m_cppEltSize * ncol();
801 // XXX -- really, really bad! Optimize for contiguous data, missing views, etc.!
802 for (int j=0; j<ncol(); ++j)
803 for (int i=0; i<nrow(); ++i)
804 copyElt(updElt(i,j), elts + i*cppRowSz + j*m_cppEltSize);
805 }
806
807 template <class S>
~MatrixHelperRep()808 MatrixHelperRep<S>::~MatrixHelperRep()
809 {
810 if (isOwner())
811 deleteAllocatedMemory(m_data);
812 }
813
814 template <class S> static void
dumpElt(const S * p,int sz)815 dumpElt(const S* p, int sz) {
816 if (sz > 1) std::cout << "{";
817 for (int k=0; k<sz; ++k) {
818 if (k>0) std::cout << " ";
819 std::cout << *p++;
820 }
821 if (sz > 1) std::cout << "}";
822 }
823
824 template <class S> void
dump(const char * msg) const825 MatrixHelperRep<S>::dump(const char* msg) const {
826 if (msg)
827 std::cout << std::string(msg) << std::endl;
828 std::cout << "Matrix " << nrow() << " X " << ncol() << " "
829 << getEltSize() << "-scalar entries:" << std::endl;
830 if (nrow()*ncol() == 0) {
831 std::cout << "<EMPTY>" << std::endl;
832 return;
833 }
834
835 S* elt = new S[getEltSize()];
836 const std::streamsize oldsz = std::cout.precision(20);
837 for (int i=0; i<nrow(); ++i) {
838 for (int j=0; j<ncol(); ++j) {
839 if (j>0) std::cout << "\t";
840 getAnyElt(i,j,elt);
841 dumpElt(elt, getEltSize());
842 }
843 std::cout << std::endl;
844 }
845 std::cout.precision(oldsz);
846 delete[] elt;
847 }
848
849 //----------------------------- RegularFullHelper ------------------------------
850 //------------------------------------------------------------------------------
851
852 template <class S> VectorHelper<S>*
createDiagonalView_()853 RegularFullHelper<S>::createDiagonalView_() {
854 VectorHelper<S>* p = 0;
855 const int length = std::min(this->nrow(), this->ncol());
856 S* data = length ? this->updElt_(0,0) : 0;
857
858 const int strideInScalars = length > 1 ? int(this->getElt_(1,1) - this->getElt_(0,0))
859 : this->m_eltSize;
860 const int strideInElements = strideInScalars / this->m_eltSize;
861
862 // No need for a stride if there's 0 or 1 element, or if the stride is 1. TODO: scalar helper
863 if (strideInElements == 1) {
864 p = (this->m_eltSize==1)
865 ? (VectorHelper<S>*)new ContiguousVectorScalarHelper<S>(length, false, data, false)
866 : (VectorHelper<S>*)new ContiguousVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
867 length, false, data, false);
868 return p;
869 }
870
871 p = (this->m_eltSize==1)
872 ? (VectorHelper<S>*)new StridedVectorScalarHelper<S>(length, false, strideInElements, data, false)
873 : (VectorHelper<S>*)new StridedVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
874 length, false, strideInElements, data, false);
875 return p;
876 }
877
878 template <class S> VectorHelper<S>*
createColumnView_(int j,int i,int m)879 RegularFullHelper<S>::createColumnView_(int j, int i, int m) {
880 VectorHelper<S>* p = 0;
881 S* data = m ? this->updElt_(i,j) : 0;
882
883 const int strideInScalars = m > 1 ? int(this->getElt_(i+1,j) - this->getElt_(i,j)) : this->m_eltSize;
884 const int strideInElements = strideInScalars / this->m_eltSize;
885
886 // No need for a stride if there's 0 or 1 element, or if the stride is 1. TODO: scalar helper
887 if (strideInElements == 1) {
888 p = (this->m_eltSize==1)
889 ? (VectorHelper<S>*)new ContiguousVectorScalarHelper<S>(m, false, data, false)
890 : (VectorHelper<S>*)new ContiguousVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
891 m, false, data, false);
892 return p;
893 }
894
895 p = (this->m_eltSize==1)
896 ? (VectorHelper<S>*)new StridedVectorScalarHelper<S>(m, false, strideInElements, data, false)
897 : (VectorHelper<S>*)new StridedVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
898 m, false, strideInElements, data, false);
899 return p;
900 }
901
902 template <class S> VectorHelper<S>*
createRowView_(int i,int j,int n)903 RegularFullHelper<S>::createRowView_(int i, int j, int n) {
904 VectorHelper<S>* p = 0;
905 S* data = n ? this->updElt_(i,j) : 0;
906
907 const int strideInScalars = n > 1 ? int(this->getElt_(i,j+1) - this->getElt_(i,j))
908 : this->m_eltSize;
909 const int strideInElements = strideInScalars / this->m_eltSize;
910
911 // No need for a stride if there's 0 or 1 element, or if the stride is 1. TODO: scalar helper
912 if (strideInElements == 1) {
913 p = (this->m_eltSize==1)
914 ? (VectorHelper<S>*)new ContiguousVectorScalarHelper<S>(n, true, data, false)
915 : (VectorHelper<S>*)new ContiguousVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
916 n, true, data, false);
917 return p;
918 }
919
920 p = (this->m_eltSize==1)
921 ? (VectorHelper<S>*)new StridedVectorScalarHelper<S>(n, true, strideInElements, data, false)
922 : (VectorHelper<S>*)new StridedVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
923 n, true, strideInElements, data, false);
924 return p;
925 }
926
927
928 //------------------------------ TriInFullHelper -------------------------------
929 //------------------------------------------------------------------------------
930
931 template <class S> VectorHelper<S>*
createDiagonalView_()932 TriInFullHelper<S>::createDiagonalView_() {
933 SimTK_ERRCHK_ALWAYS(!hasKnownDiagonal(), "TriInFullHelper::createDiagonalView_()",
934 "Diagonal view of a known-diagonal matrix is not yet implemented. Sorry.");
935
936 VectorHelper<S>* p = 0;
937 const int length = std::min(this->nrow(), this->ncol());
938 S* data = length ? this->updElt_(0,0) : 0;
939
940 const int strideInScalars = length > 1 ? int(this->getElt_(1,1) - this->getElt_(0,0))
941 : this->m_eltSize;
942 const int strideInElements = strideInScalars / this->m_eltSize;
943
944 // No need for a stride if there's 0 or 1 element, or if the stride is 1. TODO: scalar helper
945 if (strideInElements == 1) {
946 p = (this->m_eltSize==1)
947 ? (VectorHelper<S>*)new ContiguousVectorScalarHelper<S>(length, false, data, false)
948 : (VectorHelper<S>*)new ContiguousVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
949 length, false, data, false);
950 return p;
951 }
952
953 p = (this->m_eltSize==1)
954 ? (VectorHelper<S>*)new StridedVectorScalarHelper<S>(length, false, strideInElements, data, false)
955 : (VectorHelper<S>*)new StridedVectorHelper<S>(this->m_eltSize, this->m_cppEltSize,
956 length, false, strideInElements, data, false);
957 return p;
958 }
959
960 //------------------------------ INSTANTIATIONS --------------------------------
961 // Instantiations for each of the 12 Scalar types.
962 // It isn't actually necessary to instantiate these classes since they
963 // are only used internally. However, this is a good way to make sure that
964 // everything supplied at least compiles. Otherwise you won't find errors
965 // until all the code is actually used.
966
967 #define INSTANTIATE(Helper) \
968 template class Helper< float >; \
969 template class Helper< double >; \
970 template class Helper< std::complex<float> >; \
971 template class Helper< std::complex<double> >; \
972 template class Helper< conjugate<float> >; \
973 template class Helper< conjugate<double> >; \
974 template class Helper< negator< float > >; \
975 template class Helper< negator< double > >; \
976 template class Helper< negator< std::complex<float> > >; \
977 template class Helper< negator< std::complex<double> > >; \
978 template class Helper< negator< conjugate<float> > >; \
979 template class Helper< negator< conjugate<double> > >
980
981 INSTANTIATE(MatrixHelper);
982 INSTANTIATE(MatrixHelperRep);
983
984 INSTANTIATE(FullHelper);
985 INSTANTIATE(RegularFullHelper);
986
987 INSTANTIATE(TriHelper);
988
989 INSTANTIATE(VectorHelper);
990 INSTANTIATE(FullVectorHelper);
991 INSTANTIATE(ContiguousVectorHelper);
992 INSTANTIATE(ContiguousVectorScalarHelper);
993 INSTANTIATE(StridedVectorHelper);
994 INSTANTIATE(StridedVectorScalarHelper);
995 INSTANTIATE(IndexedVectorHelper);
996
997 } // namespace SimTK
998