54 namespace ConstrainedOptPack {
57 : S_size_(0), S_indef_(false), fact_updated_(false), fact_in1_(true), inertia_(0,0,0)
101 S_chol_.initialize(alpha,max_size);
115 ,
bool force_factorization
116 ,Inertia expected_inertia
117 ,PivotTolerances pivot_tols
124 typedef MatrixSymAddDelUpdateable MSADU;
125 typedef MSADU::Inertia Inertia;
127 bool throw_exception =
false;
128 std::ostringstream omsg;
136 || expected_inertia.zero_eigens == 0 ) );
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 ) {
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;
178 <<
"MatrixSymAddDelBunchKaufman::initialize(...): "
179 <<
"Error, the matrix A is singular:\n"
181 throw SingularUpdateException( omsg.str(), -1.0 );
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() ) );
212 if( throw_exception )
213 throw WarnNearSingularUpdateException(omsg.str(),gamma);
221 MatrixSymAddDelUpdateable::Inertia
235 ,
bool force_refactorization
236 ,EEigenValType add_eigen_val
237 ,PivotTolerances pivot_tols
244 typedef MatrixSymAddDelUpdateable MSADU;
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;
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);
343 abs_beta = std::fabs(beta),
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;
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;
449 n+1,fact_in1,expected_inertia,
"augment_update",pivot_tols
450 ,&inertia,&omsg,&gamma);
471 if(
inertia_.zero_eigens == Inertia::UNKNOWN || add_eigen_val == MSADU::EIGEN_VAL_UNKNOWN )
473 else if( add_eigen_val == MSADU::EIGEN_VAL_NEG )
475 else if( add_eigen_val == MSADU::EIGEN_VAL_POS )
480 if( throw_exception )
481 throw WarnNearSingularUpdateException(omsg.str(),gamma);
486 ,
bool force_refactorization
487 ,EEigenValType drop_eigen_val
488 ,PivotTolerances pivot_tols
495 typedef MatrixSymAddDelUpdateable MSADU;
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);
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 )
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" )
582 if( force_refactorization ) {
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;
616 S_size_-1,fact_in1,expected_inertia,
"delete_update",pivot_tols
617 ,&inertia,&omsg,&gamma);
627 if( !force_refactorization ) {
635 if(
inertia_.zero_eigens == Inertia::UNKNOWN || drop_eigen_val == MSADU::EIGEN_VAL_UNKNOWN )
637 else if( drop_eigen_val == MSADU::EIGEN_VAL_NEG )
639 else if( drop_eigen_val == MSADU::EIGEN_VAL_POS )
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"
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();
700 const bool fact_in1 =
true;
722 throw std::logic_error(
723 "MatrixSymAddDelBunchKaufman::assert_initialized() : "
724 "Error, this matrix is not initialized yet" );
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;
772 const value_type D_k_k =
DU(k,k), abs_D_k_k = std::fabs(D_k_k);
774 ++inertia.pos_eigens;
776 ++inertia.neg_eigens;
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;
786 ++inertia.pos_eigens;
787 ++inertia.neg_eigens;
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);
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) {
837 << inertia.neg_eigens <<
"," << inertia.zero_eigens <<
"," << inertia.pos_eigens
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
AbstractLinAlgPack::size_type size_type
value_type transVtInvMtV(const Vector &v_rhs1, const MatrixNonsing &M_rhs2, BLAS_Cpp::Transp trans_rhs2, const Vector &v_rhs3)
result = v_rhs1' * inv(op(M_rhs2)) * v_rhs3
void initialize(value_type alpha, size_type max_size)
FortranTypes::f_int f_int
void sytrf(DMatrixSliceTriEle *A, FortranTypes::f_int ipiv[], DVectorSlice *work)
Calls xSYTRF to compute the P*A*P' = L'*D*L factorization of a symmetric possibly indefinite matrix...
MatrixSymPosDefCholFactor S_chol_
void assign(DMatrix *gm_lhs, value_type alpha)
gm_lhs = alpha (elementwise)
MatrixSymAddDelUpdateable & update_interface()
Exception for factorization error.
std::ostream & output(std::ostream &out) const
const DMatrixSliceTriEle tri_ele(const DMatrixSlice &gms, BLAS_Cpp::Uplo uplo)
void factor_matrix(size_type S_size, bool fact_in1)
Factor the current set matrix in-place (do not copy the original).
PivotTolerances pivot_tols() const
int resize(OrdinalType length_in)
DMatrixSliceSym S(size_type S_size)
Get view of lower part of S.
TypeTo & implicit_ref_cast(TypeFrom &t)
This class maintains the factorization of symmetric indefinite matrix using a Bunch & Kaufman factori...
const MatrixSymOpNonsing & op_interface() const
void copy_and_factor_matrix(size_type S_size, bool fact_in1)
Copy the original matrix into the new storage location and factorize it.
DenseLinAlgPack::DMatrixSliceTriEle DMatrixSliceTriEle
void augment_update(const DVectorSlice *t, value_type alpha, bool force_refactorization, EEigenValType add_eigen_val, PivotTolerances pivot_tols)
void assert_initialized() const
void V_InvMtV(VectorMutable *v_lhs, const MatrixNonsing &M_rhs1, BLAS_Cpp::Transp trans_rhs1, const Vector &v_rhs2)
v_lhs = inv(op(M_rhs1)) * v_rhs2
value_type norm_inf(const SparseVectorSlice< T_Ele > &sv_rhs)
result = ||sv_rhs||inf (BLAS IxAMAX)
size_type max_size() const
DMatrixSliceTriEle nonconst_tri_ele(DMatrixSlice gms, BLAS_Cpp::Uplo uplo)
Return a triangular element-wise matrix.
const f_int f_dbl_prec a[]
MatrixSymAddDelBunchKaufman()
Initializes with 0x0 and pivot_tols == (0.0,0.0,0.0).
MatrixSymAddDelUpdateable::Inertia inertia_
DenseLinAlgPack::VectorSliceTmpl< value_type > DVectorSlice
void resize_DU_store(bool in_store1)
AbstractLinAlgPack::value_type value_type
void Vp_MtV_assert_sizes(size_type v_lhs_size, size_type m_rhs1_rows, size_type m_rhs1_cols, BLAS_Cpp::Transp trans_rhs1, size_type v_rhs2_size)
v_lhs += op(m_rhs1) * v_rhs2
void Vp_StMtV(DVectorSlice *vs_lhs, value_type alpha, const DMatrixSlice &gms_rhs1, BLAS_Cpp::Transp trans_rhs1, const DVectorSlice &vs_rhs2, value_type beta=1.0)
vs_lhs = alpha * op(gms_rhs1) * vs_rhs2 + beta * vs_lhs (BLAS xGEMV)
bool compute_assert_inertia(size_type S_size, bool fact_in1, const Inertia &expected_inertia, const char func_name[], PivotTolerances pivot_tols, Inertia *comp_inertia, std::ostringstream *err_msg, value_type *gamma)
Compute the new inertia and validate that it is what the client says it was.
value_type norm_inf(const DVectorSlice &vs_rhs)
result = ||vs_rhs||infinity (BLAS IxAMAX)
void delete_row_col(size_type kd, DMatrixSliceTriEle *M)
DenseLinAlgPack::DMatrixSlice DMatrixSlice
DenseLinAlgPack::DMatrixSliceSym DMatrixSliceSym
void sytrs(const DMatrixSliceTriEle &A, FortranTypes::f_int ipiv[], DMatrixSlice *B, DVectorSlice *work)
Calls xSYTRS(...) to compute the solution of the factorized system A * X = B where A was factorized b...
void delete_update(size_type jd, bool force_refactorization, EEigenValType drop_eigen_val, PivotTolerances pivot_tols)
DMatrixSliceTriEle DU(size_type S_size, bool fact_in1)
Get view of DU.
void V_InvMtV(DVectorSlice *vs_lhs, BLAS_Cpp::Transp trans_rhs1, const DVectorSlice &vs_rhs2) const
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)