STK++ 0.9.13
STK::Svd< Array > Class Template Reference

The class Svd compute the Singular Value Decomposition of a Array with the Golub-Reinsch Algorithm. More...

#include <STK_Svd.h>

Inheritance diagram for STK::Svd< Array >:
Inheritance graph

Public Types

typedef ISvd< Svd< Array > > Base
 
typedef hidden::Traits< Array >::Col ColVector
 
typedef hidden::Traits< Array >::Row RowVector
 

Public Member Functions

 Svd (Array const &A, bool ref=false, bool withU=true, bool withV=true)
 Default constructor.
 
template<class OtherArray >
 Svd (ArrayBase< OtherArray > const &A, bool withU=true, bool withV=true)
 constructor with other kind of array/expression
 
 Svd (const Svd &S)
 Copy Constructor.
 
virtual ~Svd ()
 destructor.
 
Svdoperator= (const Svd &S)
 Operator = : overwrite the Svd with S.
 
bool runImpl ()
 run the Svd
 
- Public Member Functions inherited from STK::ISvd< Svd< Array > >
Type det () const
 
Type trace () const
 
Type norm () const
 
int rank () const
 
ArrayU constU () const
 
ArrayV constV () const
 
ArrayD constD () const
 
virtual bool run ()
 implement the run method
 
void setData (OtherArray const &A, bool withU=true, bool withV=true)
 Set a new data set to ISvd class.
 
OtherArrayginv (OtherArray &res) const
 Compute the generalized inverse of the matrix and put the result in res.
 
- Public Member Functions inherited from STK::IRunnerBase
String consterror () const
 get the last error message.
 
- Public Member Functions inherited from STK::IRecursiveTemplate< Derived >
Derived & asDerived ()
 static cast : return a reference of this with a cast to the derived class.
 
Derived constasDerived () const
 static cast : return a const reference of this with a cast to the derived class.
 
Derived * asPtrDerived ()
 static cast : return a ptr on a Derived of this with a cast to the derived class.
 
Derived constasPtrDerived () const
 static cast : return a ptr on a constant Derived of this with a cast to the derived class.
 
Derived * clone () const
 create a leaf using the copy constructor of the Derived class.
 
Derived * clone (bool isRef) const
 create a leaf using the copy constructor of the Derived class and a flag determining if the clone is a reference or not.
 

Static Public Member Functions

static bool diag (ArrayDiagonalX &D, VectorX &F, Array &U, ArraySquareX &V, bool withU=true, bool withV=true, Real const &tol=Arithmetic< Real >::epsilon())
 Computing the diagonalization of a bi-diagonal matrix.
 
static void rightEliminate (ArrayDiagonalX &D, VectorX &F, int const &nrow, ArraySquareX &V, bool withV=true, Real const &tol=Arithmetic< Real >::epsilon())
 right eliminate the element on the subdiagonal of the row nrow
 

Private Member Functions

bool computeSvd ()
 Svd main steps.
 
void compU ()
 Compute U (if withU_ is true)
 
void compV ()
 Compute V (if withV_ is true)
 

Private Attributes

VectorX F_
 Values of the Sub-diagonal.
 

Additional Inherited Members

- Protected Types inherited from STK::ISvd< Svd< Array > >
typedef hidden::AlgebraTraits< Svd< Array > >::ArrayU ArrayU
 
typedef hidden::AlgebraTraits< Svd< Array > >::ArrayD ArrayD
 
typedef hidden::AlgebraTraits< Svd< Array > >::ArrayV ArrayV
 
typedef ArrayU::Type Type
 
- Protected Member Functions inherited from STK::ISvd< Svd< Array > >
 ISvd (ArrayU const &A, bool ref, bool withU=true, bool withV=true)
 Default constructor.
 
 ISvd (ArrayBase< OtherDerived > const &A, bool withU=true, bool withV=true)
 constructor with other kind of array/expression
 
 ISvd (ISvd const &S)
 Copy Constructor.
 
virtual ~ISvd ()
 destructor.
 
ISvdoperator= (const ISvd &S)
 Operator = : overwrite the ISvd with S.
 
virtual void finalize ()
 Finalize any operations that have to be done after the computation of the decomposition.
 
int nrowU () const
 
int ncolU () const
 
int nrowD () const
 
int ncolD () const
 
