1 
2 // @HEADER
3 // ***********************************************************************
4 //
5 //                    Teuchos: Common Tools Package
6 //                 Copyright (2004) Sandia Corporation
7 //
8 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9 // license for use of this work by or on behalf of the U.S. Government.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // ***********************************************************************
39 // @HEADER
40 
41 #ifndef _TEUCHOS_SERIALSYMDENSEMATRIX_HPP_
42 #define _TEUCHOS_SERIALSYMDENSEMATRIX_HPP_
43 /*! \file Teuchos_SerialSymDenseMatrix.hpp
44   \brief Templated serial, dense, symmetric matrix class.
45 */
46 
47 #include "Teuchos_CompObject.hpp"
48 #include "Teuchos_BLAS.hpp"
49 #include "Teuchos_ScalarTraits.hpp"
50 #include "Teuchos_DataAccess.hpp"
51 #include "Teuchos_ConfigDefs.hpp"
52 #include "Teuchos_Assert.hpp"
53 #include <utility>
54 #include <vector>
55 
56 /*! \class Teuchos::SerialSymDenseMatrix
57     \brief This class creates and provides basic support for symmetric, positive-definite dense matrices of templated type.
58 
59     The Teuchos_SerialSymDenseMatrix class enables the construction and use of
60     symmetric, positive-definite, dense matrices of templated type.
61 
62     The Teuchos::SerialSymDenseMatrix class is intended to provide full-featured support for solving
63     linear and eigen system problems for symmetric positive-definite (SPD) matrices.  It is written on
64     top of BLAS and LAPACK and thus has excellent performance and numerical capabilities.  Using this
65     class, one can either perform simple factorizations and solves or apply all the tricks available in
66     LAPACK to get the best possible solution for very ill-conditioned problems.
67 
68     <b>Teuchos::SerialSymDenseMatrix vs. Teuchos::LAPACK</b>
69 
70     The Teuchos::LAPACK class provides access to most of the same functionality as Teuchos::SerialSymDenseMatrix.
71     The primary difference is that Teuchos::LAPACK is a "thin" layer on top of LAPACK and
72     Teuchos::SerialSymDenseMatrix attempts to provide easy access to the more sophisticated aspects of
73     solving dense linear and eigensystems.
74 <ul>
75 <li> When you should use Teuchos::LAPACK:  If you are simply looking for a convenient wrapper around
76 the Fortran LAPACK routines and you have a well-conditioned problem, you should probably use Teuchos::LAPACK directly.
77 <li> When you should use Teuchos::SerialSymDenseMatrix: If you want to (or potentially want to) solve ill-conditioned
78      problems or want to work with a more object-oriented interface, you should probably use Teuchos::SerialSymDenseMatrix.
79 </ul>
80 
81 <b>Constructing Teuchos::SerialSymDenseMatrix Objects</b>
82 
83 There are three Teuchos::SerialSymDenseMatrix constructors.  The first constructs a zero-sized object
84 which should be made to appropriate length using the Shape() or Reshape() functions and then filled with
85 the [] or () operators. The second is a constructor that accepts user data as a 2D array, the third is a
86 copy constructor. The second constructor has two data access modes (specified by the Teuchos::DataAccess argument):
87 <ol>
88   <li> Copy mode - Allocates memory and makes a copy of the user-provided data. In this case, the
89        user data is not needed after construction.
90   <li> View mode - Creates a "view" of the user data. In this case, the
91        user data is required to remain intact for the life of the object.
92 </ol>
93 
94 \warning View mode is \e extremely dangerous from a data hiding perspective. Therefore, we strongly encourage
95 users to develop code using Copy mode first and only use the View mode in a secondary optimization phase.
96 
97 <b>Extracting Data from Teuchos::SerialSymDenseMatrix Objects</b>
98 
99 Once a Teuchos::SerialSymDenseMatrix is constructed, it is possible to view the data via access functions.
100 
101 \warning Use of these access functions cam be \e extremely dangerous from a data hiding perspective.
102 
103 <b>Vector and Utility Functions</b>
104 
105 Once a Teuchos::SerialSymDenseMatrix is constructed, several mathematical functions can be applied to
106 the object.  Specifically:
107 <ul>
108   <li> Multiplication.
109   <li> Norms.
110 </ul>
111 
112 */
113 
114 /** \example DenseMatrix/cxx_main_sym.cpp
115     This is an example of how to use the Teuchos::SerialSymDenseMatrix class.
116 */
117 
118 namespace Teuchos {
119 
120 template<typename OrdinalType, typename ScalarType>
121 class SerialSymDenseMatrix : public CompObject, public BLAS<OrdinalType,ScalarType>
122 {
123  public:
124 
125   //! Typedef for ordinal type
126   typedef OrdinalType ordinalType;
127   //! Typedef for scalar type
128   typedef ScalarType scalarType;
129 
130   //! @name Constructor/Destructor Methods
131   //@{
132   //! Default constructor; defines a zero size object.
133   /*!
134     Teuchos::SerialSymDenseMatrix objects defined by the default constructor
135     should be sized with the Shape() or Reshape() functions.
136     Values should be defined by using the [] or ()operators.
137 
138     Note: By default the active part of the matrix is assumed to be the lower triangular part.
139     To set the upper part as active, call SetUpper(). See Detailed Description section for further discussion.
140    */
141   SerialSymDenseMatrix() = default;
142 
143   //! Basic constructor; defines a matrix of \c numRowsCols size and (optionally) initializes it.
144   /*!
145     \param numRowsCols - Number of rows and columns in the matrix.
146     \param zeroOut - Initializes values to 0 if true (default)
147 
148     Creates a shaped matrix with \c numRowsCols rows and cols.  All values are initialized to 0 when \c zeroOut is true.
149     Values of this matrix should be set using the [] or the () operators.
150 
151     \note By default the active part of the matrix is assumed to be the lower triangular part.
152     To set the upper part as active, call SetUpper(). See Detailed Description section for further discussion.
153   */
154   SerialSymDenseMatrix(OrdinalType numRowsCols, bool zeroOut = true);
155 
156   //! Set object values from two-dimensional array.
157   /*!
158     \param CV - Enumerated type set to Teuchos::Copy or Teuchos::View.
159 
160     \param values - Pointer to an array of ScalarType.  The first column starts at \c values,
161                 the second at \c values+stride, etc.
162     \param stride - The stride between the columns of the matrix in memory.
163     \param numRowsCols - Number of rows and columns in the matrix.
164 
165     \note By default the active part of the matrix is assumed to be the lower triangular part.
166     To set the upper part as active, call SetUpper(). See Detailed Description section for further discussion.
167   */
168   SerialSymDenseMatrix(DataAccess CV, bool upper, ScalarType* values, OrdinalType stride, OrdinalType numRowsCols);
169 
170   //! Teuchos::SerialSymDenseMatrix copy constructor.
171   SerialSymDenseMatrix(const SerialSymDenseMatrix<OrdinalType, ScalarType> &Source);
172 
173   //! Submatrix Copy Constructor
174   /*!
175     \param CV - Enumerated type set to Teuchos::Copy or Teuchos::View.
176     \param Source - Reference to another dense matrix from which values are to be copied.
177     \param numRowCols - The number of rows and columns in this matrix.
178     \param startRowCol - The row and column of \c Source from which the submatrix copy should start.
179 
180     Creates a shaped matrix with \c numRowCols rows and columns, which is a submatrix of \c Source.
181     If \c startRowCol are not given, then the submatrix is the leading submatrix of \c Source.
182   */
183   SerialSymDenseMatrix(DataAccess CV, const SerialSymDenseMatrix<OrdinalType, ScalarType> &Source, OrdinalType numRowCols, OrdinalType startRowCol=0);
184 
185   //! Teuchos::SerialSymDenseMatrix destructor.
186   virtual ~SerialSymDenseMatrix ();
187   //@}
188 
189   //! @name Shaping Methods
190   //@{
191 
192   //! Set dimensions of a Teuchos::SerialSymDenseMatrix object; init values to zero.
193   /*!
194     \param numRowsCols - Number of rows and columns in object.
195 
196     Allows user to define the dimensions of a Teuchos::SerialSymDenseMatrix at any point. This function can
197     be called at any point after construction.  Any values that were previously in this object are
198     destroyed and the resized matrix starts off with all zero values.
199 
200     \return Integer error code, set to 0 if successful.
201   */
202   int shape(OrdinalType numRowsCols);
203 
204   //! Set dimensions of a Teuchos::SerialSymDenseMatrix object; don't initialize values.
205   /*!
206     \param numRowsCols - Number of rows and columns in object.
207 
208     Allows user to define the dimensions of a Teuchos::SerialSymDenseMatrix at any point. This function can
209     be called at any point after construction.  Any values that were previously in this object are
210     destroyed.  The resized matrix has uninitialized values.
211 
212     \return Integer error code, set to 0 if successful.
213   */
214   int shapeUninitialized(OrdinalType numRowsCols);
215 
216   //! Reshape a Teuchos::SerialSymDenseMatrix object.
217   /*!
218     \param numRowsCols - Number of rows and columns in object.
219 
220     Allows user to define the dimensions of a Teuchos::SerialSymDenseMatrix at any point. This function can
221     be called at any point after construction.  Any values that were previously in this object are
222     copied into the new shape.  If the new shape is smaller than the original, the upper left portion
223     of the original matrix (the principal submatrix) is copied to the new matrix.
224 
225     \return Integer error code, set to 0 if successful.
226   */
227   int reshape(OrdinalType numRowsCols);
228 
229   //! Specify that the lower triangle of the \e this matrix should be used.
230   /*! \warning This may necessitate the matrix values be copied from the upper to lower portion of the matrix.
231   */
232   void setLower();
233 
234   //! Specify that the upper triangle of the \e this matrix should be used.
235   /*! \warning This may necessitate the matrix values be copied from the lower to upper portion of the matrix.
236   */
237   void setUpper();
238 
239   //@}
240 
241   //! @name Set methods.
242   //@{
243 
244   //! Copies values from one matrix to another.
245   /*!
246     The operator= copies the values from one existing SerialSymDenseMatrix to another.
247     If \c Source is a view (i.e. CV = Teuchos::View), then this method will
248     return a view.  Otherwise, it will return a copy of \c Source.  \e this object
249     will be resized if it is not large enough to copy \c Source into.
250   */
251   SerialSymDenseMatrix<OrdinalType, ScalarType>& operator= (const SerialSymDenseMatrix<OrdinalType, ScalarType>& Source);
252 
253   //! Copies values from one matrix to another.
254   /*!
255     Copies the values from one existing SerialSymDenseMatrix to another if the dimension of both matrices are the same.
256     If not, \e this matrix will be returned unchanged.
257   */
258   SerialSymDenseMatrix<OrdinalType, ScalarType>& assign (const SerialSymDenseMatrix<OrdinalType, ScalarType>& Source);
259 
260   //! Set all values in the matrix to a constant value.
261   /*!
262     \param value - Value to use;
263   */
operator =(const ScalarType value)264   SerialSymDenseMatrix<OrdinalType, ScalarType>& operator= (const ScalarType value) { putScalar(value); return(*this); }
265 
266   //! Set all values in the matrix to a constant value.
267   /*!
268     \param value - Value to use; zero if none specified.
269     \param fullMatrix - set full matrix entries to \c value, not just active portion of symmetric matrix.
270     \return Integer error code, set to 0 if successful.
271   */
272   int putScalar( const ScalarType value = Teuchos::ScalarTraits<ScalarType>::zero(), bool fullMatrix = false );
273 
274   //! Swap values between this matrix and incoming matrix.
275   /*!
276     Swaps pointers and associated state without copying the matrix data.
277   */
278   void swap (SerialSymDenseMatrix<OrdinalType, ScalarType> &B);
279 
280   //! Set all values in the active area (upper/lower triangle) of this matrix to be random numbers.
281   /*! \note The diagonal will be the sum of the off diagonal elements, plus a bias, so the matrix is SPD.
282    */
283   int random( const ScalarType bias = 0.1*Teuchos::ScalarTraits<ScalarType>::one() );
284 
285   //@}
286 
287   //! @name Accessor methods.
288   //@{
289 
290   //! Element access method (non-const).
291   /*! Returns the element in the ith row and jth column if A(i,j) is specified.
292 
293     \return Element from the specified \c rowIndex row and \c colIndex column.
294     \note If the requested element lies in the inactive part of the matrix, then A(j,i) will be returned.
295     \warning The validity of \c rowIndex and \c colIndex will only be checked if Teuchos is
296     configured with --enable-teuchos-abc.
297   */
298   ScalarType& operator () (OrdinalType rowIndex, OrdinalType colIndex);
299 
300   //! Element access method (const).
301   /*! Returns the element in the ith row and jth column if A(i,j) is specified.
302 
303     \return Element from the specified \c rowIndex row and \c colIndex column.
304     \note If the requested element lies in the inactive part of the matrix, then A(j,i) will be returned.
305     \warning The validity of \c rowIndex and \c colIndex will only be checked if Teuchos is
306     configured with --enable-teuchos-abc.
307   */
308   const ScalarType& operator () (OrdinalType rowIndex, OrdinalType colIndex) const;
309 
310   //! Returns the pointer to the ScalarType data array contained in the object.
311   /*! \note The matrix values are only guaranteed to be stored in the active area of the matrix (upper/lower).
312   */
values() const313   ScalarType* values() const { return(values_); }
314 
315   //@}
316 
317   //! @name Query methods
318   //@{
319 
320   //! Returns true if upper triangular part of \e this matrix has and will be used.
upper() const321   bool upper() const {return(upper_);};
322 
323   //! Returns character value of UPLO used by LAPACK routines.
UPLO() const324   char UPLO() const {return(UPLO_);};
325   //@}
326 
327   //! @name Mathematical Methods
328   //@{
329 
330   //! Inplace scalar-matrix product A = \c alpha*A.
331   /*! Scale a matrix, entry-by-entry using the value \e alpha.  This method is sensitive to
332       the UPLO() parameter.
333 
334    \param alpha - Scalar to multiply with A.
335 
336   */
337   SerialSymDenseMatrix<OrdinalType, ScalarType>& operator*= (const ScalarType alpha);
338 
339   //! Add another matrix to \e this matrix.
340   /*! Add \c Source to \e this if the dimension of both matrices are the same.  If not, \e this matrix
341     will be returned unchanged.
342   */
343   SerialSymDenseMatrix<OrdinalType, ScalarType>& operator+= (const SerialSymDenseMatrix<OrdinalType, ScalarType>& Source);
344 
345   //! Subtract another matrix from \e this matrix.
346   /*! Subtract \c Source from \e this if the dimension of both matrices are the same.  If not, \e this matrix
347     will be returned unchanged.
348   */
349   SerialSymDenseMatrix<OrdinalType, ScalarType>& operator-= (const SerialSymDenseMatrix<OrdinalType, ScalarType>& Source);
350 
351   //@}
352 
353   //! @name Comparison methods.
354   //@{
355 
356   //! Equality of two matrices.
357   /*! \return True if \e this matrix and \c Operand are of the same shape (rows / columns) and have
358     the same entries in the active (upper / lower triangular) area of the matrix, else False will be returned.
359   */
360   bool operator== (const SerialSymDenseMatrix<OrdinalType, ScalarType> &Operand) const;
361 
362   //! Inequality of two matrices.
363   /*! \return True if \e this matrix and \c Operand of not of the same shape (rows / columns) or don't
364     have the same entries in the active (upper / lower triangular), else False will be returned.
365   */
366   bool operator!= (const SerialSymDenseMatrix<OrdinalType, ScalarType> &Operand) const;
367 
368   //@}
369 
370   //! @name Attribute methods.
371   //@{
372 
373   //! Returns the row dimension of this matrix.
numRows() const374   OrdinalType numRows() const { return(numRowCols_); }
375 
376   //! Returns the column dimension of this matrix.
numCols() const377   OrdinalType numCols() const { return(numRowCols_); }
378 
379   //! Returns the stride between the columns of this matrix in memory.
stride() const380   OrdinalType stride() const { return(stride_); }
381 
382   //! Returns whether this matrix is empty.
empty() const383   bool empty() const { return(numRowCols_ == 0); }
384 
385   //@}
386 
387   //! @name Norm methods.
388   //@{
389 
390   //! Returns the 1-norm of the matrix.
391   typename ScalarTraits<ScalarType>::magnitudeType normOne() const;
392 
393   //! Returns the Infinity-norm of the matrix.
394   typename ScalarTraits<ScalarType>::magnitudeType normInf() const;
395 
396   //! Returns the Frobenius-norm of the matrix.
397   typename ScalarTraits<ScalarType>::magnitudeType normFrobenius() const;
398   //@}
399 
400   //! @name I/O methods.
401   //@{
402   //! Print method.  Defines the behavior of the std::ostream << operator
403   virtual std::ostream& print(std::ostream& os) const;
404 
405   //@}
406 
407  protected:
408 
409   // In-place scaling of matrix.
410   void scale( const ScalarType alpha );
411 
412   // Copy the values from one matrix to the other.
413   void copyMat(bool inputUpper, ScalarType* inputMatrix, OrdinalType inputStride,
414                OrdinalType numRowCols, bool outputUpper, ScalarType* outputMatrix,
415                OrdinalType outputStride, OrdinalType startRowCol,
416                ScalarType alpha = ScalarTraits<ScalarType>::zero() );
417 
418   // Copy the values from the active triangle of the matrix to the other to make the matrix full symmetric.
419   void copyUPLOMat(bool inputUpper, ScalarType* inputMatrix,
420                    OrdinalType inputStride, OrdinalType inputRows);
421 
422   void deleteArrays();
423   void checkIndex( OrdinalType rowIndex, OrdinalType colIndex = 0 ) const;
424 
425   static ScalarType*
allocateValues(const OrdinalType numRows,const OrdinalType numCols)426   allocateValues(const OrdinalType numRows,
427                  const OrdinalType numCols)
428   {
429     const size_t size = size_t(numRows) * size_t(numCols);
430 #pragma GCC diagnostic push
431 #pragma GCC diagnostic ignored "-Wvla"
432     return new ScalarType[size];
433 #pragma GCC diagnostic pop
434   }
435 
436   OrdinalType numRowCols_ = 0;
437   OrdinalType stride_ = 0;
438   bool valuesCopied_ = false;
439   ScalarType* values_ = nullptr;
440   bool upper_ = false;
441   char UPLO_ {'L'};
442 };
443 
444 //----------------------------------------------------------------------------------------------------
445 //  Constructors and Destructor
446 //----------------------------------------------------------------------------------------------------
447 
448 template<typename OrdinalType, typename ScalarType>
SerialSymDenseMatrix(OrdinalType numRowCols_in,bool zeroOut)449 SerialSymDenseMatrix<OrdinalType, ScalarType>::SerialSymDenseMatrix(OrdinalType numRowCols_in, bool zeroOut)
450   : numRowCols_(numRowCols_in), stride_(numRowCols_in), valuesCopied_(false), upper_(false), UPLO_('L')
451 {
452   values_ = allocateValues(stride_, numRowCols_);
453   valuesCopied_ = true;
454   if (zeroOut) {
455     const ScalarType ZERO = Teuchos::ScalarTraits<ScalarType>::zero();
456     putScalar(ZERO, true);
457   }
458 }
459 
460 template<typename OrdinalType, typename ScalarType>
SerialSymDenseMatrix(DataAccess CV,bool upper_in,ScalarType * values_in,OrdinalType stride_in,OrdinalType numRowCols_in)461 SerialSymDenseMatrix<OrdinalType, ScalarType>::SerialSymDenseMatrix(
462   DataAccess CV, bool upper_in, ScalarType* values_in, OrdinalType stride_in, OrdinalType numRowCols_in
463   )
464   : numRowCols_(numRowCols_in), stride_(stride_in), valuesCopied_(false),
465     values_(values_in), upper_(upper_in)
466 {
467   if (upper_)
468     UPLO_ = 'U';
469   else
470     UPLO_ = 'L';
471 
472   if(CV == Copy)
473   {
474     stride_ = numRowCols_;
475     values_ = allocateValues(stride_, numRowCols_);
476     copyMat(upper_in, values_in, stride_in, numRowCols_, upper_, values_, stride_, 0);
477     valuesCopied_ = true;
478   }
479 }
480 
481 template<typename OrdinalType, typename ScalarType>
SerialSymDenseMatrix(const SerialSymDenseMatrix<OrdinalType,ScalarType> & Source)482 SerialSymDenseMatrix<OrdinalType, ScalarType>::SerialSymDenseMatrix(const SerialSymDenseMatrix<OrdinalType, ScalarType> &Source)
483   : numRowCols_(Source.numRowCols_), stride_(0), valuesCopied_(true),
484     values_(0), upper_(Source.upper_), UPLO_(Source.UPLO_)
485 {
486   if (!Source.valuesCopied_)
487   {
488     stride_ = Source.stride_;
489     values_ = Source.values_;
490     valuesCopied_ = false;
491   }
492   else
493   {
494     stride_ = numRowCols_;
495     if(stride_ > 0 && numRowCols_ > 0) {
496       values_ = allocateValues(stride_, numRowCols_);
497       copyMat(Source.upper_, Source.values_, Source.stride_, numRowCols_, upper_, values_, stride_, 0);
498     }
499     else {
500       numRowCols_ = 0;
501       stride_ = 0;
502       valuesCopied_ = false;
503     }
504   }
505 }
506 
507 template<typename OrdinalType, typename ScalarType>
SerialSymDenseMatrix(DataAccess CV,const SerialSymDenseMatrix<OrdinalType,ScalarType> & Source,OrdinalType numRowCols_in,OrdinalType startRowCol)508 SerialSymDenseMatrix<OrdinalType, ScalarType>::SerialSymDenseMatrix(
509                                                                     DataAccess CV, const SerialSymDenseMatrix<OrdinalType,
510                                                                     ScalarType> &Source, OrdinalType numRowCols_in, OrdinalType startRowCol )
511   : CompObject(), BLAS<OrdinalType,ScalarType>(),
512     numRowCols_(numRowCols_in), stride_(Source.stride_), valuesCopied_(false), upper_(Source.upper_), UPLO_(Source.UPLO_)
513 {
514   if(CV == Copy)
515   {
516     stride_ = numRowCols_in;
517     values_ = allocateValues(stride_, numRowCols_in);
518     copyMat(Source.upper_, Source.values_, Source.stride_, numRowCols_in, upper_, values_, stride_, startRowCol);
519     valuesCopied_ = true;
520   }
521   else // CV == View
522   {
523     values_ = Source.values_ + (stride_ * startRowCol) + startRowCol;
524   }
525 }
526 
527 template<typename OrdinalType, typename ScalarType>
~SerialSymDenseMatrix()528 SerialSymDenseMatrix<OrdinalType, ScalarType>::~SerialSymDenseMatrix()
529 {
530   deleteArrays();
531 }
532 
533 //----------------------------------------------------------------------------------------------------
534 //  Shape methods
535 //----------------------------------------------------------------------------------------------------
536 
537 template<typename OrdinalType, typename ScalarType>
shape(OrdinalType numRowCols_in)538 int SerialSymDenseMatrix<OrdinalType, ScalarType>::shape( OrdinalType numRowCols_in )
539 {
540   deleteArrays(); // Get rid of anything that might be already allocated
541   numRowCols_ = numRowCols_in;
542   stride_ = numRowCols_;
543   values_ = allocateValues(stride_, numRowCols_);
544   putScalar( Teuchos::ScalarTraits<ScalarType>::zero(), true );
545   valuesCopied_ = true;
546   return(0);
547 }
548 
549 template<typename OrdinalType, typename ScalarType>
shapeUninitialized(OrdinalType numRowCols_in)550 int SerialSymDenseMatrix<OrdinalType, ScalarType>::shapeUninitialized( OrdinalType numRowCols_in )
551 {
552   deleteArrays(); // Get rid of anything that might be already allocated
553   numRowCols_ = numRowCols_in;
554   stride_ = numRowCols_;
555   values_ = allocateValues(stride_, numRowCols_);
556   valuesCopied_ = true;
557   return(0);
558 }
559 
560 template<typename OrdinalType, typename ScalarType>
reshape(OrdinalType numRowCols_in)561 int SerialSymDenseMatrix<OrdinalType, ScalarType>::reshape( OrdinalType numRowCols_in )
562 {
563   // Allocate space for new matrix
564   ScalarType* values_tmp = allocateValues(numRowCols_in, numRowCols_in);
565   const ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
566   for(OrdinalType k = 0; k < numRowCols_in * numRowCols_in; k++)
567   {
568     values_tmp[k] = zero;
569   }
570   OrdinalType numRowCols_tmp = TEUCHOS_MIN(numRowCols_, numRowCols_in);
571   if(values_ != 0)
572   {
573     copyMat(upper_, values_, stride_, numRowCols_tmp, upper_, values_tmp, numRowCols_in, 0); // Copy principal submatrix of A to new A
574   }
575   deleteArrays(); // Get rid of anything that might be already allocated
576   numRowCols_ = numRowCols_in;
577   stride_ = numRowCols_;
578   values_ = values_tmp; // Set pointer to new A
579   valuesCopied_ = true;
580   return(0);
581 }
582 
583 //----------------------------------------------------------------------------------------------------
584 //   Set methods
585 //----------------------------------------------------------------------------------------------------
586 
587 template<typename OrdinalType, typename ScalarType>
setLower()588 void SerialSymDenseMatrix<OrdinalType, ScalarType>::setLower()
589 {
590   // Do nothing if the matrix is already a lower triangular matrix
591   if (upper_ != false) {
592     copyUPLOMat( true, values_, stride_, numRowCols_ );
593     upper_ = false;
594     UPLO_ = 'L';
595   }
596 }
597 
598 template<typename OrdinalType, typename ScalarType>
setUpper()599 void SerialSymDenseMatrix<OrdinalType, ScalarType>::setUpper()
600 {
601   // Do nothing if the matrix is already an upper triangular matrix
602   if (upper_ == false) {
603     copyUPLOMat( false, values_, stride_, numRowCols_ );
604     upper_ = true;
605     UPLO_ = 'U';
606   }
607 }
608 
609 template<typename OrdinalType, typename ScalarType>
putScalar(const ScalarType value_in,bool fullMatrix)610 int SerialSymDenseMatrix<OrdinalType, ScalarType>::putScalar( const ScalarType value_in, bool fullMatrix )
611 {
612   // Set each value of the dense matrix to "value".
613   if (fullMatrix == true) {
614     for(OrdinalType j = 0; j < numRowCols_; j++)
615       {
616         for(OrdinalType i = 0; i < numRowCols_; i++)
617           {
618             values_[i + j*stride_] = value_in;
619           }
620       }
621   }
622   // Set the active upper or lower triangular part of the matrix to "value"
623   else {
624     if (upper_) {
625       for(OrdinalType j = 0; j < numRowCols_; j++) {
626         for(OrdinalType i = 0; i <= j; i++) {
627           values_[i + j*stride_] = value_in;
628         }
629       }
630     }
631     else {
632       for(OrdinalType j = 0; j < numRowCols_; j++) {
633         for(OrdinalType i = j; i < numRowCols_; i++) {
634           values_[i + j*stride_] = value_in;
635         }
636       }
637     }
638   }
639   return 0;
640 }
641 
642 template<typename OrdinalType, typename ScalarType> void
swap(SerialSymDenseMatrix<OrdinalType,ScalarType> & B)643 SerialSymDenseMatrix<OrdinalType, ScalarType>::swap(
644   SerialSymDenseMatrix<OrdinalType, ScalarType> &B)
645 {
646   std::swap(values_ ,      B.values_);
647   std::swap(numRowCols_,   B.numRowCols_);
648   std::swap(stride_,       B.stride_);
649   std::swap(valuesCopied_, B.valuesCopied_);
650   std::swap(upper_,        B.upper_);
651   std::swap(UPLO_,         B.UPLO_);
652 }
653 
654 template<typename OrdinalType, typename ScalarType>
random(const ScalarType bias)655 int SerialSymDenseMatrix<OrdinalType, ScalarType>::random( const ScalarType bias )
656 {
657   typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MT;
658 
659   // Set each value of the dense matrix to a random value.
660   std::vector<MT> diagSum( numRowCols_, Teuchos::ScalarTraits<MT>::zero() );
661   if (upper_) {
662     for(OrdinalType j = 0; j < numRowCols_; j++) {
663       for(OrdinalType i = 0; i < j; i++) {
664         values_[i + j*stride_] = ScalarTraits<ScalarType>::random();
665         diagSum[i] += Teuchos::ScalarTraits<ScalarType>::magnitude( values_[i + j*stride_] );
666         diagSum[j] += Teuchos::ScalarTraits<ScalarType>::magnitude( values_[i + j*stride_] );
667       }
668     }
669   }
670   else {
671     for(OrdinalType j = 0; j < numRowCols_; j++) {
672       for(OrdinalType i = j+1; i < numRowCols_; i++) {
673         values_[i + j*stride_] = ScalarTraits<ScalarType>::random();
674         diagSum[i] += Teuchos::ScalarTraits<ScalarType>::magnitude( values_[i + j*stride_] );
675         diagSum[j] += Teuchos::ScalarTraits<ScalarType>::magnitude( values_[i + j*stride_] );
676       }
677     }
678   }
679 
680   // Set the diagonal.
681   for(OrdinalType i = 0; i < numRowCols_; i++) {
682     values_[i + i*stride_] = diagSum[i] + bias;
683   }
684   return 0;
685 }
686 
687 template<typename OrdinalType, typename ScalarType>
688 SerialSymDenseMatrix<OrdinalType,ScalarType>&
operator =(const SerialSymDenseMatrix<OrdinalType,ScalarType> & Source)689 SerialSymDenseMatrix<OrdinalType, ScalarType>::operator=( const SerialSymDenseMatrix<OrdinalType,ScalarType>& Source )
690 {
691   if(this == &Source)
692     return(*this); // Special case of source same as target
693   if((!valuesCopied_) && (!Source.valuesCopied_) && (values_ == Source.values_)) {
694     upper_ = Source.upper_;  // Might have to change the active part of the matrix.
695     return(*this); // Special case of both are views to same data.
696   }
697 
698   // If the source is a view then we will return a view, else we will return a copy.
699   if (!Source.valuesCopied_) {
700     if(valuesCopied_)       {
701       // Clean up stored data if this was previously a copy.
702       deleteArrays();
703     }
704     numRowCols_ = Source.numRowCols_;
705     stride_ = Source.stride_;
706     values_ = Source.values_;
707     upper_ = Source.upper_;
708     UPLO_ = Source.UPLO_;
709   }
710   else {
711     // If we were a view, we will now be a copy.
712     if(!valuesCopied_) {
713       numRowCols_ = Source.numRowCols_;
714       stride_ = Source.numRowCols_;
715       upper_ = Source.upper_;
716       UPLO_ = Source.UPLO_;
717       if(stride_ > 0 && numRowCols_ > 0) {
718         values_ = allocateValues(stride_, numRowCols_);
719         valuesCopied_ = true;
720       }
721       else {
722         values_ = 0;
723       }
724     }
725     // If we were a copy, we will stay a copy.
726     else {
727       if((Source.numRowCols_ <= stride_) && (Source.numRowCols_ == numRowCols_)) { // we don't need to reallocate
728         numRowCols_ = Source.numRowCols_;
729         upper_ = Source.upper_;
730         UPLO_ = Source.UPLO_;
731       }
732       else { // we need to allocate more space (or less space)
733         deleteArrays();
734         numRowCols_ = Source.numRowCols_;
735         stride_ = Source.numRowCols_;
736         upper_ = Source.upper_;
737         UPLO_ = Source.UPLO_;
738         if(stride_ > 0 && numRowCols_ > 0) {
739           values_ = allocateValues(stride_, numRowCols_);
740           valuesCopied_ = true;
741         }
742       }
743     }
744     copyMat(Source.upper_, Source.values_, Source.stride_, Source.numRowCols_, upper_, values_, stride_, 0);
745   }
746   return(*this);
747 }
748 
749 template<typename OrdinalType, typename ScalarType>
operator *=(const ScalarType alpha)750 SerialSymDenseMatrix<OrdinalType, ScalarType>& SerialSymDenseMatrix<OrdinalType, ScalarType>::operator*= (const ScalarType alpha)
751 {
752   this->scale(alpha);
753   return(*this);
754 }
755 
756 template<typename OrdinalType, typename ScalarType>
operator +=(const SerialSymDenseMatrix<OrdinalType,ScalarType> & Source)757 SerialSymDenseMatrix<OrdinalType, ScalarType>& SerialSymDenseMatrix<OrdinalType, ScalarType>::operator+= (const SerialSymDenseMatrix<OrdinalType,ScalarType>& Source )
758 {
759   // Check for compatible dimensions
760   if ((numRowCols_ != Source.numRowCols_))
761     {
762       TEUCHOS_CHK_REF(*this); // Return *this without altering it.
763     }
764   copyMat(Source.upper_, Source.values_, Source.stride_, numRowCols_, upper_, values_, stride_, 0, ScalarTraits<ScalarType>::one());
765   return(*this);
766 }
767 
768 template<typename OrdinalType, typename ScalarType>
operator -=(const SerialSymDenseMatrix<OrdinalType,ScalarType> & Source)769 SerialSymDenseMatrix<OrdinalType, ScalarType>& SerialSymDenseMatrix<OrdinalType, ScalarType>::operator-= (const SerialSymDenseMatrix<OrdinalType,ScalarType>& Source )
770 {
771   // Check for compatible dimensions
772   if ((numRowCols_ != Source.numRowCols_))
773   {
774     TEUCHOS_CHK_REF(*this); // Return *this without altering it.
775   }
776   copyMat(Source.upper_, Source.values_, Source.stride_, numRowCols_, upper_, values_, stride_, 0, -ScalarTraits<ScalarType>::one());
777   return(*this);
778 }
779 
780 template<typename OrdinalType, typename ScalarType>
assign(const SerialSymDenseMatrix<OrdinalType,ScalarType> & Source)781 SerialSymDenseMatrix<OrdinalType,ScalarType>& SerialSymDenseMatrix<OrdinalType, ScalarType>::assign (const SerialSymDenseMatrix<OrdinalType,ScalarType>& Source) {
782   if(this == &Source)
783     return(*this); // Special case of source same as target
784   if((!valuesCopied_) && (!Source.valuesCopied_) && (values_ == Source.values_)) {
785     upper_ = Source.upper_; // We may have to change the active part of the matrix.
786     return(*this); // Special case of both are views to same data.
787   }
788 
789   // Check for compatible dimensions
790   if ((numRowCols_ != Source.numRowCols_))
791   {
792     TEUCHOS_CHK_REF(*this); // Return *this without altering it.
793   }
794   copyMat(Source.upper_, Source.values_, Source.stride_, numRowCols_, upper_, values_, stride_, 0 );
795   return(*this);
796 }
797 
798 //----------------------------------------------------------------------------------------------------
799 //   Accessor methods
800 //----------------------------------------------------------------------------------------------------
801 
802 template<typename OrdinalType, typename ScalarType>
operator ()(OrdinalType rowIndex,OrdinalType colIndex)803 inline ScalarType& SerialSymDenseMatrix<OrdinalType, ScalarType>::operator () (OrdinalType rowIndex, OrdinalType colIndex)
804 {
805 #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK
806   checkIndex( rowIndex, colIndex );
807 #endif
808   if ( rowIndex <= colIndex ) {
809     // Accessing upper triangular part of matrix
810     if (upper_)
811       return(values_[colIndex * stride_ + rowIndex]);
812     else
813       return(values_[rowIndex * stride_ + colIndex]);
814   }
815   else {
816     // Accessing lower triangular part of matrix
817     if (upper_)
818       return(values_[rowIndex * stride_ + colIndex]);
819     else
820       return(values_[colIndex * stride_ + rowIndex]);
821   }
822 }
823 
824 template<typename OrdinalType, typename ScalarType>
operator ()(OrdinalType rowIndex,OrdinalType colIndex) const825 inline const ScalarType& SerialSymDenseMatrix<OrdinalType, ScalarType>::operator () (OrdinalType rowIndex, OrdinalType colIndex) const
826 {
827 #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK
828   checkIndex( rowIndex, colIndex );
829 #endif
830   if ( rowIndex <= colIndex ) {
831     // Accessing upper triangular part of matrix
832     if (upper_)
833       return(values_[colIndex * stride_ + rowIndex]);
834     else
835       return(values_[rowIndex * stride_ + colIndex]);
836   }
837   else {
838     // Accessing lower triangular part of matrix
839     if (upper_)
840       return(values_[rowIndex * stride_ + colIndex]);
841     else
842       return(values_[colIndex * stride_ + rowIndex]);
843   }
844 }
845 
846 //----------------------------------------------------------------------------------------------------
847 //   Norm methods
848 //----------------------------------------------------------------------------------------------------
849 
850 template<typename OrdinalType, typename ScalarType>
normOne() const851 typename ScalarTraits<ScalarType>::magnitudeType SerialSymDenseMatrix<OrdinalType, ScalarType>::normOne() const
852 {
853   return(normInf());
854 }
855 
856 template<typename OrdinalType, typename ScalarType>
normInf() const857 typename ScalarTraits<ScalarType>::magnitudeType SerialSymDenseMatrix<OrdinalType, ScalarType>::normInf() const
858 {
859   typedef typename ScalarTraits<ScalarType>::magnitudeType MT;
860 
861   OrdinalType i, j;
862 
863   MT sum, anorm = ScalarTraits<MT>::zero();
864   ScalarType* ptr;
865 
866   if (upper_) {
867     for (j=0; j<numRowCols_; j++) {
868       sum = ScalarTraits<MT>::zero();
869       ptr = values_ + j*stride_;
870       for (i=0; i<j; i++) {
871         sum += ScalarTraits<ScalarType>::magnitude( *ptr++ );
872       }
873       ptr = values_ + j + j*stride_;
874       for (i=j; i<numRowCols_; i++) {
875         sum += ScalarTraits<ScalarType>::magnitude( *ptr );
876         ptr += stride_;
877       }
878       anorm = TEUCHOS_MAX( anorm, sum );
879     }
880   }
881   else {
882     for (j=0; j<numRowCols_; j++) {
883       sum = ScalarTraits<MT>::zero();
884       ptr = values_ + j + j*stride_;
885       for (i=j; i<numRowCols_; i++) {
886         sum += ScalarTraits<ScalarType>::magnitude( *ptr++ );
887       }
888       ptr = values_ + j;
889       for (i=0; i<j; i++) {
890         sum += ScalarTraits<ScalarType>::magnitude( *ptr );
891         ptr += stride_;
892       }
893       anorm = TEUCHOS_MAX( anorm, sum );
894     }
895   }
896   return(anorm);
897 }
898 
899 template<typename OrdinalType, typename ScalarType>
normFrobenius() const900 typename ScalarTraits<ScalarType>::magnitudeType SerialSymDenseMatrix<OrdinalType, ScalarType>::normFrobenius() const
901 {
902   typedef typename ScalarTraits<ScalarType>::magnitudeType MT;
903 
904   OrdinalType i, j;
905 
906   MT sum = ScalarTraits<MT>::zero(), anorm = ScalarTraits<MT>::zero();
907 
908   if (upper_) {
909     for (j = 0; j < numRowCols_; j++) {
910       for (i = 0; i < j; i++) {
911         sum += ScalarTraits<ScalarType>::magnitude(2.0*values_[i+j*stride_]*values_[i+j*stride_]);
912       }
913       sum += ScalarTraits<ScalarType>::magnitude(values_[j + j*stride_]*values_[j + j*stride_]);
914     }
915   }
916   else {
917     for (j = 0; j < numRowCols_; j++) {
918       sum += ScalarTraits<ScalarType>::magnitude(values_[j + j*stride_]*values_[j + j*stride_]);
919       for (i = j+1; i < numRowCols_; i++) {
920         sum += ScalarTraits<ScalarType>::magnitude(2.0*values_[i+j*stride_]*values_[i+j*stride_]);
921       }
922     }
923   }
924   anorm = ScalarTraits<ScalarType>::magnitude(ScalarTraits<ScalarType>::squareroot(sum));
925   return(anorm);
926 }
927 
928 //----------------------------------------------------------------------------------------------------
929 //   Comparison methods
930 //----------------------------------------------------------------------------------------------------
931 
932 template<typename OrdinalType, typename ScalarType>
operator ==(const SerialSymDenseMatrix<OrdinalType,ScalarType> & Operand) const933 bool SerialSymDenseMatrix<OrdinalType, ScalarType>::operator== (const SerialSymDenseMatrix<OrdinalType, ScalarType> &Operand) const
934 {
935   bool result = 1;
936   if((numRowCols_ != Operand.numRowCols_)) {
937     result = 0;
938   }
939   else {
940     OrdinalType i, j;
941     for(i = 0; i < numRowCols_; i++) {
942       for(j = 0; j < numRowCols_; j++) {
943         if((*this)(i, j) != Operand(i, j)) {
944           return 0;
945         }
946       }
947     }
948   }
949   return result;
950 }
951 
952 template<typename OrdinalType, typename ScalarType>
operator !=(const SerialSymDenseMatrix<OrdinalType,ScalarType> & Operand) const953 bool SerialSymDenseMatrix<OrdinalType, ScalarType>::operator!= (const SerialSymDenseMatrix<OrdinalType, ScalarType> &Operand) const
954 {
955   return !((*this) == Operand);
956 }
957 
958 //----------------------------------------------------------------------------------------------------
959 //   Multiplication method
960 //----------------------------------------------------------------------------------------------------
961 
962 template<typename OrdinalType, typename ScalarType>
scale(const ScalarType alpha)963 void SerialSymDenseMatrix<OrdinalType, ScalarType>::scale( const ScalarType alpha )
964 {
965   OrdinalType i, j;
966   ScalarType* ptr;
967 
968   if (upper_) {
969     for (j=0; j<numRowCols_; j++) {
970       ptr = values_ + j*stride_;
971       for (i=0; i<= j; i++) { *ptr = alpha * (*ptr); ptr++; }
972     }
973   }
974   else {
975     for (j=0; j<numRowCols_; j++) {
976       ptr = values_ + j*stride_ + j;
977       for (i=j; i<numRowCols_; i++) { *ptr = alpha * (*ptr); ptr++; }
978     }
979   }
980 }
981 
982 /*
983 template<typename OrdinalType, typename ScalarType>
984 int SerialSymDenseMatrix<OrdinalType, ScalarType>::scale( const SerialSymDenseMatrix<OrdinalType,ScalarType>& A )
985 {
986   OrdinalType i, j;
987   ScalarType* ptr;
988 
989   // Check for compatible dimensions
990   if ((numRowCols_ != A.numRowCols_)) {
991     TEUCHOS_CHK_ERR(-1); // Return error
992   }
993 
994   if (upper_) {
995     for (j=0; j<numRowCols_; j++) {
996       ptr = values_ + j*stride_;
997       for (i=0; i<= j; i++) { *ptr = A(i,j) * (*ptr); ptr++; }
998     }
999   }
1000   else {
1001     for (j=0; j<numRowCols_; j++) {
1002       ptr = values_ + j*stride_;
1003       for (i=j; i<numRowCols_; i++) { *ptr = A(i,j) * (*ptr); ptr++; }
1004     }
1005   }
1006 
1007   return(0);
1008 }
1009 */
1010 
1011 template<typename OrdinalType, typename ScalarType>
print(std::ostream & os) const1012 std::ostream& SerialSymDenseMatrix<OrdinalType, ScalarType>::print(std::ostream& os) const
1013 {
1014   os << std::endl;
1015   if(valuesCopied_)
1016     os << "Values_copied : yes" << std::endl;
1017   else
1018     os << "Values_copied : no" << std::endl;
1019   os << "Rows / Columns : " << numRowCols_ << std::endl;
1020   os << "LDA : " << stride_ << std::endl;
1021   if (upper_)
1022     os << "Storage: Upper" << std::endl;
1023   else
1024     os << "Storage: Lower" << std::endl;
1025   if(numRowCols_ == 0) {
1026     os << "(matrix is empty, no values to display)" << std::endl;
1027   } else {
1028     for(OrdinalType i = 0; i < numRowCols_; i++) {
1029       for(OrdinalType j = 0; j < numRowCols_; j++){
1030         os << (*this)(i,j) << " ";
1031       }
1032       os << std::endl;
1033     }
1034   }
1035   return os;
1036 }
1037 
1038 //----------------------------------------------------------------------------------------------------
1039 //   Protected methods
1040 //----------------------------------------------------------------------------------------------------
1041 
1042 template<typename OrdinalType, typename ScalarType>
checkIndex(OrdinalType rowIndex,OrdinalType colIndex) const1043 inline void SerialSymDenseMatrix<OrdinalType, ScalarType>::checkIndex( OrdinalType rowIndex, OrdinalType colIndex ) const {
1044   TEUCHOS_TEST_FOR_EXCEPTION(rowIndex < 0 || rowIndex >= numRowCols_, std::out_of_range,
1045     "SerialSymDenseMatrix<T>::checkIndex: "
1046     "Row index " << rowIndex << " out of range [0, "<< numRowCols_ << ")");
1047   TEUCHOS_TEST_FOR_EXCEPTION(colIndex < 0 || colIndex >= numRowCols_, std::out_of_range,
1048     "SerialSymDenseMatrix<T>::checkIndex: "
1049     "Col index " << colIndex << " out of range [0, "<< numRowCols_ << ")");
1050 }
1051 
1052 template<typename OrdinalType, typename ScalarType>
deleteArrays(void)1053 void SerialSymDenseMatrix<OrdinalType, ScalarType>::deleteArrays(void)
1054 {
1055   if (valuesCopied_)
1056   {
1057     delete [] values_;
1058     values_ = 0;
1059     valuesCopied_ = false;
1060   }
1061 }
1062 
1063 template<typename OrdinalType, typename ScalarType>
copyMat(bool inputUpper,ScalarType * inputMatrix,OrdinalType inputStride,OrdinalType numRowCols_in,bool outputUpper,ScalarType * outputMatrix,OrdinalType outputStride,OrdinalType startRowCol,ScalarType alpha)1064 void SerialSymDenseMatrix<OrdinalType, ScalarType>::copyMat(
1065                                                             bool inputUpper, ScalarType* inputMatrix,
1066                                                             OrdinalType inputStride, OrdinalType numRowCols_in,
1067                                                             bool outputUpper, ScalarType* outputMatrix,
1068                                                             OrdinalType outputStride, OrdinalType startRowCol,
1069                                                             ScalarType alpha
1070                                                             )
1071 {
1072   OrdinalType i, j;
1073   ScalarType* ptr1 = 0;
1074   ScalarType* ptr2 = 0;
1075 
1076   for (j = 0; j < numRowCols_in; j++) {
1077     if (inputUpper == true) {
1078       // The input matrix is upper triangular, start at the beginning of each column.
1079       ptr2 = inputMatrix + (j + startRowCol) * inputStride + startRowCol;
1080       if (outputUpper == true) {
1081         // The output matrix matches the same pattern as the input matrix.
1082         ptr1 = outputMatrix + j*outputStride;
1083         if (alpha != Teuchos::ScalarTraits<ScalarType>::zero() ) {
1084           for(i = 0; i <= j; i++) {
1085             *ptr1++ += alpha*(*ptr2++);
1086           }
1087         } else {
1088           for(i = 0; i <= j; i++) {
1089             *ptr1++ = *ptr2++;
1090           }
1091         }
1092       }
1093       else {
1094         // The output matrix has the opposite pattern as the input matrix.
1095         // Copy down across rows of the output matrix, but down columns of the input matrix.
1096         ptr1 = outputMatrix + j;
1097         if (alpha != Teuchos::ScalarTraits<ScalarType>::zero() ) {
1098           for(i = 0; i <= j; i++) {
1099             *ptr1 += alpha*(*ptr2++);
1100             ptr1 += outputStride;
1101           }
1102         } else {
1103           for(i = 0; i <= j; i++) {
1104             *ptr1 = *ptr2++;
1105             ptr1 += outputStride;
1106           }
1107         }
1108       }
1109     }
1110     else {
1111       // The input matrix is lower triangular, start at the diagonal of each row.
1112       ptr2 = inputMatrix + (startRowCol+j) * inputStride + startRowCol + j;
1113       if (outputUpper == true) {
1114         // The output matrix has the opposite pattern as the input matrix.
1115         // Copy across rows of the output matrix, but down columns of the input matrix.
1116         ptr1 = outputMatrix + j*outputStride + j;
1117         if (alpha != Teuchos::ScalarTraits<ScalarType>::zero() ) {
1118           for(i = j; i < numRowCols_in; i++) {
1119             *ptr1 += alpha*(*ptr2++);
1120             ptr1 += outputStride;
1121           }
1122         } else {
1123           for(i = j; i < numRowCols_in; i++) {
1124             *ptr1 = *ptr2++;
1125             ptr1 += outputStride;
1126           }
1127         }
1128       }
1129       else {
1130         // The output matrix matches the same pattern as the input matrix.
1131         ptr1 = outputMatrix + j*outputStride + j;
1132         if (alpha != Teuchos::ScalarTraits<ScalarType>::zero() ) {
1133           for(i = j; i < numRowCols_in; i++) {
1134             *ptr1++ += alpha*(*ptr2++);
1135           }
1136         } else {
1137           for(i = j; i < numRowCols_in; i++) {
1138             *ptr1++ = *ptr2++;
1139           }
1140         }
1141       }
1142     }
1143   }
1144 }
1145 
1146 template<typename OrdinalType, typename ScalarType>
copyUPLOMat(bool inputUpper,ScalarType * inputMatrix,OrdinalType inputStride,OrdinalType inputRows)1147 void SerialSymDenseMatrix<OrdinalType, ScalarType>::copyUPLOMat(
1148                                                                 bool inputUpper, ScalarType* inputMatrix,
1149                                                                 OrdinalType inputStride, OrdinalType inputRows
1150                                                                 )
1151 {
1152   OrdinalType i, j;
1153   ScalarType * ptr1 = 0;
1154   ScalarType * ptr2 = 0;
1155 
1156   if (inputUpper) {
1157     for (j=1; j<inputRows; j++) {
1158       ptr1 = inputMatrix + j;
1159       ptr2 = inputMatrix + j*inputStride;
1160       for (i=0; i<j; i++) {
1161         *ptr1 = *ptr2++;
1162         ptr1+=inputStride;
1163       }
1164     }
1165   }
1166   else {
1167     for (i=1; i<inputRows; i++) {
1168       ptr1 = inputMatrix + i;
1169       ptr2 = inputMatrix + i*inputStride;
1170       for (j=0; j<i; j++) {
1171         *ptr2++ = *ptr1;
1172         ptr1+=inputStride;
1173       }
1174     }
1175   }
1176 }
1177 
1178 /// \brief Ostream manipulator for SerialSymDenseMatrix
1179 template<typename OrdinalType, typename ScalarType>
1180 struct SerialSymDenseMatrixPrinter {
1181 public:
1182   const SerialSymDenseMatrix<OrdinalType,ScalarType> &obj;
SerialSymDenseMatrixPrinterTeuchos::SerialSymDenseMatrixPrinter1183   SerialSymDenseMatrixPrinter(
1184         const SerialSymDenseMatrix<OrdinalType,ScalarType> &obj_in)
1185       : obj(obj_in) {}
1186 };
1187 
1188 /// \brief Output SerialSymDenseMatrix object through its stream manipulator.
1189 template<typename OrdinalType, typename ScalarType>
1190 std::ostream&
operator <<(std::ostream & out,const SerialSymDenseMatrixPrinter<OrdinalType,ScalarType> printer)1191 operator<<(std::ostream &out,
1192            const SerialSymDenseMatrixPrinter<OrdinalType,ScalarType> printer)
1193 {
1194   printer.obj.print(out);
1195   return out;
1196 }
1197 
1198 /// \brief Return SerialSymDenseMatrix ostream manipulator Use as:
1199 template<typename OrdinalType, typename ScalarType>
1200 SerialSymDenseMatrixPrinter<OrdinalType,ScalarType>
printMat(const SerialSymDenseMatrix<OrdinalType,ScalarType> & obj)1201 printMat(const SerialSymDenseMatrix<OrdinalType,ScalarType> &obj)
1202 {
1203   return SerialSymDenseMatrixPrinter<OrdinalType,ScalarType>(obj);
1204 }
1205 
1206 
1207 } // namespace Teuchos
1208 
1209 #endif /* _TEUCHOS_SERIALSYMDENSEMATRIX_HPP_ */
1210