1 // @HEADER
2 // ***********************************************************************
3 //
4 //                    Teuchos: Common Tools Package
5 //                 Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef _TEUCHOS_SERIALDENSEHELPERS_HPP_
43 #define _TEUCHOS_SERIALDENSEHELPERS_HPP_
44 
45 /*! \file Teuchos_SerialDenseHelpers.hpp
46   \brief Non-member helper functions on the templated serial, dense matrix/vector classes.
47 */
48 
49 #include "Teuchos_ScalarTraits.hpp"
50 #include "Teuchos_DataAccess.hpp"
51 #include "Teuchos_ConfigDefs.hpp"
52 #include "Teuchos_Assert.hpp"
53 #include "Teuchos_SerialDenseMatrix.hpp"
54 #include "Teuchos_SerialSymDenseMatrix.hpp"
55 #include "Teuchos_SerialBandDenseMatrix.hpp"
56 #include "Teuchos_SerialDenseVector.hpp"
57 
58 #include "Teuchos_CommHelpers.hpp"
59 #include "Teuchos_DefaultComm.hpp"
60 
61 namespace Teuchos {
62 
63 /*! \relates SerialSymDenseMatrix
64   \brief A templated, non-member, helper function for computing the matrix triple-product:  B = alpha*W^T*A*W or B = alpha*W*A*W^T.
65 
66   \param transw - [in] Compute B = alpha*W^T*A*W if transw = Teuchos::TRANS, else compute B = alpha*W*A*W^T if transw = Teuchos::NO_TRANS.
67   \param alpha - [in] The scaling factor.
68   \param A - [in] SerialSymDenseMatrix
69   \param W - [in] SerialDenseMatrix
70   \param B - [out] SerialSymDenseMatrix
71 
72   \note The syntax for calling this function is:  <tt> Teuchos::symMatTripleProduct<int,double>( Teuchos::TRANS, alpha, A, W, B ) </tt>
73 */
74 template<typename OrdinalType, typename ScalarType>
symMatTripleProduct(ETransp transw,const ScalarType alpha,const SerialSymDenseMatrix<OrdinalType,ScalarType> & A,const SerialDenseMatrix<OrdinalType,ScalarType> & W,SerialSymDenseMatrix<OrdinalType,ScalarType> & B)75 void symMatTripleProduct( ETransp transw, const ScalarType alpha, const SerialSymDenseMatrix<OrdinalType, ScalarType>& A,
76 			  const SerialDenseMatrix<OrdinalType, ScalarType>& W, SerialSymDenseMatrix<OrdinalType, ScalarType>& B )
77 {
78   // Local variables.
79   // Note: dimemensions of W are obtained so we can compute W^T*A*W for either cases.
80   OrdinalType A_nrowcols = A.numRows();  // A is a symmetric matrix and is assumed square.
81   OrdinalType B_nrowcols = (ETranspChar[transw]!='N') ? W.numCols() : W.numRows();
82   OrdinalType W_nrows = (ETranspChar[transw]!='N') ? W.numRows() : W.numCols();
83   OrdinalType W_ncols = (ETranspChar[transw]!='N') ? W.numCols() : W.numRows();
84 
85   bool isBUpper = B.upper();
86 
87   // Check for consistent dimensions.
88   TEUCHOS_TEST_FOR_EXCEPTION( B_nrowcols != B.numRows(), std::out_of_range,
89     "Teuchos::symMatTripleProduct<>() : "
90     "Num Rows/Cols B (" << B.numRows() << ") inconsistent with W ("<< B_nrowcols << ")");
91   TEUCHOS_TEST_FOR_EXCEPTION( A_nrowcols != W_nrows, std::out_of_range,
92     "Teuchos::symMatTripleProduct<>() : "
93     "Num Rows/Cols A (" << A_nrowcols << ") inconsistent with W ("<< W_nrows << ")");
94 
95   // Scale by zero, initialized B to zeros and return.
96   if ( alpha == ScalarTraits<ScalarType>::zero() )
97   {
98     B.putScalar();
99     return;
100   }
101 
102   // Workspace.
103   SerialDenseMatrix<OrdinalType, ScalarType> AW;
104 
105   // BLAS class.
106   BLAS<OrdinalType, ScalarType> blas;
107   ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
108   ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
109 
110   // Separate two cases because BLAS only supports symmetric matrix-matrix multply w/o transposes.
111   if (ETranspChar[transw]!='N') {
112     // Size AW to compute A*W
113     AW.shapeUninitialized(A_nrowcols,W_ncols);
114 
115     // A*W
116     AW.multiply( Teuchos::LEFT_SIDE, alpha, A, W, ScalarTraits<ScalarType>::zero() );
117 
118     // B = W^T*A*W
119     if (isBUpper) {
120       for (OrdinalType j=0; j<B_nrowcols; ++j)
121 	blas.GEMV( transw, W_nrows, j+1, one, W.values(), W.stride(), AW[j], 1, zero, &B(0,j), 1 );
122     }
123     else {
124       for (OrdinalType j=0; j<B_nrowcols; ++j)
125 	blas.GEMV( transw, W_nrows, B_nrowcols-j, one, W[j], W.stride(), AW[j], 1, zero, &B(j,j), 1 );
126     }
127   }
128   else {
129     // Size AW to compute W*A
130     AW.shapeUninitialized(W_ncols, A_nrowcols);
131 
132     // W*A
133     AW.multiply( Teuchos::RIGHT_SIDE, alpha, A, W, ScalarTraits<ScalarType>::zero() );
134 
135     // B = W*A*W^T
136     if (isBUpper) {
137       for (OrdinalType j=0; j<B_nrowcols; ++j)
138 	for (OrdinalType i=0; i<=j; ++i)
139 	  blas.GEMV( transw, 1, A_nrowcols, one, &AW(i,0), AW.stride(), &W(j,0), W.stride(), zero, &B(i,j), 1 );
140     }
141     else {
142       for (OrdinalType j=0; j<B_nrowcols; ++j)
143 	for (OrdinalType i=j; i<B_nrowcols; ++i)
144 	  blas.GEMV( transw, 1, A_nrowcols, one, &AW(i,0), AW.stride(), &W(j,0), W.stride(), zero, &B(i,j), 1 );
145     }
146   }
147 
148   return;
149 }
150 
151 /*! \relates SerialDenseMatrix
152   \brief A templated, non-member, helper function for viewing or copying a column of a SerialDenseMatrix as a SerialDenseVector.
153 
154   \param CV - [in] Enumerated type set to Teuchos::Copy or Teuchos::View
155   \param A - [in] SerialDenseMatrix
156   \param col - [in] Integer indicating which column of A to return
157 
158   \note The syntax for calling this function is:  <tt>Teuchos::SerialDenseVector<int,double> col_j = Teuchos::getCol<int,double>( Teuchos::View, A, j )</tt>
159 */
160 template<typename OrdinalType, typename ScalarType>
161 SerialDenseVector<OrdinalType,ScalarType>
getCol(DataAccess CV,SerialDenseMatrix<OrdinalType,ScalarType> & A,const OrdinalType col)162 getCol( DataAccess CV, SerialDenseMatrix<OrdinalType, ScalarType>& A, const OrdinalType col )
163 {
164   return SerialDenseVector<OrdinalType, ScalarType>(CV, A[col], A.numRows());
165 }
166 
167 /*! \relates SerialDenseMatrix
168   \brief A templated, non-member, helper function for setting a SerialDenseMatrix column using a SerialDenseVector.
169 
170   \param v - [in] SerialDenseVector
171   \param col - [in] Integer indicating which column of A to replace with v
172   \param A - [out] SerialDenseMatrix
173 
174   \note The syntax for calling this function is:  bool err = Teuchos::setCol<int,double>( v, j, A )</tt>
175 */
176 template<typename OrdinalType, typename ScalarType>
setCol(const SerialDenseVector<OrdinalType,ScalarType> & v,const OrdinalType col,SerialDenseMatrix<OrdinalType,ScalarType> & A)177 bool setCol( const SerialDenseVector<OrdinalType, ScalarType>& v,
178 	     const OrdinalType col,
179 	     SerialDenseMatrix<OrdinalType, ScalarType>& A )
180 {
181   if (v.length() != A.numRows()) return false;
182 
183   std::copy(v.values(),v.values()+v.length(),A[col]);
184 
185   return true;
186 }
187 
188 /*! \related SerialDenseMatrix
189   \brief A templated, non-member, helper function for generating a random SerialDenseMatrix that is synchronized in parallel.
190 
191   \param A - [in/out] SerialDenseMatrix to be filled with random numbers that are the same across processors
192 */
193 template <typename OrdinalType, typename ScalarType>
randomSyncedMatrix(Teuchos::SerialDenseMatrix<OrdinalType,ScalarType> & A)194 void randomSyncedMatrix( Teuchos::SerialDenseMatrix<OrdinalType, ScalarType>& A )
195 {
196   Teuchos::RCP<const Teuchos::Comm<OrdinalType> >
197     comm = Teuchos::DefaultComm<OrdinalType>::getComm();
198 
199   const OrdinalType procRank = rank(*comm);
200 
201   // Construct a separate serial dense matrix and synchronize it to get around
202   // input matrices that are subviews of a larger matrix.
203   Teuchos::SerialDenseMatrix<OrdinalType, ScalarType> newMatrix( A.numRows(), A.numCols() );
204   if (procRank == 0)
205     newMatrix.random();
206   else
207     newMatrix.putScalar( Teuchos::ScalarTraits<ScalarType>::zero() );
208 
209   broadcast(*comm, 0, A.numRows()*A.numCols(), newMatrix.values());
210 
211   // Assign the synchronized matrix to the input.
212   A.assign( newMatrix );
213 }
214 
215 
216 /*! \relates SerialBandDenseMatrix
217   \brief A templated, non-member, helper function for converting a SerialDenseMatrix to a SerialBandDenseMatrix.
218 
219   \param A - [in] SerialDenseMatrix to be converted
220   \param kl - [in] Integer indicating desired lower bandwidth of band matrix.
221   \param ku - [in] Integer indicating desired upper bandwidth of band matrix.
222   \param factorFormat - [in] Bool indicating whether kl extra superdiagonals should be stored to be used by factorization.
223 
224   \note The syntax for calling this function is:  <tt>Teuchos::SerialBandDenseMatrix<int,double> AB = Teuchos::generalToBanded<int,double>( A, kl, ku, true )</tt>
225 */
226 template<typename OrdinalType, typename ScalarType>
227 Teuchos::RCP<SerialBandDenseMatrix<OrdinalType, ScalarType> >
generalToBanded(const RCP<SerialDenseMatrix<OrdinalType,ScalarType>> & A,const OrdinalType kl,const OrdinalType ku,const bool factorFormat)228 generalToBanded(const RCP<SerialDenseMatrix<OrdinalType,ScalarType> >& A,
229 		const OrdinalType kl, const OrdinalType ku,
230 		const bool factorFormat)
231 {
232   OrdinalType m = A->numRows();
233   OrdinalType n = A->numCols();
234 
235   // Check that the new matrix is consistent.
236   TEUCHOS_TEST_FOR_EXCEPTION(A->values()==0, std::invalid_argument,
237 		     "SerialBandDenseSolver<T>::generalToBanded: A is an empty SerialDenseMatrix<T>!");
238   TEUCHOS_TEST_FOR_EXCEPTION(kl<0 || kl>m, std::invalid_argument,
239 		     "SerialBandDenseSolver<T>::generalToBanded: The lower bandwidth kl is invalid!");
240   TEUCHOS_TEST_FOR_EXCEPTION(ku<0 || ku>n, std::invalid_argument,
241 		     "SerialBandDenseSolver<T>::generalToBanded: The upper bandwidth ku is invalid!");
242 
243   OrdinalType extraBands = (factorFormat ? kl : 0);
244   Teuchos::RCP<SerialBandDenseMatrix<OrdinalType, ScalarType> > AB =
245     rcp( new SerialBandDenseMatrix<OrdinalType,ScalarType>(m,n,kl,extraBands+ku,true));
246 
247   for (OrdinalType j = 0; j < n; j++) {
248     for (OrdinalType i=TEUCHOS_MAX(0,j-ku); i<=TEUCHOS_MIN(m-1,j+kl); i++) {
249       (*AB)(i,j) = (*A)(i,j);
250     }
251   }
252   return(AB);
253 }
254 
255 /*! \relates SerialBandDenseMatrix
256   \brief A templated, non-member, helper function for converting a SerialBandDenseMatrix to a SerialDenseMatrix.
257 
258   \param A - [in] SerialBandDenseMatrix to be converted
259 
260   \note The syntax for calling this function is:  <tt>Teuchos::SerialDenseMatrix<int,double> A = Teuchos::bandedToGeneral<int,double>( AB )</tt>
261 */
262 template<typename OrdinalType, typename ScalarType>
263 Teuchos::RCP<SerialDenseMatrix<OrdinalType, ScalarType> >
bandedToGeneral(const RCP<SerialBandDenseMatrix<OrdinalType,ScalarType>> & AB)264 bandedToGeneral(const RCP<SerialBandDenseMatrix<OrdinalType,ScalarType> >& AB)
265 {
266 
267   OrdinalType m = AB->numRows();
268   OrdinalType n = AB->numCols();
269   OrdinalType kl = AB->lowerBandwidth();
270   OrdinalType ku = AB->upperBandwidth();
271 
272   // Check that the new matrix is consistent.
273   TEUCHOS_TEST_FOR_EXCEPTION(AB->values()==0, std::invalid_argument,
274 		     "SerialBandDenseSolver<T>::bandedToGeneral: AB is an empty SerialBandDenseMatrix<T>!");
275 
276   Teuchos::RCP<SerialDenseMatrix<OrdinalType, ScalarType> > A = rcp( new SerialDenseMatrix<OrdinalType,ScalarType>(m,n) );
277   for (OrdinalType j = 0; j < n; j++) {
278     for (OrdinalType i=TEUCHOS_MAX(0,j-ku); i<=TEUCHOS_MIN(m-1,j+kl); i++) {
279       (*A)(i,j) = (*AB)(i,j);
280     }
281   }
282   return(A);
283 }
284 
285 } // namespace Teuchos
286 
287 #endif /* _TEUCHOS_SERIALDENSEHELPERS_HPP_ */
288