int nrowV () const
 
int ncolV () const
 
- Protected Member Functions inherited from STK::IRunnerBase
 IRunnerBase ()
 default constructor
 
 IRunnerBase (IRunnerBase const &runner)
 copy constructor
 
virtual ~IRunnerBase ()
 destructor
 
virtual void update ()
 update the runner.
 
- Protected Member Functions inherited from STK::IRecursiveTemplate< Derived >
 IRecursiveTemplate ()
 constructor.
 
 ~IRecursiveTemplate ()
 destructor.
 
- Protected Attributes inherited from STK::ISvd< Svd< Array > >
ArrayU U_
 U_ matrix.
 
ArrayV V_
 V_ matrix.
 
ArrayD D_
 Diagonal array of the singular values.
 
bool withU_
 Compute U_ ?
 
bool withV_
 Compute V_ ?
 
Type norm_
 trace norm
 
int rank_
 rank
 
Type trace_
 trace norm
 
Type det_
 determinant
 
- Protected Attributes inherited from STK::IRunnerBase
String msg_error_
 String with the last error message.
 
bool hasRun_
 true if run has been used, false otherwise
 

Detailed Description

template<class Array>
class STK::Svd< Array >

The class Svd compute the Singular Value Decomposition of a Array with the Golub-Reinsch Algorithm.

The method take as:

  • input: a matrix A(nrow,ncol)
  • output:
    1. U Array (nrow,ncol).
    2. D diagonal matrix (min(norw,ncol))
    3. V Array (ncol,ncol). and perform the decomposition:
  • A = UDV' (transpose V). U can have more columns than A, and it is possible to compute some (all) vectors of Ker(A).
See also
SK::ISvd, STK::lapack::Svd

Definition at line 116 of file STK_Svd.h.

Member Typedef Documentation

◆ Base

template<class Array >
typedef ISvd< Svd<Array> > STK::Svd< Array >::Base

Definition at line 119 of file STK_Svd.h.

◆ ColVector

template<class Array >
typedef hidden::Traits<Array>::Col STK::Svd< Array >::ColVector

Definition at line 120 of file STK_Svd.h.

◆ RowVector

template<class Array >
typedef hidden::Traits<Array>::Row STK::Svd< Array >::RowVector

Definition at line 121 of file STK_Svd.h.

Constructor & Destructor Documentation

◆ Svd() [1/3]

template<class Array >
STK::Svd< Array >::Svd ( Array const A,
bool  ref = false,
bool  withU = true,
bool  withV = true 
)
inline

Default constructor.

Parameters
Athe matrix to decompose.
refif true, U_ is a reference of A.
withUif true, we save the left housolder transforms in U_.
withVif true, we save the right housolder transforms in V_.

Definition at line 139 of file STK_Svd.h.

140 : Base(A, ref, withU, withV)
141 {}
ISvd< Svd< Array > > Base
Definition STK_Svd.h:119

◆ Svd() [2/3]

template<class Array >
template<class OtherArray >
STK::Svd< Array >::Svd ( ArrayBase< OtherArray > const A,
bool  withU = true,
bool  withV = true 
)
inline

constructor with other kind of array/expression

Parameters
Athe matrix/expression to decompose.
withUif true save the left housolder transforms in U_.
withVif true save the right housolder transforms in V_.

Definition at line 148 of file STK_Svd.h.

149 : Base(A, withU, withV) {}

◆ Svd() [3/3]

template<class Array >
STK::Svd< Array >::Svd ( const Svd< Array > &  S)

Copy Constructor.

Parameters
Sthe Svd to copy

Definition at line 208 of file STK_Svd.h.

208: Base(S), F_(S.F_) {}
VectorX F_
Values of the Sub-diagonal.
Definition STK_Svd.h:196

◆ ~Svd()

template<class Array >
virtual STK::Svd< Array >::~Svd ( )
inlinevirtual

destructor.

Definition at line 155 of file STK_Svd.h.

155{}

Member Function Documentation

◆ compU()

template<class Array >
void STK::Svd< Array >::compU ( )
private

Compute U (if withU_ is true)

Definition at line 386 of file STK_Svd.h.

