Belos Version of the Day
Loading...
Searching...
No Matches
BelosKokkosDenseAdapter.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Belos: Block Linear Solvers Package
4//
5// Copyright 2004-2016 NTESS and the Belos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9//
10#ifndef BELOS_KOKKOS_DENSE_MAT_TRAITS_HPP
11#define BELOS_KOKKOS_DENSE_MAT_TRAITS_HPP
12
18
19#include "Teuchos_Assert.hpp"
20#include "Teuchos_RCP.hpp"
21#include "Teuchos_ScalarTraits.hpp"
22#include "Teuchos_BLAS.hpp"
23#include "Teuchos_LAPACK.hpp"
25
26#include "Kokkos_DualView.hpp"
27#include "Kokkos_Random.hpp"
28#include "KokkosKernels_ArithTraits.hpp"
29#include "KokkosBlas1_scal.hpp"
30#include "KokkosBlas1_axpby.hpp"
31
32#include <vector>
33
34namespace Belos {
35
37 template<typename V>
38 void kokkos_transpose(const V& dst, const V& src)
39 {
40 Kokkos::parallel_for(Kokkos::MDRangePolicy<typename V::execution_space, Kokkos::Rank<2>>({0, 0}, {dst.extent(0), dst.extent(1)}),
41 KOKKOS_LAMBDA(int i, int j)
42 {
43 dst(i, j) = KokkosKernels::ArithTraits<typename V::non_const_value_type>::conj( src(j, i) );
44 });
45 }
46
48 template<class Scalar, class DM>
49 class KokkosDenseSolver : public DenseSolver<Scalar, DM>
50 {
51 public:
52 typedef typename KokkosKernels::ArithTraits<Scalar>::val_type IST; //Impl Scalar Type, as used in Tpetra
54
56
57
59
61 virtual ~KokkosDenseSolver() {}
63
65
66
67 using DenseSolver<Scalar, DM>::setMatrix;
68
70 using DenseSolver<Scalar, DM>::setVectors;
72
74
75
78 using DenseSolver<Scalar, DM>::setSPD;
79
81
84
86
90
92
93
95
98 int factor()
99 {
100 int INFO = 0;
101
102 // Only factor matrix if it is new, otherwise factors have been computed
103 if (newMatrix_)
104 {
105 Teuchos::LAPACK<int,Scalar> lapack;
106
107 int M = DMT::GetNumRows(*A_);
108 int N = DMT::GetNumCols(*A_);
109 int Min_MN = TEUCHOS_MIN(M,N);
110 int LDA = DMT::GetStride(*A_);
111
112 IPIV_.resize( Min_MN );
113
115 Scalar * Aptr = DMT::GetRawHostPtr(*A_);
116
117 if (equilibrate_)
118 {
119 // Compute equilibration scalings
120 R_.resize(M);
121 if (!spd_)
122 C_.resize(N);
123
124 MagnitudeType ROWCND, COLCND, AMAX;
125 if (spd_)
126 lapack.POEQU (M, Aptr, LDA, &R_[0], &ROWCND, &AMAX, &INFO);
127 else
128 lapack.GEEQU (M, N, Aptr, LDA, &R_[0], &C_[0], &ROWCND, &COLCND, &AMAX, &INFO);
129
130 if (INFO)
131 return INFO;
132
133 // Apply equilibration to matrix
134 if (spd_) {
135 Scalar * ptr = 0;
136 for (int j=0; j<N; j++) {
137 ptr = Aptr + j*LDA;
138 Scalar s1 = R_[j];
139 for (int i=0; i<=j; i++) {
140 *ptr = *ptr*s1*R_[i];
141 ptr++;
142 }
143 }
144 }
145 else {
146 Scalar * ptr = 0;
147 for (int j=0; j<N; j++) {
148 ptr = Aptr + j*LDA;
149 Scalar s1 = C_[j];
150 for (int i=0; i<M; i++) {
151 *ptr = *ptr*s1*R_[i];
152 ptr++;
153 }
154 }
155 }
156 }
157
158 // Compute LU factor
159 if (spd_) {
160 lapack.POTRF('U', M, Aptr, LDA, &INFO);
161 }
162 else {
163 lapack.GETRF(M, N, Aptr, LDA, &IPIV_[0], &INFO);
164 }
165
167 }
168
169 return INFO;
170 }
171
173
176 int solve()
177 {
178 bool transpose = (TRANS_ != Teuchos::NO_TRANS) ? true : false;
179
181
182 // LAPACK overwrites RHS vector with solution vector, so copy if necessary
183 if (B_ != X_)
184 DMT::Assign(*X_, *B_); // Copy B to X if needed
185
186 // Since B_ = X_, perform operations on X_.
187
188 int M = DMT::GetNumRows(*X_);
189 int NRHS = DMT::GetNumCols(*X_);
190 int LDX = DMT::GetStride(*X_);
191 Scalar * X = DMT::GetRawHostPtr(*X_);
192
193 if (equilibrate_)
194 {
195 // Apply equilibration scalings to RHS vector
196 MagnitudeType * R_tmp = (transpose && !spd_) ? &C_[0] : &R_[0];
197
198 Scalar * ptr = 0;
199 for (int j=0; j<NRHS; j++) {
200 ptr = X + j*LDX;
201 for (int i=0; i<M; i++) {
202 *ptr = *ptr*R_tmp[i];
203 ptr++;
204 }
205 }
206 }
207
208 int INFO = 0;
209
210 int LDA = DMT::GetStride(*A_);
211 Scalar * Aptr = DMT::GetRawHostPtr(*A_);
212 Teuchos::LAPACK<int,Scalar> lapack;
213
214 if (spd_) {
215 lapack.POTRS('U', M, NRHS, Aptr, LDA, X, LDX, &INFO);
216 }
217 else {
218 lapack.GETRS(Teuchos::ETranspChar[TRANS_], M, NRHS,
219 Aptr, LDA, &IPIV_[0], X, LDX, &INFO);
220 }
221
222 if (equilibrate_)
223 {
224 // Apply equilibration scalings to X vector
225 MagnitudeType * C_tmp = (spd_ || transpose) ? &R_[0] : &C_[0];
226
227 Scalar * ptr = 0;
228 for (int j=0; j<NRHS; j++) {
229 ptr = X + j*LDX;
230 for (int i=0; i<M; i++) {
231 *ptr = *ptr*C_tmp[i];
232 ptr++;
233 }
234 }
235 }
236
237 // Synchronize solution vector to the device
239
240 return INFO;
241 }
242
243
244 private:
245
246 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MagnitudeType;
247
248 std::vector<int> IPIV_;
249 std::vector<MagnitudeType> R_, C_;
250
251 using DenseSolver<Scalar, DM>::newMatrix_;
252 using DenseSolver<Scalar, DM>::equilibrate_;
253 using DenseSolver<Scalar, DM>::TRANS_;
254 using DenseSolver<Scalar, DM>::spd_;
255
256 using DenseSolver<Scalar, DM>::A_;
257 using DenseSolver<Scalar, DM>::X_;
258 using DenseSolver<Scalar, DM>::B_;
259
260 };
261
263 //
264 template<class Scalar, class... Properties>
265 class DenseMatTraits<Scalar, Kokkos::DualView<typename KokkosKernels::ArithTraits<Scalar>::val_type **,Properties...>>{
266
267 public:
268 typedef typename KokkosKernels::ArithTraits<Scalar>::val_type IST;
269 using DM = Kokkos::DualView<IST**,Properties...>;
270
272
277 static Teuchos::RCP<DM> Create() {
278 return Teuchos::rcp(new DM("BelosDenseCreate",0,0));
279 }
280
287 static Teuchos::RCP<DM>
288 Create( const int numRows, const int numCols, bool initZero = true) {
289 if(initZero){
290 return Teuchos::rcp(new DM("BelosDenseCreate2",numRows,numCols));
291 }
292 else {
293 return Teuchos::rcp(new DM(Kokkos::view_alloc(Kokkos::WithoutInitializing,"BelosDenseCreate2"),numRows,numCols));
294 }
295 }
296
301 static Teuchos::RCP<DM>
302 CreateCopy(const DM & dm, bool transpose=false)
303 {
304 Teuchos::RCP<DM> tmpCopyRCP = Teuchos::null;
305
306 if (transpose) {
307 // want tmpCopyRCP to end up as dm^H in the end. Prefer doing transpose on device
308 tmpCopyRCP = Teuchos::rcp(new DM
309 (Kokkos::view_alloc(Kokkos::WithoutInitializing,"BelosDenseCreateCopy"),dm.extent_int(1),dm.extent_int(0)));
310 if(tmpCopyRCP->need_sync_device()) {
311 // tmpCopyRCP is only up to date on the host
312 kokkos_transpose(tmpCopyRCP->view_host(), dm.view_host());
313 tmpCopyRCP->clear_sync_state();
314 tmpCopyRCP->modify_host();
315 }
316 else {
317 kokkos_transpose(tmpCopyRCP->view_device(), dm.view_device());
318 tmpCopyRCP->clear_sync_state();
319 tmpCopyRCP->modify_device();
320 }
321 }
322 else {
323 tmpCopyRCP = Teuchos::rcp(new DM
324 (Kokkos::view_alloc(Kokkos::WithoutInitializing,"BelosDenseCreateCopy"),dm.extent_int(0),dm.extent_int(1)));
325 Kokkos::deep_copy(*tmpCopyRCP, dm);
326 }
327 return tmpCopyRCP;
328 }
329
340 static Scalar* GetRawHostPtr(DM & dm ) {
341 dm.sync_host();
342 dm.modify_host();
343 return reinterpret_cast<Scalar*>(dm.view_host().data());
344 //TODO: Is there any way that the user could hold on to this pointer...
345 // and everything works fine the first time they pass to LAPACK.
346 // But then... they call MvTimesMatAddMv which syncs to device.
347 // But then they keep the same pointer and pass to LAPACK again.
348 // Then they call MvTimesMatAddMv... but since they didn't call this
349 // function again, we miss the sync... See thread with Heidi on this.
350 }
351
353 static Scalar const * GetConstRawHostPtr(const DM & dm ) {
354 // CAG: This is a bit naughty.
355 const_cast<DM*>(&dm)->sync_host();
356 return reinterpret_cast<Scalar const *>(dm.view_host().data());
357 }
358
360 // Row and column indexing is zero-based.
361 static Teuchos::RCP<DM>
362 Subview( DM & source, int numRows, int numCols, int startRow=0, int startCol=0){
363 return Teuchos::rcp(new DM(source,
364 Kokkos::pair<int,int>(startRow,startRow+numRows), Kokkos::pair<int,int>(startCol,startCol+numCols)));
365 }
366
367 static Teuchos::RCP<const DM>
368 SubviewConst( const DM& source, int numRows, int numCols, int startRow=0, int startCol=0){
369 return Teuchos::rcp(new DM(source,
370 Kokkos::pair<int,int>(startRow,startRow+numRows), Kokkos::pair<int,int>(startCol,startCol+numCols)));
371 }
372
374 static Teuchos::RCP<DM>
375 SubviewCopy( const DM& source, int numRows, int numCols, int startRow=0, int startCol=0){
376 //Maaybe we could get away with just a host copy here??
377 //Hmmm... but it says we return a dual view.
378 //Maybe it should return a dual view with only host data copied in. Require sync to work on device.
379 //This is related to the functionality of the Assign function.
380 auto tmpViewRCP = Teuchos::rcp(new DM
381 (Kokkos::view_alloc(Kokkos::WithoutInitializing,"BelosDenseSubViewCopy"),numRows,numCols));
382 // I am keeping this where it copies the whole view on host and device because:
383 // a) I feel like we might be inviting some weird bugs later if we don't.
384 // But TODO Clarify to developer that this function needs to work on both host and device.
385 // b) It's not a host-device copy or vice versa. Its a copy from device to same device and from host to host.
386 // So shouldn't add much extra overhead.
387 Kokkos::deep_copy(*tmpViewRCP, Kokkos::subview(source,
388 Kokkos::pair<int,int>(startRow,startRow+numRows), Kokkos::pair<int,int>(startCol,startCol+numCols)));
389 return tmpViewRCP;
390 }
391
392
394
396 static int GetNumRows( const DM& dm ) {
397 return dm.extent_int(0);
398 }
399
401 static int GetNumCols( const DM& dm ) {
402 return dm.extent_int(1);
403 }
404
406 static int GetStride( const DM& dm ) {
407 // Note: We force LayoutLeft, which is column major, so the stride_0 is always 1.
408 // (This is the distance between two elts in same col, different rows.)
409 // Lapack wants stride_1, the distance from one col to the next col if we stay
410 // in the same row.
411 int strides[8]; // There are 8 possible strides and all will be returned
412 dm.stride(strides);
413 return strides[1];
414 //return dm.stride_1(); //This shortcut doesn't work for dualView.
415 }
416
418
420
421 /* \brief Reshaping method for changing the size of \c dm to have \c numRows rows and \c numCols columns.
422 * All values will be initialized to zero if the final argument is true.
423 * If the final argument is fale, the previous entries in
424 * the matrix will be maintained. For new entries that did not exist in the previous matrix, values will
425 * contain noise from memory.
426 */
427 static void Reshape( DM& dm, const int numRows, const int numCols, bool initZero = false) {
428 if(initZero){
429 dm.realloc(numRows,numCols);
430 Kokkos::deep_copy(dm.view_device(), 0.0);
431 dm.modify_device();
432 } else{
433 dm.resize(numRows,numCols); //keeps values in old array.
434 }
435 }
436
438
440
442 static Scalar & Value( DM& dm, const int i, const int j )
443 {
444 // Mark as modified on host, since we don't know if it will be.
445 dm.sync_host();
446 dm.modify_host();
447 return reinterpret_cast<Scalar&>((dm.view_host())(i,j));
448 }
449
451 static const Scalar & ValueConst( const DM& dm, const int i, const int j ) {
452 // CAG: This is a bit naughty.
453 const_cast<DM*>(&dm)->sync_host();
454 return reinterpret_cast<Scalar const &>((dm.view_host())(i,j));
455 }
456
458 //
459 // \note The only Belos function that results in a need to sync to
460 // host is MvTransMv. You MUST call SyncDeviceToHost before calling
461 // any other DenseMatTraits functions after a call to MvTransMv.
462 // All DenseMatTraits functions assume the necessary data is on host
463 // and perform computations only on the host.
464 //
465 static void SyncDeviceToHost(DM & dm) {
466 if(dm.need_sync_host()){
467 if(dm.view_host().span_is_contiguous() && dm.view_device().span_is_contiguous()){
468 dm.sync_host();}
469 else{
470 DM compat_view("compat view",dm.extent_int(0),dm.extent_int(1));
471 Kokkos::deep_copy(compat_view,dm);
472 compat_view.sync_host();
473 Kokkos::deep_copy(dm,compat_view);
474 dm.clear_sync_state();
475 }
476 }
477 }
478
479 static void SyncHostToDevice(DM & dm) {
480 if(dm.need_sync_device()){
481 if(dm.view_host().span_is_contiguous() && dm.view_device().span_is_contiguous()){
482 dm.sync_device();
483 }
484 else{
485 DM compat_view("compat view",dm.extent_int(0),dm.extent_int(1));
486 Kokkos::deep_copy(compat_view,dm);
487 compat_view.sync_device();
488 Kokkos::deep_copy(dm,compat_view);
489 dm.clear_sync_state();
490 }
491 }
492 }
493
494
495
497 static void Add( DM& thisDM, const DM& sourceDM) {
498 thisDM.sync_device();
499 // CAG: This is a bit naughty.
500 const_cast<DM*>(&sourceDM)->sync_device();
501 KokkosBlas::axpy(1.0,sourceDM.view_device(), thisDM.view_device()); //axpy(alpha,x,y), y = y + alpha*x
502 thisDM.modify_device();
503 }
504
506 static void PutScalar( DM& dm, Scalar value = Teuchos::ScalarTraits<Scalar>::zero()){
507 dm.clear_sync_state();
508 Kokkos::deep_copy( dm.view_device(), value);
509 dm.modify_device();
510 }
511
513 static void Scale( DM& dm, Scalar value) {
514 dm.sync_device();
515 KokkosBlas::scal( dm.view_device(), value, dm.view_device());
516 dm.modify_device();
517 }
518
521 static void Randomize( DM& dm) {
522 int rand_seed = std::rand();
523 Kokkos::Random_XorShift64_Pool<> pool(rand_seed);
524 dm.clear_sync_state();
525 Kokkos::fill_random(dm.view_device(), pool, -1,1);
526 dm.modify_device();
527 }
528
530 static void Assign( DM& dest, const DM& source) {
531 Kokkos::deep_copy(dest,source);
532 }
533
535 static typename Teuchos::ScalarTraits<Scalar>::magnitudeType NormFrobenius(const DM& dm) {
536 using KAT = KokkosKernels::ArithTraits<IST>;
537 using mag_t = typename KAT::mag_type;
538 // CAG: This is a bit naughty.
539 const_cast<DM*>(&dm)->sync_device();
540 mag_t frobNorm;
541 Kokkos::parallel_reduce(Kokkos::MDRangePolicy<Kokkos::Rank<2>>({0, 0}, {dm.extent(0), dm.extent(1)}),
542 KOKKOS_LAMBDA(size_t i, size_t j, mag_t& lfrobNorm)
543 {
544 mag_t absVal = KAT::abs((dm.view_device())(i, j));
545 lfrobNorm += absVal * absVal;
546 }, frobNorm);
547 return Kokkos::sqrt(frobNorm);
548 }
549
551 static typename Teuchos::ScalarTraits<Scalar>::magnitudeType NormOne(const DM& dm) {
552 using KAT = KokkosKernels::ArithTraits<IST>;
553 using mag_t = typename KAT::mag_type;
554 // CAG: This is a bit naughty.
555 const_cast<DM*>(&dm)->sync_device();
556 mag_t max_sum = 0;
557
558 Kokkos::parallel_reduce(dm.extent(1), KOKKOS_LAMBDA(const int j, mag_t& norm) {
559 mag_t sum = 0;
560 for(int i = 0; i < dm.extent_int(0); i++){ //rows
561 sum += KAT::abs((dm.view_device())(i,j));
562 }
563 norm = Kokkos::max(norm, sum);
564 }, Kokkos::Max<mag_t>(max_sum));
565 return KAT::abs(max_sum);
566 }
567
568
570
572 static Teuchos::RCP<DenseSolver<Scalar, DM>>
574
575 Teuchos::RCP<DenseSolver<Scalar, DM>> newSolver
576 = Teuchos::rcp( new KokkosDenseSolver<Scalar, DM>() );
577 return newSolver;
578 }
579
580
581 };
582
583} // namespace Belos
584
585#endif // end file BELOS_KOKKOS_DENSE_MAT_TRAITS_HPP
static void Randomize(DM &dm)
Fill the Kokkos::DualView with random entries. Entries are assumed to be the same on each MPI rank (e...
static Teuchos::RCP< DM > Subview(DM &source, int numRows, int numCols, int startRow=0, int startCol=0)
Returns an RCP to a Kokkos::DualView which has a subview of the given Kokkos::DualView.
static Teuchos::RCP< DM > SubviewCopy(const DM &source, int numRows, int numCols, int startRow=0, int startCol=0)
Returns a deep copy of the requested subview.
static Teuchos::RCP< DenseSolver< Scalar, DM > > createDenseSolver()
Returns a dense solver object for the dense matrix.
static Teuchos::RCP< DM > Create(const int numRows, const int numCols, bool initZero=true)
Creates a new empty Kokkos::DualView containing and numRows rows and numCols columns....
static Teuchos::RCP< DM > CreateCopy(const DM &dm, bool transpose=false)
Create a new copy DM, possibly transposed.
static const Scalar & ValueConst(const DM &dm, const int i, const int j)
Access a const reference to the (i,j) entry of dm, e_i^T dm e_j.
static Scalar & Value(DM &dm, const int i, const int j)
Access a reference to the (i,j) entry of dm, e_i^T dm e_j.
static Teuchos::RCP< const DM > SubviewConst(const DM &source, int numRows, int numCols, int startRow=0, int startCol=0)
static Teuchos::ScalarTraits< Scalar >::magnitudeType NormOne(const DM &dm)
Returns the one-norm of the dense matrix.
static void PutScalar(DM &dm, Scalar value=Teuchos::ScalarTraits< Scalar >::zero())
Fill all entries with value. Value is zero if not specified.
static void Add(DM &thisDM, const DM &sourceDM)
Adds sourceDM to thisDM and returns answer in thisDM.
static Teuchos::ScalarTraits< Scalar >::magnitudeType NormFrobenius(const DM &dm)
Returns the Frobenius norm of the dense matrix.
Virtual base class which defines basic traits for the multi-vector type.
static void Assign(DM &thisDM, const DM &sourceDM)
void solveWithTransposeFlag(Teuchos::ETransp trans)
virtual int setMatrix(const Teuchos::RCP< DM > &A)
virtual int setVectors(const Teuchos::RCP< DM > &X, const Teuchos::RCP< DM > &B)
Full specialization of Belos::DenseMatSolver for Kokkos::DualView.
virtual ~KokkosDenseSolver()
KokkosDenseSolver destructor.
int solve()
Computes the solution X to AX = B for the this matrix and the B provided.
int factor()
Computes the in-place LU factorization of the matrix.
KokkosDenseSolver()
Default constructor; matrix should be set using setMatrix(), LHS and RHS set with setVectors().
KokkosKernels::ArithTraits< Scalar >::val_type IST
DenseMatTraits< Scalar, DM > DMT
void kokkos_transpose(const V &dst, const V &src)
Helper function for copying Kokkos::DualView into conjugate Kokkos::DualView.

Generated for Belos by doxygen 1.15.0