374 Teuchos::Array<mat_ptr> C,
376 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q)
380 return projectAndNormalizeImpl (X, X,
false, C, B, Q);
405 Teuchos::Array<mat_ptr> C,
407 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q)
411 return projectAndNormalizeImpl (X_in, X_out,
true, C, B, Q);
421 const Scalar ONE = SCT::one();
426 for (
int k = 0; k < ncols; ++k) {
456 Teuchos::RCP<Teuchos::ParameterList> params_;
459 mutable Teuchos::RCP<const Teuchos::ParameterList> defaultParams_;
465 tsqr_adaptor_type tsqrAdaptor_;
484 bool randomizeNullSpace_;
491 bool reorthogonalizeBlocks_;
496 bool throwOnReorthogFault_;
510 bool forceNonnegativeDiagonal_;
512#ifdef BELOS_TEUCHOS_TIME_MONITOR
514 Teuchos::RCP<Teuchos::Time> timerOrtho_;
517 Teuchos::RCP<Teuchos::Time> timerProject_;
520 Teuchos::RCP<Teuchos::Time> timerNormalize_;
524 Teuchos::RCP<ReorthogonalizationCallback<Scalar> > reorthogCallback_;
526#ifdef BELOS_TEUCHOS_TIME_MONITOR
535 static Teuchos::RCP<Teuchos::Time>
536 makeTimer (
const std::string& prefix,
537 const std::string& timerName)
539 const std::string timerLabel =
540 prefix.empty() ? timerName : (prefix +
": " + timerName);
541 return Teuchos::TimeMonitor::getNewCounter (timerLabel);
550 clearTimer (
const std::string& prefix,
551 const std::string& timerName)
553 const std::string timerLabel =
554 prefix.empty() ? timerName : (prefix +
": " + timerName);
555 Teuchos::TimeMonitor::clearCounter (timerLabel);
561 raiseReorthogFault (
const std::vector<magnitude_type>& normsAfterFirstPass,
562 const std::vector<magnitude_type>& normsAfterSecondPass,
563 const std::vector<int>& faultIndices);
575 checkProjectionDims (
int& ncols_X,
579 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q)
const;
592 allocateProjectionCoefficients (Teuchos::Array<mat_ptr>& C,
593 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q,
595 const bool attemptToRecycle =
true)
const;
606 projectAndNormalizeImpl (MV& X_in,
608 const bool outOfPlace,
609 Teuchos::Array<mat_ptr> C,
611 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q);
620 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q,
621 Teuchos::ArrayView<mat_ptr> C)
const;
626 const Teuchos::RCP<const MV>& Q,
655 int rawNormalize (MV& X, MV& Q,
mat_type& B);
674 int normalizeOne (MV& X,
mat_ptr B)
const;
703 int normalizeImpl (MV& X, MV& Q,
mat_ptr B,
const bool outOfPlace);
706 template<
class Scalar,
class MV,
class DM>
711 using Teuchos::ParameterList;
712 using Teuchos::parameterList;
714 using Teuchos::sublist;
719 RCP<ParameterList> tsqrParams;
721 RCP<ParameterList> theParams;
722 if (params.is_null()) {
723 theParams = parameterList (*defaultParams);
731 randomizeNullSpace_ =
732 theParams->get<
bool> (
"randomizeNullSpace",
733 defaultParams->get<
bool> (
"randomizeNullSpace"));
734 reorthogonalizeBlocks_ =
735 theParams->get<
bool> (
"reorthogonalizeBlocks",
736 defaultParams->get<
bool> (
"reorthogonalizeBlocks"));
737 throwOnReorthogFault_ =
738 theParams->get<
bool> (
"throwOnReorthogFault",
739 defaultParams->get<
bool> (
"throwOnReorthogFault"));
740 blockReorthogThreshold_ =
741 theParams->get<M> (
"blockReorthogThreshold",
742 defaultParams->get<M> (
"blockReorthogThreshold"));
743 relativeRankTolerance_ =
744 theParams->get<M> (
"relativeRankTolerance",
745 defaultParams->get<M> (
"relativeRankTolerance"));
746 forceNonnegativeDiagonal_ =
747 theParams->get<
bool> (
"forceNonnegativeDiagonal",
748 defaultParams->get<
bool> (
"forceNonnegativeDiagonal"));
752 if (! theParams->isSublist (
"TSQR implementation")) {
753 theParams->set (
"TSQR implementation",
754 defaultParams->sublist (
"TSQR implementation"));
756 tsqrParams = sublist (theParams,
"TSQR implementation",
true);
760 tsqrAdaptor_.setParameterList (tsqrParams);
763 setMyParamList (theParams);
766 template<
class Scalar,
class MV,
class DM>
769 const std::string& label) :
773 randomizeNullSpace_ (true),
774 reorthogonalizeBlocks_ (true),
775 throwOnReorthogFault_ (false),
776 blockReorthogThreshold_ (0),
777 relativeRankTolerance_ (0),
778 forceNonnegativeDiagonal_ (false)
782#ifdef BELOS_TEUCHOS_TIME_MONITOR
783 timerOrtho_ = makeTimer (label,
"All orthogonalization");
784 timerProject_ = makeTimer (label,
"Projection");
785 timerNormalize_ = makeTimer (label,
"Normalization");
789 template<
class Scalar,
class MV,
class DM>
795 randomizeNullSpace_ (true),
796 reorthogonalizeBlocks_ (true),
797 throwOnReorthogFault_ (false),
798 blockReorthogThreshold_ (0),
799 relativeRankTolerance_ (0),
800 forceNonnegativeDiagonal_ (false)
804#ifdef BELOS_TEUCHOS_TIME_MONITOR
805 timerOrtho_ = makeTimer (label,
"All orthogonalization");
806 timerProject_ = makeTimer (label,
"Projection");
807 timerNormalize_ = makeTimer (label,
"Normalization");
811 template<
class Scalar,
class MV,
class DM>
814 norm (
const MV& X, std::vector<magnitude_type>& normVec)
const
819 if (normVec.size() <
static_cast<size_t>(numCols))
820 normVec.resize (numCols);
824 template<
class Scalar,
class MV,
class DM>
827 Teuchos::Array<mat_ptr> C,
828 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q)
830#ifdef BELOS_TEUCHOS_TIME_MONITOR
838 Teuchos::TimeMonitor timerMonitorOrtho(*timerOrtho_);
841 int ncols_X, num_Q_blocks, ncols_Q_total;
842 checkProjectionDims (ncols_X, num_Q_blocks, ncols_Q_total, X, Q);
846 if (ncols_X == 0 || num_Q_blocks == 0 || ncols_Q_total == 0)
850 allocateProjectionCoefficients (C, Q, X,
true);
854 std::vector<magnitude_type> columnNormsBefore (ncols_X,
magnitude_type(0));
855 if (reorthogonalizeBlocks_)
860 rawProject (X, Q, C);
864 if (reorthogonalizeBlocks_) {
865 std::vector<magnitude_type> columnNormsAfter (ncols_X,
magnitude_type(0));
874 bool reorthogonalize =
false;
875 for (
int j = 0; j < ncols_X; ++j) {
876 if (columnNormsAfter[j] < relThres * columnNormsBefore[j]) {
877 reorthogonalize =
true;
881 if (reorthogonalize) {
884 if (! reorthogCallback_.is_null()) {
885 reorthogCallback_->operator() (Teuchos::arrayViewFromVector (columnNormsBefore),
886 Teuchos::arrayViewFromVector (columnNormsAfter));
889 Teuchos::Array<mat_ptr> C2;
890 allocateProjectionCoefficients (C2, Q, X,
false);
894 rawProject (X, Q, C2);
896 for (
int k = 0; k < num_Q_blocks; ++k)
903 template<
class Scalar,
class MV,
class DM>
907 using Teuchos::Range1D;
910#ifdef BELOS_TEUCHOS_TIME_MONITOR
911 Teuchos::TimeMonitor timerMonitorNormalize(*timerNormalize_);
916 Teuchos::TimeMonitor timerMonitorOrtho(*timerOrtho_);
931 return normalizeOne (X, B);
973 return normalizeImpl (X, *Q_, B,
false);
976 return normalizeImpl (X, *Q_view, B,
false);
980 template<
class Scalar,
class MV,
class DM>
984 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q,
986 const bool attemptToRecycle)
const
988 const int num_Q_blocks = Q.size();
989 const int ncols_X = MVT::GetNumberVecs (X);
990 C.resize (num_Q_blocks);
991 if (attemptToRecycle)
993 for (
int i = 0; i < num_Q_blocks; ++i)
995 const int ncols_Qi = MVT::GetNumberVecs (*Q[i]);
999 C[i] = DMT::Create(ncols_Qi, ncols_X);
1002 mat_type& Ci = *C[i];
1003 if (DMT::GetNumRows(Ci) != ncols_Qi || DMT::GetNumCols(Ci) != ncols_X)
1004 DMT::Reshape(Ci, ncols_Qi, ncols_X);
1006 DMT::PutScalar(Ci, SCT::zero());
1012 for (
int i = 0; i < num_Q_blocks; ++i)
1014 const int ncols_Qi = MVT::GetNumberVecs (*Q[i]);
1015 C[i] = DMT::Create(ncols_Qi, ncols_X);
1020 template<
class Scalar,
class MV,
class DM>
1025#ifdef BELOS_TEUCHOS_TIME_MONITOR
1026 Teuchos::TimeMonitor timerMonitorOrtho(*timerOrtho_);
1027 Teuchos::TimeMonitor timerMonitorNormalize(*timerNormalize_);
1033 }
else if (numVecs == 1) {
1035 using Teuchos::Range1D;
1040 const int rank = normalizeOne (X, B);
1049 return normalizeImpl (X, Q, B,
true);
1053 template<
class Scalar,
class MV,
class DM>
1058 const bool outOfPlace,
1059 Teuchos::Array<mat_ptr> C,
1061 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q)
1063 using Teuchos::Range1D;
1067#ifdef BELOS_TEUCHOS_TIME_MONITOR
1070 Teuchos::TimeMonitor timerMonitorOrtho(*timerOrtho_);
1075 TEUCHOS_TEST_FOR_EXCEPTION(MVT::GetNumberVecs(X_out) < MVT::GetNumberVecs(X_in),
1076 std::invalid_argument,
1077 "Belos::TsqrOrthoManagerImpl::"
1078 "projectAndNormalizeImpl(..., outOfPlace=true, ...):"
1079 "X_out has " << MVT::GetNumberVecs(X_out)
1080 <<
" columns, but X_in has "
1081 << MVT::GetNumberVecs(X_in) <<
" columns.");
1085 int ncols_X, num_Q_blocks, ncols_Q_total;
1086 checkProjectionDims (ncols_X, num_Q_blocks, ncols_Q_total, X_in, Q);
1093 if (num_Q_blocks == 0 || ncols_Q_total == 0) {
1095 return normalizeOutOfPlace (X_in, X_out, B);
1097 return normalize (X_in, B);
1104 allocateProjectionCoefficients (C, Q, X_in,
true);
1109 std::vector<magnitude_type> normsBeforeFirstPass (ncols_X, SCTM::zero());
1110 if (reorthogonalizeBlocks_) {
1111 MVT::MvNorm (X_in, normsBeforeFirstPass);
1115 rawProject (X_in, Q, C);
1128 B_out = DMT::Create(ncols_X, ncols_X);
1131 TEUCHOS_TEST_FOR_EXCEPTION(DMT::GetNumRows(*B) < ncols_X ||
1132 DMT::GetNumCols(*B) < ncols_X,
1133 std::invalid_argument,
1134 "normalizeOne: Input matrix B must be at "
1135 "least " << ncols_X <<
" x " << ncols_X
1136 <<
", but is instead " << DMT::GetNumRows(*B)
1137 <<
" x " << DMT::GetNumCols(*B) <<
".");
1141 B_out = DMT::Subview(*B, ncols_X, ncols_X);
1147 const int firstPassRank = outOfPlace ?
1148 normalizeOutOfPlace (X_in, X_out, B_out) :
1149 normalize (X_in, B_out);
1158 int rank = firstPassRank;
1174 if (firstPassRank < ncols_X && randomizeNullSpace_) {
1175 const int numNullSpaceCols = ncols_X - firstPassRank;
1176 const Range1D nullSpaceIndices (firstPassRank, ncols_X - 1);
1179 Teuchos::Array<mat_ptr> C_null (num_Q_blocks);
1180 for (
int k = 0; k < num_Q_blocks; ++k) {
1181 const int numColsQk = MVT::GetNumberVecs(*Q[k]);
1182 C_null[k] = DMT::Create(numColsQk, numNullSpaceCols);
1185 mat_ptr B_null = DMT::Create(numNullSpaceCols, numNullSpaceCols);
1187 int randomVectorsRank;
1191 RCP<MV> X_out_null = MVT::CloneViewNonConst (X_out, nullSpaceIndices);
1196 RCP<MV> X_in_null = MVT::CloneViewNonConst (X_in, nullSpaceIndices);
1197 MVT::Assign (*X_out_null, *X_in_null);
1200 rawProject (*X_in_null, Q, C_null);
1201 randomVectorsRank = normalizeOutOfPlace (*X_in_null, *X_out_null, B_null);
1205 RCP<MV> X_null = MVT::CloneViewNonConst (X_in, nullSpaceIndices);
1208 rawProject (*X_null, Q, C_null);
1209 randomVectorsRank = normalize (*X_null, B_null);
1215 TEUCHOS_TEST_FOR_EXCEPTION(randomVectorsRank != numNullSpaceCols,
1217 "Belos::TsqrOrthoManagerImpl::projectAndNormalize"
1218 "OutOfPlace(): After projecting and normalizing the "
1219 "random vectors (used to replace the null space "
1220 "basis vectors from normalizing X), they have rank "
1221 << randomVectorsRank <<
", but should have full "
1222 "rank " << numNullSpaceCols <<
".");
1227 if (reorthogonalizeBlocks_) {
1230 std::vector<magnitude_type>
1231 normsAfterFirstPass (firstPassRank, SCTM::zero());
1232 std::vector<magnitude_type>
1233 normsAfterSecondPass (firstPassRank, SCTM::zero());
1247 Teuchos::BLAS<int, Scalar> blas;
1248 DMT::SyncDeviceToHost( *B_out );
1249 for (
int j = 0; j < firstPassRank; ++j) {
1250 mat_ptr B_j = DMT::Subview( *B_out, firstPassRank, 1, 0, j );
1253 normsAfterFirstPass[j] = blas.NRM2 (firstPassRank, DMT::GetRawHostPtr(*B_j), 1);
1257 bool reorthogonalize =
false;
1258 for (
int j = 0; j < firstPassRank; ++j) {
1265 const magnitude_type curThreshold =
1266 blockReorthogThreshold() * normsBeforeFirstPass[j];
1267 if (normsAfterFirstPass[j] < curThreshold) {
1268 reorthogonalize =
true;
1275 if (! reorthogCallback_.is_null()) {
1276 using Teuchos::arrayViewFromVector;
1277 (*reorthogCallback_) (arrayViewFromVector (normsBeforeFirstPass),
1278 arrayViewFromVector (normsAfterFirstPass));
1292 bool reorthogFault =
false;
1294 std::vector<int> faultIndices;
1295 if (reorthogonalize) {
1296 using Teuchos::Copy;
1297 using Teuchos::NO_TRANS;
1303 MVT::Assign (X_out, X_in);
1309 Teuchos::Array<mat_ptr> C2;
1310 allocateProjectionCoefficients (C2, Q, X_in,
false);
1315 rawProject (X_in, Q, C2);
1318 mat_ptr B2 = DMT::Create(ncols_X, ncols_X);
1321 const int secondPassRank = outOfPlace ?
1322 normalizeOutOfPlace (X_in, X_out, B2) :
1323 normalize (X_in, B2);
1324 rank = secondPassRank;
1329 mat_ptr B_copy = DMT::CreateCopy(*B_out);
1331 DMT::SyncDeviceToHost( *B2 );
1332 DMT::SyncDeviceToHost( *B_out );
1333 blas.GEMM( NO_TRANS, NO_TRANS, DMT::GetNumRows( *B2 ), DMT::GetNumCols( *B_copy ),
1334 DMT::GetNumCols( *B2 ), SCT::one(), DMT::GetRawHostPtr( *B2 ),
1335 DMT::GetStride( *B2 ), DMT::GetRawHostPtr( *B_copy ),
1336 DMT::GetStride( *B_copy ), SCT::zero(),
1337 DMT::GetRawHostPtr( *B_out ), DMT::GetStride( *B_out ) );
1338 DMT::SyncHostToDevice( *B_out );
1343 for (
int k = 0; k < num_Q_blocks; ++k) {
1345 DMT::SyncDeviceToHost( *C[k] );
1346 DMT::SyncDeviceToHost( *C2[k] );
1348 blas.GEMM( NO_TRANS, NO_TRANS, DMT::GetNumRows( *C2[k] ), DMT::GetNumCols( *B_copy ),
1349 DMT::GetNumCols( *C2[k] ), SCT::one(), DMT::GetRawHostPtr( *C2[k] ),
1350 DMT::GetStride( *C2[k] ), DMT::GetRawHostPtr( *B_copy ),
1351 DMT::GetStride( *B_copy ), SCT::one(),
1352 DMT::GetRawHostPtr( *C[k] ), DMT::GetStride( *C[k] ) );
1353 DMT::SyncHostToDevice( *C[k] );
1358 for (
int j = 0; j < rank; ++j) {
1359 mat_ptr B2_j = DMT::Subview( *B2, rank, 1, 0, j );
1360 normsAfterSecondPass[j] = blas.NRM2 (rank, DMT::GetRawHostPtr(*B2_j), 1);
1365 reorthogFault =
false;
1366 for (
int j = 0; j < rank; ++j) {
1367 const magnitude_type relativeLowerBound =
1368 blockReorthogThreshold() * normsAfterFirstPass[j];
1369 if (normsAfterSecondPass[j] < relativeLowerBound) {
1370 reorthogFault =
true;
1371 faultIndices.push_back (j);
1376 if (reorthogFault) {
1377 if (throwOnReorthogFault_) {
1378 raiseReorthogFault (normsAfterFirstPass,
1379 normsAfterSecondPass,
1387 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::logic_error,
1388 "TsqrOrthoManagerImpl has not yet implemented"
1389 " recovery from an orthogonalization fault.");
1396 template<
class Scalar,
class MV,
class DM>
1400 const std::vector<magnitude_type>& normsAfterSecondPass,
1401 const std::vector<int>& faultIndices)
1404 typedef std::vector<int>::size_type size_type;
1405 std::ostringstream os;
1407 os <<
"Orthogonalization fault at the following column(s) of X:" << endl;
1408 os <<
"Column\tNorm decrease factor" << endl;
1409 for (size_type k = 0; k < faultIndices.size(); ++k) {
1410 const int index = faultIndices[k];
1411 const magnitude_type decreaseFactor =
1412 normsAfterSecondPass[index] / normsAfterFirstPass[index];
1413 os << index <<
"\t" << decreaseFactor << endl;
1418 template<
class Scalar,
class MV,
class DM>
1419 Teuchos::RCP<const Teuchos::ParameterList>
1422 using Teuchos::ParameterList;
1423 using Teuchos::parameterList;
1426 if (defaultParams_.is_null()) {
1427 RCP<ParameterList> params = parameterList (
"TsqrOrthoManagerImpl");
1431 params->set (
"TSQR implementation", *(tsqrAdaptor_.getValidParameters()),
1432 "TSQR implementation parameters.");
1436 const bool defaultRandomizeNullSpace =
true;
1437 params->set (
"randomizeNullSpace", defaultRandomizeNullSpace,
1438 "Whether to fill in null space vectors with random data.");
1440 const bool defaultReorthogonalizeBlocks =
true;
1441 params->set (
"reorthogonalizeBlocks", defaultReorthogonalizeBlocks,
1442 "Whether to do block reorthogonalization as necessary.");
1448 params->set (
"blockReorthogThreshold", defaultBlockReorthogThreshold,
1449 "If reorthogonalizeBlocks==true, and if the norm of "
1450 "any column within a block decreases by this much or "
1451 "more after orthogonalization, we reorthogonalize.");
1456 Teuchos::as<magnitude_type>(10) * SCTM::eps();
1461 params->set (
"relativeRankTolerance", defaultRelativeRankTolerance,
1462 "Relative tolerance to determine the numerical rank of a "
1463 "block when normalizing.");
1467 const bool defaultThrowOnReorthogFault =
true;
1468 params->set (
"throwOnReorthogFault", defaultThrowOnReorthogFault,
1469 "Whether to throw an exception if an orthogonalization "
1470 "fault occurs. This only matters if reorthogonalization "
1471 "is enabled (reorthogonalizeBlocks==true).");
1473 const bool defaultForceNonnegativeDiagonal =
false;
1474 params->set (
"forceNonnegativeDiagonal", defaultForceNonnegativeDiagonal,
1475 "Whether to force the R factor produced by the normalization "
1476 "step to have a nonnegative diagonal.");
1478 defaultParams_ = params;
1480 return defaultParams_;
1483 template<
class Scalar,
class MV,
class DM>
1484 Teuchos::RCP<const Teuchos::ParameterList>
1487 using Teuchos::ParameterList;
1493 RCP<ParameterList> params = rcp (
new ParameterList (*defaultParams));
1502 const bool randomizeNullSpace =
false;
1503 params->set (
"randomizeNullSpace", randomizeNullSpace);
1504 const bool reorthogonalizeBlocks =
false;
1505 params->set (
"reorthogonalizeBlocks", reorthogonalizeBlocks);
1510 template<
class Scalar,
class MV,
class DM>
1522 tsqrAdaptor_.factorExplicit (X, Q, B, forceNonnegativeDiagonal_);
1525 rank = tsqrAdaptor_.revealRank (Q, B, relativeRankTolerance_);
1526 }
catch (std::exception& e) {
1527 throw TsqrOrthoError (e.what());
1532 template<
class Scalar,
class MV,
class DM>
1536 Teuchos::RCP<DM> B)
const
1543 B_out = DMT::Create(1, 1);
1545 const int theNumRows = DMT::GetNumRows(*B);
1546 const int theNumCols = DMT::GetNumCols(*B;
1547 TEUCHOS_TEST_FOR_EXCEPTION(
1548 theNumRows < 1 || theNumCols < 1, std::invalid_argument,
1549 "normalizeOne: Input matrix B must be at least 1 x 1, but "
1550 "is instead " << theNumRows <<
" x " << theNumCols <<
".");
1552 B_out = DMT::Subview(*B, 1, 1);
1556 std::vector<magnitude_type> theNorm (1, SCTM::zero());
1557 MVT::MvNorm (X, theNorm);
1558 DMT::PutScalar(*B_out, theNorm[0]);
1572 if (theNorm[0] == SCTM::zero()) {
1575 if (randomizeNullSpace_) {
1577 MVT::MvNorm (X, theNorm);
1578 if (theNorm[0] == SCTM::zero()) {
1584 "vector has norm zero!");
1589 const Scalar alpha = SCT::one() / theNorm[0];
1590 MVT::MvScale (X, alpha);
1597 const Scalar alpha = SCT::one() / theNorm[0];
1598 MVT::MvScale (X, alpha);
1604 template<
class Scalar,
class MV,
class DM>
1608 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q,
1609 Teuchos::ArrayView<Teuchos::RCP<DM> > C)
const
1611#ifdef BELOS_TEUCHOS_TIME_MONITOR
1612 Teuchos::TimeMonitor timerMonitorNormalize(*timerProject_);
1616 const int num_Q_blocks = Q.size();
1617 for (
int i = 0; i < num_Q_blocks; ++i)
1625 mat_type& Ci = *C[i];
1626 const MV& Qi = *Q[i];
1627 innerProd (Qi, X, Ci);
1628 MVT::MvTimesMatAddMv (-SCT::one(), Qi, Ci, SCT::one(), X);
1633 template<
class Scalar,
class MV,
class DM>
1637 const Teuchos::RCP<const MV>& Q,
1638 const Teuchos::RCP<DM>& C)
const
1640#ifdef BELOS_TEUCHOS_TIME_MONITOR
1641 Teuchos::TimeMonitor timerMonitorNormalize(*timerProject_);
1645 innerProd (*Q, X, *C);
1646 MVT::MvTimesMatAddMv (-SCT::one(), *Q, *C, SCT::one(), X);
1649 template<
class Scalar,
class MV,
class DM>
1655 const bool outOfPlace)
1657 using Teuchos::Range1D;
1660 using Teuchos::ScalarTraits;
1661 using Teuchos::tuple;
1663 const int numCols = MVT::GetNumberVecs (X);
1670 TEUCHOS_TEST_FOR_EXCEPTION(
1671 MVT::GetNumberVecs (Q) < numCols, std::invalid_argument,
1672 "TsqrOrthoManagerImpl::normalizeImpl: Q has "
1673 << MVT::GetNumberVecs(Q) <<
" columns. This is too "
1674 "few, since X has " << numCols <<
" columns.");
1678 RCP<MV> Q_view = MVT::CloneViewNonConst (Q, Range1D (0, numCols-1));
1686 B_out = DMT::Create(numCols, numCols);
1689 TEUCHOS_TEST_FOR_EXCEPTION(
1690 DMT::GetNumRows(*B) < numCols || DMT::GetNumCols(*B) < numCols, std::invalid_argument,
1691 "TsqrOrthoManagerImpl::normalizeImpl: Input matrix B must be at least "
1692 << numCols <<
" x " << numCols <<
", but is instead " << DMT::GetNumRows (*B)
1693 <<
" x " << DMT::GetNumCols(*B) <<
".");
1696 B_out = DMT::Subview(*B, numCols, numCols);
1708 const int rank = rawNormalize (X, *Q_view, *B_out);
1718 TEUCHOS_TEST_FOR_EXCEPTION(
1719 rank < 0 || rank > numCols, std::logic_error,
1720 "Belos::TsqrOrthoManagerImpl::normalizeImpl: rawNormalize returned rank "
1721 " = " << rank <<
" for a matrix X with " << numCols <<
" columns. "
1722 "Please report this bug to the Belos developers.");
1726 if (rank == numCols || ! randomizeNullSpace_) {
1730 MVT::Assign (*Q_view, X);
1735 if (randomizeNullSpace_ && rank < numCols) {
1742 const int nullSpaceNumCols = numCols - rank;
1745 Range1D nullSpaceIndices (rank, numCols-1);
1752 RCP<MV> Q_null = MVT::CloneViewNonConst (*Q_view, nullSpaceIndices);
1754 MVT::MvRandom (*Q_null);
1760 std::vector<magnitude_type> norms (MVT::GetNumberVecs (*Q_null));
1761 MVT::MvNorm (*Q_null, norms);
1763 bool anyZero =
false;
1764 typedef typename std::vector<magnitude_type>::const_iterator iter_type;
1765 for (iter_type it = norms.begin(); it != norms.end(); ++it) {
1766 if (*it == SCTM::zero()) {
1771 std::ostringstream os;
1772 os <<
"TsqrOrthoManagerImpl::normalizeImpl: "
1773 "We are being asked to randomize the null space, for a matrix "
1774 "with " << numCols <<
" columns and reported column rank "
1775 << rank <<
". The inclusive range of columns to fill with "
1776 "random data is [" << nullSpaceIndices.lbound() <<
","
1777 << nullSpaceIndices.ubound() <<
"]. After filling the null "
1778 "space vectors with random numbers, at least one of the vectors"
1779 " has norm zero. Here are the norms of all the null space "
1781 for (iter_type it = norms.begin(); it != norms.end(); ++it) {
1783 if (it+1 != norms.end())
1786 os <<
"].) There is a tiny probability that this could happen "
1787 "randomly, but it is likely a bug. Please report it to the "
1788 "Belos developers, especially if you are able to reproduce the "
1801 RCP<const MV> Q_col = MVT::CloneView (*Q_view, Range1D (0, rank-1));
1806 mat_ptr C_null = DMT::Create(rank, nullSpaceNumCols);
1807 rawProject (*Q_null, Q_col, C_null);
1816 RCP<MV> X_null = MVT::CloneViewNonConst (X, nullSpaceIndices);
1819 mat_ptr B_null = DMT::Create(nullSpaceNumCols, nullSpaceNumCols);
1821 const int nullSpaceBasisRank = rawNormalize (*Q_null, *X_null, *B_null);
1835 if (nullSpaceBasisRank < nullSpaceNumCols) {
1836 std::vector<magnitude_type> norms (MVT::GetNumberVecs(*X_null));
1837 MVT::MvNorm (*X_null, norms);
1838 std::ostringstream os;
1839 os <<
"TsqrOrthoManagerImpl::normalizeImpl: "
1840 <<
"We are being asked to randomize the null space, "
1841 <<
"for a matrix with " << numCols <<
" columns and "
1842 <<
"column rank " << rank <<
". After projecting and "
1843 <<
"normalizing the generated random vectors, they "
1844 <<
"only have rank " << nullSpaceBasisRank <<
". They"
1845 <<
" should have full rank " << nullSpaceNumCols
1846 <<
". (The inclusive range of columns to fill with "
1847 <<
"random data is [" << nullSpaceIndices.lbound()
1848 <<
"," << nullSpaceIndices.ubound() <<
"]. The "
1849 <<
"column norms of the resulting Q factor are: [";
1850 for (
typename std::vector<magnitude_type>::size_type k = 0;
1851 k < norms.size(); ++k) {
1853 if (k != norms.size()-1) {
1857 os <<
"].) There is a tiny probability that this could "
1858 <<
"happen randomly, but it is likely a bug. Please "
1859 <<
"report it to the Belos developers, especially if "
1860 <<
"you are able to reproduce the behavior.";
1862 TEUCHOS_TEST_FOR_EXCEPTION(nullSpaceBasisRank < nullSpaceNumCols,
1873 MVT::Assign (*X_null, *Q_null);
1874 }
else if (rank > 0) {
1876 RCP<const MV> Q_col = MVT::CloneView (*Q_view, Range1D (0, rank-1));
1877 RCP<MV> X_col = MVT::CloneViewNonConst (X, Range1D (0, rank-1));
1878 MVT::Assign (*Q_col, *X_col);
1885 template<
class Scalar,
class MV,
class DM>
1892 Teuchos::ArrayView<Teuchos::RCP<const MV> > Q)
const
1900 int the_ncols_X, the_num_Q_blocks, the_ncols_Q_total;
1901 the_num_Q_blocks = Q.size();
1902 the_ncols_X = MVT::GetNumberVecs (X);
1905 the_ncols_Q_total = 0;
1908 using Teuchos::ArrayView;
1910 typedef typename ArrayView<RCP<const MV> >::const_iterator iter_type;
1911 for (iter_type it = Q.begin(); it != Q.end(); ++it) {
1912 const MV& Qi = **it;
1913 the_ncols_Q_total += MVT::GetNumberVecs (Qi);
1917 ncols_X = the_ncols_X;
1918 num_Q_blocks = the_num_Q_blocks;
1919 ncols_Q_total = the_ncols_Q_total;