387{
388 int niter = D_.size(); // Number of iterations
389 int ncol = std::min(nrowU(), ncolU()); // number of non zero cols of U_
390
391 // initialization of the remaining cols of U_ to 0.0
392 // put 0 to unused cols
393 U_.col(Range(ncol+1, ncolU(), 0)) = 0.0;
394 // Computation of U_
395 for (int iter=niter, iter1=niter+1; iter>=1; iter--, iter1--)
396 {
397 // ref of the column iter
398 ColVector X(U_, Range(iter1,nrowU(), 0), iter);
399 // ref of the row iter
400 RowVector P(U_, Range(iter,ncolU(), 0), iter);
401 // Get beta and test
402 Real beta = P[iter];
403 if (beta)
404 {
405 // update the column iter
406 P[iter] = 1.0 + beta;
407 // Updating the cols iter+1 to ncolU_
408 for (int j=iter1; j<=niter; j++)
409 { // product of U_iter by U_j
410 Real aux;
411 ColVector Y(U_, Range(iter1, nrowU(), 0), j); // ref on the column j
412 // U_j = aux = beta * X'Y
413 P[j] = (aux = dot( X, Y) *beta);
414 // U^j += aux * U^iter
415 for (int i= iter1; i <= nrowU(); ++i)
416 {
417 Y[i] += X[i] * aux;
418 }
419 }
420 // compute the vector v
421 X *= beta;
422 }
423 else // U^iter = identity
424 {
425 P[iter] = 1.0;
426 X = 0.0;
427 }
428 // update the column iter
429 U_.col(Range(1,iter-1, 0), iter) = 0.0;
430 }
431}
ArrayD D_
Diagonal array of the singular values.
Definition STK_ISvd.h:193
ArrayU U_
U_ matrix.
Definition STK_ISvd.h:189
hidden::Traits< Array >::Col ColVector
Definition STK_Svd.h:120
hidden::Traits< Array >::Row RowVector
Definition STK_Svd.h:121
Real dot(ExprBase< Container1D1 > const &x, ExprBase< Container1D2 > const &y)
Compute the dot product.
double Real
STK fundamental type of Real values.
TRange< UnknownSize > Range
Definition STK_Range.h:59

References STK::dot().

◆ computeSvd()

template<class Array >
bool STK::Svd< Array >::computeSvd ( )
private

Svd main steps.

Definition at line 235 of file STK_Svd.h.

236{
237 // if the container is empty, there is nothing to do
238 if (U_.empty())
239 { rank_ = 0;
240 norm_ = 0.0;
241 return true;
242 }
243 int beginRow = U_.beginRows(), beginCol = U_.beginCols();
244 // if U_ is just a copy of A, translate begin to 1
245 // if U_ is a ref on A, this can generate an error
246 U_.shift(1,1);
247 // Bidiagonalize (U_)
248 norm_ = bidiag(U_, D_, F_);
249 // right householder vectors are in upper part of U_
250 // We need to create V_ before rightEliminate
251 if (withV_) { compV();}
252 // rightEliminate last element of F_ if any
253 if (nrowU() < ncolV())
255 // If (U_) is not needed, we can destroy the storage
256 if (withU_) { compU();}
257 // Diagonalize
258 bool error = diag(D_, F_, U_, V_, withU_, withV_, norm_);
259 // The sub diagonal is now zero
260 F_.resize(0,0);
261 U_.shift(beginRow, beginCol);
262 D_.shift(beginCol);
263 V_.shift(beginCol);
264 return error;
265}
Derived & resize(Range const &I, Range const &J)
resize the array.
String const & error() const
get the last error message.
Definition STK_IRunner.h:82
bool withU_
Compute U_ ?
Definition STK_ISvd.h:195
Type norm_
trace norm
Definition STK_ISvd.h:199
ArrayV V_
V_ matrix.
Definition STK_ISvd.h:191
bool withV_
Compute V_ ?
Definition STK_ISvd.h:197
static bool diag(ArrayDiagonalX &D, VectorX &F, Array &U, ArraySquareX &V, bool withU=true, bool withV=true, Real const &tol=Arithmetic< Real >::epsilon())
Computing the diagonalization of a bi-diagonal matrix.
Definition STK_Svd.h:503
void compV()
Compute V (if withV_ is true)
Definition STK_Svd.h:324
void compU()
Compute U (if withU_ is true)
Definition STK_Svd.h:386
static void rightEliminate(ArrayDiagonalX &D, VectorX &F, int const &nrow, ArraySquareX &V, bool withV=true, Real const &tol=Arithmetic< Real >::epsilon())
right eliminate the element on the subdiagonal of the row nrow
Definition STK_Svd.h:436

