Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_computeRowAndColumnOneNorms_def.hpp
Go to the documentation of this file.
1// @HEADER
2// ***********************************************************************
3//
4// Tpetra: Templated Linear Algebra Services Package
5// Copyright (2008) Sandia Corporation
6//
7// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8// the U.S. Government retains certain rights in this software.
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 TPETRA_COMPUTEROWANDCOLUMNONENORMS_DEF_HPP
43#define TPETRA_COMPUTEROWANDCOLUMNONENORMS_DEF_HPP
44
51
53#include "Tpetra_CrsMatrix.hpp"
54#include "Tpetra_Export.hpp"
55#include "Tpetra_Map.hpp"
56#include "Tpetra_MultiVector.hpp"
57#include "Tpetra_RowMatrix.hpp"
58#include "Kokkos_Core.hpp"
59#include "Teuchos_CommHelpers.hpp"
60#include <memory>
61
62namespace Tpetra {
63namespace Details {
64
65template<class SC, class LO, class GO, class NT>
66std::size_t
67lclMaxNumEntriesRowMatrix (const Tpetra::RowMatrix<SC, LO, GO, NT>& A)
68{
69 const auto& rowMap = * (A.getRowMap ());
70 const LO lclNumRows = static_cast<LO> (rowMap.getLocalNumElements ());
71
72 std::size_t maxNumEnt {0};
73 for (LO lclRow = 0; lclRow < lclNumRows; ++lclRow) {
74 const std::size_t numEnt = A.getNumEntriesInLocalRow (lclRow);
75 maxNumEnt = numEnt > maxNumEnt ? numEnt : maxNumEnt;
76 }
77 return maxNumEnt;
78}
79
80template<class SC, class LO, class GO, class NT>
81void
82forEachLocalRowMatrixRow (
84 const LO lclNumRows,
85 const std::size_t maxNumEnt,
86 std::function<void (
87 const LO lclRow,
88 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_local_inds_host_view_type& /*ind*/,
89 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_values_host_view_type& /*val*/,
90 std::size_t /*numEnt*/ )> doForEachRow)
91{
92 using lids_type = typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_local_inds_host_view_type;
93 using vals_type = typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_values_host_view_type;
94 lids_type indBuf("indices",maxNumEnt);
95 vals_type valBuf("values",maxNumEnt);
96
97 for (LO lclRow = 0; lclRow < lclNumRows; ++lclRow) {
98 std::size_t numEnt = A.getNumEntriesInLocalRow (lclRow);
99 lids_type ind = Kokkos::subview(indBuf,std::make_pair((size_t)0, numEnt));
100 vals_type val = Kokkos::subview(valBuf,std::make_pair((size_t)0, numEnt));
101 A.getLocalRowCopy (lclRow, ind, val, numEnt);
102 doForEachRow (lclRow, ind, val, numEnt);
103 }
104}
105
106template<class SC, class LO, class GO, class NT>
107void
108forEachLocalRowMatrixRow (
110 std::function<void (
111 const LO lclRow,
112 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_local_inds_host_view_type& /*ind*/,
113 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_values_host_view_type& /*val*/,
114 std::size_t /*numEnt*/ )> doForEachRow)
115{
116 const auto& rowMap = * (A.getRowMap ());
117 const LO lclNumRows = static_cast<LO> (rowMap.getLocalNumElements ());
118 const std::size_t maxNumEnt = lclMaxNumEntriesRowMatrix (A);
119
120 forEachLocalRowMatrixRow<SC, LO, GO, NT> (A, lclNumRows, maxNumEnt, doForEachRow);
121}
122
126template<class SC, class LO, class GO, class NT>
127void
128computeLocalRowScaledColumnNorms_RowMatrix (EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
129 typename NT::device_type>& result,
131{
132 using KAT = Kokkos::ArithTraits<SC>;
133 using mag_type = typename KAT::mag_type;
134 using KAV = Kokkos::ArithTraits<typename KAT::val_type>;
135
136 auto rowNorms_h = Kokkos::create_mirror_view (result.rowNorms);
137
138 // DEEP_COPY REVIEW - NOT TESTED
139 Kokkos::deep_copy (rowNorms_h, result.rowNorms);
140 auto rowScaledColNorms_h = Kokkos::create_mirror_view (result.rowScaledColNorms);
141
142 forEachLocalRowMatrixRow<SC, LO, GO, NT> (A,
143 [&] (const LO lclRow,
144 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_local_inds_host_view_type& ind,
145 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_values_host_view_type& val,
146 std::size_t numEnt) {
147 const mag_type rowNorm = rowNorms_h[lclRow];
148 for (std::size_t k = 0; k < numEnt; ++k) {
149 const mag_type matrixAbsVal = KAV::abs (val[k]);
150 const LO lclCol = ind[k];
151
152 rowScaledColNorms_h[lclCol] += matrixAbsVal / rowNorm;
153 }
154 });
155
156 // DEEP_COPY REVIEW - NOT TESTED
157 Kokkos::deep_copy (result.rowScaledColNorms, rowScaledColNorms_h);
158}
159
162template<class SC, class LO, class GO, class NT>
163EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type, typename NT::device_type>
165{
166 using KAT = Kokkos::ArithTraits<SC>;
167 using val_type = typename KAT::val_type;
168 using KAV = Kokkos::ArithTraits<val_type>;
169 using mag_type = typename KAT::mag_type;
170 using KAM = Kokkos::ArithTraits<mag_type>;
171 using device_type = typename NT::device_type;
172 using equib_info_type = EquilibrationInfo<val_type, device_type>;
173
174 const auto& rowMap = * (A.getRowMap ());
175 const auto& colMap = * (A.getColMap ());
176 const LO lclNumRows = static_cast<LO> (rowMap.getLocalNumElements ());
177 const LO lclNumCols = 0; // don't allocate column-related Views
178 constexpr bool assumeSymmetric = false; // doesn't matter here
179 equib_info_type result (lclNumRows, lclNumCols, assumeSymmetric);
180 auto result_h = result.createMirrorView ();
181
182 forEachLocalRowMatrixRow<SC, LO, GO, NT> (A,
183 [&] (const LO lclRow,
184 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_local_inds_host_view_type& ind,
185 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_values_host_view_type& val,
186 std::size_t numEnt) {
187 mag_type rowNorm {0.0};
188 val_type diagVal {0.0};
189 const GO gblRow = rowMap.getGlobalElement (lclRow);
190 // OK if invalid(); then we simply won't find the diagonal entry.
191 const GO lclDiagColInd = colMap.getLocalElement (gblRow);
192
193 for (std::size_t k = 0; k < numEnt; ++k) {
194 const val_type matrixVal = val[k];
195 if (KAV::isInf (matrixVal)) {
196 result_h.foundInf = true;
197 }
198 if (KAV::isNan (matrixVal)) {
199 result_h.foundNan = true;
200 }
201 const mag_type matrixAbsVal = KAV::abs (matrixVal);
202 rowNorm += matrixAbsVal;
203 const LO lclCol = ind[k];
204 if (lclCol == lclDiagColInd) {
205 diagVal += val[k]; // repeats count additively
206 }
207 } // for each entry in row
208
209 // This is a local result. If the matrix has an overlapping
210 // row Map, then the global result might differ.
211 if (diagVal == KAV::zero ()) {
212 result_h.foundZeroDiag = true;
213 }
214 if (rowNorm == KAM::zero ()) {
215 result_h.foundZeroRowNorm = true;
216 }
217 // NOTE (mfh 24 May 2018) We could actually compute local
218 // rowScaledColNorms in situ at this point, if ! assumeSymmetric
219 // and row Map is the same as range Map (so that the local row
220 // norms are the same as the global row norms).
221 result_h.rowDiagonalEntries[lclRow] += diagVal;
222 result_h.rowNorms[lclRow] = rowNorm;
223 });
224
225 result.assign (result_h);
226 return result;
227}
228
231template<class SC, class LO, class GO, class NT>
232EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type, typename NT::device_type>
234 const bool assumeSymmetric)
235{
236 using KAT = Kokkos::ArithTraits<SC>;
237 using val_type = typename KAT::val_type;
238 using KAV = Kokkos::ArithTraits<val_type>;
239 using mag_type = typename KAT::mag_type;
240 using KAM = Kokkos::ArithTraits<mag_type>;
241 using device_type = typename NT::device_type;
242
243 const auto& rowMap = * (A.getRowMap ());
244 const auto& colMap = * (A.getColMap ());
245 const LO lclNumRows = static_cast<LO> (rowMap.getLocalNumElements ());
246 const LO lclNumCols = static_cast<LO> (colMap.getLocalNumElements ());
247
249 (lclNumRows, lclNumCols, assumeSymmetric);
250 auto result_h = result.createMirrorView ();
251
252 forEachLocalRowMatrixRow<SC, LO, GO, NT> (A,
253 [&] (const LO lclRow,
254 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_local_inds_host_view_type& ind,
255 const typename Tpetra::RowMatrix<SC, LO, GO, NT>::nonconst_values_host_view_type& val,
256 std::size_t numEnt) {
257 mag_type rowNorm {0.0};
258 val_type diagVal {0.0};
259 const GO gblRow = rowMap.getGlobalElement (lclRow);
260 // OK if invalid(); then we simply won't find the diagonal entry.
261 const GO lclDiagColInd = colMap.getLocalElement (gblRow);
262
263 for (std::size_t k = 0; k < numEnt; ++k) {
264 const val_type matrixVal = val[k];
265 if (KAV::isInf (matrixVal)) {
266 result_h.foundInf = true;
267 }
268 if (KAV::isNan (matrixVal)) {
269 result_h.foundNan = true;
270 }
271 const mag_type matrixAbsVal = KAV::abs (matrixVal);
272 rowNorm += matrixAbsVal;
273 const LO lclCol = ind[k];
274 if (lclCol == lclDiagColInd) {
275 diagVal += val[k]; // repeats count additively
276 }
277 if (! assumeSymmetric) {
278 result_h.colNorms[lclCol] += matrixAbsVal;
279 }
280 } // for each entry in row
281
282 // This is a local result. If the matrix has an overlapping
283 // row Map, then the global result might differ.
284 if (diagVal == KAV::zero ()) {
285 result_h.foundZeroDiag = true;
286 }
287 if (rowNorm == KAM::zero ()) {
288 result_h.foundZeroRowNorm = true;
289 }
290 // NOTE (mfh 24 May 2018) We could actually compute local
291 // rowScaledColNorms in situ at this point, if ! assumeSymmetric
292 // and row Map is the same as range Map (so that the local row
293 // norms are the same as the global row norms).
294 result_h.rowDiagonalEntries[lclRow] += diagVal;
295 result_h.rowNorms[lclRow] = rowNorm;
296 if (! assumeSymmetric &&
297 lclDiagColInd != Tpetra::Details::OrdinalTraits<LO>::invalid ()) {
298 result_h.colDiagonalEntries[lclDiagColInd] += diagVal;
299 }
300 });
301
302 result.assign (result_h);
303 return result;
304}
305
306template<class SC, class LO, class GO, class NT>
307class ComputeLocalRowScaledColumnNorms {
308public:
309 using crs_matrix_type = ::Tpetra::CrsMatrix<SC, LO, GO, NT>;
310 using val_type = typename Kokkos::ArithTraits<SC>::val_type;
311 using mag_type = typename Kokkos::ArithTraits<val_type>::mag_type;
312 using device_type = typename crs_matrix_type::device_type;
313
314 ComputeLocalRowScaledColumnNorms (const Kokkos::View<mag_type*, device_type>& rowScaledColNorms,
315 const Kokkos::View<const mag_type*, device_type>& rowNorms,
316 const crs_matrix_type& A) :
317 rowScaledColNorms_ (rowScaledColNorms),
318 rowNorms_ (rowNorms),
319 A_lcl_ (A.getLocalMatrixDevice ())
320 {}
321
322 KOKKOS_INLINE_FUNCTION void operator () (const LO lclRow) const {
323 using KAT = Kokkos::ArithTraits<val_type>;
324
325 const auto curRow = A_lcl_.rowConst (lclRow);
326 const mag_type rowNorm = rowNorms_[lclRow];
327 const LO numEnt = curRow.length;
328 for (LO k = 0; k < numEnt; ++k) {
329 const mag_type matrixAbsVal = KAT::abs (curRow.value(k));
330 const LO lclCol = curRow.colidx(k);
331
332 Kokkos::atomic_add (&rowScaledColNorms_[lclCol], matrixAbsVal / rowNorm);
333 }
334 }
335
336 static void
337 run (const Kokkos::View<mag_type*, device_type>& rowScaledColNorms,
338 const Kokkos::View<const mag_type*, device_type>& rowNorms,
339 const crs_matrix_type& A)
340 {
341 using execution_space = typename device_type::execution_space;
342 using range_type = Kokkos::RangePolicy<execution_space, LO>;
343 using functor_type = ComputeLocalRowScaledColumnNorms<SC, LO, GO, NT>;
344
345 functor_type functor (rowScaledColNorms, rowNorms, A);
346 const LO lclNumRows =
347 static_cast<LO> (A.getRowMap ()->getLocalNumElements ());
348 Kokkos::parallel_for ("computeLocalRowScaledColumnNorms",
349 range_type (0, lclNumRows), functor);
350 }
351
352private:
353 Kokkos::View<mag_type*, device_type> rowScaledColNorms_;
354 Kokkos::View<const mag_type*, device_type> rowNorms_;
355
356 using local_matrix_device_type = typename crs_matrix_type::local_matrix_device_type;
357 local_matrix_device_type A_lcl_;
358};
359
360template<class SC, class LO, class GO, class NT>
361void
362computeLocalRowScaledColumnNorms_CrsMatrix (EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
363 typename NT::device_type>& result,
365{
366 using impl_type = ComputeLocalRowScaledColumnNorms<SC, LO, GO, NT>;
367 impl_type::run (result.rowScaledColNorms, result.rowNorms, A);
368}
369
370template<class SC, class LO, class GO, class NT>
371void
372computeLocalRowScaledColumnNorms (EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
373 typename NT::device_type>& result,
375{
376 using crs_matrix_type = Tpetra::CrsMatrix<SC, LO, GO, NT>;
377 using val_type = typename Kokkos::ArithTraits<SC>::val_type;
378 using mag_type = typename Kokkos::ArithTraits<val_type>::mag_type;
379 using device_type = typename NT::device_type;
380
381 auto colMapPtr = A.getColMap ();
382 TEUCHOS_TEST_FOR_EXCEPTION
383 (colMapPtr.get () == nullptr, std::invalid_argument,
384 "computeLocalRowScaledColumnNorms: "
385 "Input matrix A must have a nonnull column Map.");
386 const LO lclNumCols = static_cast<LO> (colMapPtr->getLocalNumElements ());
387 if (static_cast<std::size_t> (result.rowScaledColNorms.extent (0)) !=
388 static_cast<std::size_t> (lclNumCols)) {
389 result.rowScaledColNorms =
390 Kokkos::View<mag_type*, device_type> ("rowScaledColNorms", lclNumCols);
391 }
392
393 const crs_matrix_type* A_crs = dynamic_cast<const crs_matrix_type*> (&A);
394 if (A_crs == nullptr) {
396 }
397 else {
398 computeLocalRowScaledColumnNorms_CrsMatrix (result, *A_crs);
399 }
400}
401
402// Kokkos::parallel_reduce functor that is part of the implementation
403// of computeLocalRowOneNorms_CrsMatrix.
404template<class SC, class LO, class GO, class NT>
405class ComputeLocalRowOneNorms {
406public:
407 using val_type = typename Kokkos::ArithTraits<SC>::val_type;
408 using equib_info_type = EquilibrationInfo<val_type, typename NT::device_type>;
409 using local_matrix_device_type =
410 typename ::Tpetra::CrsMatrix<SC, LO, GO, NT>::local_matrix_device_type;
411 using local_map_type = typename ::Tpetra::Map<LO, GO, NT>::local_map_type;
412
413 ComputeLocalRowOneNorms (const equib_info_type& equib, // in/out
414 const local_matrix_device_type& A_lcl, // in
415 const local_map_type& rowMap, // in
416 const local_map_type& colMap) : // in
417 equib_ (equib),
418 A_lcl_ (A_lcl),
419 rowMap_ (rowMap),
420 colMap_ (colMap)
421 {}
422
423 // (result & 1) != 0 means "found Inf."
424 // (result & 2) != 0 means "found NaN."
425 // (result & 4) != 0 means "found zero diag."
426 // (result & 8) != 0 means "found zero row norm."
427 // Pack into a single int so the reduction is cheaper,
428 // esp. on GPU.
429 using value_type = int;
430
431 KOKKOS_INLINE_FUNCTION void init (value_type& dst) const
432 {
433 dst = 0;
434 }
435
436 KOKKOS_INLINE_FUNCTION void
437 join (value_type& dst,
438 const value_type& src) const
439 {
440 dst |= src;
441 }
442
443 KOKKOS_INLINE_FUNCTION void
444 operator () (const LO lclRow, value_type& dst) const
445 {
446 using KAT = Kokkos::ArithTraits<val_type>;
447 using mag_type = typename KAT::mag_type;
448 using KAM = Kokkos::ArithTraits<mag_type>;
449
450 const GO gblRow = rowMap_.getGlobalElement (lclRow);
451 // OK if invalid(); then we simply won't find the diagonal entry.
452 const GO lclDiagColInd = colMap_.getLocalElement (gblRow);
453
454 const auto curRow = A_lcl_.rowConst (lclRow);
455 const LO numEnt = curRow.length;
456
457 mag_type rowNorm {0.0};
458 val_type diagVal {0.0};
459
460 for (LO k = 0; k < numEnt; ++k) {
461 const val_type matrixVal = curRow.value (k);
462 if (KAT::isInf (matrixVal)) {
463 dst |= 1;
464 }
465 if (KAT::isNan (matrixVal)) {
466 dst |= 2;
467 }
468 const mag_type matrixAbsVal = KAT::abs (matrixVal);
469 rowNorm += matrixAbsVal;
470 const LO lclCol = curRow.colidx (k);
471 if (lclCol == lclDiagColInd) {
472 diagVal = curRow.value (k); // assume no repeats
473 }
474 } // for each entry in row
475
476 // This is a local result. If the matrix has an overlapping
477 // row Map, then the global result might differ.
478 if (diagVal == KAT::zero ()) {
479 dst |= 4;
480 }
481 if (rowNorm == KAM::zero ()) {
482 dst |= 8;
483 }
484 equib_.rowDiagonalEntries[lclRow] = diagVal;
485 equib_.rowNorms[lclRow] = rowNorm;
486 }
487
488private:
489 equib_info_type equib_;
490 local_matrix_device_type A_lcl_;
491 local_map_type rowMap_;
492 local_map_type colMap_;
493};
494
495// Kokkos::parallel_reduce functor that is part of the implementation
496// of computeLocalRowAndColumnOneNorms_CrsMatrix.
497template<class SC, class LO, class GO, class NT>
498class ComputeLocalRowAndColumnOneNorms {
499public:
500 using val_type = typename Kokkos::ArithTraits<SC>::val_type;
501 using equib_info_type = EquilibrationInfo<val_type, typename NT::device_type>;
502 using local_matrix_device_type = typename ::Tpetra::CrsMatrix<SC, LO, GO, NT>::local_matrix_device_type;
503 using local_map_type = typename ::Tpetra::Map<LO, GO, NT>::local_map_type;
504
505public:
506 ComputeLocalRowAndColumnOneNorms (const equib_info_type& equib, // in/out
507 const local_matrix_device_type& A_lcl, // in
508 const local_map_type& rowMap, // in
509 const local_map_type& colMap) : // in
510 equib_ (equib),
511 A_lcl_ (A_lcl),
512 rowMap_ (rowMap),
513 colMap_ (colMap)
514 {}
515
516 // (result & 1) != 0 means "found Inf."
517 // (result & 2) != 0 means "found NaN."
518 // (result & 4) != 0 means "found zero diag."
519 // (result & 8) != 0 means "found zero row norm."
520 // Pack into a single int so the reduction is cheaper,
521 // esp. on GPU.
522 using value_type = int;
523
524 KOKKOS_INLINE_FUNCTION void init (value_type& dst) const
525 {
526 dst = 0;
527 }
528
529 KOKKOS_INLINE_FUNCTION void
530 join (value_type& dst,
531 const value_type& src) const
532 {
533 dst |= src;
534 }
535
536 KOKKOS_INLINE_FUNCTION void
537 operator () (const LO lclRow, value_type& dst) const
538 {
539 using KAT = Kokkos::ArithTraits<val_type>;
540 using mag_type = typename KAT::mag_type;
541 using KAM = Kokkos::ArithTraits<mag_type>;
542
543 const GO gblRow = rowMap_.getGlobalElement (lclRow);
544 // OK if invalid(); then we simply won't find the diagonal entry.
545 const GO lclDiagColInd = colMap_.getLocalElement (gblRow);
546
547 const auto curRow = A_lcl_.rowConst (lclRow);
548 const LO numEnt = curRow.length;
549
550 mag_type rowNorm {0.0};
551 val_type diagVal {0.0};
552
553 for (LO k = 0; k < numEnt; ++k) {
554 const val_type matrixVal = curRow.value (k);
555 if (KAT::isInf (matrixVal)) {
556 dst |= 1;
557 }
558 if (KAT::isNan (matrixVal)) {
559 dst |= 2;
560 }
561 const mag_type matrixAbsVal = KAT::abs (matrixVal);
562 rowNorm += matrixAbsVal;
563 const LO lclCol = curRow.colidx (k);
564 if (lclCol == lclDiagColInd) {
565 diagVal = curRow.value (k); // assume no repeats
566 }
567 if (! equib_.assumeSymmetric) {
568 Kokkos::atomic_add (&(equib_.colNorms[lclCol]), matrixAbsVal);
569 }
570 } // for each entry in row
571
572 // This is a local result. If the matrix has an overlapping
573 // row Map, then the global result might differ.
574 if (diagVal == KAT::zero ()) {
575 dst |= 4;
576 }
577 if (rowNorm == KAM::zero ()) {
578 dst |= 8;
579 }
580 // NOTE (mfh 24 May 2018) We could actually compute local
581 // rowScaledColNorms in situ at this point, if ! assumeSymmetric
582 // and row Map is the same as range Map (so that the local row
583 // norms are the same as the global row norms).
584 equib_.rowDiagonalEntries[lclRow] = diagVal;
585 equib_.rowNorms[lclRow] = rowNorm;
586 if (! equib_.assumeSymmetric &&
587 lclDiagColInd != Tpetra::Details::OrdinalTraits<LO>::invalid ()) {
588 // Don't need an atomic update here, since this lclDiagColInd is
589 // a one-to-one function of lclRow.
590 equib_.colDiagonalEntries[lclDiagColInd] += diagVal;
591 }
592 }
593
594private:
595 equib_info_type equib_;
596 local_matrix_device_type A_lcl_;
597 local_map_type rowMap_;
598 local_map_type colMap_;
599};
600
603template<class SC, class LO, class GO, class NT>
604EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type, typename NT::device_type>
606{
607 using execution_space = typename NT::device_type::execution_space;
608 using range_type = Kokkos::RangePolicy<execution_space, LO>;
609 using functor_type = ComputeLocalRowOneNorms<SC, LO, GO, NT>;
610 using val_type = typename Kokkos::ArithTraits<SC>::val_type;
611 using device_type = typename NT::device_type;
612 using equib_info_type = EquilibrationInfo<val_type, device_type>;
613
614 const LO lclNumRows = static_cast<LO> (A.getRowMap ()->getLocalNumElements ());
615 const LO lclNumCols = 0; // don't allocate column-related Views
616 constexpr bool assumeSymmetric = false; // doesn't matter here
617 equib_info_type equib (lclNumRows, lclNumCols, assumeSymmetric);
618
619 functor_type functor (equib, A.getLocalMatrixDevice (),
620 A.getRowMap ()->getLocalMap (),
621 A.getColMap ()->getLocalMap ());
622 int result = 0;
623 Kokkos::parallel_reduce ("computeLocalRowOneNorms",
624 range_type (0, lclNumRows), functor,
625 result);
626 equib.foundInf = (result & 1) != 0;
627 equib.foundNan = (result & 2) != 0;
628 equib.foundZeroDiag = (result & 4) != 0;
629 equib.foundZeroRowNorm = (result & 8) != 0;
630 return equib;
631}
632
635template<class SC, class LO, class GO, class NT>
636EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type, typename NT::device_type>
638 const bool assumeSymmetric)
639{
640 using execution_space = typename NT::device_type::execution_space;
641 using range_type = Kokkos::RangePolicy<execution_space, LO>;
642 using functor_type = ComputeLocalRowAndColumnOneNorms<SC, LO, GO, NT>;
643 using val_type = typename Kokkos::ArithTraits<SC>::val_type;
644 using device_type = typename NT::device_type;
645 using equib_info_type = EquilibrationInfo<val_type, device_type>;
646
647 const LO lclNumRows = static_cast<LO> (A.getRowMap ()->getLocalNumElements ());
648 const LO lclNumCols = static_cast<LO> (A.getColMap ()->getLocalNumElements ());
649 equib_info_type equib (lclNumRows, lclNumCols, assumeSymmetric);
650
651 functor_type functor (equib, A.getLocalMatrixDevice (),
652 A.getRowMap ()->getLocalMap (),
653 A.getColMap ()->getLocalMap ());
654 int result = 0;
655 Kokkos::parallel_reduce ("computeLocalRowAndColumnOneNorms",
656 range_type (0, lclNumRows), functor,
657 result);
658 equib.foundInf = (result & 1) != 0;
659 equib.foundNan = (result & 2) != 0;
660 equib.foundZeroDiag = (result & 4) != 0;
661 equib.foundZeroRowNorm = (result & 8) != 0;
662 return equib;
663}
664
669template<class SC, class LO, class GO, class NT>
670EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
671 typename NT::device_type>
673{
674 using crs_matrix_type = Tpetra::CrsMatrix<SC, LO, GO, NT>;
675 const crs_matrix_type* A_crs = dynamic_cast<const crs_matrix_type*> (&A);
676
677 if (A_crs == nullptr) {
679 }
680 else {
681 return computeLocalRowOneNorms_CrsMatrix (*A_crs);
682 }
683}
684
706template<class SC, class LO, class GO, class NT>
707EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type, typename NT::device_type>
709 const bool assumeSymmetric)
710{
711 using crs_matrix_type = Tpetra::CrsMatrix<SC, LO, GO, NT>;
712 const crs_matrix_type* A_crs = dynamic_cast<const crs_matrix_type*> (&A);
713
714 if (A_crs == nullptr) {
715 return computeLocalRowAndColumnOneNorms_RowMatrix (A, assumeSymmetric);
716 }
717 else {
718 return computeLocalRowAndColumnOneNorms_CrsMatrix (*A_crs, assumeSymmetric);
719 }
720}
721
722template<class SC, class LO, class GO, class NT>
723auto getLocalView_1d_readOnly (
725 const LO whichColumn)
726-> decltype (Kokkos::subview (X.getLocalViewDevice(Access::ReadOnly),
727 Kokkos::ALL (), whichColumn))
728{
729 if (X.isConstantStride ()) {
730 return Kokkos::subview (X.getLocalViewDevice(Access::ReadOnly),
731 Kokkos::ALL (), whichColumn);
732 }
733 else {
734 auto X_whichColumn = X.getVector (whichColumn);
735 return Kokkos::subview (X_whichColumn->getLocalViewDevice(Access::ReadOnly),
736 Kokkos::ALL (), 0);
737 }
738}
739
740template<class SC, class LO, class GO, class NT>
741auto getLocalView_1d_writeOnly (
743 const LO whichColumn)
744-> decltype (Kokkos::subview (X.getLocalViewDevice(Access::ReadWrite),
745 Kokkos::ALL (), whichColumn))
746{
747 if (X.isConstantStride ()) {
748 return Kokkos::subview (X.getLocalViewDevice(Access::ReadWrite),
749 Kokkos::ALL (), whichColumn);
750 }
751 else {
752 auto X_whichColumn = X.getVectorNonConst (whichColumn);
753 return Kokkos::subview(X_whichColumn->getLocalViewDevice(Access::ReadWrite),
754 Kokkos::ALL (), 0);
755 }
756}
757
758template<class SC, class LO, class GO, class NT, class ViewValueType>
759void
760copy1DViewIntoMultiVectorColumn (
762 const LO whichColumn,
763 const Kokkos::View<ViewValueType*, typename NT::device_type>& view)
764{
765 auto X_lcl = getLocalView_1d_writeOnly (X, whichColumn);
766 Tpetra::Details::copyConvert (X_lcl, view);
767}
768
769template<class SC, class LO, class GO, class NT, class ViewValueType>
770void
771copyMultiVectorColumnInto1DView (
772 const Kokkos::View<ViewValueType*, typename NT::device_type>& view,
774 const LO whichColumn)
775{
776 auto X_lcl = getLocalView_1d_readOnly (X, whichColumn);
777 Tpetra::Details::copyConvert (view, X_lcl);
778}
779
780template<class OneDViewType, class IndexType>
781class FindZero {
782public:
783 static_assert (OneDViewType::Rank == 1,
784 "OneDViewType must be a rank-1 Kokkos::View.");
785 static_assert (std::is_integral<IndexType>::value,
786 "IndexType must be a built-in integer type.");
787 FindZero (const OneDViewType& x) : x_ (x) {}
788 // Kokkos historically didn't like bool reduction results on CUDA,
789 // so we use int as the reduction result type.
790 KOKKOS_INLINE_FUNCTION void
791 operator () (const IndexType i, int& result) const {
792 using val_type = typename OneDViewType::non_const_value_type;
793 result = (x_(i) == Kokkos::ArithTraits<val_type>::zero ()) ? 1 : result;
794 }
795private:
796 OneDViewType x_;
797};
798
799template<class OneDViewType>
800bool findZero (const OneDViewType& x)
801{
802 using view_type = typename OneDViewType::const_type;
803 using execution_space = typename view_type::execution_space;
804 using size_type = typename view_type::size_type;
805 using functor_type = FindZero<view_type, size_type>;
806
807 Kokkos::RangePolicy<execution_space, size_type> range (0, x.extent (0));
808 range.set (Kokkos::ChunkSize (500)); // adjust as needed
809
810 int foundZero = 0;
811 Kokkos::parallel_reduce ("findZero", range, functor_type (x), foundZero);
812 return foundZero == 1;
813}
814
815template<class SC, class LO, class GO, class NT>
816void
817globalizeRowOneNorms (EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
818 typename NT::device_type>& equib,
820{
822
823 auto G = A.getGraph ();
824 TEUCHOS_TEST_FOR_EXCEPTION
825 (G.get () == nullptr, std::invalid_argument,
826 "globalizeRowOneNorms: Input RowMatrix A must have a nonnull graph "
827 "(that is, getGraph() must return nonnull).");
828 TEUCHOS_TEST_FOR_EXCEPTION
829 (! G->isFillComplete (), std::invalid_argument,
830 "globalizeRowOneNorms: Input CrsGraph G must be fillComplete.");
831
832 auto exp = G->getExporter ();
833 if (! exp.is_null ()) {
834 // If the matrix has an overlapping row Map, first Export the
835 // local row norms with ADD CombineMode to a range Map Vector to
836 // get the global row norms, then reverse them back with REPLACE
837 // CombineMode to the row Map Vector. Ditto for the local row
838 // diagonal entries. Use SC instead of mag_type, so we can
839 // communicate both row norms and row diagonal entries at once.
840
841 // FIXME (mfh 16 May 2018) Clever DualView tricks could possibly
842 // avoid the local copy here.
843 mv_type rowMapMV (G->getRowMap (), 2, false);
844
845 copy1DViewIntoMultiVectorColumn (rowMapMV, 0, equib.rowNorms);
846 copy1DViewIntoMultiVectorColumn (rowMapMV, 1, equib.rowDiagonalEntries);
847 {
848 mv_type rangeMapMV (G->getRangeMap (), 2, true);
849 rangeMapMV.doExport (rowMapMV, *exp, Tpetra::ADD); // forward mode
850 rowMapMV.doImport (rangeMapMV, *exp, Tpetra::REPLACE); // reverse mode
851 }
852 copyMultiVectorColumnInto1DView (equib.rowNorms, rowMapMV, 0);
853 copyMultiVectorColumnInto1DView (equib.rowDiagonalEntries, rowMapMV, 1);
854
855 // It's not common for users to solve linear systems with a
856 // nontrival Export, so it's OK for this to cost an additional
857 // pass over rowDiagonalEntries.
858 equib.foundZeroDiag = findZero (equib.rowDiagonalEntries);
859 equib.foundZeroRowNorm = findZero (equib.rowNorms);
860 }
861
862 constexpr int allReduceCount = 4;
863 int lclNaughtyMatrix[allReduceCount];
864 lclNaughtyMatrix[0] = equib.foundInf ? 1 : 0;
865 lclNaughtyMatrix[1] = equib.foundNan ? 1 : 0;
866 lclNaughtyMatrix[2] = equib.foundZeroDiag ? 1 : 0;
867 lclNaughtyMatrix[3] = equib.foundZeroRowNorm ? 1 : 0;
868
869 using Teuchos::outArg;
870 using Teuchos::REDUCE_MAX;
871 using Teuchos::reduceAll;
872 auto comm = G->getComm ();
873 int gblNaughtyMatrix[allReduceCount];
874 reduceAll<int, int> (*comm, REDUCE_MAX, allReduceCount,
875 lclNaughtyMatrix, gblNaughtyMatrix);
876
877 equib.foundInf = gblNaughtyMatrix[0] == 1;
878 equib.foundNan = gblNaughtyMatrix[1] == 1;
879 equib.foundZeroDiag = gblNaughtyMatrix[2] == 1;
880 equib.foundZeroRowNorm = gblNaughtyMatrix[3] == 1;
881}
882
883template<class SC, class LO, class GO, class NT>
884void
885globalizeColumnOneNorms (EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
886 typename NT::device_type>& equib,
888 const bool assumeSymmetric) // if so, use row norms
889{
890 using val_type = typename Kokkos::ArithTraits<SC>::val_type;
891 using mag_type = typename Kokkos::ArithTraits<val_type>::mag_type;
893 using device_type = typename NT::device_type;
894
895 auto G = A.getGraph ();
896 TEUCHOS_TEST_FOR_EXCEPTION
897 (G.get () == nullptr, std::invalid_argument,
898 "globalizeColumnOneNorms: Input RowMatrix A must have a nonnull graph "
899 "(that is, getGraph() must return nonnull).");
900 TEUCHOS_TEST_FOR_EXCEPTION
901 (! G->isFillComplete (), std::invalid_argument,
902 "globalizeColumnOneNorms: Input CrsGraph G must be fillComplete.");
903
904 auto imp = G->getImporter ();
905 if (assumeSymmetric) {
906 const LO numCols = 2;
907 // Redistribute local row info to global column info.
908
909 // Get the data into a MultiVector on the domain Map.
910 mv_type rowNorms_domMap (G->getDomainMap (), numCols, false);
911 const bool rowMapSameAsDomainMap = G->getRowMap ()->isSameAs (* (G->getDomainMap ()));
912 if (rowMapSameAsDomainMap) {
913 copy1DViewIntoMultiVectorColumn (rowNorms_domMap, 0, equib.rowNorms);
914 copy1DViewIntoMultiVectorColumn (rowNorms_domMap, 1, equib.rowDiagonalEntries);
915 }
916 else {
917 // This is not a common case; it would normally arise when the
918 // matrix has an overlapping row Map.
919 Tpetra::Export<LO, GO, NT> rowToDom (G->getRowMap (), G->getDomainMap ());
920 mv_type rowNorms_rowMap (G->getRowMap (), numCols, true);
921 copy1DViewIntoMultiVectorColumn (rowNorms_rowMap, 0, equib.rowNorms);
922 copy1DViewIntoMultiVectorColumn (rowNorms_rowMap, 1, equib.rowDiagonalEntries);
923 rowNorms_domMap.doExport (rowNorms_rowMap, rowToDom, Tpetra::REPLACE);
924 }
925
926 // Use the existing Import to redistribute the row norms from the
927 // domain Map to the column Map.
928 std::unique_ptr<mv_type> rowNorms_colMap;
929 if (imp.is_null ()) {
930 // Shallow copy of rowNorms_domMap.
931 rowNorms_colMap =
932 std::unique_ptr<mv_type> (new mv_type (rowNorms_domMap, * (G->getColMap ())));
933 }
934 else {
935 rowNorms_colMap =
936 std::unique_ptr<mv_type> (new mv_type (G->getColMap (), numCols, true));
937 rowNorms_colMap->doImport (rowNorms_domMap, *imp, Tpetra::REPLACE);
938 }
939
940 // Make sure the result has allocations of the right size.
941 const LO lclNumCols =
942 static_cast<LO> (G->getColMap ()->getLocalNumElements ());
943 if (static_cast<LO> (equib.colNorms.extent (0)) != lclNumCols) {
944 equib.colNorms =
945 Kokkos::View<mag_type*, device_type> ("colNorms", lclNumCols);
946 }
947 if (static_cast<LO> (equib.colDiagonalEntries.extent (0)) != lclNumCols) {
948 equib.colDiagonalEntries =
949 Kokkos::View<val_type*, device_type> ("colDiagonalEntries", lclNumCols);
950 }
951
952 // Copy row norms and diagonal entries, appropriately
953 // redistributed, into column norms resp. diagonal entries.
954 copyMultiVectorColumnInto1DView (equib.colNorms, *rowNorms_colMap, 0);
955 copyMultiVectorColumnInto1DView (equib.colDiagonalEntries, *rowNorms_colMap, 1);
956 }
957 else {
958 if (! imp.is_null ()) {
959 const LO numCols = 3;
960 // If the matrix has an overlapping column Map (this is usually
961 // the case), first Export (reverse-mode Import) the local info
962 // to a domain Map Vector to get the global info, then Import
963 // them back with REPLACE CombineMode to the column Map Vector.
964 // Ditto for the row-scaled column norms.
965
966 // FIXME (mfh 16 May 2018) Clever DualView tricks could possibly
967 // avoid the local copy here.
968 mv_type colMapMV (G->getColMap (), numCols, false);
969
970 copy1DViewIntoMultiVectorColumn (colMapMV, 0, equib.colNorms);
971 copy1DViewIntoMultiVectorColumn (colMapMV, 1, equib.colDiagonalEntries);
972 copy1DViewIntoMultiVectorColumn (colMapMV, 2, equib.rowScaledColNorms);
973 {
974 mv_type domainMapMV (G->getDomainMap (), numCols, true);
975 domainMapMV.doExport (colMapMV, *imp, Tpetra::ADD); // reverse mode
976 colMapMV.doImport (domainMapMV, *imp, Tpetra::REPLACE); // forward mode
977 }
978 copyMultiVectorColumnInto1DView (equib.colNorms, colMapMV, 0);
979 copyMultiVectorColumnInto1DView (equib.colDiagonalEntries, colMapMV, 1);
980 copyMultiVectorColumnInto1DView (equib.rowScaledColNorms, colMapMV, 2);
981 }
982 }
983}
984
985} // namespace Details
986
987template<class SC, class LO, class GO, class NT>
988Details::EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
989 typename NT::device_type>
991{
992 TEUCHOS_TEST_FOR_EXCEPTION
993 (! A.isFillComplete (), std::invalid_argument,
994 "computeRowOneNorms: Input matrix A must be fillComplete.");
995 auto result = Details::computeLocalRowOneNorms (A);
996
997 Details::globalizeRowOneNorms (result, A);
998 return result;
999}
1000
1001template<class SC, class LO, class GO, class NT>
1002Details::EquilibrationInfo<typename Kokkos::ArithTraits<SC>::val_type,
1003 typename NT::device_type>
1005 const bool assumeSymmetric)
1006{
1007 TEUCHOS_TEST_FOR_EXCEPTION
1008 (! A.isFillComplete (), std::invalid_argument,
1009 "computeRowAndColumnOneNorms: Input matrix A must be fillComplete.");
1010 auto result = Details::computeLocalRowAndColumnOneNorms (A, assumeSymmetric);
1011
1012 Details::globalizeRowOneNorms (result, A);
1013 if (! assumeSymmetric) {
1014 // Row-norm-scaled column norms are trivial if the matrix is
1015 // symmetric, since the row norms and column norms are the same in
1016 // that case.
1017 Details::computeLocalRowScaledColumnNorms (result, A);
1018 }
1019 Details::globalizeColumnOneNorms (result, A, assumeSymmetric);
1020 return result;
1021}
1022
1023} // namespace Tpetra
1024
1025//
1026// Explicit instantiation macro
1027//
1028// Must be expanded from within the Tpetra namespace!
1029//
1030
1031#define TPETRA_COMPUTEROWANDCOLUMNONENORMS_INSTANT(SC,LO,GO,NT) \
1032 template Details::EquilibrationInfo<Kokkos::ArithTraits<SC>::val_type, NT::device_type> \
1033 computeRowOneNorms (const Tpetra::RowMatrix<SC, LO, GO, NT>& A); \
1034 \
1035 template Details::EquilibrationInfo<Kokkos::ArithTraits<SC>::val_type, NT::device_type> \
1036 computeRowAndColumnOneNorms (const Tpetra::RowMatrix<SC, LO, GO, NT>& A, \
1037 const bool assumeSymmetric);
1038
1039#endif // TPETRA_COMPUTEROWANDCOLUMNONENORMS_DEF_HPP
Declare and define Tpetra::Details::copyConvert, an implementation detail of Tpetra (in particular,...
Sparse matrix that presents a row-oriented interface that lets users read or modify entries.
typename Node::device_type device_type
The Kokkos device type.
KokkosSparse::CrsMatrix< impl_scalar_type, local_ordinal_type, device_type, void, typename local_graph_device_type::size_type > local_matrix_device_type
The specialization of Kokkos::CrsMatrix that represents the part of the sparse matrix on each MPI pro...
local_matrix_device_type getLocalMatrixDevice() const
The local sparse matrix.
Teuchos::RCP< const map_type > getColMap() const override
The Map that describes the column distribution in this matrix.
Teuchos::RCP< const map_type > getRowMap() const override
The Map that describes the row distribution in this matrix.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
One or more distributed dense vectors.
A read-only, row-oriented interface to a sparse matrix.
virtual void getLocalRowCopy(LocalOrdinal LocalRow, nonconst_local_inds_host_view_type &Indices, nonconst_values_host_view_type &Values, size_t &NumEntries) const =0
Get a copy of the given local row's entries.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getColMap() const =0
The Map that describes the distribution of columns over processes.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getRowMap() const =0
The Map that describes the distribution of rows over processes.
virtual Teuchos::RCP< const RowGraph< LocalOrdinal, GlobalOrdinal, Node > > getGraph() const =0
The RowGraph associated with this matrix.
virtual size_t getNumEntriesInLocalRow(LocalOrdinal localRow) const =0
The current number of entries on the calling process in the specified local row.
virtual bool isFillComplete() const =0
Whether fillComplete() has been called.
Implementation details of Tpetra.
EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeLocalRowAndColumnOneNorms_RowMatrix(const Tpetra::RowMatrix< SC, LO, GO, NT > &A, const bool assumeSymmetric)
Implementation of computeLocalRowAndColumnOneNorms for a Tpetra::RowMatrix that is NOT a Tpetra::CrsM...
EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeLocalRowOneNorms_RowMatrix(const Tpetra::RowMatrix< SC, LO, GO, NT > &A)
Implementation of computeLocalRowOneNorms for a Tpetra::RowMatrix that is NOT a Tpetra::CrsMatrix.
EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeLocalRowAndColumnOneNorms_CrsMatrix(const Tpetra::CrsMatrix< SC, LO, GO, NT > &A, const bool assumeSymmetric)
Implementation of computeLocalRowAndColumnOneNorms for a Tpetra::CrsMatrix.
void copyConvert(const OutputViewType &dst, const InputViewType &src)
Copy values from the 1-D Kokkos::View src, to the 1-D Kokkos::View dst, of the same length....
EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeLocalRowAndColumnOneNorms(const Tpetra::RowMatrix< SC, LO, GO, NT > &A, const bool assumeSymmetric)
Compute LOCAL row and column one-norms ("row sums" etc.) of the input sparse matrix A....
void computeLocalRowScaledColumnNorms_RowMatrix(EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > &result, const Tpetra::RowMatrix< SC, LO, GO, NT > &A)
For a given Tpetra::RowMatrix that is not a Tpetra::CrsMatrix, assume that result....
EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeLocalRowOneNorms(const Tpetra::RowMatrix< SC, LO, GO, NT > &A)
Compute LOCAL row one-norms ("row sums" etc.) of the input sparse matrix A.
EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeLocalRowOneNorms_CrsMatrix(const Tpetra::CrsMatrix< SC, LO, GO, NT > &A)
Implementation of computeLocalRowOneNorms for a Tpetra::CrsMatrix.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Details::EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeRowOneNorms(const Tpetra::RowMatrix< SC, LO, GO, NT > &A)
Compute global row one-norms ("row sums") of the input sparse matrix A, in a way suitable for one-sid...
Details::EquilibrationInfo< typename Kokkos::ArithTraits< SC >::val_type, typename NT::device_type > computeRowAndColumnOneNorms(const Tpetra::RowMatrix< SC, LO, GO, NT > &A, const bool assumeSymmetric)
Compute global row and column one-norms ("row sums" and "column sums") of the input sparse matrix A,...
@ REPLACE
Replace existing values with new values.
@ ADD
Sum new values.
Struct storing results of Tpetra::computeRowAndColumnOneNorms.
void assign(const EquilibrationInfo< ScalarType, SrcDeviceType > &src)
Deep-copy src into *this.