1 #ifndef SimTK_SIMMATRIX_MATRIX_CHARACTERISTICS_H_
2 #define SimTK_SIMMATRIX_MATRIX_CHARACTERISTICS_H_
3 
4 /* -------------------------------------------------------------------------- *
5  *                       Simbody(tm): SimTKcommon                             *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from           *
8  * Simbios, the NIH National Center for Physics-Based Simulation of           *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
11  *                                                                            *
12  * Portions copyright (c) 2005-13 Stanford University and the Authors.        *
13  * Authors: Michael Sherman                                                   *
14  * Contributors:                                                              *
15  *                                                                            *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
17  * not use this file except in compliance with the License. You may obtain a  *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
19  *                                                                            *
20  * Unless required by applicable law or agreed to in writing, software        *
21  * distributed under the License is distributed on an "AS IS" BASIS,          *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
23  * See the License for the specific language governing permissions and        *
24  * limitations under the License.                                             *
25  * -------------------------------------------------------------------------- */
26 
27 /** @file
28  *
29  * Here we declare the classes needed for managing the properties of matrices,
30  * which we call Matrix Characteristics.
31  */
32 
33 #include "SimTKcommon/Scalar.h"
34 
35 #include <iostream>
36 #include <cassert>
37 #include <complex>
38 #include <cstddef>
39 #include <utility> // for std::pair
40 
41 namespace SimTK {
42 
43 
44 class MatrixStructure;
45 class MatrixStorage;
46 class MatrixOutline;
47 class MatrixCondition;
48 class MatrixCharacter;
49 class MatrixCommitment;
50 
51 
52 //  ------------------------------ MatrixStructure -----------------------------
53 /// Matrix "structure" refers to an inherent mathematical (or at least
54 /// algorithmic) characteristic of the matrix rather than a storage strategy.
55 /// Symmetry is the clearest example of this; it is far more significant
56 /// mathematically than just a way to save storage and reduce operation count.
57 //  ----------------------------------------------------------------------------
58 class SimTK_SimTKCOMMON_EXPORT MatrixStructure {
59 public:
60     enum Structure {
61         NoStructure      = 0x00000000,  ///< unspecified structure
62         Matrix1d         = 0x00000001,  ///< a 1-d matrix (could be row or column)
63         Zero             = 0x00000002,  ///< a matrix of all zeroes
64         Identity         = 0x00000004,  ///< diagonal matrix with repeated 1's
65         Permutation      = 0x00000008,  ///< permutation of an identity matrix
66         RepeatedDiagonal = 0x00000010,  ///< diagonal matrix with repeated element
67         Diagonal         = 0x00000020,  ///< diagonal matrix with arbitrary elements
68         BiDiagonal       = 0x00000040,  ///< diagonal plus one upper or lower band
69         TriDiagonal      = 0x00000080,  ///< diagonal plus one upper and one lower band
70         BandedSymmetric  = 0x00000100,  ///< diagonal plus adjacent symmetric bands
71         BandedHermitian  = 0x00000200,  ///< diagonal plus adjacent conjugate bands
72         Banded           = 0x00000400,  ///< diagonal plus upper and lower bands
73         Triangular       = 0x00000800,  ///< diagonal plus all upper or all lower bands
74         QuasiTriangular  = 0x00001000,  ///< triangular but with 2x2 blocks on the diagonal
75         Hessenberg       = 0x00002000,  ///< triangular plus one band above/below diagonal
76         Symmetric        = 0x00004000,  ///< symmetric: elt(i,j)==elt(j,i)
77         Hermitian        = 0x00008000,  ///< hermitian: elt(i,j)==conjugate(elt(j,i))
78         SkewSymmetric    = 0x00010000,  ///< skew symmetric: elt(i,j) == -elt(j,i)
79         SkewHermitian    = 0x00020000,  ///< skew hermitian: elt(i,j) == -conjugate(elt(j,i))
80         Full             = 0x00040000   ///< full mxn matrix, all elements distinct
81     };
82     static const char* name(Structure);
83 
84     typedef unsigned int StructureMask; // 32 bits
85     static const StructureMask AnyStructure         = 0x0007ffffU; // see above
86     static const StructureMask UncommittedStructure = 0xffffffffU;
87     static StructureMask calcStructureMask(Structure);
88 
89     /// For triangular matrices, we have to know which triangle
90     /// we're talking about. Don't confuse this with MatrixStorage::Placement
91     /// which has to do with where we put it in memory, *not* what
92     /// matrix is being represented.
93     enum Position {
94         NoPosition = 0x0000,
95         Lower      = 0x0001,  // matrix is lower triangular (default)
96         Upper      = 0x0002   // matrix is upper triangular
97     };
98     static const char* name(Position);
99 
100     typedef unsigned short PositionMask; // 16 bits
101     static const PositionMask AnyPosition         = 0x0003U;  // see above
102     static const PositionMask UncommittedPosition = 0xffffU;
103     static PositionMask calcPositionMask(Structure);
104 
105     /// For triangular, symmetric, and hermitian matrices the diagonal elements
106     /// may have a single, assumed value rather than being stored in memory.
107     /// This specifies the value. Don't confuse this with the similar
108     /// MatrixStorage type which simply says whether there is a known value
109     /// rather than stored values, *not* what that value is.
110     enum DiagValue {
111         NoDiagValue = 0x0000,
112         StoredDiag  = 0x0001, // could be anything (default)
113         ZeroDiag    = 0x0002, // zero (e.g. for skew matrices)
114         UnitDiag    = 0x0004  // unit (one) diagonal is used frequently by Lapack
115     };
116     static const char* name(DiagValue);
117 
118     typedef unsigned short DiagValueMask; // 16 bits
119     static const DiagValueMask AnyDiagValue         = 0x0003U;
120     static const DiagValueMask UncommittedDiagValue = 0xffffU;
121     static DiagValueMask calcDiagValueMask(Structure);
122 
setMissingAttributes()123     MatrixStructure& setMissingAttributes() {
124         if (structure == NoStructure)
125             structure = Full;
126         if (position == NoPosition)
127             position = Lower;
128         if (diagValue == NoDiagValue)
129             diagValue = StoredDiag;
130         return *this;
131     }
132 
name()133     std::string name() const {
134         return std::string(name(getStructure()))
135             + "|" + std::string(name(getPosition()))
136             + "|" + std::string(name(getDiagValue()));
137     }
138 
139     struct Mask {
MaskMask140         Mask() {setToUncommitted();}
MaskMask141         Mask(StructureMask sm, PositionMask pm, DiagValueMask dm)
142         :   structure(sm), position(pm), diagValue(dm) {}
setToUncommittedMask143         Mask& setToUncommitted()
144         {   structure=UncommittedStructure; position=UncommittedPosition;
145             diagValue=UncommittedDiagValue; return *this; }
isUncommittedMask146         bool isUncommitted() const
147         {   return structure==UncommittedStructure && position==UncommittedPosition
148                 && diagValue==UncommittedDiagValue; }
isSatisfiedByMask149         bool isSatisfiedBy(Structure str, Position pos, DiagValue diag) const
150         {   return ((StructureMask)str&structure)==(StructureMask)str
151                 && ((PositionMask)pos&position)==(PositionMask)pos
152                 && ((DiagValueMask)diag&diagValue)==(DiagValueMask)diag; }
isSatisfiedByMask153         bool isSatisfiedBy(const MatrixStructure& actual) const
154         {  return isSatisfiedBy(actual.getStructure(), actual.getPosition(),
155                                 actual.getDiagValue()); }
156 
157         StructureMask  structure;
158         PositionMask   position;
159         DiagValueMask  diagValue;
160     };
161 
MatrixStructure()162     MatrixStructure() {setToNone();}
163 
164     /// This constructor is also an implicit conversion from the Structure enum
165     /// to a MatrixStructure object which does not specify Position or DiagValue.
166     MatrixStructure(Structure s, Position p=NoPosition, DiagValue d=NoDiagValue)
structure(s)167         :   structure(s), position(p), diagValue(d) {}
168 
169     /// Given a Structure commitment, which more-restrictive Structures will
170     /// still satisfy this commitment? Returned value is a mask with a bit
171     /// set for every Structure that is satisfactory. For example, if the
172     /// commitment is "Banded", "Diagonal" is also acceptable.
173     Mask mask() const;
174 
getStructure()175     Structure   getStructure() const {return structure;}
getPosition()176     Position    getPosition()  const {return position;}
getDiagValue()177     DiagValue   getDiagValue() const {return diagValue;}
178 
setStructure(Structure s)179     MatrixStructure& setStructure(Structure s) {structure=s; return *this;}
setPosition(Position p)180     MatrixStructure& setPosition (Position  p) {position=p; return *this;}
setDiagValue(DiagValue d)181     MatrixStructure& setDiagValue(DiagValue d) {diagValue=d; return *this;}
182 
set(Structure s,Position p,DiagValue d)183     MatrixStructure& set(Structure s, Position p, DiagValue d)
184     {   structure=s; position=p; diagValue=d; return *this; }
185 
setToNone()186     MatrixStructure& setToNone()
187     {   structure=NoStructure; position=NoPosition;
188         diagValue=NoDiagValue; return *this; }
189 
190 private:
191     Structure  structure:32;
192     Position   position:16;
193     DiagValue  diagValue:16;
194 };
195 
196 
197 //  ------------------------------ MatrixStorage -------------------------------
198 /// Matrix "storage" refers to the physical layout of data in the computer's
199 /// memory. Whenever possible we attempt to store data in a format that enables
200 /// use of special high performance methods, such as those available in the
201 /// SimTK LAPACK/BLAS implementation.
202 //  ----------------------------------------------------------------------------
203 class SimTK_SimTKCOMMON_EXPORT MatrixStorage {
204 public:
205     enum Packing {
206         NoPacking    = 0x0000,
207         Full         = 0x0001,  // full storage layout
208         TriInFull    = 0x0002,  // a triangular piece of a full storage layout
209         TriPacked    = 0x0004,  // triangle packed into minimal storage, at performance cost
210         Banded       = 0x0008,  // a packed, banded storage format
211         Vector       = 0x0010,  // a possibly-strided or scattered vector
212         Scalar       = 0x0020,  // a single scalar is stored
213         Permutation  = 0x0040   // a permuted identity matrix
214     };
215     static const char* name(Packing);
216     typedef unsigned short PackingMask;
217     static const PackingMask AllPacking = 0x007fU; // see above
218     static const PackingMask UncommittedPacking = 0xffffU;
219 
220     enum Placement {
221         NoPlacement  = 0x0000,
222         Lower        = 0x0001,  // stored in lower triangle of full matrix
223         Upper        = 0x0002,  // stored in upper triangle of full matrix
224     };
225     static const char* name(Placement);
226     typedef unsigned short PlacementMask;
227     static const PlacementMask AllPlacement = 0x0003U; // see above
228     static const PlacementMask UncommittedPlacement = 0xffffU;
229 
230     enum Order {
231         NoOrder      = 0x0000,
232         ColumnOrder  = 0x0001,  // matrix is stored by columns
233         RowOrder     = 0x0002,  // matrix is stored by rows
234     };
235     static const char* name(Order);
236     typedef unsigned short OrderMask;
237     static const OrderMask AllOrder = 0x03U; // see above
238     static const OrderMask UncommittedOrder = 0xffU;
239 
240     enum Diagonal {
241         NoDiag       = 0x0000,
242         StoredDiag   = 0x0001,  // matrix diagonal is stored
243         AssumedDiag  = 0x0002   // matrix diagonal is not stored but has known value
244     };
245     static const char* name(Diagonal);
246     typedef unsigned short DiagonalMask;
247     static const DiagonalMask AllDiagonal = 0x0003U; // see above
248     static const DiagonalMask UncommittedDiagonal = 0xffffU;
249 
250     /// Use this class to represent sets of acceptable values for each of
251     /// the storage attributes (packing, position, order, diagonal).
252     struct Mask {
MaskMask253         Mask()
254         :   packing(UncommittedPacking), placement(UncommittedPlacement),
255             order(UncommittedOrder), diagonal(UncommittedDiagonal) {}
MaskMask256         Mask(PackingMask pkm, PlacementMask plm, OrderMask om, DiagonalMask dm)
257         :   packing(pkm), placement(plm), order(om), diagonal(dm) {}
setToUncommittedMask258         Mask& setToUncommitted()
259         {   packing=UncommittedPacking; placement=UncommittedPlacement;
260             order=UncommittedOrder;     diagonal=UncommittedDiagonal; return *this; }
isUncommittedMask261         bool isUncommitted() const
262         {   return packing==UncommittedPacking && placement==UncommittedPlacement
263                 && order==UncommittedOrder     && diagonal==UncommittedDiagonal; }
isSatisfiedByMask264         bool isSatisfiedBy(Packing pack, Placement place, Order ord, Diagonal diag) const
265         {   return ((PackingMask)pack    & packing)   == (PackingMask)  pack
266                 && ((PlacementMask)place & placement) == (PlacementMask)place
267                 && ((OrderMask)ord       & order)     == (OrderMask)    ord
268                 && ((DiagonalMask)diag   & diagonal)  == (DiagonalMask) diag; }
isSatisfiedByMask269         bool isSatisfiedBy(const MatrixStorage& actual) const
270         {   return isSatisfiedBy(actual.getPacking(), actual.getPlacement(),
271                                  actual.getOrder(),   actual.getDiagonal());}
272 
273         PackingMask   packing;
274         PlacementMask placement;
275         OrderMask     order;
276         DiagonalMask  diagonal;
277     };
278 
279     static MatrixStorage calcDefaultStorage(const MatrixStructure&,
280                                             const MatrixOutline&);
281 
name()282     std::string name() const {
283         return std::string(name(getPacking()))
284             + "|" + std::string(name(getPlacement()))
285             + "|" + std::string(name(getOrder()))
286             + "|" + std::string(name(getDiagonal()));
287     }
288 
289     /// Calculate the commitment mask associated with specifying "this" set
290     /// of storage attributes as a commitment. Here the mask will either be
291     /// fully uncommitted or set to a specific value for each attribute; they
292     /// are all mutually exclusive.
mask()293     Mask mask() const {
294         Mask ms; // initially uncommitted
295         if (packing)   ms.packing   = (PackingMask)packing;
296         if (placement) ms.placement = (PlacementMask)placement;
297         if (order)     ms.order     = (OrderMask)order;
298         if (diagonal)  ms.diagonal  = (DiagonalMask)diagonal;
299         return ms;
300     }
301 
302     /// Default constructor leaves all fields unspecified.
MatrixStorage()303     MatrixStorage()
304     :   packing(NoPacking), placement(NoPlacement), order(NoOrder), diagonal(NoDiag) {}
305 
306     /// This constructor is also an implicit conversion from the Packing enum to a
307     /// MatrixStorage object which does not contain any specification for placement,
308     /// order, or storage of diagonal elements.
309     MatrixStorage(Packing pk, Placement pl=NoPlacement, Order o=NoOrder, Diagonal d=NoDiag)
packing(pk)310     :   packing(pk), placement(pl), order(o), diagonal(d) {}
311 
312     /// This constructor is for the common case of just packing and order, with
313     /// no particular placement and a stored diagonal.
MatrixStorage(Packing pk,Order o)314     MatrixStorage(Packing pk, Order o)
315     :   packing(pk), placement(NoPlacement), order(o), diagonal(StoredDiag) {}
316 
317     /// Assuming this is an actual matrix description, set any unspecified attributes
318     /// to appropriate defaults to match the specified packing.
setMissingAttributes()319     MatrixStorage& setMissingAttributes() {
320         if (packing==NoPacking)
321             packing = Full;
322         if (placement==NoPlacement)
323             placement = Lower;
324         if (order==NoOrder)
325             order = ColumnOrder;
326         if (diagonal==NoDiag)
327             diagonal = StoredDiag;
328         return *this;
329     }
330 
331     /// Restore this object to its default-constructed state of "none".
setToNone()332     MatrixStorage& setToNone()
333     {   packing=NoPacking; placement=NoPlacement;
334         order=NoOrder;     diagonal=NoDiag; return *this; }
335 
setPacking(Packing p)336     MatrixStorage& setPacking(Packing p)     {packing   = p; return *this;}
setPlacement(Placement p)337     MatrixStorage& setPlacement(Placement p) {placement = p; return *this;}
setOrder(Order o)338     MatrixStorage& setOrder(Order o)         {order     = o; return *this;}
setDiagonal(Diagonal d)339     MatrixStorage& setDiagonal(Diagonal d)   {diagonal  = d; return *this;}
340 
getPacking()341     Packing   getPacking()   const {return packing;}
getPlacement()342     Placement getPlacement() const {return placement;}
getOrder()343     Order     getOrder()     const {return order;}
getDiagonal()344     Diagonal  getDiagonal()  const {return diagonal;}
345 
346 private:
347     Packing   packing:16;
348     Placement placement:16;
349     Order     order:16;
350     Diagonal  diagonal:16;
351 };
352 
353 
354 //  ------------------------------- MatrixOutline ------------------------------
355 /// Matrix "outline" refers to the characteristic relationship between the number
356 /// of rows and columns of a matrix, without necessarily specifying the absolute
357 /// dimensions.
358 ///
359 /// There are seven possible outline attributes:
360 /// - Rectangular (any m x n)
361 /// - Tall (m >= n)
362 /// - Wide (m <= n)
363 /// - Square (m == n)
364 /// - Column (m x 1)
365 /// - Row (1 x n)
366 /// - Scalar (1 x 1)
367 ///
368 /// A matrix handle with no outline commitment can hold a general (rectangular)
369 /// matrix, which of course includes all the other outlines as well. Vector
370 /// handles are always committed to column outline, RowVector handles to row
371 /// outline. Scalar matrices are also rows, columns, and square and some
372 /// rows and columns are square (if they are 1x1).
373 ///
374 /// Note that certain outlines imply fixed sizes of one or both dimensions.
375 //  ----------------------------------------------------------------------------
376 class SimTK_SimTKCOMMON_EXPORT MatrixOutline {
377 public:
378     enum Outline {
379         NoOutline   = 0x0000,
380         Scalar      = 0x0001,    // 1x1
381         Column      = 0x0002,    // mx1, m != 1
382         Row         = 0x0004,    // 1xn, n != 1
383         Square      = 0x0008,    // mxn, m == n
384         Wide        = 0x0010,    // mxn, m < n
385         Tall        = 0x0020,    // mxn, m > n
386         Rectangular = 0x0040     // mxn
387     };
388     static const char* name(Outline);
389 
390     typedef unsigned short OutlineMask;
391     static const OutlineMask AnyOutline  = 0x007fU; // see above
392     static const OutlineMask UncommittedOutline = 0xffffU;
393 
394     struct Mask {
MaskMask395         Mask() : outline(UncommittedOutline) {}
MaskMask396         explicit Mask(OutlineMask mask) : outline(mask) {}
setToUncommittedMask397         Mask& setToUncommitted() {outline=UncommittedOutline; return *this;}
isUncommittedMask398         bool isUncommitted() const {return outline==UncommittedOutline;}
isSatisfiedByMask399         bool isSatisfiedBy(const MatrixOutline& actual) const
400         {  return ((OutlineMask)actual.outline & outline) == (OutlineMask)actual.outline; }
401 
402         OutlineMask outline;
403     };
404 
name()405     std::string name() const {return std::string(name(getOutline()));}
406 
407     /// Default constructor produces an object containing no outline specification.
408     /// If used as a commitment it won't accept \e any outline!
MatrixOutline()409     MatrixOutline() : outline(NoOutline) {}
410 
411     /// This is an implicit conversion from the Outline enum to a MatrixOutline object.
MatrixOutline(Outline outline)412     MatrixOutline(Outline outline) : outline(outline) {}
413 
414     /// Set the outline back to its default-constructed value of "none".
setToNone()415     MatrixOutline& setToNone() {outline=NoOutline; return *this;}
416 
417     /// Compute a mask of acceptable Outline values given a particular
418     /// value specified as a commitment. For example, if the commitment
419     /// is "Wide" then Square, Row, and Scalar outlines are also acceptable.
420     static OutlineMask calcMask(Outline);
421 
422     /// When "this" outline is used as a commitment, it represents a mask of
423     /// acceptable outlines. Calculate and return that mask.
mask()424     Mask mask() const {return Mask(calcMask(getOutline()));}
425 
426     /// Determine if the proposed shape satisfies this outline.
427     bool isSizeOK(int m, int n) const;
428 
429     /// Return the minimum shape that will satisfy this outline.
430     void getMinimumSize(int& m, int& n) const;
431 
432     /// Determine the outline from given actual dimensions.
433     static MatrixOutline calcFromSize(int m, int n);
434 
435     /// Return the outline value stored in this MatrixOutline object.
getOutline()436     Outline getOutline() const {return outline;}
437 
438 private:
439     Outline outline:16;
440 };
441 
442 
443 
444 //  ---------------------------- MatrixCondition -------------------------------
445 /// Matrix "condition" is a statement about the numerical characteristics of a
446 /// Matrix. It can be set as a result of an operation, or by a knowledgeable user.
447 /// Simmatrix is entitled to rely on the correctness of these assertions,
448 /// although it will try to check them if requested or when it is possible to do
449 /// so without sacrificing performance.
450 /// In most cases the condition will not be set at all, which we interpret to
451 /// mean "unknown condition" in an actual character, and "uncommitted" in
452 /// a character commitment.
453 //  ----------------------------------------------------------------------------
454 class SimTK_SimTKCOMMON_EXPORT MatrixCondition {
455 public:
456     enum Condition {
457         UnknownCondition = 0x0000,
458         Orthogonal       = 0x0001, // implies well conditioned
459         PositiveDefinite = 0x0002, // implies well conditioned
460         WellConditioned  = 0x0004, // implies full rank
461         FullRank         = 0x0008, // but might have bad conditioning
462         Singular         = 0x0010  // implies possible bad conditioning
463     };
464     static const char* name(Condition);
465 
466     typedef unsigned short ConditionMask;   // 16 bits in mask
467     static const ConditionMask AnyCondition          = 0x001fU;  // see above
468     static const ConditionMask UncommittedCondition  = 0xffffU;
469 
470     enum Diagonal {
471         UnknownDiagonal   = 0x0000,   ///< we don't know the condition of the diagonal elements
472         ZeroDiagonal      = 0x0001,   ///< all diagonal elements are zero (also pure real and pure imaginary)
473         OneDiagonal       = 0x0002,   ///< all diagonal elements are one (and real)
474         RealDiagonal      = 0x0004,   ///< all diagonal elements are pure real
475         ImaginaryDiagonal = 0x0008    ///< all diagonal elements are pure imaginary
476     };
477     static const char* name(Diagonal);
478 
479     typedef unsigned short DiagonalMask;   // 16 bits in mask
480     static const DiagonalMask AnyDiagonal          = 0x000fU;  // see above
481     static const DiagonalMask UncommittedDiagonal  = 0xffffU;
482 
483     /// Use this class to represent a set of acceptable Condition values.
484     struct Mask {
MaskMask485         Mask() : condition(UncommittedCondition), diagonal(UncommittedDiagonal) {}
MaskMask486         Mask(ConditionMask cmask, DiagonalMask dmask) : condition(cmask), diagonal(dmask) {}
setToUncommittedMask487         Mask& setToUncommitted()
488         {   condition=UncommittedCondition; diagonal=UncommittedDiagonal; return *this;}
isUncommittedMask489         bool isUncommitted() const
490         {   return condition==UncommittedCondition && diagonal==UncommittedDiagonal;}
isSatisfiedByMask491         bool isSatisfiedBy(const MatrixCondition& actual) const
492         {   return ((ConditionMask)actual.condition & condition) == (ConditionMask)actual.condition
493                 && ((DiagonalMask) actual.diagonal  & diagonal)  == (DiagonalMask)actual.diagonal; }
494 
495         ConditionMask   condition;
496         DiagonalMask    diagonal;
497     };
498 
name()499     std::string name() const
500     {   return std::string(name(getCondition())) + "|" + std::string(name(getDiagonal()));}
501 
502     /// The default constructor sets the condition to Unknown, which is typically
503     /// where it remains.
MatrixCondition()504     MatrixCondition() : condition(UnknownCondition), diagonal(UnknownDiagonal) {}
505 
506     /// This is an implicit conversion from the Condition enum to a
507     /// MatrixCondition object.
508     MatrixCondition(Condition cond, Diagonal diag=UnknownDiagonal)
condition(cond)509     :   condition(cond), diagonal(diag) {}
510 
511     /// Restore to default-constructed state of "none".
setToNone()512     MatrixCondition& setToNone() {condition=UnknownCondition; diagonal=UnknownDiagonal; return *this;}
513 
514     /// Given a particular Condition provided as a commitment, calculate
515     /// the mask of all Condition values that would satisfy that commitment.
516     /// For example, if the commitment is "WellConditioned" then "Orthogonal"
517     /// and "PositiveDefinite" also qualify since they are automatically
518     /// well conditioned. If the Condition is "Unknown" we'll return an Uncommitted mask.
519     static ConditionMask calcMask(Condition);
520 
521     /// Given a particular Diagonal condition provided as a commitment, calculate
522     /// the mask of all Diagonal conditions that would satisfy that commitment.
523     /// For example, if the commitment is "RealDiagonal" then "ZeroDiagonal"
524     /// and "OneDiagonal" would also be acceptable. If the Diagonal condition
525     /// is specified as "UnknownDiagonal" then we'll return an Uncommitted mask.
526     static DiagonalMask calcMask(Diagonal);
527 
528     /// Return the commitment mask corresponding to use of "this" condition
529     /// as a commitment.
mask()530     Mask mask() const
531     {   return Mask(calcMask(getCondition()), calcMask(getDiagonal())); }
532 
getCondition()533     Condition getCondition() const {return condition;}
getDiagonal()534     Diagonal  getDiagonal()  const {return diagonal;}
535 
setCondition(Condition c)536     MatrixCondition& setCondition(Condition c) {condition=c; return *this;}
setDiagonal(Diagonal d)537     MatrixCondition& setDiagonal (Diagonal d)  {diagonal=d; return *this;}
538 
539 private:
540     Condition condition:16;
541     Diagonal  diagonal:16;
542 };
543 
544 
545 
546 //  ------------------------------ MatrixCharacter -----------------------------
547 /** A MatrixCharacter is a set containing a value for each of the matrix
548 characteristics except element type, which is part of the templatized
549 declaration of a Matrix_, Vector_, or RowVector_ handle. MatrixCharacters are
550 used both as the handle "commitment", setting restrictions on what kinds
551 of matrices a handle can reference, and as the "facts on the ground" current
552 character of the matrix being referenced. The current character must always
553 satisfy the character commitment.
554 
555 %Matrix characteristics are specifications of particular aspects of matrices:
556  - Element type
557  - Size
558  - Structure
559  - Storage format
560  - Outline
561  - Conditioning
562 
563 Collectively, the set of values for the above properties is called a <i>matrix
564 character</i>. A matrix character can be used to describe an existing matrix,
565 or a character mask can be used to describe the range of characteristics that
566 a matrix handle may support. The  character mask describing the acceptable
567 matrices for a matrix handle is called the handle's <i>character commitment</i>
568 or just the <i>handle commitment</i>. The character describing an existing
569 matrix is called the <i>actual character</i> of that matrix. Thus there are
570 always two sets of characteristics associated with a matrix: the handle's
571 commitment, and the actual character of the matrix to which the handle currently
572 refers. The actual character must always \e satisfy the character commitment.
573 
574 When a handle presents a view into another handle's data, it is the
575 characteristics of the matrix as seen through the view that must satisfy the
576 handle's character commitment. So for example, a view showing one column of a
577 full matrix satisfies a "column" outline commitment.
578 
579 Element type for a matrix handle is always determined at compile time via the
580 template argument used in the declaration. For example, a matrix handle declared
581 \c Matrix_<Vec3> can only hold matrices whose elements are \c Vec3s. Also,
582 recall that \c Matrix is an abbreviation for \c Matrix_<Real> so that
583 declaration commits the matrix handle to Real-element matrices. Element type
584 is the only matrix characteristic for which no matrix handle can remain
585 uncommitted. However, different handles can provide views of the same data
586 through which that data is seen to contain different element types.
587 
588 Each matrix characteristic other than sizes is represented by a class
589 defining one or more enumerated types, where individual characteristics are
590 assigned a single bit. Then an appropriate mask type (an unsigned integral
591 type) is defined which can represent a set of allowable characteristics.
592 The actual character of a matrix is represented via enumeration values; the
593 character commitment is represented by the compatible masks. The operation
594 of determining whether a particular actual character satisfies a handle
595 commitment can then be performed very quickly via bitwise logical operations.
596 **/
597 class SimTK_SimTKCOMMON_EXPORT MatrixCharacter {
598 public:
599     /// Default constructor sets lengths to zero and the other characteristics
600     /// to "none specified".
MatrixCharacter()601     MatrixCharacter() : nr(0), nc(0), lband(0), uband(0) {}
602 
603     // Some handy predefined MatrixCharacters.
604     class LapackFull;
605     class Vector;
606     class RowVector;
607 
608     /// Restore this MatrixCharacter to its default-constructed state of "none".
setToNone()609     MatrixCharacter& setToNone() {
610         nr=nc=lband=uband=0;
611         structure.setToNone(); outline.setToNone();
612         storage.setToNone();   condition.setToNone();
613         return *this;
614     }
615 
616     /// These are dimensions of the logical matrix and have nothing to do with
617     /// how much storage may be used to hold the elements.
nrow()618     int                nrow()       const {return nr;}
ncol()619     int                ncol()       const {return nc;}
getSize()620     std::pair<int,int> getSize()    const {return std::pair<int,int>(nrow(),ncol());}
nelt()621     ptrdiff_t          nelt()       const {return (ptrdiff_t)nrow() * (ptrdiff_t)ncol();}
622 
getLowerBandwidth()623     int                getLowerBandwidth() const {return lband;}
getUpperBandwidth()624     int                getUpperBandwidth() const {return uband;}
getBandwidth()625     std::pair<int,int> getBandwidth()      const
626     {   return std::pair<int,int>(getLowerBandwidth(), getUpperBandwidth()); }
627 
getStructure()628     const MatrixStructure&  getStructure() const {return structure;}
getStorage()629     const MatrixStorage&    getStorage()   const {return storage;}
getOutline()630     const MatrixOutline&    getOutline()   const {return outline;}
getCondition()631     const MatrixCondition&  getCondition() const {return condition;}
632 
updStructure()633     MatrixStructure&  updStructure() {return structure;}
updStorage()634     MatrixStorage&    updStorage()   {return storage;}
updOutline()635     MatrixOutline&    updOutline()   {return outline;}
updCondition()636     MatrixCondition&  updCondition() {return condition;}
637 
setStructure(const MatrixStructure & sa)638     MatrixCharacter& setStructure(const MatrixStructure& sa)  {structure = sa; return *this;}
setStorage(const MatrixStorage & sa)639     MatrixCharacter& setStorage  (const MatrixStorage&   sa)  {storage   = sa; return *this;}
setOutline(const MatrixOutline & oa)640     MatrixCharacter& setOutline  (const MatrixOutline&   oa)  {outline   = oa; return *this;}
setCondition(const MatrixCondition & ca)641     MatrixCharacter& setCondition(const MatrixCondition& ca)  {condition = ca; return *this;}
642 
643 
644     /// Set the actual size and update the outline to match.
setActualSize(int m,int n)645     MatrixCharacter& setActualSize(int m, int n)
646     {   setSize(m,n); outline = MatrixOutline::calcFromSize(m,n); return *this; }
setActualNumRows(int m)647     MatrixCharacter& setActualNumRows(int m)
648     {   setNumRows(m); outline = MatrixOutline::calcFromSize(m,ncol()); return *this; }
setActualNumCols(int n)649     MatrixCharacter& setActualNumCols(int n)
650     {   setNumCols(n); outline = MatrixOutline::calcFromSize(nrow(),n); return *this; }
651 
setBandwidth(int lb,int ub)652     MatrixCharacter& setBandwidth(int lb, int ub) {
653         assert(lb>=0 && lb>=0);
654         lband = lb; uband = ub;
655         return *this;
656     }
setLowerBandwidth(int lb)657     MatrixCharacter& setLowerBandwidth(int lb) {
658         assert(lb>=0);
659         lband = lb;
660         return *this;
661     }
setUpperBandwidth(int ub)662     MatrixCharacter& setUpperBandwidth(int ub) {
663         assert(ub>=0);
664         uband = ub;
665         return *this;
666     }
667 
668     class Mask; // defined below
669 
670 protected:
MatrixCharacter(int m,int n,int lb,int ub,MatrixStructure structure,MatrixStorage storage,MatrixCondition condition)671     MatrixCharacter(int m, int n,
672                     int lb, int ub,
673                     MatrixStructure structure,
674                     MatrixStorage   storage,
675                     MatrixCondition condition)
676     :   nr(m), nc(n), lband(lb), uband(ub),
677         structure(structure), storage(storage),
678         outline(MatrixOutline::calcFromSize(m,n)),
679         condition(condition) {}
680 
681 
682     int              nr,            ///< actual number of rows
683                      nc;            ///< actual number of columns
684     int              lband,         ///< actual lower bandwidth, if banded
685                      uband;         ///< actual upper bandwidth, if banded
686     MatrixStructure  structure;
687     MatrixStorage    storage;
688     MatrixOutline    outline;
689     MatrixCondition  condition;
690 
691 private:
692     // These are private because they don't set the outline as well.
setSize(int m,int n)693     MatrixCharacter& setSize(int m, int n)
694     {   assert(m>=0 && n>=0); nr = m; nc = n; return *this; }
setNumRows(int m)695     MatrixCharacter& setNumRows(int m)
696     {   assert(m>=0); nr = m; return *this; }
setNumCols(int n)697     MatrixCharacter& setNumCols(int n)
698     {   assert(n>=0); nc = n; return *this; }
699 };
700 
701 /// Output a textual description of a MatrixCharacter; handy for debugging.
702 /// @relates SimTK::MatrixCharacter
703 SimTK_SimTKCOMMON_EXPORT std::ostream&
704 operator<<(std::ostream& o, const MatrixCharacter&);
705 
706 /// Predefined MatrixCharacter for an ordinary Lapack-style full matrix
707 /// of a particular dimension m x n (nrows X ncols). Note that the storage
708 /// format allows for a "leading dimension" larger than m, but that the
709 /// leading dimension is not considered part of the matrix character. It is
710 /// dealt with separately.
711 class MatrixCharacter::LapackFull : public MatrixCharacter {
712 public:
LapackFull(int m,int n)713     LapackFull(int m, int n)
714     :   MatrixCharacter(m,n,0,0,
715             MatrixStructure(MatrixStructure::Full),
716             MatrixStorage(MatrixStorage::Full,MatrixStorage::ColumnOrder),
717             MatrixCondition()) {}
718 };
719 
720 /// Predefined MatrixCharacter for an ordinary column vector of a particular
721 /// size. Note that standard vector storage allows for a "stride" greater than
722 /// 1, but that is not considered part of the matrix character. Stride is
723 /// dealt with separately.
724 class MatrixCharacter::Vector : public MatrixCharacter {
725 public:
Vector(int m)726     Vector(int m)
727     :   MatrixCharacter(m,1,0,0,
728             MatrixStructure(MatrixStructure::Matrix1d),
729             MatrixStorage(MatrixStorage::Vector,MatrixStorage::ColumnOrder),
730             MatrixCondition()) {}
731 };
732 
733 /// Predefined MatrixCharacter for an ordinary row vector of a particular
734 /// size. Note that standard vector storage allows for a "stride" greater than
735 /// 1, but that is not considered part of the matrix character. Stride is
736 /// dealt with separately.
737 class MatrixCharacter::RowVector : public MatrixCharacter {
738 public:
RowVector(int n)739     RowVector(int n)
740     :   MatrixCharacter(1,n,0,0,
741             MatrixStructure(MatrixStructure::Matrix1d),
742             MatrixStorage(MatrixStorage::Vector,MatrixStorage::RowOrder),
743             MatrixCondition()) {}
744 };
745 
746 //  -------------------------- MatrixCharacter::Mask ---------------------------
747 /// This class collects masks of each characteristic type for representing sets
748 /// of accceptable characteristics.
749 //  ----------------------------------------------------------------------------
750 class MatrixCharacter::Mask {
751 public:
Mask()752     Mask() {setToUncommitted();}
753 
754     typedef unsigned int SizeMask;
755     static const SizeMask SizeUncommitted = 0xffffffffU;
756 
isResizeable()757     bool isResizeable()      const {return nr==SizeUncommitted || nc==SizeUncommitted;}
isFullyResizeable()758     bool isFullyResizeable() const {return nr==SizeUncommitted && nc==SizeUncommitted;}
isNumRowsLocked()759     bool isNumRowsLocked()   const {return nr!=SizeUncommitted;}
isNumColsLocked()760     bool isNumColsLocked()   const {return nc!=SizeUncommitted;}
761 
getNumRowsMask()762     unsigned int getNumRowsMask() const {return nr;}
getNumColsMask()763     unsigned int getNumColsMask() const {return nc;}
getLowerBandwidthMask()764     unsigned int getLowerBandwidthMask() const {return lband;}
getUpperBandwidthMask()765     unsigned int getUpperBandwidthMask() const {return uband;}
766 
getDefaultNumRows()767     int getDefaultNumRows() const {return isNumRowsLocked() ? nr : 0;}
getDefaultNumCols()768     int getDefaultNumCols() const {return isNumColsLocked() ? nc : 0;}
769 
isLowerBandwidthLocked()770     bool isLowerBandwidthLocked()  const {return lband!=SizeUncommitted;}
isUpperBandwidthLocked()771     bool isUpperBandwidthLocked()  const {return uband!=SizeUncommitted;}
getDefaultLowerBandwidth()772     int getDefaultLowerBandwidth() const {return isLowerBandwidthLocked() ? lband : 0;}
getDefaultUpperBandwidth()773     int getDefaultUpperBandwidth() const {return isUpperBandwidthLocked() ? uband : 0;}
774 
775     /// Set all bits to one ("Uncommitted").
setToUncommitted()776     Mask& setToUncommitted() {
777         nr=nc=lband=uband=SizeUncommitted;
778         structure.setToUncommitted(); storage.setToUncommitted();
779         outline.setToUncommitted();   condition.setToUncommitted();
780         return *this;
781     }
782 
783     /// Return if all fields are set to "Uncommitted" (all bits are one).
isUncommitted()784     bool isUncommitted() const {
785         return nr==SizeUncommitted       && nc==SizeUncommitted
786             && lband==SizeUncommitted    && uband==SizeUncommitted
787             && structure.isUncommitted() && storage.isUncommitted()
788             && outline.isUncommitted()   && condition.isUncommitted();
789     }
790 
791     /// Check whether an actual matrix character satisfies this matrix commitment.
isSatisfiedBy(const MatrixCharacter & actual)792     bool isSatisfiedBy(const MatrixCharacter& actual) const {
793         return isSizeOK(actual.nr, actual.nc)
794             && isBandwidthOK(actual.lband, actual.uband)
795             && structure.isSatisfiedBy(actual.getStructure())
796             && storage.isSatisfiedBy(actual.getStorage())
797             && outline.isSatisfiedBy(actual.getOutline())
798             && condition.isSatisfiedBy(actual.getCondition());
799     }
800 
801     /// Check whether an actual size satisfies the size commitment.
isSizeOK(int m,int n)802     bool isSizeOK(int m, int n) const
803     {   return ((SizeMask)m & nr)      == (SizeMask)m
804             && ((SizeMask)n & nc)      == (SizeMask)n; }
805 
806     /// Check whether an actual bandwidth satisfies the bandwidth commitment.
807     /// (If the matrix isn't banded any bandwidth will be OK.)
isBandwidthOK(int lower,int upper)808     bool isBandwidthOK(int lower, int upper) const
809     {   return ((SizeMask)lower & lband) == (SizeMask)lower
810             && ((SizeMask)upper & uband) == (SizeMask)upper; }
811 
812     SizeMask                nr,         ///< number of rows
813                             nc;         ///< number of columns
814     SizeMask                lband,      ///< lower bandwidth, if banded
815                             uband;      ///< upper bandwidth, if banded
816     MatrixStructure::Mask   structure;
817     MatrixStorage::Mask     storage;
818     MatrixOutline::Mask     outline;
819     MatrixCondition::Mask   condition;
820 
821 friend class MatrixCommitment;
822 };
823 
824 //  ----------------------------- MatrixCommitment -----------------------------
825 
826 /// A MatrixCommitment provides a set of acceptable matrix characteristics.
827 /// Since we define the characteristics each with its own bit, a commitment
828 /// is implemented as a set of masks with bits set corresponding to the
829 /// acceptable characteristics.
830 
831 //  ----------------------------------------------------------------------------
832 class SimTK_SimTKCOMMON_EXPORT MatrixCommitment {
833 public:
MatrixCommitment()834     MatrixCommitment() {} // set commitments to "none" and masks to "uncommitted"
835 
836     /// This is an implicit conversion from a MatrixStructure specification to
837     /// a MatrixCommitment with storage, outline, and condition uncommitted.
MatrixCommitment(const MatrixStructure & str)838     MatrixCommitment(const MatrixStructure& str)
839     { new (this) MatrixCommitment(str, MatrixStorage(), MatrixOutline(), MatrixCondition());}
840 
841     class Vector;
842     class RowVector;
843     class Triangular;
844     class Symmetric;
845     class Hermitian;
846     class SkewSymmetric;
847     class SkewHermitian;
848 
commitSize(int m,int n)849     MatrixCommitment& commitSize(int m, int n)
850     {   commitNumRows(m); commitNumCols(n); return *this; }
commitNumRows(int m)851     MatrixCommitment& commitNumRows(int m)
852     {   SimTK_SIZECHECK_NONNEG(m, "MatrixCommitment::commitNumRows()");
853         masks.nr = m; return *this; }
commitNumCols(int n)854     MatrixCommitment& commitNumCols(int n)
855     {   SimTK_SIZECHECK_NONNEG(n, "MatrixCommitment::commitNumCols()");
856         masks.nc = n; return *this; }
857 
commitBandwidth(int lb,int ub)858     MatrixCommitment& commitBandwidth(int lb, int ub)
859     {  commitLowerBandwidth(lb); commitUpperBandwidth(ub); return *this;}
commitLowerBandwidth(int lb)860     MatrixCommitment& commitLowerBandwidth(int lb)
861     {   SimTK_SIZECHECK_NONNEG(lb, "MatrixCommitment::commitLowerBandwidth()");
862         masks.lband = lb; return *this; }
commitUpperBandwidth(int ub)863     MatrixCommitment& commitUpperBandwidth(int ub)
864     {   SimTK_SIZECHECK_NONNEG(ub, "MatrixCommitment::commitUpperBandwidth()");
865         masks.uband = ub; return *this; }
866 
commitStructure(const MatrixStructure & s)867     MatrixCommitment& commitStructure(const MatrixStructure& s)
868     {   structure=s; masks.structure=s.mask(); return *this; }
commitStorage(const MatrixStorage & s)869     MatrixCommitment& commitStorage  (const MatrixStorage&   s)
870     {   storage=s;   masks.storage  =s.mask(); return *this; }
commitOutline(const MatrixOutline & o)871     MatrixCommitment& commitOutline  (const MatrixOutline&   o)
872     {   outline=o;   masks.outline  =o.mask(); return *this; }
commitCondition(const MatrixCondition & c)873     MatrixCommitment& commitCondition(const MatrixCondition& c)
874     {   condition=c; masks.condition=c.mask(); return *this; }
875 
876     /// For any handle commitment, we can calculate a "best character" for
877     /// an allocation that satisfies the commitment, optionally with an
878     /// initial allocation size. Typically it is the least-restrictive
879     /// actual character that satisfies the commitment. For
880     /// example, if the commitment is Triangular we'll allocate a full triangular
881     /// matrix, not a banded one, or a symmetric one, or for that matter an
882     /// identity matrix, all of which would satisfy the commitment.
883     /// The supplied sizes are used as minima -- if the commitment requires
884     /// a larger minimum size you'll get that. For example, if you specify
885     /// 0x0 but you're committed to a Column outline, you'll get 0x1.
886     MatrixCharacter calcDefaultCharacter(int minNumRows, int minNumCols) const;
887 
888     /// These report the commitment as it was specified.
getStructureCommitment()889     const MatrixStructure&  getStructureCommitment() const {return structure;}
getStorageCommitment()890     const MatrixStorage&    getStorageCommitment()   const {return storage;}
getOutlineCommitment()891     const MatrixOutline&    getOutlineCommitment()   const {return outline;}
getConditionCommitment()892     const MatrixCondition&  getConditionCommitment() const {return condition;}
893 
894     /// These report the masks of acceptable values generated from the commitment.
getStructureMask()895     const MatrixStructure::Mask&   getStructureMask() const {return masks.structure;}
getStorageMask()896     const MatrixStorage::Mask&     getStorageMask()   const {return masks.storage;}
getOutlineMask()897     const MatrixOutline::Mask&     getOutlineMask()   const {return masks.outline;}
getConditionMask()898     const MatrixCondition::Mask&   getConditionMask() const {return masks.condition;}
899 
getNumRowsMask()900     MatrixCharacter::Mask::SizeMask getNumRowsMask() const {return masks.nr;}
getNumColsMask()901     MatrixCharacter::Mask::SizeMask getNumColsMask() const {return masks.nc;}
getLowerBandwidthMask()902     MatrixCharacter::Mask::SizeMask getLowerBandwidthMask() const {return masks.lband;}
getUpperBandwidthMask()903     MatrixCharacter::Mask::SizeMask getUpperBandwidthMask() const {return masks.uband;}
904 
getDefaultNumRows()905     int getDefaultNumRows() const {return masks.getDefaultNumRows();}
getDefaultNumCols()906     int getDefaultNumCols() const {return masks.getDefaultNumCols();}
907 
isSizeOK(int m,int n)908     bool isSizeOK(int m, int n) const {return masks.isSizeOK(m,n);}
isSizeOK(const std::pair<int,int> & mn)909     bool isSizeOK(const std::pair<int,int>& mn) const
910     {   return isSizeOK(mn.first, mn.second); }
911 
isBandwidthOK(int lower,int upper)912     bool isBandwidthOK(int lower, int upper) const {return masks.isBandwidthOK(lower,upper);}
913 
isSatisfiedBy(const MatrixCharacter & actual)914     bool isSatisfiedBy(const MatrixCharacter& actual) const
915     {   return masks.isSatisfiedBy(actual); }
isStructureOK(const MatrixStructure & s)916     bool isStructureOK(const MatrixStructure& s) const
917     {   return getStructureMask().isSatisfiedBy(s); }
isStorageOK(const MatrixStorage & s)918     bool isStorageOK(const MatrixStorage& s) const
919     {   return getStorageMask().isSatisfiedBy(s); }
isOutlineOK(const MatrixOutline & o)920     bool isOutlineOK(const MatrixOutline& o) const
921     {   return getOutlineMask().isSatisfiedBy(o); }
isConditionOK(const MatrixCondition & c)922     bool isConditionOK(const MatrixCondition& c) const
923     {   return getConditionMask().isSatisfiedBy(c); }
924 
isResizeable()925     bool isResizeable()      const {return masks.isResizeable();}
isFullyResizeable()926     bool isFullyResizeable() const {return masks.isFullyResizeable();;}
isNumRowsLocked()927     bool isNumRowsLocked()  const {return masks.isNumRowsLocked();}
isNumColsLocked()928     bool isNumColsLocked()  const {return masks.isNumColsLocked();}
929 
isStructureCommitted()930     bool isStructureCommitted() const
931     {   return !getStructureMask().isUncommitted(); }
isStorageCommitted()932     bool isStorageCommitted()   const
933     {   return !getStorageMask().isUncommitted();}
isOutlineCommitted()934     bool isOutlineCommitted()   const
935     {   return !getOutlineMask().isUncommitted(); }
isConditionCommitted()936     bool isConditionCommitted() const
937     {   return !getConditionMask().isUncommitted();}
938 
939     /// Set commitment s to "none" and masks to "uncommitted" for all characteristics.
clear()940     void clear() {
941         structure.setToNone();
942         storage.setToNone();
943         outline.setToNone();
944         condition.setToNone();
945         masks.setToUncommitted();
946     }
947 
948 protected:
MatrixCommitment(const MatrixStructure & structure,const MatrixStorage & storage,const MatrixOutline & outline,const MatrixCondition & condition)949     MatrixCommitment(const MatrixStructure& structure,
950                      const MatrixStorage&   storage,
951                      const MatrixOutline&   outline,
952                      const MatrixCondition& condition)
953     :   structure(structure), storage(storage),
954         outline(outline), condition(condition),
955         masks() // set to all 1's
956     {
957         if (outline.getOutline()==MatrixOutline::Scalar) commitSize(1,1);
958         else if (outline.getOutline()==MatrixOutline::Column) commitNumCols(1);
959         else if (outline.getOutline()==MatrixOutline::Row) commitNumRows(1);
960 
961         masks.structure = structure.mask();
962         masks.storage   = storage.mask();
963         masks.outline   = outline.mask();
964         masks.condition = condition.mask();
965     }
966 
967     /// These are the commitments as specified. They are used to fill in
968     /// the corresponding bitmasks of acceptable characteristics below.
969     MatrixStructure         structure;
970     MatrixStorage           storage;
971     MatrixOutline           outline;
972     MatrixCondition         condition;
973 
974     /// These are the bitmasks of acceptable characteristics which
975     /// would satisfy the above-specified commitments.
976     MatrixCharacter::Mask   masks;
977 };
978 
979 
980 /// This is the default commitment for a column vector.
981 class MatrixCommitment::Vector : public MatrixCommitment {
982 public:
983     /// Commit to a resizeable column vector.
Vector()984     Vector()
985     :   MatrixCommitment
986         (   MatrixStructure(MatrixStructure::Matrix1d),
987             MatrixStorage(),
988             MatrixOutline(MatrixOutline::Column),
989             MatrixCondition())
990     {
991     }
992     /// Commit to a column vector of a particular length.
Vector(int m)993     explicit Vector(int m)
994     :   MatrixCommitment
995         (   MatrixStructure(MatrixStructure::Matrix1d),
996             MatrixStorage(),
997             MatrixOutline(MatrixOutline::Column),
998             MatrixCondition())
999     {
1000         commitNumRows(m);
1001     }
1002 };
1003 
1004 /// This is the default commitment for a row vector.
1005 class MatrixCommitment::RowVector : public MatrixCommitment {
1006 public:
1007     /// Commit to a resizeable row vector.
RowVector()1008     RowVector()
1009     :   MatrixCommitment
1010         (   MatrixStructure(MatrixStructure::Matrix1d),
1011             MatrixStorage(),
1012             MatrixOutline(MatrixOutline::Row),
1013             MatrixCondition())
1014     {
1015     }
1016     /// Commit to a row vector of a particular length.
RowVector(int n)1017     explicit RowVector(int n)
1018     :   MatrixCommitment
1019         (   MatrixStructure(MatrixStructure::Matrix1d),
1020             MatrixStorage(),
1021             MatrixOutline(MatrixOutline::Row),
1022             MatrixCondition())
1023     {
1024         commitNumCols(n);
1025     }
1026 };
1027 
1028 /// This is the default commitment for a triangular matrix.
1029 class MatrixCommitment::Triangular : public MatrixCommitment {
1030 public:
Triangular()1031     Triangular()
1032     :   MatrixCommitment(MatrixStructure::Triangular, MatrixStorage(),
1033                          MatrixOutline(), MatrixCondition())
1034     {
1035     }
1036 };
1037 
1038 /// This is the default commitment for a symmetric (*not* Hermitian) matrix.
1039 /// There are no restrictions on the underlying elements or diagonals.
1040 class MatrixCommitment::Symmetric : public MatrixCommitment {
1041 public:
Symmetric()1042     Symmetric()
1043     :   MatrixCommitment(MatrixStructure::Symmetric, MatrixStorage(),
1044                          MatrixOutline(), MatrixCondition())
1045     {
1046     }
1047 };
1048 
1049 /// This is the default commitment for a Hermitian (*not* symmetric) matrix.
1050 /// Diagonal elements must be real since they have to serve as their own
1051 /// conjugates.
1052 class MatrixCommitment::Hermitian : public MatrixCommitment {
1053 public:
Hermitian()1054     Hermitian()
1055     :   MatrixCommitment
1056         (   MatrixStructure::Hermitian,
1057             MatrixStorage(),
1058             MatrixOutline(),
1059             MatrixCondition().setDiagonal(MatrixCondition::RealDiagonal))
1060     {
1061     }
1062 };
1063 
1064 /// This is the default commitment for skew symmetric (*not* skew Hermitian)
1065 /// matrix. Diagonal elements must be all-zero since they have to be their
1066 /// own negation. Otherwise any elements are acceptable.
1067 class MatrixCommitment::SkewSymmetric : public MatrixCommitment {
1068 public:
SkewSymmetric()1069     SkewSymmetric()
1070     :   MatrixCommitment
1071         (   MatrixStructure::SkewSymmetric,
1072             MatrixStorage(),
1073             MatrixOutline(),
1074             MatrixCondition().setDiagonal(MatrixCondition::ZeroDiagonal))
1075     {
1076     }
1077 };
1078 
1079 /// This is the default commitment for a skew Hermitian (*not* skew symmetric)
1080 /// matrix. Diagonal elements must be pure imaginary since when conjugated they
1081 /// must be their own negation for a skew matrix.
1082 class MatrixCommitment::SkewHermitian : public MatrixCommitment {
1083 public:
SkewHermitian()1084     SkewHermitian()
1085     :   MatrixCommitment
1086         (   MatrixStructure::SkewHermitian,
1087             MatrixStorage(),
1088             MatrixOutline(),
1089             MatrixCondition().setDiagonal(MatrixCondition::ImaginaryDiagonal))
1090     {
1091     }
1092 };
1093 
1094 /// Output a textual description of a MatrixCommitment; handy for debugging.
1095 /// @relates SimTK::MatrixCommitment
1096 SimTK_SimTKCOMMON_EXPORT std::ostream&
1097 operator<<(std::ostream& o, const MatrixCommitment&);
1098 
1099 } //namespace SimTK
1100 
1101 #endif // SimTK_SIMMATRIX_MATRIX_CHARACTERISTICS_H_
1102