References STK::IRunnerBase::error().

◆ compV()

template<class Array >
void STK::Svd< Array >::compV ( )
private

Compute V (if withV_ is true)

Definition at line 324 of file STK_Svd.h.

325{
326 // Construction of V_
327 V_.resize(U_.cols());
328 // Number of right Householder rotations
329 int niter = (ncolV()>nrowU()) ? (nrowU()) : (ncolV()-1);
330 // initialization of the remaining rows and cols of V_ to Identity
331 for (int iter=niter+2; iter<=ncolV(); iter++)
332 {
333 VectorX W(V_, V_.cols(), iter);
334 W = 0.0;
335 W[iter] = 1.0;
336 }
337
338 Range range1(niter+1, ncolV(), 0), range2(niter+2, ncolV(), 0);
339 for ( int iter0=niter, iter1=niter+1, iter2=niter+2; iter0>=1
340 ; iter0--, iter1--, iter2--
341 , range1.decFirst(1), range2.decFirst(1)
342 )
343 {
344 // get beta and test
345 Real beta = U_(iter0, iter1);
346 if (beta)
347 {
348 // ref on the row iter1 of V_
349 PointX Vrow1(V_, range1, iter1);
350 // diagonal element
351 Vrow1[iter1] = 1.0+beta;
352 // ref on the column iter1
353 VectorX Vcol1(V_, range2, iter1);
354 // get the Householder vector
355 Vcol1 = RowVector(U_, range2, iter0);
356 // Apply housholder to next cols
357 for (int j=iter2; j<=ncolV(); j++)
358 {
359 Real aux;
360 // ref on the column j
361 VectorX Vcolj( V_, range2, j);
362 // update column j
363 Vrow1[j] = (aux = dot(Vcol1, Vcolj) * beta);
364 for (int i= iter2; i <= ncolV(); ++i)
365 { Vcolj[i] += Vcol1[i] * aux;}
366 }
367 // compute the Householder vector
368 Vcol1 *= beta;
369 }
370 else // nothing to do
371 {
372 V_(range2, iter1) = 0.0;
373 V_(iter1, iter1) = 1.0;
374 V_(iter1, range2) = 0.0;
375 }
376 }
377 // First column and rows
378 V_(1,1) =1.0;
379 V_(Range(2,ncolV(), 0),1) =0.0;
380 V_(1,Range(2,ncolV(), 0)) =0.0;
381}
Array2DPoint< Real > PointX
final class for a Real horizontal container.
Array2DVector< Real > VectorX

References STK::dot().

◆ diag()

template<class Array >
bool STK::Svd< Array >::diag ( ArrayDiagonalX D,
VectorX F,
Array &  U,
ArraySquareX V,
bool  withU = true,
bool  withV = true,
Real const tol = Arithmetic<Real>::epsilon() 
)
static

Computing the diagonalization of a bi-diagonal matrix.

Parameters
Dthe diagonal of the matrix
Fthe subdiagonal of the matrix
Ua left orthogonal Array
withUtrue if we want to update U
Va right orthogonal Square Array
withVtrue if we want to update V
tolthe tolerance to use

Definition at line 503 of file STK_Svd.h.

