47 #include "ConstrainedOptPack_MatrixSymAddDelBunchKaufman.hpp"
48 #include "DenseLinAlgLAPack.hpp"
49 #include "DenseLinAlgPack_DMatrixOut.hpp"
50 #include "DenseLinAlgPack_DMatrixOp.hpp"
51 #include "DenseLinAlgPack_AssertOp.hpp"
52 #include "DenseLinAlgPack_delete_row_col.hpp"
54 namespace ConstrainedOptPack {
57 : S_size_(0), S_indef_(false), fact_updated_(false), fact_in1_(true), inertia_(0,0,0)
62 S_chol_.pivot_tols(pivot_tols);
67 return S_chol_.pivot_tols();
96 if( S_store1_.rows() < max_size+1 && S_store1_.cols() < max_size+1 )
97 S_store1_.resize(max_size+1,max_size+1);
100 S_chol_.init_setup(&S_store1_(),Teuchos::null,0,
true,
true,
true,
false,0.0);
101 S_chol_.initialize(alpha,max_size);
113 const DMatrixSliceSym &A
115 ,
bool force_factorization
116 ,Inertia expected_inertia
117 ,PivotTolerances pivot_tols
120 using BLAS_Cpp::upper;
121 using BLAS_Cpp::lower;
122 using DenseLinAlgPack::tri_ele;
123 using DenseLinAlgPack::nonconst_tri_ele;
124 typedef MatrixSymAddDelUpdateable MSADU;
125 typedef MSADU::Inertia Inertia;
127 bool throw_exception =
false;
128 std::ostringstream omsg;
136 || expected_inertia.zero_eigens == 0 ) );
140 if( S_store1_.rows() < max_size+1 && S_store1_.cols() < max_size+1 )
141 S_store1_.resize(max_size+1,max_size+1);
144 const bool not_indefinite
145 = ( ( expected_inertia.neg_eigens == 0 && expected_inertia.pos_eigens == n )
146 || ( expected_inertia.neg_eigens == n && expected_inertia.pos_eigens == 0 ) );
148 if( not_indefinite ) {
151 S_chol_.init_setup(&S_store1_(),Teuchos::null,0,
true,
true,
true,
false,0.0);
153 S_chol_.initialize(A,max_size,force_factorization,expected_inertia,pivot_tols);
155 catch(
const MSADU::WarnNearSingularUpdateException& except) {
156 throw_exception =
true;
157 omsg << except.what();
158 gamma = except.gamma;
169 bool fact_in1 = !fact_in1_;
174 factor_matrix( n, fact_in1 );
178 <<
"MatrixSymAddDelBunchKaufman::initialize(...): "
179 <<
"Error, the matrix A is singular:\n"
181 throw SingularUpdateException( omsg.str(), -1.0 );
185 throw_exception = compute_assert_inertia(
186 n,fact_in1,expected_inertia,
"initialize",pivot_tols
187 ,&inertia,&omsg,&gamma);
191 if( inertia.pos_eigens == n || inertia.neg_eigens == n ) {
198 , tri_ele( A.gms(), A.uplo() ) );
202 fact_updated_ =
true;
203 fact_in1_ = fact_in1;
212 if( throw_exception )
213 throw WarnNearSingularUpdateException(omsg.str(),gamma);
218 return S_store1_.rows() -1;
221 MatrixSymAddDelUpdateable::Inertia
224 return S_indef_ ? inertia_ : S_chol_.inertia();
233 const DVectorSlice *t
235 ,
bool force_refactorization
236 ,EEigenValType add_eigen_val
237 ,PivotTolerances pivot_tols
242 using DenseLinAlgPack::norm_inf;
244 typedef MatrixSymAddDelUpdateable MSADU;
246 assert_initialized();
249 if (implicit_ref_cast<const MatrixBase>(*this).rows() >=
max_size()) {
250 throw MaxSizeExceededException(
251 "MatrixSymAddDelBunchKaufman::augment_update(...) : "
252 "Error, the maximum size would be exceeded." );
254 if (t && t->dim() != S_size_) {
255 throw std::length_error(
256 "MatrixSymAddDelBunchKaufman::augment_update(...): "
257 "Error, t.dim() must be equal to this->rows()." );
259 if (!(add_eigen_val == MSADU::EIGEN_VAL_UNKNOWN
260 || add_eigen_val != MSADU::EIGEN_VAL_ZERO))
262 throw SingularUpdateException(
263 "MatrixSymAddDelBunchKaufman::augment_update(...): "
264 "Error, the client has specified a singular update in add_eigen_val.", -1.0 );
268 bool throw_exception =
false;
269 std::ostringstream omsg;
277 MSADU::Inertia
inertia = S_chol_.inertia();
280 = ( ( inertia.pos_eigens > 0
281 && ( add_eigen_val == MSADU::EIGEN_VAL_POS || add_eigen_val == MSADU::EIGEN_VAL_UNKNOWN ) )
282 || ( inertia.neg_eigens > 0
283 && ( add_eigen_val == MSADU::EIGEN_VAL_NEG || add_eigen_val == MSADU::EIGEN_VAL_UNKNOWN ) )
285 if( !new_S_not_indef ) {
290 bool update_successful =
false;
292 S_chol_.augment_update(t,alpha,force_refactorization,add_eigen_val,pivot_tols);
293 update_successful =
true;
295 catch(
const MSADU::WrongInertiaUpdateException&) {
296 if( add_eigen_val != MSADU::EIGEN_VAL_UNKNOWN )
301 catch(
const MSADU::WarnNearSingularUpdateException& except) {
302 throw_exception =
true;
303 update_successful =
true;
304 omsg << except.what();
305 gamma = except.gamma;
307 if( update_successful ) {
310 throw MSADU::WarnNearSingularUpdateException(omsg.str(),gamma);
324 DMatrixSlice S_bar = this->S(n+1).gms();
340 if( force_refactorization && fact_updated_ ) {
343 abs_beta = std::fabs(beta),
344 nrm_D_diag = norm_inf(DU(n,fact_in1_).gms().diag());
345 gamma = abs_beta / nrm_D_diag;
349 add_eigen_val == MSADU::EIGEN_VAL_UNKNOWN
350 || beta > 0.0 && add_eigen_val == MSADU::EIGEN_VAL_POS
351 || beta < 0.0 && add_eigen_val == MSADU::EIGEN_VAL_NEG
353 PivotTolerances use_pivot_tols = S_chol_.pivot_tols();
354 if( pivot_tols.warning_tol != PivotTolerances::UNKNOWN )
355 use_pivot_tols.warning_tol = pivot_tols.warning_tol;
356 if( pivot_tols.singular_tol != PivotTolerances::UNKNOWN )
357 use_pivot_tols.singular_tol = pivot_tols.singular_tol;
358 if( pivot_tols.wrong_inertia_tol != PivotTolerances::UNKNOWN )
359 use_pivot_tols.wrong_inertia_tol = pivot_tols.wrong_inertia_tol;
362 || correct_inertia && gamma <= use_pivot_tols.singular_tol
366 std::ostringstream onum_msg;
367 if(throw_exception) {
369 <<
"gamma = |alpha-t'*inv(S)*t)|/||diag(D)||inf = |" << beta <<
"|/" << nrm_D_diag
372 <<
"MatrixSymAddDelBunchKaufman::augment_update(...): ";
373 if( correct_inertia && gamma <= use_pivot_tols.singular_tol ) {
375 <<
"Singular update!\n" << onum_msg.str() <<
" <= singular_tol = "
376 << use_pivot_tols.singular_tol;
377 throw SingularUpdateException( omsg.str(), gamma );
379 else if( !correct_inertia && gamma <= use_pivot_tols.singular_tol ) {
381 <<
"Singular update!\n" << onum_msg.str() <<
" <= wrong_inertia_tol = "
382 << use_pivot_tols.wrong_inertia_tol;
383 throw SingularUpdateException( omsg.str(), gamma );
386 else if( !correct_inertia ) {
388 <<
"Indefinite update!\n" << onum_msg.str() <<
" >= wrong_inertia_tol = "
389 << use_pivot_tols.wrong_inertia_tol;
390 throw WrongInertiaUpdateException( omsg.str(), gamma );
400 S_bar.row(n+1)(1,n) = *t;
402 S_bar.row(n+1)(1,n) = 0.0;
403 S_bar(n+1,n+1) = alpha;
408 if( force_refactorization ) {
410 bool fact_in1 =
false;
415 fact_in1 = !fact_in1_;
426 copy_and_factor_matrix(n+1,fact_in1);
429 std::ostringstream omsg;
431 <<
"MatrixSymAddDelBunchKaufman::augment_update(...): "
432 <<
"Error, singular update but the original matrix was be maintianed:\n"
434 throw SingularUpdateException( omsg.str(), -1.0 );
437 Inertia expected_inertia = this->
inertia();
438 if( expected_inertia.zero_eigens == Inertia::UNKNOWN || add_eigen_val == MSADU::EIGEN_VAL_UNKNOWN )
439 expected_inertia = Inertia();
440 else if( add_eigen_val == MSADU::EIGEN_VAL_NEG )
441 ++expected_inertia.neg_eigens;
442 else if( add_eigen_val == MSADU::EIGEN_VAL_POS )
443 ++expected_inertia.pos_eigens;
448 throw_exception = compute_assert_inertia(
449 n+1,fact_in1,expected_inertia,
"augment_update",pivot_tols
450 ,&inertia,&omsg,&gamma);
453 S_chol_.init_setup(NULL);
457 fact_updated_ =
true;
458 fact_in1_ = fact_in1;
466 inertia_ = S_chol_.inertia();
469 fact_updated_ =
false;
471 if( inertia_.zero_eigens == Inertia::UNKNOWN || add_eigen_val == MSADU::EIGEN_VAL_UNKNOWN )
472 inertia_ = Inertia();
473 else if( add_eigen_val == MSADU::EIGEN_VAL_NEG )
474 ++inertia_.neg_eigens;
475 else if( add_eigen_val == MSADU::EIGEN_VAL_POS )
476 ++inertia_.pos_eigens;
480 if( throw_exception )
481 throw WarnNearSingularUpdateException(omsg.str(),gamma);
486 ,
bool force_refactorization
487 ,EEigenValType drop_eigen_val
488 ,PivotTolerances pivot_tols
491 using BLAS_Cpp::upper;
492 using BLAS_Cpp::lower;
493 using DenseLinAlgPack::tri_ele;
494 using DenseLinAlgPack::nonconst_tri_ele;
495 typedef MatrixSymAddDelUpdateable MSADU;
497 assert_initialized();
499 if( jd < 1 || S_size_ < jd )
500 throw std::out_of_range(
501 "MatrixSymAddDelBunchKaufman::delete_update(jd,...): "
502 "Error, the indice jd must be 1 <= jd <= rows()" );
504 bool throw_exception =
false;
505 std::ostringstream omsg;
512 S_chol_.delete_update(jd,force_refactorization,drop_eigen_val,pivot_tols);
532 Inertia
inertia = S_chol_.inertia();
533 if( (drop_eigen_val == MSADU::EIGEN_VAL_POS && inertia.pos_eigens == 1 )
534 || (drop_eigen_val == MSADU::EIGEN_VAL_NEG && inertia.neg_eigens == 1 )
543 DMatrixSlice S = this->S(S_size_).gms();
544 DenseLinAlgPack::delete_row_col( jd, &DenseLinAlgPack::nonconst_tri_ele(S,BLAS_Cpp::lower) );
546 S_chol_.init_setup(&S_store1_(),Teuchos::null,0,
true,
true,
true,
false,0.0);
547 S_chol_.initialize( this->S(S_size_-1), S_store1_.rows()-1
548 , force_refactorization, Inertia(), PivotTolerances() );
550 catch(
const SingularUpdateException& excpt ) {
552 throw SingularUpdateException(
554 "MatrixSymAddDelBunchKaufman::delete_update(...) : "
555 "Error, the client incorrectly specified that the new "
556 "matrix would be nonsingular and not indefinite:\n" )
561 catch(
const WrongInertiaUpdateException& excpt ) {
563 throw WrongInertiaUpdateException(
565 "MatrixSymAddDelBunchKaufman::delete_update(...) : "
566 "Error, the client incorrectly specified that the new "
567 "matrix would not be indefinite:\n" )
581 DMatrixSlice S = this->S(S_size_).gms();
582 if( force_refactorization ) {
586 const bool fact_in1 = !fact_in1_;
588 DMatrixSliceTriEle DU = this->DU(S_size_,fact_in1);
591 DenseLinAlgPack::delete_row_col( jd, &DU );
594 factor_matrix(S_size_-1,fact_in1);
598 <<
"MatrixSymAddDelBunchKaufman::delete_update(...): "
599 <<
"Error, singular update but the original matrix was maintianed:\n"
601 throw SingularUpdateException( omsg.str(), -1.0 );
604 Inertia expected_inertia = this->
inertia();
605 if( expected_inertia.zero_eigens == Inertia::UNKNOWN || drop_eigen_val == MSADU::EIGEN_VAL_UNKNOWN )
606 expected_inertia = Inertia();
607 else if( drop_eigen_val == MSADU::EIGEN_VAL_NEG )
608 --expected_inertia.neg_eigens;
609 else if( drop_eigen_val == MSADU::EIGEN_VAL_POS )
610 --expected_inertia.pos_eigens;
615 throw_exception = compute_assert_inertia(
616 S_size_-1,fact_in1,expected_inertia,
"delete_update",pivot_tols
617 ,&inertia,&omsg,&gamma);
621 fact_updated_ =
true;
622 fact_in1_ = fact_in1;
626 DenseLinAlgPack::delete_row_col( jd, &nonconst_tri_ele(S,lower) );
627 if( !force_refactorization ) {
633 fact_updated_ =
false;
635 if( inertia_.zero_eigens == Inertia::UNKNOWN || drop_eigen_val == MSADU::EIGEN_VAL_UNKNOWN )
636 inertia_ = Inertia();
637 else if( drop_eigen_val == MSADU::EIGEN_VAL_NEG )
638 --inertia_.neg_eigens;
639 else if( drop_eigen_val == MSADU::EIGEN_VAL_POS )
640 --inertia_.pos_eigens;
646 if( throw_exception )
647 throw WarnNearSingularUpdateException(omsg.str(),gamma);
660 out <<
"Unfactored symmetric matrix stored as lower triangle (ignore upper nonzeros):\n"
663 out <<
"Upper symmetric indefinite factor DU returned from sytrf(...) (ignore lower nonzeros):\n"
664 << DU(S_size_,fact_in1_).gms();
665 out <<
"Permutation array IPIV returned from sytrf(...):\n";
667 out <<
" " << IPIV_[i];
671 out <<
"Upper cholesky factor (ignore lower nonzeros):\n" << DU(S_size_,
true).gms();
682 ,
const DVectorSlice& x, value_type b
685 DenseLinAlgPack::Vp_MtV_assert_sizes( y->dim(), S_size_, S_size_, M_trans, x.dim() );
692 ,
const DVectorSlice& x
696 DenseLinAlgPack::Vp_MtV_assert_sizes( y->dim(), n, n, M_trans, x.dim() );
700 const bool fact_in1 =
true;
703 nc_this->copy_and_factor_matrix(S_size_,fact_in1);
704 nc_this->fact_updated_ =
true;
705 nc_this->fact_in1_ = fact_in1;
708 DenseLinAlgLAPack::sytrs(
709 DU(S_size_,fact_in1_), &const_cast<IPIV_t&>(IPIV_)[0]
710 , &DMatrixSlice(y->raw_ptr(),n,n,n,1), &WORK_() );
719 void MatrixSymAddDelBunchKaufman::assert_initialized()
const
722 throw std::logic_error(
723 "MatrixSymAddDelBunchKaufman::assert_initialized() : "
724 "Error, this matrix is not initialized yet" );
727 void MatrixSymAddDelBunchKaufman::resize_DU_store(
bool in_store1 )
729 if(!in_store1 && S_store2_.rows() < S_store1_.rows() )
730 S_store2_.resize( S_store1_.rows(), S_store1_.cols() );
733 void MatrixSymAddDelBunchKaufman::copy_and_factor_matrix(
738 , DenseLinAlgPack::tri_ele(S(S_size).gms(),BLAS_Cpp::lower) );
739 factor_matrix(S_size,fact_in1);
742 void MatrixSymAddDelBunchKaufman::factor_matrix(
size_type S_size,
bool fact_in1 )
746 if( WORK_.dim() < S_store1_.rows() * opt_block_size )
747 WORK_.resize(S_store1_.rows()*opt_block_size);
748 if( IPIV_.size() < S_store1_.rows() )
749 IPIV_.resize(S_store1_.rows());
751 DenseLinAlgLAPack::sytrf( &DU(S_size,fact_in1), &IPIV_[0], &WORK_() );
754 bool MatrixSymAddDelBunchKaufman::compute_assert_inertia(
755 size_type S_size,
bool fact_in1,
const Inertia& exp_inertia,
const char func_name[]
756 ,PivotTolerances pivot_tols, Inertia* comp_inertia, std::ostringstream* omsg, value_type* gamma )
758 bool throw_exception =
false;
762 const DMatrixSlice DU = this->DU(S_size,fact_in1).gms();
765 value_type max_diag = 0.0;
766 value_type min_diag = std::numeric_limits<value_type>::max();
768 const FortranTypes::f_int k_p = IPIV_[k-1];
772 const value_type D_k_k = DU(k,k), abs_D_k_k = std::fabs(D_k_k);
777 if(abs_D_k_k > max_diag) max_diag = abs_D_k_k;
778 if(abs_D_k_k < min_diag) min_diag = abs_D_k_k;
791 a = DU(k,k), b = DU(k,k+1), c = DU(k+1,k+1),
792 abs_a = std::fabs(a), abs_b = std::fabs(b);
793 value_type pivot_1, pivot_2;
794 if( abs_a > abs_b ) {
796 pivot_2 = std::fabs(c - b*b/a);
800 pivot_2 = std::fabs(b - a*c/b);
802 if(pivot_1 > max_diag) max_diag = pivot_1;
803 if(pivot_1 < min_diag) min_diag = pivot_1;
804 if(pivot_2 > max_diag) max_diag = pivot_2;
805 if(pivot_2 < min_diag) min_diag = pivot_2;
810 *gamma = min_diag / max_diag;
814 ( exp_inertia.neg_eigens != Inertia::UNKNOWN
815 && exp_inertia.neg_eigens !=
inertia.neg_eigens )
816 || ( exp_inertia.pos_eigens != Inertia::UNKNOWN
817 && exp_inertia.pos_eigens !=
inertia.pos_eigens ) ;
818 PivotTolerances use_pivot_tols = S_chol_.pivot_tols();
819 if( pivot_tols.warning_tol != PivotTolerances::UNKNOWN )
820 use_pivot_tols.warning_tol = pivot_tols.warning_tol;
821 if( pivot_tols.singular_tol != PivotTolerances::UNKNOWN )
822 use_pivot_tols.singular_tol = pivot_tols.singular_tol;
823 if( pivot_tols.wrong_inertia_tol != PivotTolerances::UNKNOWN )
824 use_pivot_tols.wrong_inertia_tol = pivot_tols.wrong_inertia_tol;
827 || !wrong_inertia && *gamma <= use_pivot_tols.warning_tol
828 || !wrong_inertia && *gamma <= use_pivot_tols.singular_tol
832 std::ostringstream onum_msg;
833 if(throw_exception) {
838 <<
") != expected_inertia = ("
839 << exp_inertia.neg_eigens <<
"," << exp_inertia.zero_eigens <<
"," << exp_inertia.pos_eigens <<
")"
843 <<
"gamma = min(|diag(D)(k)|)/max(|diag(D)(k)|) = " << min_diag <<
"/" << max_diag
846 <<
"MatrixSymAddDelBunchKaufman::"<<func_name<<
"(...): ";
847 if( *gamma == 0.0 || (!wrong_inertia && *gamma <= use_pivot_tols.singular_tol) ) {
849 <<
"Singular update!\n" << onum_msg.str() <<
" <= singular_tol = "
850 << use_pivot_tols.singular_tol;
851 throw SingularUpdateException( omsg->str(), *gamma );
853 else if( wrong_inertia && *gamma <= use_pivot_tols.singular_tol ) {
855 <<
"Singular update!\n" << onum_msg.str() <<
" <= wrong_inertia_tol = "
856 << use_pivot_tols.wrong_inertia_tol;
857 throw SingularUpdateException( omsg->str(), *gamma );
859 else if( wrong_inertia ) {
861 <<
"Indefinite update!\n" << onum_msg.str() <<
" >= wrong_inertia_tol = "
862 << use_pivot_tols.wrong_inertia_tol;
863 throw WrongInertiaUpdateException( omsg->str(), *gamma );
865 else if( !wrong_inertia && *gamma <= use_pivot_tols.warning_tol ) {
867 <<
"Warning, near singular update!\nsingular_tol = " << use_pivot_tols.singular_tol
868 <<
" < " << onum_msg.str() <<
" <= warning_tol = "
869 << use_pivot_tols.warning_tol;
878 return throw_exception;
void Vp_StMtV(DVectorSlice *vs_lhs, value_type alpha, BLAS_Cpp::Transp trans_rhs1, const DVectorSlice &vs_rhs2, value_type beta) const
value_type transVtInvMtV(const Vector &v_rhs1, const MatrixNonsing &M_rhs2, BLAS_Cpp::Transp trans_rhs2, const Vector &v_rhs3)
void initialize(value_type alpha, size_type max_size)
MatrixSymAddDelUpdateable & update_interface()
std::ostream & output(std::ostream &out) const
TypeTo & implicit_ref_cast(TypeFrom &t)
PivotTolerances pivot_tols() const
This class maintains the factorization of symmetric indefinite matrix using a Bunch & Kaufman factori...
void assign(MatrixOp *M_lhs, const MatrixOp &M_rhs, BLAS_Cpp::Transp trans_rhs)
const MatrixSymOpNonsing & op_interface() const
void augment_update(const DVectorSlice *t, value_type alpha, bool force_refactorization, EEigenValType add_eigen_val, PivotTolerances pivot_tols)
void V_InvMtV(VectorMutable *v_lhs, const MatrixNonsing &M_rhs1, BLAS_Cpp::Transp trans_rhs1, const Vector &v_rhs2)
void Vp_StMtV(VectorMutable *v_lhs, value_type alpha, const MatrixOp &M_rhs1, BLAS_Cpp::Transp trans_rhs1, const Vector &v_rhs2, value_type beta=1.0)
size_type max_size() const
MatrixSymAddDelBunchKaufman()
Initializes with 0x0 and pivot_tols == (0.0,0.0,0.0).
void delete_update(size_type jd, bool force_refactorization, EEigenValType drop_eigen_val, PivotTolerances pivot_tols)
void V_InvMtV(DVectorSlice *vs_lhs, BLAS_Cpp::Transp trans_rhs1, const DVectorSlice &vs_rhs2) const
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)