511{
512 // result of the diag process
513 bool error = false;
514 // Diagonalization of A : Reduction of la matrice bidiagonale
515 for (int end=D.lastIdx(); end>=D.begin(); --end)
516 { // 30 iter max
517 int iter;
518 for (iter=1; iter<=MAX_ITER; iter++)
519 { // if the last element of the subdiagonale is 0.0
520 // stop the iterations
521 int beg;
522 if (std::abs(F[end-1])+tol == tol) { F[end-1] = 0.0; break;}
523 // now F[end-1] !=0
524 // if D[end] == 0, we can annulate F[end-1]
525 // with rotations of the columns.
526 if (std::abs(D[end])+tol == tol)
527 {
528 D[end] = 0.0;
529 rightEliminate(D, F, end-1, V, withV, tol);
530 break; // Last element of the subdiagonal is 0
531 }
532 // now D[end] != 0 and F[end-1] != 0
533 // look for the greatest matrix such that all the elements
534 // of the diagonal and subdiagonal are not zeros
535 for (beg = end-1; beg>D.begin(); --beg)
536 {
537 if ((std::abs(D[beg])+tol == tol)||(std::abs(F[beg])+tol == tol))
538 break;
539 }
540 // now F[beg-1]!=0
541 // if D[beg] == 0 and F[beg] != 0,
542 // we can eliminate the element F[beg]
543 // with rotations of the rows
544 if ((std::abs(D[beg])+tol == tol) && (std::abs(F[beg])+tol != tol))
545 {
546 D[beg] = 0.0;
547 leftEliminate(D, F, beg, U, withU, tol);
548 }
549
550 // Si F[beg]==0, on augmente beg
551 if (std::abs(F[beg])+tol == tol) { F[beg] = 0.0; beg++;}
552
553 // On peut commencer les rotations QR entre les lignes beg et end
554 // Shift computation
555 // easy shift : commented
556 // Real aux = norm(D[end],F[end-1]);
557 // Real y = (D[beg]+aux)*(D[beg]-aux);
558 // Real z = D[beg]*F[beg];
559 // Wilkinson shift : look at the doc
560 Real dd1 = D[end-1]; // d_1
561 Real dd2 = D[end]; // d_2
562 Real ff1 = F[end-2]; // f_1
563 Real ff2 = F[end-1]; // f_2
564 // g
565 Real aux = ( (dd1+dd2)*(dd1-dd2)
566 + (ff1-ff2)*(ff1+ff2))/(2*dd1*ff2);
567 // A - mu
568 Real d1 = D[beg];
569 Real f1 = F[beg];
570 Real y = (d1+dd2)*(d1-dd2)
571 + ff2*(dd1/(aux+sign(aux,norm(1.0,aux)))- ff2);
572 Real z = d1*f1;
573 // chase no null element
574 int k, k1;
575 for (k=beg, k1 = beg+1; k<end; ++k, ++k1)
576 { // Rotation colonnes (k,k+1)
577 // Input : d1 contient D[k],
578 // f1 contient F[k],
579 // y contient F[k-1]
580 // Output : d1 contient F[k],
581 // d2 contient D[k+1],
582 // y contient D[k]
583 Real cosinus=1., sinus=0.;
584 Real d2 = D[k1];
585 F[k-1] = (aux = norm(y,z)); // F[k-1]
586 // arbitrary rotation if y = z = 0.0
587 if (aux)
588 y = (cosinus = y/aux) * d1 - (sinus = -z/aux) * f1; // D[k]
589 else
590 y = cosinus * d1 - sinus * f1; // D[k]
591
592 z = -sinus * d2; // z
593 d1 = sinus * d1 + cosinus * f1; // F[k]
594 d2 *= cosinus; // D[k+1]
595 // Update V
596 if (withV)
597 rightGivens(V, k1, k, cosinus, sinus);
598 // avoid underflow
599 // Rotation lignes (k,k+1)
600 // Input : d1 contient F[k],
601 // d2 contient D[k+1],
602 // y contient D[k]
603 // Output : d1 contient D[k+1],
604 // f1 contient F[k+1],
605 // y contient F[k]
606 f1 = F[k1];
607 D[k] = (aux = norm(y,z)); // D[k]
608 // arbitrary rotation if y = z = 0.0
609 if (aux)
610 y = (cosinus = y/aux) * d1 - (sinus = -z/aux) * d2; // F[k]
611 else
612 y = cosinus * d1 - sinus * d2; // F[k]
613
614 z = -sinus * f1; // z
615 d1 = sinus *d1 + cosinus * d2; // D[k+1]
616 f1 *= cosinus; // F[k+1]
617 // Update U
618 if (withU)
619 rightGivens(U, k1, k, cosinus, sinus);
620 } // end of the QR updating iteration
621 D[end] = d1;
622 F[end-1] = y;
623 F[beg-1] = 0.0; // F[beg-1] is overwritten, we have to set 0.0
624 } // iter
625 // too many iterations
626 if (iter >= 30) { error = true;}
627 // positive singular value only
628 if (D[end]< 0.0)
629 {
630 // change sign of the singular value
631 D[end]= -D[end];
632 // change sign of the column end of V
633 if (withV)
634 {
635 for (int i= V.beginRows(); i <= V.lastIdxRows(); ++i)
636 { V(i,end) = -V(i,end);}
637 }
638 }
639
640 // We have to sort the singular value : we use a basic strategy
641 Real z = D[end]; // current value
642 for (int i=end+1; i<=D.lastIdx(); i++)
643 { if (D[i]> z) // if the ith singular value is greater
644 { D.swap(i-1, i); // swap the cols
645 if (withU) U.swapCols(i-1, i);
646 if (withV) V.swapCols(i-1, i);
647 }
648 else break;
649 } // end sort
650 } // boucle end
651 return error;
652}
#define d2(z)
#define d1(z)
#define MAX_ITER
Definition STK_Svd.h:49
ArrayD const & D() const
Definition STK_ISvd.h:152
ArrayU const & U() const
Definition STK_ISvd.h:148
ArrayV const & V() const
Definition STK_ISvd.h:150
void rightGivens(ArrayBase< TContainer2D > &M, int j1, int j2, typename TContainer2D::Type const &cosinus, typename TContainer2D::Type const &sinus)
Apply Givens rotation.
Definition STK_Givens.h:119
Type sign(Type const &x, Type const &y=Type(1))
template sign value sign(x) * y: Type should be an integral type
Definition STK_Misc.h:53

References STK::IArray2D< Derived >::beginRows(), d1, d2, STK::IRunnerBase::error(), STK::IArray2D< Derived >::lastIdxRows(), MAX_ITER, STK::norm(), STK::rightGivens(), STK::sign(), STK::IArray2D< Derived >::swap(), and STK::IArray2D< Derived >::swapCols().

◆ operator=()

template<class Array >
Svd< Array > & STK::Svd< Array >::operator= ( const Svd< Array > &  S)

Operator = : overwrite the Svd with S.

Parameters
Sthe Svd to copy

Definition at line 212 of file STK_Svd.h.

213{
214 U_ = S.U_;
215 V_ = S.V_;
216 D_ = S.D_;
217 withU_ = S.withU_;
218 withV_ = S.withV_;
219 norm_ = S.norm_;
220 rank_ = S.rank_;
221 return *this;
222}

◆ rightEliminate()

template<class Array >
void STK::Svd< Array >::rightEliminate ( ArrayDiagonalX D,
VectorX F,
int const nrow,
ArraySquareX V,
bool  withV = true,
Real const tol = Arithmetic<Real>::epsilon() 
)
static

right eliminate the element on the subdiagonal of the row nrow

Parameters
Dthe diagonal of the matrix
Fthe subdiagonal of the matrix
nrowthe number of the row were we want to rightEliminate
Va right orthogonal Square Array
withVtrue if we want to update V
tolthe tolerance to use

Definition at line 436 of file STK_Svd.h.

439{
440 // the element to eliminate
441 Real z = F[nrow];
442 // if the element is not 0.0
443 if (std::abs(z)+tol != tol)
444 {
445 // column of the element to eliminate
446 int ncol1 = nrow+1;
447 // begin the Givens rotations
448 for (int k=nrow, k1=nrow-1; k>=1 ; k--, k1--)
449 {
450 // compute and apply Givens rotation to the rows (k, k+1)
451 Real aux, sinus, cosinus;
452 Real y = D[k];
453 D[k] = (aux = norm(y,z));
454 z = (sinus = -z/aux) * F[k1];
455 F[k1] *= (cosinus = y/aux);
456 // Update V_
457 if (withV)
458 rightGivens(V, ncol1, k, cosinus, sinus);
459 // if 0.0 we can break now
460 if (std::abs(z)+tol == tol) break;
461 }
462 }
463 // the element is now 0
464 F[nrow] = 0.0; // is 0.0
465}

References STK::norm(), and STK::rightGivens().

◆ runImpl()

template<class Array >
bool STK::Svd< Array >::runImpl ( )

run the Svd

Definition at line 226 of file STK_Svd.h.

227{
228 if (!computeSvd()) return false;
229 return true;
230}
bool computeSvd()
Svd main steps.
Definition STK_Svd.h:235

Member Data Documentation

◆ F_

template<class Array >
VectorX STK::Svd< Array >::F_
private

Values of the Sub-diagonal.

Definition at line 196 of file STK_Svd.h.


The documentation for this class was generated from the following file: