bool MoochoPack::CrossTermExactStd_Step::do_step(Algorithm& _algo , poss_type step_poss, IterationPack::EDoStepType type, poss_type assoc_step_poss) { using LinAlgOpPack::V_MtV; using DenseLinAlgPack::norm_inf; NLPAlgo &algo = rsqp_algo(_algo); NLPAlgoState &s = algo.rsqp_state(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); std::ostream& out = algo.track().journal_out(); // print step header. if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( _algo, step_poss, type, assoc_step_poss, out ); } // tmp = HL * Ypy DVector tmp; V_MtV( &tmp, s.HL().get_k(0), BLAS_Cpp::no_trans, s.Ypy().get_k(0)() ); // w = Z' * tmp V_MtV( &s.w().set_k(0).v(), s.Z().get_k(0), BLAS_Cpp::trans, tmp() ); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n||w||inf = " << s.w().get_k(0).norm_inf() << std::endl; } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nw_k =\n" << s.w().get_k(0)(); } return true; }
const MatrixOp::MatNorm MatrixOpNonsing::calc_cond_num( EMatNormType requested_norm_type ,bool allow_replacement ) const { using BLAS_Cpp::no_trans; using BLAS_Cpp::trans; using LinAlgOpPack::V_InvMtV; const VectorSpace &space_cols = this->space_cols(), &space_rows = this->space_rows(); const index_type num_cols = space_rows.dim(); TEST_FOR_EXCEPTION( !(requested_norm_type == MAT_NORM_1 || requested_norm_type == MAT_NORM_INF), MethodNotImplemented ,"MatrixOp::calc_norm(...): Error, This default implemenation can only " "compute the one norm or the infinity norm!" ); // // Here we implement Algorithm 2.5 in "Applied Numerical Linear Algebra", Demmel (1997) // using the momenclature in the text. This is applied to the inverse matrix. // const MatrixOpNonsing &B = *this; bool do_trans = requested_norm_type == MAT_NORM_INF; VectorSpace::vec_mut_ptr_t x = (do_trans ? space_rows : space_cols).create_member(1.0/num_cols), w = (do_trans ? space_cols : space_rows).create_member(), zeta = (do_trans ? space_cols : space_rows).create_member(), z = (do_trans ? space_rows : space_cols).create_member(); const index_type max_iter = 5; // Recommended by Highman 1988, (see Demmel's reference) value_type w_nrm = 0.0; for( index_type k = 0; k <= max_iter; ++k ) { V_InvMtV( w.get(), B, !do_trans ? no_trans : trans, *x ); // w = B*x sign( *w, zeta.get() ); // zeta = sign(w) V_InvMtV( z.get(), B, !do_trans ? trans : no_trans, *zeta ); // z = B'*zeta value_type z_j = 0.0; // max |z(j)| = ||z||inf index_type j = 0; max_abs_ele( *z, &z_j, &j ); const value_type zTx = dot(*z,*x); // z'*x w_nrm = w->norm_1(); // ||w||1 if( ::fabs(z_j) <= zTx ) { // Update break; } else { *x = 0.0; x->set_ele(j,1.0); } } const MatNorm M_nrm = this->calc_norm(requested_norm_type); return MatNorm( w_nrm * M_nrm.value ,requested_norm_type ); }
bool CheckDescentQuasiNormalStep_Step::do_step( Algorithm& _algo, poss_type step_poss, IterationPack::EDoStepType type ,poss_type assoc_step_poss ) { using BLAS_Cpp::no_trans; using AbstractLinAlgPack::dot; using LinAlgOpPack::V_MtV; NLPAlgo &algo = rsqp_algo(_algo); NLPAlgoState &s = algo.rsqp_state(); NLP &nlp = algo.nlp(); const Range1D equ_decomp = s.equ_decomp(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); std::ostream& out = algo.track().journal_out(); // print step header. if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( algo, step_poss, type, assoc_step_poss, out ); } const size_type nb = nlp.num_bounded_x(); // Get iteration quantities IterQuantityAccess<VectorMutable> &c_iq = s.c(), &Ypy_iq = s.Ypy(); const Vector::vec_ptr_t cd_k = c_iq.get_k(0).sub_view(equ_decomp); const Vector &Ypy_k = Ypy_iq.get_k(0); value_type descent_c = -1.0; if( s.get_iter_quant_id( Gc_name ) != AlgorithmState::DOES_NOT_EXIST ) { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nGc_k exists; compute descent_c = c_k(equ_decomp)'*Gc_k(:,equ_decomp)'*Ypy_k ...\n"; } const MatrixOp::mat_ptr_t Gcd_k = s.Gc().get_k(0).sub_view(Range1D(),equ_decomp); VectorSpace::vec_mut_ptr_t t = cd_k->space().create_member(); V_MtV( t.get(), *Gcd_k, BLAS_Cpp::trans, Ypy_k ); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nGc_k(:,equ_decomp)'*Ypy_k =\n" << *t; } descent_c = dot( *cd_k, *t ); } else { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nGc_k does not exist; compute descent_c = c_k(equ_decomp)'*FDGc_k(:,equ_decomp)'*Ypy_k " << "using finite differences ...\n"; } VectorSpace::vec_mut_ptr_t t = nlp.space_c()->create_member(); calc_fd_prod().calc_deriv_product( s.x().get_k(0),nb?&nlp.xl():NULL,nb?&nlp.xu():NULL ,Ypy_k,NULL,&c_iq.get_k(0),true,&nlp ,NULL,t.get() ,static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ? &out : NULL ); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nFDGc_k(:,equ_decomp)'*Ypy_k =\n" << *t->sub_view(equ_decomp); } descent_c = dot( *cd_k, *t->sub_view(equ_decomp) ); } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\ndescent_c = " << descent_c << std::endl; } if( descent_c > 0.0 ) { // ToDo: add some allowance for > 0.0 for finite difference errors! if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nError, descent_c > 0.0; this is not a descent direction\n" << "Throw TestFailed and terminate the algorithm ...\n"; } TEST_FOR_EXCEPTION( true, TestFailed ,"CheckDescentQuasiNormalStep_Step::do_step(...) : Error, descent for the decomposed constraints " "with respect to the quasi-normal step c_k(equ_decomp)'*FDGc_k(:,equ_decomp)'*Ypy_k = " << descent_c << " > 0.0; This is not a descent direction!\n" ); } return true; }
void NLPDakota::imp_calc_point( ERequiredFunc required ,const DVectorSlice &x_full ,bool newx ,const ZeroOrderInfoSerial *zero_order_info ,const ObjGradInfoSerial *obj_grad_info ,const FirstOrderExplInfo *first_order_expl_info ) const { using LinAlgOpPack::Vp_StV; typedef FirstOrderExplInfo::val_t G_val_t; typedef FirstOrderExplInfo::ivect_t G_ivect_t; typedef FirstOrderExplInfo::jvect_t G_jvect_t; Cout << "\nEntering NLPDakota::imp_calc_point(...) ...\n"; // throw std::logic_error("NLPDakota::imp_calc_point(): End, dam it!"); if( newx ) { f_orig_updated_ = false; c_orig_updated_ = false; h_orig_updated_ = false; Gf_orig_updated_ = false; Gc_orig_updated_ = false; Gh_orig_updated_ = false; my_vec_view(dakota_functions_) = 0.0; } const DVectorSlice x_orig = x_full(1,n_orig_); // // Determine which quantities to compute // const bool calc_f = ( required==CALC_F || multi_calc_ ) && !f_orig_updated_; const bool calc_c = ( required==CALC_C || multi_calc_ ) && !c_orig_updated_; const bool calc_h = ( required==CALC_H || multi_calc_ ) && !h_orig_updated_; const bool calc_Gf = ( required==CALC_GF || ( (int)required >= (int)CALC_GF && multi_calc_ ) ) && !Gf_orig_updated_; const bool calc_Gc = ( required==CALC_GC || ( (int)required >= (int)CALC_GF && multi_calc_ ) ) && !Gc_orig_updated_; const bool calc_Gh = ( required==CALC_GH || ( (int)required >= (int)CALC_GF && multi_calc_ ) ) && !Gh_orig_updated_; if( !calc_f && !calc_c && !calc_h && !calc_Gf && !calc_Gc && !calc_Gh ) return; // Everything is already computed at this point! value_type *f = NULL; DVector *c = NULL; DVector *h = NULL; DVector *Gf = NULL; G_val_t *Gc_val = NULL; G_ivect_t *Gc_ivect = NULL; G_jvect_t *Gc_jvect = NULL; G_val_t *Gh_val = NULL; G_ivect_t *Gh_ivect = NULL; G_jvect_t *Gh_jvect = NULL; if(zero_order_info) { if(calc_f) f = zero_order_info->f; if(calc_c) c = zero_order_info->c; if(calc_h) h = zero_order_info->h; } else if(obj_grad_info) { if(calc_f) f = obj_grad_info->f; if(calc_c) c = obj_grad_info->c; if(calc_h) h = obj_grad_info->h; if(calc_Gf) Gf = obj_grad_info->Gf; } else if(first_order_expl_info) { if(calc_f) f = first_order_expl_info->f; if(calc_c) c = first_order_expl_info->c; if(calc_h) h = first_order_expl_info->h; if(calc_Gf) Gf = first_order_expl_info->Gf; if(calc_Gc) { Gc_val = first_order_expl_info->Gc_val; Gc_ivect = first_order_expl_info->Gc_ivect; Gc_jvect = first_order_expl_info->Gc_jvect; } if(calc_Gh) { Gh_val = first_order_expl_info->Gh_val; Gh_ivect = first_order_expl_info->Gh_ivect; Gh_jvect = first_order_expl_info->Gh_jvect; } } else { THROW_EXCEPTION( !(zero_order_info || obj_grad_info || first_order_expl_info), std::logic_error ,"NLPDakota::imp_calc_point(): Error!" ); } // // Set the Dakota active-set vector. // // Dakota sorts the responce functions as general inequalities first // and general equalities second. // std::fill_n( &dakota_asv_[0], dakota_asv_.length(), 0 ); const int num_obj_funcs = multi_obj_weights_.length(); if( calc_f || calc_Gf ) { std::fill_n( &dakota_asv_[0], num_obj_funcs ,(calc_f ? 1 : 0) + (calc_Gf ? 2 : 0) ); } if( ( calc_c || calc_Gc ) && num_nonlin_eq_ ) { std::fill_n( &dakota_asv_[num_obj_funcs + num_nonlin_ineq_], num_nonlin_eq_ ,(calc_c ? 1 : 0) + (calc_Gc ? 2 : 0) ); } if( ( calc_h || calc_Gh ) && num_nonlin_ineq_ ) { std::fill_n( &dakota_asv_[num_obj_funcs], num_nonlin_ineq_ ,(calc_h ? 1 : 0) + (calc_Gh ? 2 : 0) ); } // // Compute the nonlinear functions // my_vec_view(dakota_x_) = x_orig; model_->continuous_variables(dakota_x_); model_->compute_response(dakota_asv_); const Dakota::Response& local_response = model_->current_response(); const Dakota::RealVector& local_function_values = local_response.function_values(); const Dakota::RealMatrix& local_function_gradients = local_response.function_gradients(); // Look for failed response const bool eval_failed = (local_function_values[0] == dakota_failed_value_); // // Map to the NLP objects // if(!eval_failed) { // // The evaluation succeeded so copy the values // // f, Gf if(calc_f) *f = 0.0; if(calc_Gf) *Gf = 0.0; for( int i = 0; i < num_obj_funcs; ++i ) { if(calc_f) { *f += multi_obj_weights_[i] * local_function_values[i]; dakota_functions_[i] = local_function_values[i]; // Save in dakota_functions } if(calc_Gf) { Vp_StV( &(*Gf)(1,n_orig_), multi_obj_weights_[i] ,DVectorSlice(&const_cast<Dakota::RealMatrix&>(local_function_gradients)[i][0],n_orig_) ); } } if(calc_Gf && Gf->dim() > n_orig_ ) (*Gf)(n_orig_+1,Gf->dim()) = 0.0; // Zero for slack variables // c = [ A_lin_eq' * x - lin_eq_targ ] // [ response(num_obj_funcs+num_nonlin_ineq+1:num_obj_funs+num_nonlin_ineq+num_nonlin_eq) - nonlin_eq_targ ] if( calc_c ) { if( num_lin_eq_ ) { DVectorSlice c_lin = (*c)(1,num_lin_eq_); V_mV( &c_lin, my_vec_view(dakota_rsqp_opt_->lin_eq_targ()) ); const Dakota::RealMatrix &lin_eq_jac = dakota_rsqp_opt_->lin_eq_jac(); for( int j = 0; j < num_lin_eq_; ++j ) { for( int i = 0; i < n_orig_; ++i ) { c_lin[j] += lin_eq_jac[j][i] * x_orig[i]; } } } if( num_nonlin_eq_ ) { const value_type *nonlin_eq_ptr = &const_cast<Dakota::RealVector&>(local_function_values)[num_obj_funcs+num_nonlin_ineq_]; V_VmV( &(*c)(num_lin_eq_+1,num_lin_eq_+num_nonlin_eq_) ,DVectorSlice(const_cast<value_type*>(nonlin_eq_ptr),num_nonlin_eq_) ,my_vec_view(dakota_rsqp_opt_->nonlin_eq_targ()) ); // Save in dakota_functions std::copy( nonlin_eq_ptr, nonlin_eq_ptr + num_nonlin_eq_, &dakota_functions_[num_obj_funcs+num_nonlin_ineq_] ); } } // h = [ A_lin_ineq' * x ] // [ response(num_obj_funcs+1:num_obj_funs+num_lin_eq) ] if( calc_h ) { // if( num_lin_ineq_ ) { DVectorSlice h_lin = (*h)(1,num_lin_ineq_); const Dakota::RealMatrix &lin_ineq_jac = dakota_rsqp_opt_->lin_ineq_jac(); for( int j = 0; j < num_lin_ineq_; ++j ) { for( int i = 0; i < n_orig_; ++i ) { h_lin[j] += lin_ineq_jac[j][i] * x_orig[i]; } } } // if( num_nonlin_ineq_ ) { const value_type *nonlin_ineq_ptr = &const_cast<Dakota::RealVector&>(local_function_values)[num_obj_funcs]; (*h)(num_lin_ineq_+1,num_lin_ineq_+num_nonlin_ineq_) = DVectorSlice(const_cast<value_type*>(nonlin_ineq_ptr),num_nonlin_ineq_); // Save in dakota_functions std::copy( nonlin_ineq_ptr, nonlin_ineq_ptr + num_nonlin_ineq_, &dakota_functions_[num_obj_funcs] ); } } // Gc = [ A_lin_eq' ] // [ response.grad[num_nonlin_ineq+1]' ] // [ .. ] // [ response.grad[num_nonlin_ineq+num_nonlin_eq]' ] if( calc_Gc ) { index_type nz = 0; if( num_lin_eq_ ) { const Dakota::RealMatrix &lin_eq_jac = dakota_rsqp_opt_->lin_eq_jac(); for( int j = 1; j <= num_lin_eq_; ++j ) { for( int i = 1; i <= n_orig_; ++i ) { (*Gc_val)[nz] = lin_eq_jac[j-1][i-1]; (*Gc_ivect)[nz] = i; (*Gc_jvect)[nz] = j; ++nz; } } } if( num_nonlin_eq_ ) { for( int j = 1; j <= num_nonlin_eq_; ++j ) { for( int i = 1; i <= n_orig_; ++i ) { (*Gc_val)[nz] = local_function_gradients[num_obj_funcs+num_nonlin_ineq_+j-1][i-1]; (*Gc_ivect)[nz] = i; (*Gc_jvect)[nz] = j + num_lin_eq_; ++nz; } } } } // Gh = [ A_lin_ineq' ] // [ response.grad[1]' ] // [ .. ] // [ response.grad[num_nonlin_eq]' ] if( calc_Gh ) { index_type nz = 0; if( num_lin_ineq_ ) { const Dakota::RealMatrix &lin_ineq_jac = dakota_rsqp_opt_->lin_ineq_jac(); for( int j = 1; j <= num_lin_ineq_; ++j ) { for( int i = 1; i <= n_orig_; ++i ) { (*Gh_val)[nz] = lin_ineq_jac[j-1][i-1]; (*Gh_ivect)[nz] = i; (*Gh_jvect)[nz] = j; ++nz; } } } if( num_nonlin_ineq_ ) { for( int j = 1; j <= num_nonlin_ineq_; ++j ) { for( int i = 1; i <= n_orig_; ++i ) { (*Gh_val)[nz] = local_function_gradients[num_obj_funcs+j-1][i-1]; (*Gh_ivect)[nz] = i; (*Gh_jvect)[nz] = j; ++nz; } } } } } else { // // The evaluation failed so just fill everything with // and invalid number that will trigger a back tracking // // f, Gf if(calc_f) *f = invalid_func_value_; if(calc_Gf) *Gf = invalid_func_value_; // c if(calc_c) *c = invalid_func_value_; // h if(calc_h) *h = invalid_func_value_; // Gc if(calc_Gc) { index_type nz = 0; for( int j = 1; j <= m_orig_; ++j ) { for( int i = 1; i <= n_orig_; ++i ) { (*Gc_val)[nz] = invalid_func_value_; (*Gc_ivect)[nz] = i; (*Gc_jvect)[nz] = j; ++nz; } } } // Gh if( calc_Gh ) { index_type nz = 0; for( int j = 1; j <= mI_orig_; ++j ) { for( int i = 1; i <= n_orig_; ++i ) { (*Gh_val)[nz] = invalid_func_value_; (*Gh_ivect)[nz] = i; (*Gh_jvect)[nz] = j; ++nz; } } } } if(calc_f) f_orig_updated_ = true; if(calc_c) c_orig_updated_ = true; if(calc_h) h_orig_updated_ = true; if(calc_Gf) Gf_orig_updated_ = true; if(calc_Gc) Gc_orig_updated_ = true; if(calc_Gh) Gh_orig_updated_ = true; }
bool TangentialStepIP_Step::do_step( Algorithm& _algo, poss_type step_poss, IterationPack::EDoStepType type ,poss_type assoc_step_poss ) { using BLAS_Cpp::no_trans; using Teuchos::dyn_cast; using AbstractLinAlgPack::assert_print_nan_inf; using LinAlgOpPack::Vt_S; using LinAlgOpPack::Vp_StV; using LinAlgOpPack::V_StV; using LinAlgOpPack::V_MtV; using LinAlgOpPack::V_InvMtV; using LinAlgOpPack::M_StM; using LinAlgOpPack::Mp_StM; using LinAlgOpPack::assign; NLPAlgo &algo = rsqp_algo(_algo); IpState &s = dyn_cast<IpState>(_algo.state()); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); std::ostream& out = algo.track().journal_out(); // print step header. if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( algo, step_poss, type, assoc_step_poss, out ); } // Compute qp_grad which is an approximation to rGf + Z'*(mu*(invXu*e-invXl*e) + no_cross_term // minimize round off error by calc'ing Z'*(Gf + mu*(invXu*e-invXl*e)) // qp_grad_k = Z'*(Gf + mu*(invXu*e-invXl*e)) const MatrixSymDiagStd &invXu = s.invXu().get_k(0); const MatrixSymDiagStd &invXl = s.invXl().get_k(0); const value_type &mu = s.barrier_parameter().get_k(0); const MatrixOp &Z_k = s.Z().get_k(0); Teuchos::RCP<VectorMutable> rhs = s.Gf().get_k(0).clone(); Vp_StV( rhs.get(), mu, invXu.diag() ); Vp_StV( rhs.get(), -1.0*mu, invXl.diag() ); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\n||Gf_k + mu_k*(invXu_k-invXl_k)||inf = " << rhs->norm_inf() << std::endl; } if( (int)olevel >= (int)PRINT_VECTORS) { out << "\nGf_k + mu_k*(invXu_k-invXl_k) =\n" << *rhs; } VectorMutable &qp_grad_k = s.qp_grad().set_k(0); V_MtV(&qp_grad_k, Z_k, BLAS_Cpp::trans, *rhs); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\n||Z_k'*(Gf_k + mu_k*(invXu_k-invXl_k))||inf = " << qp_grad_k.norm_inf() << std::endl; } if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\nZ_k'*(Gf_k + mu_k*(invXu_k-invXl_k)) =\n" << qp_grad_k; } // error check for cross term value_type &zeta = s.zeta().set_k(0); const Vector &w_sigma = s.w_sigma().get_k(0); // need code to calculate damping parameter zeta = 1.0; Vp_StV(&qp_grad_k, zeta, w_sigma); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\n||qp_grad_k||inf = " << qp_grad_k.norm_inf() << std::endl; } if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\nqp_grad_k =\n" << qp_grad_k; } // build the "Hessian" term B = rHL + rHB // should this be MatrixSymOpNonsing const MatrixSymOp &rHL_k = s.rHL().get_k(0); const MatrixSymOp &rHB_k = s.rHB().get_k(0); MatrixSymOpNonsing &B_k = dyn_cast<MatrixSymOpNonsing>(s.B().set_k(0)); if (B_k.cols() != Z_k.cols()) { // Initialize space in rHB dyn_cast<MatrixSymInitDiag>(B_k).init_identity(Z_k.space_rows(), 0.0); } // M_StM(&B_k, 1.0, rHL_k, no_trans); assign(&B_k, rHL_k, BLAS_Cpp::no_trans); if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\nB_k = rHL_k =\n" << B_k; } Mp_StM(&B_k, 1.0, rHB_k, BLAS_Cpp::no_trans); if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\nB_k = rHL_k + rHB_k =\n" << B_k; } // Solve the system pz = - inv(rHL) * qp_grad VectorMutable &pz_k = s.pz().set_k(0); V_InvMtV( &pz_k, B_k, no_trans, qp_grad_k ); Vt_S( &pz_k, -1.0 ); // Zpz = Z * pz V_MtV( &s.Zpz().set_k(0), s.Z().get_k(0), no_trans, pz_k ); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) { out << "\n||pz||inf = " << s.pz().get_k(0).norm_inf() << "\nsum(Zpz) = " << AbstractLinAlgPack::sum(s.Zpz().get_k(0)) << std::endl; } if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\npz_k = \n" << s.pz().get_k(0); out << "\nnu_k = \n" << s.nu().get_k(0); out << "\nZpz_k = \n" << s.Zpz().get_k(0); out << std::endl; } if(algo.algo_cntr().check_results()) { assert_print_nan_inf(s.pz().get_k(0), "pz_k",true,&out); assert_print_nan_inf(s.Zpz().get_k(0), "Zpz_k",true,&out); } return true; }
bool MoochoPack::CalcDFromYPYZPZ_Step::do_step(Algorithm& _algo , poss_type step_poss, IterationPack::EDoStepType type, poss_type assoc_step_poss) { using Teuchos::implicit_cast; using AbstractLinAlgPack::dot; using LinAlgOpPack::V_VpV; NLPAlgo &algo = rsqp_algo(_algo); NLPAlgoState &s = algo.rsqp_state(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); EJournalOutputLevel ns_olevel = algo.algo_cntr().null_space_journal_output_level(); std::ostream& out = algo.track().journal_out(); // print step header. if( implicit_cast<int>(olevel) >= implicit_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( algo, step_poss, type, assoc_step_poss, out ); } // d = Ypy + Zpz VectorMutable &d_k = s.d().set_k(0); const Vector &Ypy_k = s.Ypy().get_k(0); const Vector &Zpz_k = s.Zpz().get_k(0); V_VpV( &d_k, Ypy_k, Zpz_k ); Range1D var_dep = s.var_dep(), var_indep = s.var_indep(); if( implicit_cast<int>(olevel) >= implicit_cast<int>(PRINT_ALGORITHM_STEPS) ) { const value_type very_small = std::numeric_limits<value_type>::min(); out << "\n(Ypy_k'*Zpz_k)/(||Ypy_k||2 * ||Zpz_k||2 + eps)\n" << " = ("<<dot(Ypy_k,Zpz_k)<<")/("<<Ypy_k.norm_2()<<" * "<<Zpz_k.norm_2()<<" + "<<very_small<<")\n" << " = " << dot(Ypy_k,Zpz_k) / ( Ypy_k.norm_2() * Zpz_k.norm_2() + very_small ) << "\n"; /* ConstrainedOptPack::print_vector_change_stats( s.x().get_k(0), "x", s.d().get_k(0), "d", out ); */ // ToDo: Replace the above with a reduction operator! } if( implicit_cast<int>(olevel) >= implicit_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n||d_k||inf = " << d_k.norm_inf(); if( var_dep.size() ) out << "\n||d(var_dep)_k||inf = " << d_k.sub_view(var_dep)->norm_inf(); if( var_indep.size() ) out << "\n||d(var_indep)_k||inf = " << d_k.sub_view(var_indep)->norm_inf(); out << std::endl; } if( implicit_cast<int>(olevel) >= implicit_cast<int>(PRINT_VECTORS) ) { out << "\nd_k = \n" << d_k; if( var_dep.size() ) out << "\nd(var_dep)_k = \n" << *d_k.sub_view(var_dep); } if( implicit_cast<int>(ns_olevel) >= implicit_cast<int>(PRINT_VECTORS) ) { if( var_indep.size() ) out << "\nd(var_indep)_k = \n" << *d_k.sub_view(var_indep); } return true; }
bool TangentialStepWithInequStd_Step::do_step( Algorithm& _algo, poss_type step_poss, IterationPack::EDoStepType type ,poss_type assoc_step_poss ) { using Teuchos::RCP; using Teuchos::dyn_cast; using ::fabs; using LinAlgOpPack::Vt_S; using LinAlgOpPack::V_VpV; using LinAlgOpPack::V_VmV; using LinAlgOpPack::Vp_StV; using LinAlgOpPack::Vp_V; using LinAlgOpPack::V_StV; using LinAlgOpPack::V_MtV; // using ConstrainedOptPack::min_abs; using AbstractLinAlgPack::max_near_feas_step; typedef VectorMutable::vec_mut_ptr_t vec_mut_ptr_t; NLPAlgo &algo = rsqp_algo(_algo); NLPAlgoState &s = algo.rsqp_state(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); EJournalOutputLevel ns_olevel = algo.algo_cntr().null_space_journal_output_level(); std::ostream &out = algo.track().journal_out(); //const bool check_results = algo.algo_cntr().check_results(); // print step header. if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( algo, step_poss, type, assoc_step_poss, out ); } // problem dimensions const size_type //n = algo.nlp().n(), m = algo.nlp().m(), r = s.equ_decomp().size(); // Get the iteration quantity container objects IterQuantityAccess<value_type> &alpha_iq = s.alpha(), &zeta_iq = s.zeta(), &eta_iq = s.eta(); IterQuantityAccess<VectorMutable> &dl_iq = dl_iq_(s), &du_iq = du_iq_(s), &nu_iq = s.nu(), *c_iq = m > 0 ? &s.c() : NULL, *lambda_iq = m > 0 ? &s.lambda() : NULL, &rGf_iq = s.rGf(), &w_iq = s.w(), &qp_grad_iq = s.qp_grad(), &py_iq = s.py(), &pz_iq = s.pz(), &Ypy_iq = s.Ypy(), &Zpz_iq = s.Zpz(); IterQuantityAccess<MatrixOp> &Z_iq = s.Z(), //*Uz_iq = (m > r) ? &s.Uz() : NULL, *Uy_iq = (m > r) ? &s.Uy() : NULL; IterQuantityAccess<MatrixSymOp> &rHL_iq = s.rHL(); IterQuantityAccess<ActSetStats> &act_set_stats_iq = act_set_stats_(s); // Accessed/modified/updated (just some) VectorMutable *Ypy_k = (m ? &Ypy_iq.get_k(0) : NULL); const MatrixOp &Z_k = Z_iq.get_k(0); VectorMutable &pz_k = pz_iq.set_k(0); VectorMutable &Zpz_k = Zpz_iq.set_k(0); // Comupte qp_grad which is an approximation to rGf + Z'*HL*Y*py // qp_grad = rGf VectorMutable &qp_grad_k = ( qp_grad_iq.set_k(0) = rGf_iq.get_k(0) ); // qp_grad += zeta * w if( w_iq.updated_k(0) ) { if(zeta_iq.updated_k(0)) Vp_StV( &qp_grad_k, zeta_iq.get_k(0), w_iq.get_k(0) ); else Vp_V( &qp_grad_k, w_iq.get_k(0) ); } // // Set the bounds for: // // dl <= Z*pz + Y*py <= du -> dl - Ypy <= Z*pz <= du - Ypz vec_mut_ptr_t bl = s.space_x().create_member(), bu = s.space_x().create_member(); if(m) { // bl = dl_k - Ypy_k V_VmV( bl.get(), dl_iq.get_k(0), *Ypy_k ); // bu = du_k - Ypy_k V_VmV( bu.get(), du_iq.get_k(0), *Ypy_k ); } else { *bl = dl_iq.get_k(0); *bu = du_iq.get_k(0); } // Print out the QP bounds for the constraints if( static_cast<int>(ns_olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nqp_grad_k = \n" << qp_grad_k; } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nbl = \n" << *bl; out << "\nbu = \n" << *bu; } // // Determine if we should perform a warm start or not. // bool do_warm_start = false; if( act_set_stats_iq.updated_k(-1) ) { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nDetermining if the QP should use a warm start ...\n"; } // We need to see if we should preform a warm start for the next iteration ActSetStats &stats = act_set_stats_iq.get_k(-1); const size_type num_active = stats.num_active(), num_adds = stats.num_adds(), num_drops = stats.num_drops(); const value_type frac_same = ( num_adds == ActSetStats::NOT_KNOWN || num_active == 0 ? 0.0 : my_max(((double)(num_active)-num_adds-num_drops) / num_active, 0.0 ) ); do_warm_start = ( num_active > 0 && frac_same >= warm_start_frac() ); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nnum_active = " << num_active; if( num_active ) { out << "\nmax(num_active-num_adds-num_drops,0)/(num_active) = " << "max("<<num_active<<"-"<<num_adds<<"-"<<num_drops<<",0)/("<<num_active<<") = " << frac_same; if( do_warm_start ) out << " >= "; else out << " < "; out << "warm_start_frac = " << warm_start_frac(); } if( do_warm_start ) out << "\nUse a warm start this time!\n"; else out << "\nDon't use a warm start this time!\n"; } } // Use active set from last iteration as an estimate for current active set // if we are to use a warm start. // // ToDo: If the selection of dependent and independent variables changes // then you will have to adjust this or not perform a warm start at all! if( do_warm_start ) { nu_iq.set_k(0,-1); } else { nu_iq.set_k(0) = 0.0; // No guess of the active set } VectorMutable &nu_k = nu_iq.get_k(0); // // Setup the reduced QP subproblem // // The call to the QP is setup for the more flexible call to the QPSolverRelaxed // interface to deal with the three independent variabilities: using simple // bounds for pz or not, general inequalities included or not, and extra equality // constraints included or not. // If this method of calling the QP solver were not used then 4 separate // calls to solve_qp(...) would have to be included to handle the four possible // QP formulations. // // The numeric arguments for the QP solver (in the nomenclatrue of QPSolverRelaxed) const value_type qp_bnd_inf = NLP::infinite_bound(); const Vector &qp_g = qp_grad_k; const MatrixSymOp &qp_G = rHL_iq.get_k(0); const value_type qp_etaL = 0.0; vec_mut_ptr_t qp_dL = Teuchos::null; vec_mut_ptr_t qp_dU = Teuchos::null; Teuchos::RCP<const MatrixOp> qp_E = Teuchos::null; BLAS_Cpp::Transp qp_trans_E = BLAS_Cpp::no_trans; vec_mut_ptr_t qp_b = Teuchos::null; vec_mut_ptr_t qp_eL = Teuchos::null; vec_mut_ptr_t qp_eU = Teuchos::null; Teuchos::RCP<const MatrixOp> qp_F = Teuchos::null; BLAS_Cpp::Transp qp_trans_F = BLAS_Cpp::no_trans; vec_mut_ptr_t qp_f = Teuchos::null; value_type qp_eta = 0.0; VectorMutable &qp_d = pz_k; // pz_k will be updated directly! vec_mut_ptr_t qp_nu = Teuchos::null; vec_mut_ptr_t qp_mu = Teuchos::null; vec_mut_ptr_t qp_Ed = Teuchos::null; vec_mut_ptr_t qp_lambda = Teuchos::null; // // Determine if we can use simple bounds on pz. // // If we have a variable-reduction null-space matrix // (with any choice for Y) then: // // d = Z*pz + (1-eta) * Y*py // // [ d(var_dep) ] = [ D ] * pz + (1-eta) * [ Ypy(var_dep) ] // [ d(var_indep) ] [ I ] [ Ypy(var_indep) ] // // For a cooridinate decomposition (Y = [ I ; 0 ]) then Ypy(var_indep) == // 0.0 and in this case the bounds on d(var_indep) become simple bounds on // pz even with the relaxation. Also, if dl(var_dep) and du(var_dep) are // unbounded, then we can also use simple bounds since we don't need the // relaxation and we can set eta=0. In this case we just have to subtract // from the upper and lower bounds on pz! // // Otherwise, we can not use simple variable bounds and implement the // relaxation properly. // const MatrixIdentConcat *Zvr = dynamic_cast<const MatrixIdentConcat*>( &Z_k ); const Range1D var_dep = Zvr ? Zvr->D_rng() : Range1D::Invalid, var_indep = Zvr ? Zvr->I_rng() : Range1D(); RCP<Vector> Ypy_indep; const value_type Ypy_indep_norm_inf = ( m ? (Ypy_indep=Ypy_k->sub_view(var_indep))->norm_inf() : 0.0); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) out << "\nDetermine if we can use simple bounds on pz ...\n" << " m = " << m << std::endl << " dynamic_cast<const MatrixIdentConcat*>(&Z_k) = " << Zvr << std::endl << " ||Ypy_k(var_indep)||inf = " << Ypy_indep_norm_inf << std::endl; const bool bounded_var_dep = ( m > 0 && num_bounded( *bl->sub_view(var_dep), *bu->sub_view(var_dep), qp_bnd_inf ) ); const bool use_simple_pz_bounds = ( m == 0 || ( Zvr != NULL && ( Ypy_indep_norm_inf == 0.0 || bounded_var_dep == 0 ) ) ); if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) out << (use_simple_pz_bounds ? "\nUsing simple bounds on pz ...\n" : "\nUsing bounds on full Z*pz ...\n") << (bounded_var_dep ? "\nThere are finite bounds on dependent variables. Adding extra inequality constrints for D*pz ...\n" : "\nThere are no finite bounds on dependent variables. There will be no extra inequality constraints added on D*pz ...\n" ) ; if( use_simple_pz_bounds ) { // Set simple bound constraints on pz qp_dL = bl->sub_view(var_indep); qp_dU = bu->sub_view(var_indep); qp_nu = nu_k.sub_view(var_indep); // nu_k(var_indep) will be updated directly! if( m && bounded_var_dep ) { // Set general inequality constraints for D*pz qp_E = Teuchos::rcp(&Zvr->D(),false); qp_b = Ypy_k->sub_view(var_dep); qp_eL = bl->sub_view(var_dep); qp_eU = bu->sub_view(var_dep); qp_mu = nu_k.sub_view(var_dep); // nu_k(var_dep) will be updated directly! qp_Ed = Zpz_k.sub_view(var_dep); // Zpz_k(var_dep) will be updated directly! } else { // Leave these as NULL since there is no extra general inequality constraints } } else if( !use_simple_pz_bounds ) { // ToDo: Leave out parts for unbounded dependent variables! // There are no simple bounds! (leave qp_dL, qp_dU and qp_nu as null) // Set general inequality constraints for Z*pz qp_E = Teuchos::rcp(&Z_k,false); qp_b = Teuchos::rcp(Ypy_k,false); qp_eL = bl; qp_eU = bu; qp_mu = Teuchos::rcp(&nu_k,false); qp_Ed = Teuchos::rcp(&Zpz_k,false); // Zpz_k will be updated directly! } else { TEST_FOR_EXCEPT(true); } // Set the general equality constriants (if they exist) Range1D equ_undecomp = s.equ_undecomp(); if( m > r && m > 0 ) { // qp_f = Uy_k * py_k + c_k(equ_undecomp) qp_f = s.space_c().sub_space(equ_undecomp)->create_member(); V_MtV( qp_f.get(), Uy_iq->get_k(0), BLAS_Cpp::no_trans, py_iq.get_k(0) ); Vp_V( qp_f.get(), *c_iq->get_k(0).sub_view(equ_undecomp) ); // Must resize for the undecomposed constriants if it has not already been qp_F = Teuchos::rcp(&Uy_iq->get_k(0),false); qp_lambda = lambda_iq->set_k(0).sub_view(equ_undecomp); // lambda_k(equ_undecomp), will be updated directly! } // Setup the rest of the arguments QPSolverRelaxed::EOutputLevel qp_olevel; switch( olevel ) { case PRINT_NOTHING: qp_olevel = QPSolverRelaxed::PRINT_NONE; break; case PRINT_BASIC_ALGORITHM_INFO: qp_olevel = QPSolverRelaxed::PRINT_NONE; break; case PRINT_ALGORITHM_STEPS: qp_olevel = QPSolverRelaxed::PRINT_BASIC_INFO; break; case PRINT_ACTIVE_SET: qp_olevel = QPSolverRelaxed::PRINT_ITER_SUMMARY; break; case PRINT_VECTORS: qp_olevel = QPSolverRelaxed::PRINT_ITER_VECTORS; break; case PRINT_ITERATION_QUANTITIES: qp_olevel = QPSolverRelaxed::PRINT_EVERY_THING; break; default: TEST_FOR_EXCEPT(true); } // ToDo: Set print options so that only vectors matrices etc // are only printed in the null space // // Solve the QP // qp_solver().infinite_bound(qp_bnd_inf); const QPSolverStats::ESolutionType solution_type = qp_solver().solve_qp( int(olevel) == int(PRINT_NOTHING) ? NULL : &out ,qp_olevel ,( algo.algo_cntr().check_results() ? QPSolverRelaxed::RUN_TESTS : QPSolverRelaxed::NO_TESTS ) ,qp_g, qp_G, qp_etaL, qp_dL.get(), qp_dU.get() ,qp_E.get(), qp_trans_E, qp_E.get() ? qp_b.get() : NULL ,qp_E.get() ? qp_eL.get() : NULL, qp_E.get() ? qp_eU.get() : NULL ,qp_F.get(), qp_trans_F, qp_F.get() ? qp_f.get() : NULL ,NULL // obj_d ,&qp_eta, &qp_d ,qp_nu.get() ,qp_mu.get(), qp_E.get() ? qp_Ed.get() : NULL ,qp_F.get() ? qp_lambda.get() : NULL ,NULL // qp_Fd ); // // Check the optimality conditions for the QP // std::ostringstream omsg; bool throw_qp_failure = false; if( qp_testing() == QP_TEST || ( qp_testing() == QP_TEST_DEFAULT && algo.algo_cntr().check_results() ) ) { if( int(olevel) >= int(PRINT_ALGORITHM_STEPS) ) { out << "\nChecking the optimality conditions of the reduced QP subproblem ...\n"; } if(!qp_tester().check_optimality_conditions( solution_type,qp_solver().infinite_bound() ,int(olevel) == int(PRINT_NOTHING) ? NULL : &out ,int(olevel) >= int(PRINT_VECTORS) ? true : false ,int(olevel) >= int(PRINT_ITERATION_QUANTITIES) ? true : false ,qp_g, qp_G, qp_etaL, qp_dL.get(), qp_dU.get() ,qp_E.get(), qp_trans_E, qp_E.get() ? qp_b.get() : NULL ,qp_E.get() ? qp_eL.get() : NULL, qp_E.get() ? qp_eU.get() : NULL ,qp_F.get(), qp_trans_F, qp_F.get() ? qp_f.get() : NULL ,NULL // obj_d ,&qp_eta, &qp_d ,qp_nu.get() ,qp_mu.get(), qp_E.get() ? qp_Ed.get() : NULL ,qp_F.get() ? qp_lambda.get() : NULL ,NULL // qp_Fd )) { omsg << "\n*** Alert! at least one of the QP optimality conditions did not check out.\n"; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << omsg.str(); } throw_qp_failure = true; } } // // Set the solution // if( !use_simple_pz_bounds ) { // Everything is already updated! } else if( use_simple_pz_bounds ) { // Just have to set Zpz_k(var_indep) = pz_k *Zpz_k.sub_view(var_indep) = pz_k; if( m && !bounded_var_dep ) { // Must compute Zpz_k(var_dep) = D*pz LinAlgOpPack::V_MtV( &*Zpz_k.sub_view(var_dep), Zvr->D(), BLAS_Cpp::no_trans, pz_k ); // ToDo: Remove the compuation of Zpz here unless you must } } else { TEST_FOR_EXCEPT(true); } // Set the solution statistics qp_solver_stats_(s).set_k(0) = qp_solver().get_qp_stats(); // Cut back Ypy_k = (1-eta) * Ypy_k const value_type eps = std::numeric_limits<value_type>::epsilon(); if( fabs(qp_eta - 0.0) > eps ) { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n*** Alert! the QP was infeasible (eta = "<<qp_eta<<"). Cutting back Ypy_k = (1.0 - eta)*Ypy_k ...\n"; } Vt_S( Ypy_k, 1.0 - qp_eta ); } // eta_k eta_iq.set_k(0) = qp_eta; // // Modify the solution if we have to! // switch(solution_type) { case QPSolverStats::OPTIMAL_SOLUTION: break; // we are good! case QPSolverStats::PRIMAL_FEASIBLE_POINT: { omsg << "\n*** Alert! the returned QP solution is PRIMAL_FEASIBLE_POINT but not optimal!\n"; if( primal_feasible_point_error() ) omsg << "\n*** primal_feasible_point_error == true, this is an error!\n"; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << omsg.str(); } throw_qp_failure = primal_feasible_point_error(); break; } case QPSolverStats::DUAL_FEASIBLE_POINT: { omsg << "\n*** Alert! the returned QP solution is DUAL_FEASIBLE_POINT" << "\n*** but not optimal so we cut back the step ...\n"; if( dual_feasible_point_error() ) omsg << "\n*** dual_feasible_point_error == true, this is an error!\n"; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << omsg.str(); } // Cut back the step to fit in the bounds // // dl <= u*(Ypy_k+Zpz_k) <= du // vec_mut_ptr_t zero = s.space_x().create_member(0.0), d_tmp = s.space_x().create_member(); V_VpV( d_tmp.get(), *Ypy_k, Zpz_k ); const std::pair<value_type,value_type> u_steps = max_near_feas_step( *zero, *d_tmp, dl_iq.get_k(0), du_iq.get_k(0), 0.0 ); const value_type u = my_min( u_steps.first, 1.0 ); // largest positive step size alpha_iq.set_k(0) = u; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nFinding u s.t. dl <= u*(Ypy_k+Zpz_k) <= du\n" << "max step length u = " << u << std::endl << "alpha_k = u = " << alpha_iq.get_k(0) << std::endl; } throw_qp_failure = dual_feasible_point_error(); break; } case QPSolverStats::SUBOPTIMAL_POINT: { omsg << "\n*** Alert!, the returned QP solution is SUBOPTIMAL_POINT!\n"; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << omsg.str(); } throw_qp_failure = true; break; } default: TEST_FOR_EXCEPT(true); // should not happen! } // // Output the final solution! // if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n||pz_k||inf = " << s.pz().get_k(0).norm_inf() << "\nnu_k.nz() = " << s.nu().get_k(0).nz() << "\nmax(|nu_k(i)|) = " << s.nu().get_k(0).norm_inf() // << "\nmin(|nu_k(i)|) = " << min_abs( s.nu().get_k(0)() ) ; if( m > r ) out << "\n||lambda_k(undecomp)||inf = " << s.lambda().get_k(0).norm_inf(); out << "\n||Zpz_k||2 = " << s.Zpz().get_k(0).norm_2() ; if(qp_eta > 0.0) out << "\n||Ypy||2 = " << s.Ypy().get_k(0).norm_2(); out << std::endl; } if( static_cast<int>(ns_olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\npz_k = \n" << s.pz().get_k(0); if(var_indep.size()) out << "\nnu_k(var_indep) = \n" << *s.nu().get_k(0).sub_view(var_indep); } if( static_cast<int>(ns_olevel) >= static_cast<int>(PRINT_VECTORS) ) { if(var_indep.size()) out << "\nZpz(var_indep)_k = \n" << *s.Zpz().get_k(0).sub_view(var_indep); out << std::endl; } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { if(var_dep.size()) out << "\nZpz(var_dep)_k = \n" << *s.Zpz().get_k(0).sub_view(var_dep); out << "\nZpz_k = \n" << s.Zpz().get_k(0); out << std::endl; } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nnu_k = \n" << s.nu().get_k(0); if(var_dep.size()) out << "\nnu_k(var_dep) = \n" << *s.nu().get_k(0).sub_view(var_dep); if( m > r ) out << "\nlambda_k(equ_undecomp) = \n" << *s.lambda().get_k(0).sub_view(equ_undecomp); if(qp_eta > 0.0) out << "\nYpy = \n" << s.Ypy().get_k(0); } if( qp_eta == 1.0 ) { omsg << "TangentialStepWithInequStd_Step::do_step(...) : Error, a QP relaxation parameter\n" << "of eta = " << qp_eta << " was calculated and therefore it must be assumed\n" << "that the NLP's constraints are infeasible\n" << "Throwing an InfeasibleConstraints exception!\n"; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << omsg.str(); } throw InfeasibleConstraints(omsg.str()); } if( throw_qp_failure ) throw QPFailure( omsg.str(), qp_solver().get_qp_stats() ); return true; }
bool NLPDirectTester::finite_diff_check( NLPDirect *nlp ,const Vector &xo ,const Vector *xl ,const Vector *xu ,const Vector *c ,const Vector *Gf ,const Vector *py ,const Vector *rGf ,const MatrixOp *GcU ,const MatrixOp *D ,const MatrixOp *Uz ,bool print_all_warnings ,std::ostream *out ) const { using std::setw; using std::endl; using std::right; using AbstractLinAlgPack::sum; using AbstractLinAlgPack::dot; using AbstractLinAlgPack::Vp_StV; using AbstractLinAlgPack::random_vector; using AbstractLinAlgPack::assert_print_nan_inf; using LinAlgOpPack::V_StV; using LinAlgOpPack::V_StMtV; using LinAlgOpPack::Vp_MtV; using LinAlgOpPack::M_StM; using LinAlgOpPack::M_StMtM; typedef VectorSpace::vec_mut_ptr_t vec_mut_ptr_t; // using AbstractLinAlgPack::TestingPack::CompareDenseVectors; // using AbstractLinAlgPack::TestingPack::CompareDenseSparseMatrices; using TestingHelperPack::update_success; bool success = true, preformed_fd; if(out) { *out << std::boolalpha << std::endl << "*********************************************************\n" << "*** NLPDirectTester::finite_diff_check(...) ***\n" << "*********************************************************\n"; } const Range1D var_dep = nlp->var_dep(), var_indep = nlp->var_indep(), con_decomp = nlp->con_decomp(), con_undecomp = nlp->con_undecomp(); NLP::vec_space_ptr_t space_x = nlp->space_x(), space_c = nlp->space_c(); // ////////////////////////////////////////////// // Validate the input TEST_FOR_EXCEPTION( py && !c, std::invalid_argument ,"NLPDirectTester::finite_diff_check(...) : " "Error, if py!=NULL then c!=NULL must also be true!" ); const CalcFiniteDiffProd &fd_deriv_prod = this->calc_fd_prod(); const value_type rand_y_l = -1.0, rand_y_u = 1.0, small_num = ::sqrt(std::numeric_limits<value_type>::epsilon()); try { // /////////////////////////////////////////////// // (1) Check Gf if(Gf) { switch( Gf_testing_method() ) { case FD_COMPUTE_ALL: { // Compute FDGf outright TEST_FOR_EXCEPT(true); // ToDo: update above! break; } case FD_DIRECTIONAL: { // Compute FDGF'*y using random y's if(out) *out << "\nComparing products Gf'*y with finite difference values FDGf'*y for " << "random y's ...\n"; vec_mut_ptr_t y = space_x->create_member(); value_type max_warning_viol = 0.0; int num_warning_viol = 0; const int num_fd_directions_used = ( num_fd_directions() > 0 ? num_fd_directions() : 1 ); for( int direc_i = 1; direc_i <= num_fd_directions_used; ++direc_i ) { if( num_fd_directions() > 0 ) { random_vector( rand_y_l, rand_y_u, y.get() ); if(out) *out << "\n****" << "\n**** Random directional vector " << direc_i << " ( ||y||_1 / n = " << (y->norm_1() / y->dim()) << " )" << "\n***\n"; } else { *y = 1.0; if(out) *out << "\n****" << "\n**** Ones vector y ( ||y||_1 / n = "<<(y->norm_1()/y->dim())<<" )" << "\n***\n"; } value_type Gf_y = dot( *Gf, *y ), FDGf_y; preformed_fd = fd_deriv_prod.calc_deriv_product( xo,xl,xu ,*y,NULL,NULL,true,nlp,&FDGf_y,NULL,out,dump_all(),dump_all() ); if( !preformed_fd ) goto FD_NOT_PREFORMED; assert_print_nan_inf(FDGf_y, "FDGf'*y",true,out); const value_type calc_err = ::fabs( ( Gf_y - FDGf_y )/( ::fabs(Gf_y) + ::fabs(FDGf_y) + small_num ) ); if( calc_err >= Gf_warning_tol() ) { max_warning_viol = my_max( max_warning_viol, calc_err ); ++num_warning_viol; } if(out) *out << "\nrel_err(Gf'*y,FDGf'*y) = " << "rel_err(" << Gf_y << "," << FDGf_y << ") = " << calc_err << endl; if( calc_err >= Gf_error_tol() ) { if(out) { *out << "Error, above relative error exceeded Gf_error_tol = " << Gf_error_tol() << endl; if(dump_all()) { *out << "\ny =\n" << *y; } } } } if(out && num_warning_viol) *out << "\nThere were " << num_warning_viol << " warning tolerance " << "violations out of num_fd_directions = " << num_fd_directions() << " computations of FDGf'*y\n" << "and the maximum violation was " << max_warning_viol << " > Gf_waring_tol = " << Gf_warning_tol() << endl; break; } default: TEST_FOR_EXCEPT(true); // Invalid value } } // ///////////////////////////////////////////// // (2) Check py = -inv(C)*c // // We want to check; // // FDC * (inv(C)*c) \approx c // \_________/ // -py // // We can compute this as: // // FDC * py = [ FDC, FDN ] * [ -py ; 0 ] // \__________/ // FDA' // // t1 = [ -py ; 0 ] // // t2 = FDA'*t1 // // Compare t2 \approx c // if(py) { if(out) *out << "\nComparing c with finite difference product FDA'*[ -py; 0 ] = -FDC*py ...\n"; // t1 = [ -py ; 0 ] VectorSpace::vec_mut_ptr_t t1 = space_x->create_member(); V_StV( t1->sub_view(var_dep).get(), -1.0, *py ); *t1->sub_view(var_indep) = 0.0; // t2 = FDA'*t1 VectorSpace::vec_mut_ptr_t t2 = nlp->space_c()->create_member(); preformed_fd = fd_deriv_prod.calc_deriv_product( xo,xl,xu ,*t1,NULL,NULL,true,nlp,NULL,t2.get(),out,dump_all(),dump_all() ); if( !preformed_fd ) goto FD_NOT_PREFORMED; const value_type sum_c = sum(*c), sum_t2 = sum(*t2); assert_print_nan_inf(sum_t2, "sum(-FDC*py)",true,out); const value_type calc_err = ::fabs( ( sum_c - sum_t2 )/( ::fabs(sum_c) + ::fabs(sum_t2) + small_num ) ); if(out) *out << "\nrel_err(sum(c),sum(-FDC*py)) = " << "rel_err(" << sum_c << "," << sum_t2 << ") = " << calc_err << endl; if( calc_err >= Gc_error_tol() ) { if(out) *out << "Error, above relative error exceeded Gc_error_tol = " << Gc_error_tol() << endl; if(print_all_warnings) *out << "\nt1 = [ -py; 0 ] =\n" << *t1 << "\nt2 = FDA'*t1 = -FDC*py =\n" << *t2; update_success( false, &success ); } if( calc_err >= Gc_warning_tol() ) { if(out) *out << "\nWarning, above relative error exceeded Gc_warning_tol = " << Gc_warning_tol() << endl; } } // ///////////////////////////////////////////// // (3) Check D = -inv(C)*N if(D) { switch( Gc_testing_method() ) { case FD_COMPUTE_ALL: { // // Compute FDN outright and check // -FDC * D \aprox FDN // // We want to compute: // // FDC * -D = [ FDC, FDN ] * [ -D; 0 ] // \__________/ // FDA' // // To compute the above we perform: // // T = FDA' * [ -D; 0 ] (one column at a time) // // Compare T \approx FDN // /* // FDN DMatrix FDN(m,n-m); fd_deriv_computer.calc_deriv( xo, xl, xu , Range1D(m+1,n), nlp, NULL , &FDN() ,BLAS_Cpp::trans, out ); // T = FDA' * [ -D; 0 ] (one column at a time) DMatrix T(m,n-m); DVector t(n); t(m+1,n) = 0.0; for( int s = 1; s <= n-m; ++s ) { // t = [ -D(:,s); 0 ] V_StV( &t(1,m), -1.0, D->col(s) ); // T(:,s) = FDA' * t fd_deriv_prod.calc_deriv_product( xo,xl,xu,t(),NULL,NULL,nlp,NULL,&T.col(s),out); } // Compare T \approx FDN if(out) *out << "\nChecking the computed D = -inv(C)*N\n" << "where D(i,j) = (-FDC*D)(i,j), dM(i,j) = FDN(i,j) ...\n"; result = comp_M.comp( T(), FDN, BLAS_Cpp::no_trans , CompareDenseSparseMatrices::FULL_MATRIX , CompareDenseSparseMatrices::REL_ERR_BY_COL , Gc_warning_tol(), Gc_error_tol() , print_all_warnings, out ); update_success( result, &success ); if(!result) return false; */ TEST_FOR_EXCEPT(true); // Todo: Implement above! break; } case FD_DIRECTIONAL: { // // Compute -FDC * D * v \aprox FDN * v // for random v's // // We will compute this as: // // t1 = [ 0; y ] <: R^(n) // // t2 = FDA' * t1 ( FDN * y ) <: R^(m) // // t1 = [ -D * y ; 0 ] <: R^(n) // // t3 = FDA' * t1 ( -FDC * D * y ) <: R^(m) // // Compare t2 \approx t3 // if(out) *out << "\nComparing finite difference products -FDC*D*y with FDN*y for " "random vectors y ...\n"; VectorSpace::vec_mut_ptr_t y = space_x->sub_space(var_indep)->create_member(), t1 = space_x->create_member(), t2 = space_c->create_member(), t3 = space_c->create_member(); value_type max_warning_viol = 0.0; int num_warning_viol = 0; const int num_fd_directions_used = ( num_fd_directions() > 0 ? num_fd_directions() : 1 ); for( int direc_i = 1; direc_i <= num_fd_directions_used; ++direc_i ) { if( num_fd_directions() > 0 ) { random_vector( rand_y_l, rand_y_u, y.get() ); if(out) *out << "\n****" << "\n**** Random directional vector " << direc_i << " ( ||y||_1 / n = " << (y->norm_1() / y->dim()) << " )" << "\n***\n"; } else { *y = 1.0; if(out) *out << "\n****" << "\n**** Ones vector y ( ||y||_1 / n = "<<(y->norm_1()/y->dim())<<" )" << "\n***\n"; } // t1 = [ 0; y ] <: R^(n) *t1->sub_view(var_dep) = 0.0; *t1->sub_view(var_indep) = *y; // t2 = FDA' * t1 ( FDN * y ) <: R^(m) preformed_fd = fd_deriv_prod.calc_deriv_product( xo,xl,xu ,*t1,NULL,NULL,true,nlp,NULL,t2.get(),out,dump_all(),dump_all() ); if( !preformed_fd ) goto FD_NOT_PREFORMED; // t1 = [ -D * y ; 0 ] <: R^(n) V_StMtV( t1->sub_view(var_dep).get(), -1.0, *D, BLAS_Cpp::no_trans, *y ); *t1->sub_view(var_indep) = 0.0; // t3 = FDA' * t1 ( -FDC * D * y ) <: R^(m) preformed_fd = fd_deriv_prod.calc_deriv_product( xo,xl,xu ,*t1,NULL,NULL,true,nlp,NULL,t3.get(),out,dump_all(),dump_all() ); // Compare t2 \approx t3 const value_type sum_t2 = sum(*t2), sum_t3 = sum(*t3); const value_type calc_err = ::fabs( ( sum_t2 - sum_t3 )/( ::fabs(sum_t2) + ::fabs(sum_t3) + small_num ) ); if(out) *out << "\nrel_err(sum(-FDC*D*y),sum(FDN*y)) = " << "rel_err(" << sum_t3 << "," << sum_t2 << ") = " << calc_err << endl; if( calc_err >= Gc_warning_tol() ) { max_warning_viol = my_max( max_warning_viol, calc_err ); ++num_warning_viol; } if( calc_err >= Gc_error_tol() ) { if(out) *out << "Error, above relative error exceeded Gc_error_tol = " << Gc_error_tol() << endl << "Stoping the tests!\n"; if(print_all_warnings) *out << "\ny =\n" << *y << "\nt1 = [ -D*y; 0 ] =\n" << *t1 << "\nt2 = FDA' * [ 0; y ] = FDN * y =\n" << *t2 << "\nt3 = FDA' * t1 = -FDC * D * y =\n" << *t3; update_success( false, &success ); } } if(out && num_warning_viol) *out << "\nThere were " << num_warning_viol << " warning tolerance " << "violations out of num_fd_directions = " << num_fd_directions() << " computations of sum(FDC*D*y) and sum(FDN*y)\n" << "and the maximum relative iolation was " << max_warning_viol << " > Gc_waring_tol = " << Gc_warning_tol() << endl; break; } default: TEST_FOR_EXCEPT(true); } } // /////////////////////////////////////////////// // (4) Check rGf = Gf(var_indep) + D'*Gf(var_dep) if(rGf) { if( Gf && D ) { if(out) *out << "\nComparing rGf_tmp = Gf(var_indep) - D'*Gf(var_dep) with rGf ...\n"; VectorSpace::vec_mut_ptr_t rGf_tmp = space_x->sub_space(var_indep)->create_member(); *rGf_tmp = *Gf->sub_view(var_indep); Vp_MtV( rGf_tmp.get(), *D, BLAS_Cpp::trans, *Gf->sub_view(var_dep) ); const value_type sum_rGf_tmp = sum(*rGf_tmp), sum_rGf = sum(*rGf); const value_type calc_err = ::fabs( ( sum_rGf_tmp - sum_rGf )/( ::fabs(sum_rGf_tmp) + ::fabs(sum_rGf) + small_num ) ); if(out) *out << "\nrel_err(sum(rGf_tmp),sum(rGf)) = " << "rel_err(" << sum_rGf_tmp << "," << sum_rGf << ") = " << calc_err << endl; if( calc_err >= Gc_error_tol() ) { if(out) *out << "Error, above relative error exceeded Gc_error_tol = " << Gc_error_tol() << endl; if(print_all_warnings) *out << "\nrGf_tmp =\n" << *rGf_tmp << "\nrGf =\n" << *rGf; update_success( false, &success ); } if( calc_err >= Gc_warning_tol() ) { if(out) *out << "\nWarning, above relative error exceeded Gc_warning_tol = " << Gc_warning_tol() << endl; } } else if( D ) { if(out) *out << "\nComparing rGf'*y with the finite difference product" << " fd_prod(f,[D*y;y]) for random vectors y ...\n"; VectorSpace::vec_mut_ptr_t y = space_x->sub_space(var_indep)->create_member(), t = space_x->create_member(); value_type max_warning_viol = 0.0; int num_warning_viol = 0; const int num_fd_directions_used = ( num_fd_directions() > 0 ? num_fd_directions() : 1 ); for( int direc_i = 1; direc_i <= num_fd_directions_used; ++direc_i ) { if( num_fd_directions() > 0 ) { random_vector( rand_y_l, rand_y_u, y.get() ); if(out) *out << "\n****" << "\n**** Random directional vector " << direc_i << " ( ||y||_1 / n = " << (y->norm_1() / y->dim()) << " )" << "\n***\n"; } else { *y = 1.0; if(out) *out << "\n****" << "\n**** Ones vector y ( ||y||_1 / n = "<<(y->norm_1()/y->dim())<<" )" << "\n***\n"; } // t = [ D*y; y ] LinAlgOpPack::V_MtV(&*t->sub_view(var_dep),*D,BLAS_Cpp::no_trans,*y); *t->sub_view(var_indep) = *y; value_type fd_rGf_y = 0.0; // fd_Gf_y preformed_fd = fd_deriv_prod.calc_deriv_product( xo,xl,xu ,*t,NULL,NULL,true,nlp,&fd_rGf_y,NULL,out,dump_all(),dump_all() ); if( !preformed_fd ) goto FD_NOT_PREFORMED; if(out) *out << "fd_prod(f,[D*y;y]) = " << fd_rGf_y << "\n"; // rGf_y = rGf'*y const value_type rGf_y = dot(*rGf,*y); if(out) *out << "rGf'*y = " << rGf_y << "\n"; // Compare fd_rGf_y and rGf*y const value_type calc_err = ::fabs( ( rGf_y - fd_rGf_y )/( ::fabs(rGf_y) + ::fabs(fd_rGf_y) + small_num ) ); if( calc_err >= Gc_warning_tol() ) { max_warning_viol = my_max( max_warning_viol, calc_err ); ++num_warning_viol; } if(out) *out << "\nrel_err(rGf'*y,fd_prod(f,[D*y;y])) = " << "rel_err(" << fd_rGf_y << "," << rGf_y << ") = " << calc_err << endl; if( calc_err >= Gf_error_tol() ) { if(out) *out << "Error, above relative error exceeded Gc_error_tol = " << Gc_error_tol() << endl; if(print_all_warnings) *out << "\ny =\n" << *y << "\nt = [ D*y; y ] =\n" << *t; update_success( false, &success ); } } } else { TEST_FOR_EXCEPT(true); // ToDo: Test rGf without D? (This is not going to be easy!) } } // /////////////////////////////////////////////////// // (5) Check GcU, and/or Uz (for undecomposed equalities) if(GcU || Uz) { TEST_FOR_EXCEPT(true); // ToDo: Implement! } FD_NOT_PREFORMED: if(!preformed_fd) { if(out) *out << "\nError, the finite difference computation was not preformed due to cramped bounds\n" << "Finite difference test failed!\n" << endl; return false; } } // end try catch( const AbstractLinAlgPack::NaNInfException& except ) { if(out) *out << "Error, found a NaN or Inf. Stoping tests\n"; success = false; } if( out ) { if( success ) *out << "\nCongradulations, all the finite difference errors where within the\n" "specified error tolerances!\n"; else *out << "\nOh no, at least one of the above finite difference tests failed!\n"; } return success; }
QPSolverStats::ESolutionType QPSolverRelaxedQPKWIK::imp_solve_qp( std::ostream* out, EOutputLevel olevel, ERunTests test_what ,const Vector& g, const MatrixSymOp& G ,value_type etaL ,const Vector* dL, const Vector* dU ,const MatrixOp* E, BLAS_Cpp::Transp trans_E, const Vector* b ,const Vector* eL, const Vector* eU ,const MatrixOp* F, BLAS_Cpp::Transp trans_F, const Vector* f ,value_type* obj_d ,value_type* eta, VectorMutable* d ,VectorMutable* nu ,VectorMutable* mu, VectorMutable* Ed ,VectorMutable* lambda, VectorMutable* Fd ) { using Teuchos::dyn_cast; using DenseLinAlgPack::nonconst_tri_ele; using LinAlgOpPack::dot; using LinAlgOpPack::V_StV; using LinAlgOpPack::assign; using LinAlgOpPack::V_StV; using LinAlgOpPack::V_MtV; using AbstractLinAlgPack::EtaVector; using AbstractLinAlgPack::transVtMtV; using AbstractLinAlgPack::num_bounded; using ConstrainedOptPack::MatrixExtractInvCholFactor; // ///////////////////////// // Map to QPKWIK input // Validate that rHL is of the proper type. const MatrixExtractInvCholFactor &cG = dyn_cast<const MatrixExtractInvCholFactor>(G); // Determine the number of sparse bounds on variables and inequalities. // By default set for the dense case const value_type inf = this->infinite_bound(); const size_type nd = d->dim(), m_in = E ? b->dim() : 0, m_eq = F ? f->dim() : 0, nvarbounds = dL ? num_bounded(*dL,*dU,inf) : 0, ninequbounds = E ? num_bounded(*eL,*eU,inf) : 0, nequalities = F ? f->dim() : 0; // Determine if this is a QP with a structure different from the // one just solved. const bool same_qp_struct = ( N_ == nd && M1_ == nvarbounds && M2_ == ninequbounds && M3_ == nequalities ); ///////////////////////////////////////////////////////////////// // Set the input parameters to be sent to QPKWIKNEW // N N_ = nd; // M1 M1_ = nvarbounds; // M2 M2_ = ninequbounds; // M3 M3_ = nequalities; // GRAD GRAD_ = VectorDenseEncap(g)(); // UINV_AUG // // UINV_AUG = [ sqrt(bigM) 0 ] // [ 0 L' ] // UINV_AUG_.resize(N_+1,N_+1); cG.extract_inv_chol( &nonconst_tri_ele( UINV_AUG_(2,N_+1,2,N_+1), BLAS_Cpp::upper ) ); UINV_AUG_(1,1) = 1.0 / ::sqrt( NUMPARAM_[2] ); UINV_AUG_.col(1)(2,N_+1) = 0.0; UINV_AUG_.row(1)(2,N_+1) = 0.0; // LDUINV_AUG LDUINV_AUG_ = UINV_AUG_.rows(); // IBND, BL , BU, A, LDA, YPY IBND_INV_.resize( nd + m_in); std::fill( IBND_INV_.begin(), IBND_INV_.end(), 0 ); // Initialize the zero IBND_.resize( my_max( 1, M1_ + M2_ ) ); BL_.resize( my_max( 1, M1_ + M2_ ) ); BU_.resize( my_max( 1, M1_ + M2_ + M3_ ) ); LDA_ = my_max( 1, M2_ + M3_ ); A_.resize( LDA_, ( M2_ + M3_ > 0 ? N_ : 1 ) ); YPY_.resize( my_max( 1, M1_ + M2_ ) ); if(M1_) YPY_(1,M1_) = 0.0; // Must be for this QP interface // Initialize variable bound constraints if( dL ) { VectorDenseEncap dL_de(*dL); VectorDenseEncap dU_de(*dU); // read iterators AbstractLinAlgPack::sparse_bounds_itr dLU_itr( dL_de().begin(), dL_de().end() ,dU_de().begin(), dU_de().end() ,inf ); // written iterators IBND_t::iterator IBND_itr = IBND_.begin(), IBND_end = IBND_.begin() + M1_; DVector::iterator BL_itr = BL_.begin(), BU_itr = BU_.begin(), YPY_itr = YPY_.begin(); // Loop for( size_type ibnd_i = 1; IBND_itr != IBND_end; ++ibnd_i, ++dLU_itr ) { IBND_INV_[dLU_itr.index()-1] = ibnd_i; *IBND_itr++ = dLU_itr.index(); *BL_itr++ = dLU_itr.lbound(); *BU_itr++ = dLU_itr.ubound(); *YPY_itr++ = 0.0; // Must be zero with this QP interface } } // Initialize inequality constraints if(M2_) { VectorDenseEncap eL_de(*eL); VectorDenseEncap eU_de(*eU); VectorDenseEncap b_de(*b); AbstractLinAlgPack::sparse_bounds_itr eLU_itr( eL_de().begin(), eL_de().end() ,eU_de().begin(), eU_de().end() ,inf ); if( M2_ < m_in ) { // Initialize BL, BU, YPY and A for sparse bounds on general inequalities // written iterators DVector::iterator BL_itr = BL_.begin() + M1_, BU_itr = BU_.begin() + M1_, YPY_itr = YPY_.begin() + M1_; IBND_t::iterator ibnds_itr = IBND_.begin() + M1_; // loop for(size_type i = 1; i <= M2_; ++i, ++eLU_itr, ++ibnds_itr ) { TEST_FOR_EXCEPT( !( !eLU_itr.at_end() ) ); const size_type k = eLU_itr.index(); *BL_itr++ = eLU_itr.lbound(); *BU_itr++ = eLU_itr.ubound(); *YPY_itr++ = b_de()(k); *ibnds_itr = k; // Only for my record, not used by QPKWIK IBND_INV_[nd+k-1] = M1_ + i; // Add the corresponding row of op(E) to A // y == A.row(i)' // y' = e_k' * op(E) => y = op(E')*e_k DVectorSlice y = A_.row(i); EtaVector e_k(k,eL_de().dim()); V_MtV( &y( 1, N_ ), *E, BLAS_Cpp::trans_not(trans_E), e_k() ); // op(E')*e_k } } else { // // Initialize BL, BU, YPY and A for dense bounds on general inequalities // // Initialize BL(M1+1:M1+M2), BU(M1+1:M1+M2) // and IBND(M1+1:M1+M2) = identity (only for my record, not used by QPKWIK) DVector::iterator BL_itr = BL_.begin() + M1_, BU_itr = BU_.begin() + M1_; IBND_t::iterator ibnds_itr = IBND_.begin() + M1_; for(size_type i = 1; i <= m_in; ++i ) { if( !eLU_itr.at_end() && eLU_itr.index() == i ) { *BL_itr++ = eLU_itr.lbound(); *BU_itr++ = eLU_itr.ubound(); ++eLU_itr; } else { *BL_itr++ = -inf; *BU_itr++ = +inf; } *ibnds_itr++ = i; IBND_INV_[nd+i-1]= M1_ + i; } // A(1:M2,1:N) = op(E) assign( &A_(1,M2_,1,N_), *E, trans_E ); // YPY YPY_(M1_+1,M1_+M2_) = b_de(); } } // Initialize equalities if(M3_) { V_StV( &BU_( M1_ + M2_ + 1, M1_ + M2_ + M3_ ), -1.0, VectorDenseEncap(*f)() ); assign( &A_( M2_ + 1, M2_ + M3_, 1, N_ ), *F, trans_F ); } // IYPY IYPY_ = 1; // ??? // WARM WARM_ = 0; // Cold start by default // MAX_ITER MAX_ITER_ = static_cast<f_int>(max_qp_iter_frac() * N_); // INF INF_ = ( same_qp_struct ? 1 : 0 ); // Initilize output, internal state and workspace quantities. if(!same_qp_struct) { X_.resize(N_); NACTSTORE_ = 0; IACTSTORE_.resize(N_+1); IACT_.resize(N_+1); UR_.resize(N_+1); ISTATE_.resize( QPKWIKNEW_CppDecl::qpkwiknew_listate(N_,M1_,M2_,M3_) ); LRW_ = QPKWIKNEW_CppDecl::qpkwiknew_lrw(N_,M1_,M2_,M3_); RW_.resize(LRW_); } // ///////////////////////////////////////////// // Setup a warm start form the input arguments // // Interestingly enough, QPKWIK sorts all of the // constraints according to scaled multiplier values // and mixes equality with inequality constriants. // It seems to me that you should start with equality // constraints first. WARM_ = 0; NACTSTORE_ = 0; if( m_eq ) { // Add equality constraints first since we know these will // be part of the active set. for( size_type j = 1; j <= m_eq; ++j ) { IACTSTORE_[NACTSTORE_] = 2*M1_ + 2*M2_ + j; ++NACTSTORE_; } } if( ( nu && nu->nz() ) || ( mu && mu->nz() ) ) { // Add inequality constraints const size_type nu_nz = nu ? nu->nz() : 0, mu_nz = mu ? mu->nz() : 0; // Combine all the multipliers for the bound and general inequality // constraints and sort them from the largest to the smallest. Hopefully // the constraints with the larger multiplier values will not be dropped // from the active set. SpVector gamma( nd + 1 + m_in , nu_nz + mu_nz ); typedef SpVector::element_type ele_t; if(nu && nu_nz) { VectorDenseEncap nu_de(*nu); DVectorSlice::const_iterator nu_itr = nu_de().begin(), nu_end = nu_de().end(); index_type i = 1; while( nu_itr != nu_end ) { for( ; *nu_itr == 0.0; ++nu_itr, ++i ); gamma.add_element(ele_t(i,*nu_itr)); ++nu_itr; ++i; } } if(mu && mu_nz) { VectorDenseEncap mu_de(*mu); DVectorSlice::const_iterator mu_itr = mu_de().begin(), mu_end = mu_de().end(); index_type i = 1; while( mu_itr != mu_end ) { for( ; *mu_itr == 0.0; ++mu_itr, ++i ); gamma.add_element(ele_t(i+nd,*mu_itr)); ++mu_itr; ++i; } } std::sort( gamma.begin(), gamma.end() , AbstractLinAlgPack::SortByDescendingAbsValue() ); // Now add the inequality constraints in decreasing order const SpVector::difference_type o = gamma.offset(); for( SpVector::const_iterator itr = gamma.begin(); itr != gamma.end(); ++itr ) { const size_type j = itr->index() + o; const value_type val = itr->value(); if( j <= nd ) { // Variable bound const size_type ibnd_i = IBND_INV_[j-1]; TEST_FOR_EXCEPT( !( ibnd_i ) ); IACTSTORE_[NACTSTORE_] = (val < 0.0 ? ibnd_i // lower bound (see IACT(*)) : M1_ + M2_ + ibnd_i // upper bound (see IACT(*)) ); ++NACTSTORE_; } else if( j <= nd + m_in ) { // General inequality constraint const size_type ibnd_i = IBND_INV_[j-1]; // offset into M1_ + ibnd_j TEST_FOR_EXCEPT( !( ibnd_i ) ); IACTSTORE_[NACTSTORE_] = (val < 0.0 ? ibnd_i // lower bound (see IACT(*)) : M1_ + M2_ + ibnd_i // upper bound (see IACT(*)) ); ++NACTSTORE_; } } } if( NACTSTORE_ > 0 ) WARM_ = 1; // ///////////////////////// // Call QPKWIK if( out && olevel > PRINT_NONE ) { *out << "\nCalling QPKWIK to solve QP problem ...\n"; } QPKWIKNEW_CppDecl::qpkwiknew( N_, M1_, M2_, M3_, &GRAD_(1), &UINV_AUG_(1,1), LDUINV_AUG_, &IBND_[0] ,&BL_(1), &BU_(1), &A_(1,1), LDA_, &YPY_(1), IYPY_, WARM_, NUMPARAM_, MAX_ITER_, &X_(1) ,&NACTSTORE_, &IACTSTORE_[0], &INF_, &NACT_, &IACT_[0], &UR_[0], &EXTRA_ ,&ITER_, &NUM_ADDS_, &NUM_DROPS_, &ISTATE_[0], LRW_, &RW_[0] ); // //////////////////////// // Map from QPKWIK output // eta *eta = EXTRA_; // d (VectorDenseMutableEncap(*d))() = X_(); // nu (simple variable bounds) and mu (general inequalities) if(nu) *nu = 0.0; if(mu) *mu = 0.0; // ToDo: Create VectorDenseMutableEncap views for faster access! {for(size_type i = 1; i <= NACT_; ++i) { size_type j = IACT_[i-1]; EConstraintType type = constraint_type(M1_,M2_,M3_,j); FortranTypes::f_int idc = constraint_index(M1_,M2_,M3_,&IBND_[0],type,j); switch(type) { case NU_L: nu->set_ele( idc , -UR_(i) ); break; case GAMA_L: mu->set_ele( IBND_[ M1_ + idc - 1 ], -UR_(i) ); break; case NU_U: nu->set_ele( idc, UR_(i)) ; break; case GAMA_U: mu->set_ele( IBND_[ M1_ + idc - 1 ], UR_(i) ); break; case LAMBDA: lambda->set_ele( idc, UR_(i) ); break; } }} // obj_d (This could be updated within QPKWIK in the future) if(obj_d) { // obj_d = g'*d + 1/2 * d' * G * g *obj_d = dot(g,*d) + 0.5 * transVtMtV(*d,G,BLAS_Cpp::no_trans,*d); } // Ed (This could be updated within QPKWIK in the future) if(Ed) { V_MtV( Ed, *E, trans_E, *d ); } // Fd (This could be updated within QPKWIK in the future) if(Fd) { V_MtV( Fd, *F, trans_F, *d ); } // Set the QP statistics QPSolverStats::ESolutionType solution_type; if( INF_ >= 0 ) { solution_type = QPSolverStats::OPTIMAL_SOLUTION; } else if( INF_ == -1 ) { // Infeasible constraints TEST_FOR_EXCEPTION( true, QPSolverRelaxed::Infeasible ,"QPSolverRelaxedQPKWIK::solve_qp(...) : Error, QP is infeasible" ); } else if( INF_ == -2 ) { // LRW too small TEST_FOR_EXCEPT( !( INF_ != -2 ) ); // Local programming error? } else if( INF_ == -3 ) { // Max iterations exceeded solution_type = QPSolverStats::DUAL_FEASIBLE_POINT; } else { TEST_FOR_EXCEPT(true); // Unknown return value! } qp_stats_.set_stats( solution_type, QPSolverStats::CONVEX ,ITER_, NUM_ADDS_, NUM_DROPS_ ,WARM_==1, *eta > 0.0 ); return qp_stats_.solution_type(); }
bool PostEvalNewPointBarrier_Step::do_step( Algorithm& _algo, poss_type step_poss, IterationPack::EDoStepType type ,poss_type assoc_step_poss ) { using Teuchos::dyn_cast; using IterationPack::print_algorithm_step; using AbstractLinAlgPack::inv_of_difference; using AbstractLinAlgPack::correct_upper_bound_multipliers; using AbstractLinAlgPack::correct_lower_bound_multipliers; using LinAlgOpPack::Vp_StV; NLPAlgo &algo = dyn_cast<NLPAlgo>(_algo); IpState &s = dyn_cast<IpState>(_algo.state()); NLP &nlp = algo.nlp(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); std::ostream& out = algo.track().journal_out(); if(!nlp.is_initialized()) nlp.initialize(algo.algo_cntr().check_results()); // print step header. if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( _algo, step_poss, type, assoc_step_poss, out ); } IterQuantityAccess<VectorMutable> &x_iq = s.x(); IterQuantityAccess<MatrixSymDiagStd> &Vl_iq = s.Vl(); IterQuantityAccess<MatrixSymDiagStd> &Vu_iq = s.Vu(); ///*********************************************************** // Calculate invXl = diag(1/(x-xl)) // and invXu = diag(1/(xu-x)) matrices ///*********************************************************** // get references to x, invXl, and invXu VectorMutable& x = x_iq.get_k(0); MatrixSymDiagStd& invXu = s.invXu().set_k(0); MatrixSymDiagStd& invXl = s.invXl().set_k(0); //std::cout << "xu=\n"; //nlp.xu().output(std::cout); inv_of_difference(1.0, nlp.xu(), x, &invXu.diag()); inv_of_difference(1.0, x, nlp.xl(), &invXl.diag()); //std::cout << "invXu=\v"; //invXu.output(std::cout); //std::cout << "\ninvXl=\v"; //invXl.output(std::cout); // Check for divide by zeros - using AbstractLinAlgPack::assert_print_nan_inf; assert_print_nan_inf(invXu.diag(), "invXu", true, &out); assert_print_nan_inf(invXl.diag(), "invXl", true, &out); // These should never go negative either - could be a useful check // Initialize Vu and Vl if necessary if ( /*!Vu_iq.updated_k(0) */ Vu_iq.last_updated() == IterQuantity::NONE_UPDATED ) { VectorMutable& vu = Vu_iq.set_k(0).diag(); vu = 0; Vp_StV(&vu, s.barrier_parameter().get_k(-1), invXu.diag()); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nInitialize Vu with barrier_parameter * invXu ...\n"; } } if ( /*!Vl_iq.updated_k(0) */ Vl_iq.last_updated() == IterQuantity::NONE_UPDATED ) { VectorMutable& vl = Vl_iq.set_k(0).diag(); vl = 0; Vp_StV(&vl, s.barrier_parameter().get_k(-1), invXl.diag()); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nInitialize Vl with barrier_parameter * invXl ...\n"; } } if (s.num_basis().updated_k(0)) { // Basis changed, reorder Vl and Vu if (Vu_iq.updated_k(-1)) { Vu_iq.set_k(0,-1); } if (Vl_iq.updated_k(-1)) { Vl_iq.set_k(0,-1); } VectorMutable& vu = Vu_iq.set_k(0).diag(); VectorMutable& vl = Vl_iq.set_k(0).diag(); s.P_var_last().permute( BLAS_Cpp::trans, &vu ); // Permute back to original order s.P_var_last().permute( BLAS_Cpp::trans, &vl ); // Permute back to original order if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\nx resorted vl and vu to the original order\n" << x; } s.P_var_current().permute( BLAS_Cpp::no_trans, &vu ); // Permute to new (current) order s.P_var_current().permute( BLAS_Cpp::no_trans, &vl ); // Permute to new (current) order if( (int)olevel >= (int)PRINT_VECTORS ) { out << "\nx resorted to new basis \n" << x; } } correct_upper_bound_multipliers(nlp.xu(), +NLP::infinite_bound(), &Vu_iq.get_k(0).diag()); correct_lower_bound_multipliers(nlp.xl(), -NLP::infinite_bound(), &Vl_iq.get_k(0).diag()); if( (int)olevel >= (int)PRINT_VECTORS ) { out << "x=\n" << s.x().get_k(0); out << "xl=\n" << nlp.xl(); out << "vl=\n" << s.Vl().get_k(0).diag(); out << "xu=\n" << nlp.xu(); out << "vu=\n" << s.Vu().get_k(0).diag(); } // Update general algorithm bound multipliers VectorMutable& v = s.nu().set_k(0); v = Vu_iq.get_k(0).diag(); Vp_StV(&v,-1.0,Vl_iq.get_k(0).diag()); // Print vector information if( static_cast<int>(olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "invXu_k.diag()=\n" << invXu.diag(); out << "invXl_k.diag()=\n" << invXl.diag(); out << "Vu_k.diag()=\n" << Vu_iq.get_k(0).diag(); out << "Vl_k.diag()=\n" << Vl_iq.get_k(0).diag(); out << "nu_k=\n" << s.nu().get_k(0); } return true; }
bool CalcReducedGradLagrangianStd_AddedStep::do_step( Algorithm& _algo, poss_type step_poss, IterationPack::EDoStepType type ,poss_type assoc_step_poss ) { using BLAS_Cpp::trans; using LinAlgOpPack::V_VpV; using LinAlgOpPack::V_MtV; using LinAlgOpPack::Vp_V; using LinAlgOpPack::Vp_MtV; NLPAlgo &algo = rsqp_algo(_algo); NLPAlgoState &s = algo.rsqp_state(); EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level(); EJournalOutputLevel ns_olevel = algo.algo_cntr().null_space_journal_output_level(); std::ostream& out = algo.track().journal_out(); // print step header. if( static_cast<int>(ns_olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { using IterationPack::print_algorithm_step; print_algorithm_step( algo, step_poss, type, assoc_step_poss, out ); } // Calculate: rGL = rGf + Z' * nu + Uz' * lambda(equ_undecomp) IterQuantityAccess<VectorMutable> &rGL_iq = s.rGL(), &nu_iq = s.nu(), &Gf_iq = s.Gf(); VectorMutable &rGL_k = rGL_iq.set_k(0); if( nu_iq.updated_k(0) && nu_iq.get_k(0).nz() > 0 ) { // Compute rGL = Z'*(Gf + nu) to reduce the effect of roundoff in this // catastropic cancelation const Vector &nu_k = nu_iq.get_k(0); VectorSpace::vec_mut_ptr_t tmp = nu_k.space().create_member(); if( (int)olevel >= (int)PRINT_VECTORS ) out << "\nnu_k = \n" << nu_k; V_VpV( tmp.get(), Gf_iq.get_k(0), nu_k ); if( (int)olevel >= (int)PRINT_VECTORS ) out << "\nGf_k+nu_k = \n" << *tmp; V_MtV( &rGL_k, s.Z().get_k(0), trans, *tmp ); if( (int)ns_olevel >= (int)PRINT_VECTORS ) out << "\nrGL_k = \n" << rGL_k; } else { rGL_k = s.rGf().get_k(0); } // ToDo: Add terms for undecomposed equalities and inequalities! // + Uz' * lambda(equ_undecomp) if( static_cast<int>(ns_olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n||rGL_k||inf = " << rGL_k.norm_inf() << "\n"; } if( static_cast<int>(ns_olevel) >= static_cast<int>(PRINT_VECTORS) ) { out << "\nrGL_k = \n" << rGL_k; } return true; }
bool ReducedHessianSecantUpdateLPBFGS_Strategy::perform_update( DVectorSlice* s_bfgs, DVectorSlice* y_bfgs, bool first_update ,std::ostream& out, EJournalOutputLevel olevel, NLPAlgo *algo, NLPAlgoState *s ,MatrixOp *rHL_k ) { using std::setw; using std::endl; using std::right; using Teuchos::dyn_cast; namespace rcp = MemMngPack; using Teuchos::RCP; using LinAlgOpPack::V_MtV; using DenseLinAlgPack::dot; using AbstractLinAlgPack::norm_inf; using AbstractLinAlgPack::transVtMtV; typedef ConstrainedOptPack::MatrixHessianSuperBasic MHSB_t; using Teuchos::Workspace; Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get(); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n*** (LPBFGS) Full limited memory BFGS to projected BFGS ...\n"; } #ifdef _WINDOWS MHSB_t &rHL_super = dynamic_cast<MHSB_t&>(*rHL_k); #else MHSB_t &rHL_super = dyn_cast<MHSB_t>(*rHL_k); #endif const size_type n = algo->nlp().n(), r = algo->nlp().r(), n_pz = n-r; bool do_projected_rHL_RR = false; // See if we still have a limited memory BFGS update matrix RCP<MatrixSymPosDefLBFGS> // We don't want this to be deleted until we are done with it lbfgs_rHL_RR = Teuchos::rcp_const_cast<MatrixSymPosDefLBFGS>( Teuchos::rcp_dynamic_cast<const MatrixSymPosDefLBFGS>(rHL_super.B_RR_ptr()) ); if( lbfgs_rHL_RR.get() && rHL_super.Q_R().is_identity() ) { // // We have a limited memory BFGS matrix and have not started projected BFGS updating // yet so lets determine if it is time to consider switching // // Check that the current update is sufficiently p.d. before we do anything const value_type sTy = dot(*s_bfgs,*y_bfgs), yTy = dot(*y_bfgs,*y_bfgs); if( !ConstrainedOptPack::BFGS_sTy_suff_p_d( *s_bfgs,*y_bfgs,&sTy , int(olevel) >= int(PRINT_ALGORITHM_STEPS) ? &out : NULL ) && !proj_bfgs_updater().bfgs_update().use_dampening() ) { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nWarning! use_damening == false so there is no way we can perform any" " kind of BFGS update (projected or not) so we will skip it!\n"; } quasi_newton_stats_(*s).set_k(0).set_updated_stats( QuasiNewtonStats::INDEF_SKIPED ); return true; } // Consider if we can even look at the active set yet. const bool consider_switch = lbfgs_rHL_RR->num_secant_updates() >= min_num_updates_proj_start(); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nnum_previous_updates = " << lbfgs_rHL_RR->num_secant_updates() << ( consider_switch ? " >= " : " < " ) << "min_num_updates_proj_start = " << min_num_updates_proj_start() << ( consider_switch ? "\nConsidering if we should switch to projected BFGS updating of superbasics ...\n" : "\nNot time to consider switching to projected BFGS updating of superbasics yet!" ); } if( consider_switch ) { // // Our job here is to determine if it is time to switch to projected projected // BFGS updating. // if( act_set_stats_(*s).updated_k(-1) ) { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nDetermining if projected BFGS updating of superbasics should begin ...\n"; } // Determine if the active set has calmed down enough const SpVector &nu_km1 = s->nu().get_k(-1); const SpVectorSlice nu_indep = nu_km1(s->var_indep()); const bool act_set_calmed_down = PBFGSPack::act_set_calmed_down( act_set_stats_(*s).get_k(-1) ,proj_bfgs_updater().act_set_frac_proj_start() ,olevel,out ), max_num_updates_exceeded = lbfgs_rHL_RR->m_bar() >= max_num_updates_proj_start(); do_projected_rHL_RR = act_set_calmed_down || max_num_updates_exceeded; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { if( act_set_calmed_down ) { out << "\nThe active set has calmed down enough so lets further consider switching to\n" << "projected BFGS updating of superbasic variables ...\n"; } else if( max_num_updates_exceeded ) { out << "\nThe active set has not calmed down enough but num_previous_updates = " << lbfgs_rHL_RR->m_bar() << " >= max_num_updates_proj_start = " << max_num_updates_proj_start() << "\nso we will further consider switching to projected BFGS updating of superbasic variables ...\n"; } else { out << "\nIt is not time to switch to projected BFGS so just keep performing full limited memory BFGS for now ...\n"; } } if( do_projected_rHL_RR ) { // // Determine the set of initially fixed and free independent variables. // typedef Workspace<size_type> i_x_t; typedef Workspace<ConstrainedOptPack::EBounds> bnd_t; i_x_t i_x_free(wss,n_pz); i_x_t i_x_fixed(wss,n_pz); bnd_t bnd_fixed(wss,n_pz); i_x_t l_x_fixed_sorted(wss,n_pz); size_type n_pz_X = 0, n_pz_R = 0; // rHL = rHL_scale * I value_type rHL_scale = sTy > 0.0 ? yTy/sTy : 1.0; if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nScaling for diagonal intitial rHL = rHL_scale*I, rHL_scale = " << rHL_scale << std::endl; } value_type sRTBRRsR = 0.0, sRTyR = 0.0, sXTBXXsX = 0.0, sXTyX = 0.0; // Get the elements in i_x_free[] for variables that are definitely free // and initialize s_R'*B_RR*s_R and s_R'*y_R PBFGSPack::init_i_x_free_sRTsR_sRTyR( nu_indep, *s_bfgs, *y_bfgs , &n_pz_R, &i_x_free[0], &sRTBRRsR, &sRTyR ); sRTBRRsR *= rHL_scale; Workspace<value_type> rHL_XX_diag_ws(wss,nu_indep.nz()); DVectorSlice rHL_XX_diag(&rHL_XX_diag_ws[0],rHL_XX_diag_ws.size()); rHL_XX_diag = rHL_scale; // Sort fixed variables according to |s_X(i)^2*B_XX(i,i)|/|sRTBRRsR| + |s_X(i)*y_X(i)|/|sRTyR| // and initialize s_X'*B_XX*s_X and s_X*y_X PBFGSPack::sort_fixed_max_cond_viol( nu_indep,*s_bfgs,*y_bfgs,rHL_XX_diag,sRTBRRsR,sRTyR ,&sXTBXXsX,&sXTyX,&l_x_fixed_sorted[0]); // Pick initial set of i_x_free[] and i_x_fixed[] (sorted!) PBFGSPack::choose_fixed_free( proj_bfgs_updater().project_error_tol() ,proj_bfgs_updater().super_basic_mult_drop_tol(),nu_indep ,*s_bfgs,*y_bfgs,rHL_XX_diag,&l_x_fixed_sorted[0] ,olevel,out,&sRTBRRsR,&sRTyR,&sXTBXXsX,&sXTyX ,&n_pz_X,&n_pz_R,&i_x_free[0],&i_x_fixed[0],&bnd_fixed[0] ); if( n_pz_R < n_pz ) { // // We are ready to transition to projected BFGS updating! // // Determine if we are be using dense or limited memory BFGS? const bool low_num_super_basics = n_pz_R <= num_superbasics_switch_dense(); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_BASIC_ALGORITHM_INFO) ) { out << "\nSwitching to projected BFGS updating ..." << "\nn_pz_R = " << n_pz_R << ( low_num_super_basics ? " <= " : " > " ) << " num_superbasics_switch_dense = " << num_superbasics_switch_dense() << ( low_num_super_basics ? "\nThere are not too many superbasic variables so use dense projected BFGS ...\n" : "\nThere are too many superbasic variables so use limited memory projected BFGS ...\n" ); } // Create new matrix to use for rHL_RR initialized to rHL_RR = rHL_scale*I RCP<MatrixSymSecant> rHL_RR = NULL; if( low_num_super_basics ) { rHL_RR = new MatrixSymPosDefCholFactor( NULL // Let it allocate its own memory ,NULL // ... ,n_pz // maximum size ,lbfgs_rHL_RR->maintain_original() ,lbfgs_rHL_RR->maintain_inverse() ); } else { rHL_RR = new MatrixSymPosDefLBFGS( n_pz, lbfgs_rHL_RR->m() ,lbfgs_rHL_RR->maintain_original() ,lbfgs_rHL_RR->maintain_inverse() ,lbfgs_rHL_RR->auto_rescaling() ); } rHL_RR->init_identity( n_pz_R, rHL_scale ); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ITERATION_QUANTITIES) ) { out << "\nrHL_RR after intialized to rHL_RR = rHL_scale*I but before performing current BFGS update:\nrHL_RR =\n" << dynamic_cast<MatrixOp&>(*rHL_RR); // I know this is okay! } // Initialize rHL_XX = rHL_scale*I #ifdef _WINDOWS MatrixSymInitDiag &rHL_XX = dynamic_cast<MatrixSymInitDiag&>( const_cast<MatrixSymOp&>(*rHL_super.B_XX_ptr())); #else MatrixSymInitDiag &rHL_XX = dyn_cast<MatrixSymInitDiag>( const_cast<MatrixSymOp&>(*rHL_super.B_XX_ptr())); #endif rHL_XX.init_identity( n_pz_X, rHL_scale ); // Reinitialize rHL rHL_super.initialize( n_pz, n_pz_R, &i_x_free[0], &i_x_fixed[0], &bnd_fixed[0] ,Teuchos::rcp_const_cast<const MatrixSymWithOpFactorized>( Teuchos::rcp_dynamic_cast<MatrixSymWithOpFactorized>(rHL_RR)) ,NULL,BLAS_Cpp::no_trans,rHL_super.B_XX_ptr() ); // // Perform the current BFGS update first // MatrixSymOp &rHL_RR_op = dynamic_cast<MatrixSymOp&>(*rHL_RR); const GenPermMatrixSlice &Q_R = rHL_super.Q_R(), &Q_X = rHL_super.Q_X(); // Get projected BFGS update vectors y_bfgs_R, s_bfgs_R Workspace<value_type> y_bfgs_R_ws(wss,Q_R.cols()), s_bfgs_R_ws(wss,Q_R.cols()), y_bfgs_X_ws(wss,Q_X.cols()), s_bfgs_X_ws(wss,Q_X.cols()); DVectorSlice y_bfgs_R(&y_bfgs_R_ws[0],y_bfgs_R_ws.size()); DVectorSlice s_bfgs_R(&s_bfgs_R_ws[0],s_bfgs_R_ws.size()); DVectorSlice y_bfgs_X(&y_bfgs_X_ws[0],y_bfgs_X_ws.size()); DVectorSlice s_bfgs_X(&s_bfgs_X_ws[0],s_bfgs_X_ws.size()); V_MtV( &y_bfgs_R, Q_R, BLAS_Cpp::trans, *y_bfgs ); // y_bfgs_R = Q_R'*y_bfgs V_MtV( &s_bfgs_R, Q_R, BLAS_Cpp::trans, *s_bfgs ); // s_bfgs_R = Q_R'*s_bfgs V_MtV( &y_bfgs_X, Q_X, BLAS_Cpp::trans, *y_bfgs ); // y_bfgs_X = Q_X'*y_bfgs V_MtV( &s_bfgs_X, Q_X, BLAS_Cpp::trans, *s_bfgs ); // s_bfgs_X = Q_X'*s_bfgs // Update rHL_RR if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nPerform current BFGS update on " << n_pz_R << " x " << n_pz_R << " projected " << "reduced Hessian for the superbasic variables where B = rHL_RR...\n"; } QuasiNewtonStats quasi_newton_stats; proj_bfgs_updater().bfgs_update().perform_update( &s_bfgs_R(),&y_bfgs_R(),false,out,olevel,algo->algo_cntr().check_results() ,&rHL_RR_op, &quasi_newton_stats ); // Perform previous updates if possible if( lbfgs_rHL_RR->m_bar() ) { const size_type num_add_updates = std::_MIN(num_add_recent_updates(),lbfgs_rHL_RR->m_bar()); if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nAdd the min(num_previous_updates,num_add_recent_updates) = min(" << lbfgs_rHL_RR->m_bar() << "," << num_add_recent_updates() << ") = " << num_add_updates << " most recent BFGS updates if possible ...\n"; } // Now add previous update vectors const value_type project_error_tol = proj_bfgs_updater().project_error_tol(); const DMatrixSlice S = lbfgs_rHL_RR->S(), Y = lbfgs_rHL_RR->Y(); size_type k = lbfgs_rHL_RR->k_bar(); // Location in S and Y of most recent update vectors for( size_type l = 1; l <= num_add_updates; ++l, --k ) { if(k == 0) k = lbfgs_rHL_RR->m_bar(); // see MatrixSymPosDefLBFGS // Check to see if this update satisfies the required conditions. // Start with the condition on s'*y since this are cheap to check. V_MtV( &s_bfgs_X(), Q_X, BLAS_Cpp::trans, S.col(k) ); // s_bfgs_X = Q_X'*s_bfgs V_MtV( &y_bfgs_X(), Q_X, BLAS_Cpp::trans, Y.col(k) ); // y_bfgs_X = Q_X'*y_bfgs sRTyR = dot( s_bfgs_R, y_bfgs_R ); sXTyX = dot( s_bfgs_X, y_bfgs_X ); bool sXTyX_cond = ::fabs(sXTyX/sRTyR) <= project_error_tol, do_update = sXTyX_cond, sXTBXXsX_cond = false; if( sXTyX_cond ) { // Check the second more expensive condition V_MtV( &s_bfgs_R(), Q_R, BLAS_Cpp::trans, S.col(k) ); // s_bfgs_R = Q_R'*s_bfgs V_MtV( &y_bfgs_R(), Q_R, BLAS_Cpp::trans, Y.col(k) ); // y_bfgs_R = Q_R'*y_bfgs sRTBRRsR = transVtMtV( s_bfgs_R, rHL_RR_op, BLAS_Cpp::no_trans, s_bfgs_R ); sXTBXXsX = rHL_scale * dot( s_bfgs_X, s_bfgs_X ); sXTBXXsX_cond = sXTBXXsX/sRTBRRsR <= project_error_tol; do_update = sXTBXXsX_cond && sXTyX_cond; } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n---------------------------------------------------------------------" << "\nprevious update " << l << "\n\nChecking projection error:\n" << "\n|s_X'*y_X|/|s_R'*y_R| = |" << sXTyX << "|/|" << sRTyR << "| = " << ::fabs(sXTyX/sRTyR) << ( sXTyX_cond ? " <= " : " > " ) << " project_error_tol = " << project_error_tol; if( sXTyX_cond ) { out << "\n(s_X'*rHL_XX*s_X/s_R'*rHL_RR*s_R) = (" << sXTBXXsX << ") = " << (sXTBXXsX/sRTBRRsR) << ( sXTBXXsX_cond ? " <= " : " > " ) << " project_error_tol = " << project_error_tol; } out << ( do_update ? "\n\nAttemping to add this previous update where B = rHL_RR ...\n" : "\n\nCan not add this previous update ...\n" ); } if( do_update ) { // ( rHL_RR, s_bfgs_R, y_bfgs_R ) -> rHL_RR (this should not throw an exception!) try { proj_bfgs_updater().bfgs_update().perform_update( &s_bfgs_R(),&y_bfgs_R(),false,out,olevel,algo->algo_cntr().check_results() ,&rHL_RR_op, &quasi_newton_stats ); } catch( const MatrixSymSecant::UpdateSkippedException& excpt ) { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nOops! The " << l << "th most recent BFGS update was rejected?:\n" << excpt.what() << std::endl; } } } } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\n---------------------------------------------------------------------\n"; } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ITERATION_QUANTITIES) ) { out << "\nrHL_RR after adding previous BFGS updates:\nrHL_BRR =\n" << dynamic_cast<MatrixOp&>(*rHL_RR); } } else { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nThere were no previous update vectors to add!\n"; } } if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ITERATION_QUANTITIES) ) { out << "\nFull rHL after complete reinitialization:\nrHL =\n" << *rHL_k; } quasi_newton_stats_(*s).set_k(0).set_updated_stats( QuasiNewtonStats::REINITIALIZED ); return true; } else { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nn_pz_R == n_pz = " << n_pz_R << ", No variables would be removed from " << "the superbasis so just keep on performing limited memory BFGS for now ...\n"; } do_projected_rHL_RR = false; } } } } // If we have not switched to PBFGS then just update the full limited memory BFGS matrix if(!do_projected_rHL_RR) { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nPerform current BFGS update on " << n_pz << " x " << n_pz << " full " << "limited memory reduced Hessian B = rHL ...\n"; } proj_bfgs_updater().bfgs_update().perform_update( s_bfgs,y_bfgs,first_update,out,olevel,algo->algo_cntr().check_results() ,lbfgs_rHL_RR.get() ,&quasi_newton_stats_(*s).set_k(0) ); return true; } } else { if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) { out << "\nWe have already switched to projected BFGS updating ...\n"; } } // // If we get here then we must have switched to // projected updating so lets just pass it on! // return proj_bfgs_updater().perform_update( s_bfgs,y_bfgs,first_update,out,olevel,algo,s,rHL_k); }
void MatrixSymPosDefLBFGS::secant_update( VectorMutable* s, VectorMutable* y, VectorMutable* Bs ) { using AbstractLinAlgPack::BFGS_sTy_suff_p_d; using AbstractLinAlgPack::dot; using LinAlgOpPack::V_MtV; using Teuchos::Workspace; Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get(); assert_initialized(); // Check skipping the BFGS update const value_type sTy = dot(*s,*y); std::ostringstream omsg; if( !BFGS_sTy_suff_p_d(*s,*y,&sTy,&omsg,"MatrixSymPosDefLBFGS::secant_update(...)" ) ) { throw UpdateSkippedException( omsg.str() ); } try { // Update counters if( m_bar_ == m_ ) { // We are at the end of the storage so remove the oldest stored update // and move updates to make room for the new update. This has to be done for the // the matrix to behave properly {for( size_type k = 1; k <= m_-1; ++k ) { S_->col(k) = S_->col(k+1); // Shift S.col() to the left Y_->col(k) = Y_->col(k+1); // Shift Y.col() to the left STY_.col(k)(1,m_-1) = STY_.col(k+1)(2,m_); // Move submatrix STY(2,m-1,2,m-1) up and left STSYTY_.col(k)(k+1,m_) = STSYTY_.col(k+1)(k+2,m_+1); // Move triangular submatrix STS(2,m-1,2,m-1) up and left STSYTY_.col(k+1)(1,k) = STSYTY_.col(k+2)(2,k+1); // Move triangular submatrix YTY(2,m-1,2,m-1) up and left }} // ToDo: Create an abstract interface, call it MultiVectorShiftVecs, to rearrange S and Y all at once. // This will be important for parallel performance. } else { m_bar_++; } // Set the update vectors *S_->col(m_bar_) = *s; *Y_->col(m_bar_) = *y; // ///////////////////////////////////////////////////////////////////////////////////// // Update S'Y // // Update the row and column m_bar // // S'Y = // // [ s(1)'*y(1) ... s(1)'*y(m_bar) ... s(1)'*y(m_bar) ] // [ . . . ] row // [ s(m_bar)'*y(1) ... s(m_bar)'*y(m_bar) ... s(m_bar)'*y(m_bar) ] m_bar // [ . . . ] // [ s(m_bar)'*y(1) ... s(m_bar)'*y(m_bar) ... s(m_bar)'*y(m_bar) ] // // col m_bar // // Therefore we set: // (S'Y)(:,m_bar) = S'*y(m_bar) // (S'Y)(m_bar,:) = s(m_bar)'*Y const multi_vec_ptr_t S = this->S(), Y = this->Y(); VectorSpace::vec_mut_ptr_t t = S->space_rows().create_member(); // temporary workspace // (S'Y)(:,m_bar) = S'*y(m_bar) V_MtV( t.get(), *S, BLAS_Cpp::trans, *y ); STY_.col(m_bar_)(1,m_bar_) = VectorDenseEncap(*t)(); // (S'Y)(m_bar,:)' = Y'*s(m_bar) V_MtV( t.get(), *Y, BLAS_Cpp::trans, *s ); STY_.row(m_bar_)(1,m_bar_) = VectorDenseEncap(*t)(); // ///////////////////////////////////////////////////////////////// // Update S'S // // S'S = // // [ s(1)'*s(1) ... symmetric symmetric ] // [ . . . ] row // [ s(m_bar)'*s(1) ... s(m_bar)'*s(m_bar) ... symmetric ] m_bar // [ . . . ] // [ s(m_bar)'*s(1) ... s(m_bar)'*s(m_bar) ... s(m_bar)'*s(m_bar) ] // // col m_bar // // Here we will update the lower triangular part of S'S. To do this we // only need to compute: // t = S'*s(m_bar) = { s(m_bar)' * [ s(1),..,s(m_bar),..,s(m_bar) ] }' // then set the appropriate rows and columns of S'S. Workspace<value_type> work_ws(wss,m_bar_); DVectorSlice work(&work_ws[0],work_ws.size()); // work = S'*s(m_bar) V_MtV( t.get(), *S, BLAS_Cpp::trans, *s ); work = VectorDenseEncap(*t)(); // Set row elements STSYTY_.row(m_bar_+1)(1,m_bar_) = work; // Set column elements STSYTY_.col(m_bar_)(m_bar_+1,m_bar_+1) = work(m_bar_,m_bar_); // ///////////////////////////////////////////////////////////////////////////////////// // Update Y'Y // // Update the row and column m_bar // // Y'Y = // // [ y(1)'*y(1) ... y(1)'*y(m_bar) ... y(1)'*y(m_bar) ] // [ . . . ] row // [ symmetric ... y(m_bar)'*y(m_bar) ... y(m_bar)'*y(m_bar) ] m_bar // [ . . . ] // [ symmetric ... symmetric ... y(m_bar)'*y(m_bar) ] // // col m_bar // // Here we will update the upper triangular part of Y'Y. To do this we // only need to compute: // t = Y'*y(m_bar) = { y(m_bar)' * [ y(1),..,y(m_bar),..,y(m_bar) ] }' // then set the appropriate rows and columns of Y'Y. // work = Y'*y(m_bar) V_MtV( t.get(), *Y, BLAS_Cpp::trans, *y ); work = VectorDenseEncap(*t)(); // Set row elements STSYTY_.col(m_bar_+1)(1,m_bar_) = work; // Set column elements STSYTY_.row(m_bar_)(m_bar_+1,m_bar_+1) = work(m_bar_,m_bar_); // ///////////////////////////// // Update gamma_k // gamma_k = s'*y / y'*y if(auto_rescaling_) gamma_k_ = STY_(m_bar_,m_bar_) / STSYTY_(m_bar_,m_bar_+1); // We do not initially update Q unless we have to form a matrix-vector // product later. Q_updated_ = false; num_secant_updates_++; } // end try catch(...) { // If we throw any exception the we should make the matrix uninitialized // so that we do not leave this object in an inconsistant state. n_ = 0; throw; } }
void MatrixSymPosDefLBFGS::V_InvMtV( VectorMutable* y, BLAS_Cpp::Transp trans_rhs1 , const Vector& x ) const { using AbstractLinAlgPack::Vp_StMtV; using DenseLinAlgPack::V_InvMtV; using LinAlgOpPack::V_mV; using LinAlgOpPack::V_StV; using LinAlgOpPack::Vp_V; using LinAlgOpPack::V_MtV; using LinAlgOpPack::V_StMtV; using LinAlgOpPack::Vp_MtV; using DenseLinAlgPack::Vp_StMtV; typedef VectorDenseEncap vde; typedef VectorDenseMutableEncap vdme; using Teuchos::Workspace; Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get(); assert_initialized(); TEUCHOS_TEST_FOR_EXCEPT( !( inverse_is_updated_ ) ); // For now just always update // y = inv(Bk) * x = Hk * x // // = gk*x + [S gk*Y] * [ inv(R')*(D+gk*Y'Y)*inv(R) -inv(R') ] * [ S' ] * x // [ -inv(R) 0 ] [ gk*Y' ] // // Perform in the following (in order): // // y = gk*x // // t1 = [ S'*x ] <: R^(2*m) // [ gk*Y'*x ] // // t2 = inv(R) * t1(1:m) <: R^(m) // // t3 = - inv(R') * t1(m+1,2*m) <: R^(m) // // t4 = gk * Y'Y * t2 <: R^(m) // // t4 += D*t2 // // t5 = inv(R') * t4 <: R^(m) // // t5 += t3 // // y += S*t5 // // y += -gk*Y*t2 // y = gk*x V_StV( y, gamma_k_, x ); const size_type mb = m_bar_; if( !mb ) return; // No updates have been performed. const multi_vec_ptr_t S = this->S(), Y = this->Y(); // Get workspace Workspace<value_type> t1_ws(wss,2*mb); DVectorSlice t1(&t1_ws[0],t1_ws.size()); Workspace<value_type> t2_ws(wss,mb); DVectorSlice t2(&t2_ws[0],t2_ws.size()); Workspace<value_type> t3_ws(wss,mb); DVectorSlice t3(&t3_ws[0],t3_ws.size()); Workspace<value_type> t4_ws(wss,mb); DVectorSlice t4(&t4_ws[0],t4_ws.size()); Workspace<value_type> t5_ws(wss,mb); DVectorSlice t5(&t5_ws[0],t5_ws.size()); VectorSpace::vec_mut_ptr_t t = S->space_rows().create_member(); const DMatrixSliceTri &R = this->R(); const DMatrixSliceSym &YTY = this->YTY(); // t1 = [ S'*x ] // [ gk*Y'*x ] V_MtV( t.get(), *S, BLAS_Cpp::trans, x ); t1(1,mb) = vde(*t)(); V_StMtV( t.get(), gamma_k_, *Y, BLAS_Cpp::trans, x ); t1(mb+1,2*mb) = vde(*t)(); // t2 = inv(R) * t1(1:m) V_InvMtV( &t2, R, BLAS_Cpp::no_trans, t1(1,mb) ); // t3 = - inv(R') * t1(m+1,2*m) V_mV( &t3, t1(mb+1,2*mb) ); V_InvMtV( &t3, R, BLAS_Cpp::trans, t3 ); // t4 = gk * Y'Y * t2 V_StMtV( &t4, gamma_k_, YTY, BLAS_Cpp::no_trans, t2 ); // t4 += D*t2 Vp_DtV( &t4, t2 ); // t5 = inv(R') * t4 V_InvMtV( &t5, R, BLAS_Cpp::trans, t4 ); // t5 += t3 Vp_V( &t5, t3 ); // y += S*t5 (vdme(*t)() = t5); Vp_MtV( y, *S, BLAS_Cpp::no_trans, *t ); // y += -gk*Y*t2 (vdme(*t)() = t2); Vp_StMtV( y, -gamma_k_, *Y, BLAS_Cpp::no_trans, *t ); }
void MatrixSymPosDefLBFGS::Vp_StMtV( VectorMutable* y, value_type alpha, BLAS_Cpp::Transp trans_rhs1 , const Vector& x, value_type beta ) const { using AbstractLinAlgPack::Vt_S; using AbstractLinAlgPack::Vp_StV; using AbstractLinAlgPack::Vp_StMtV; using LinAlgOpPack::V_StMtV; using LinAlgOpPack::V_MtV; typedef VectorDenseEncap vde; typedef VectorDenseMutableEncap vdme; using Teuchos::Workspace; Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get(); assert_initialized(); TEUCHOS_TEST_FOR_EXCEPT( !( original_is_updated_ ) ); // For now just always update // y = b*y + Bk * x // // y = b*y + (1/gk)*x - [ (1/gk)*S Y ] * inv(Q) * [ (1/gk)*S' ] * x // [ Y' ] // Perform the following operations (in order): // // y = b*y // // y += (1/gk)*x // // t1 = [ (1/gk)*S'*x ] <: R^(2*m) // [ Y'*x ] // // t2 = inv(Q) * t1 <: R^(2*m) // // y += -(1/gk) * S * t2(1:m) // // y += -1.0 * Y * t2(m+1,2m) const value_type invgk = 1.0 / gamma_k_; // y = b*y Vt_S( y, beta ); // y += (1/gk)*x Vp_StV( y, invgk, x ); if( !m_bar_ ) return; // No updates have been added yet. const multi_vec_ptr_t S = this->S(), Y = this->Y(); // Get workspace const size_type mb = m_bar_; Workspace<value_type> t1_ws(wss,2*mb); DVectorSlice t1(&t1_ws[0],t1_ws.size()); Workspace<value_type> t2_ws(wss,2*mb); DVectorSlice t2(&t2_ws[0],t2_ws.size()); VectorSpace::vec_mut_ptr_t t = S->space_rows().create_member(); // t1 = [ (1/gk)*S'*x ] // [ Y'*x ] V_StMtV( t.get(), invgk, *S, BLAS_Cpp::trans, x ); t1(1,mb) = vde(*t)(); V_MtV( t.get(), *Y, BLAS_Cpp::trans, x ); t1(mb+1,2*mb) = vde(*t)(); // t2 = inv(Q) * t1 V_invQtV( &t2, t1 ); // y += -(1/gk) * S * t2(1:m) (vdme(*t)() = t2(1,mb)); Vp_StMtV( y, -invgk, *S, BLAS_Cpp::no_trans, *t ); // y += -1.0 * Y * t2(m+1,2m (vdme(*t)() = t2(mb+1,2*mb)); Vp_StMtV( y, -1.0, *Y, BLAS_Cpp::no_trans, *t ); }
bool MatrixOpNonsingTester::test_matrix( const MatrixOpNonsing &M ,const char M_name[] ,std::ostream *out ) { namespace rcp = MemMngPack; using BLAS_Cpp::no_trans; using BLAS_Cpp::trans; using BLAS_Cpp::left; using BLAS_Cpp::right; using AbstractLinAlgPack::sum; using AbstractLinAlgPack::dot; using AbstractLinAlgPack::Vp_StV; using AbstractLinAlgPack::assert_print_nan_inf; using AbstractLinAlgPack::random_vector; using LinAlgOpPack::V_StMtV; using LinAlgOpPack::V_MtV; using LinAlgOpPack::V_StV; using LinAlgOpPack::V_VpV; using LinAlgOpPack::Vp_V; // ToDo: Check the preconditions bool success = true, result, lresult; const value_type rand_y_l = -1.0, rand_y_u = 1.0, small_num = ::pow(std::numeric_limits<value_type>::epsilon(),0.25), alpha = 2.0; // // Perform the tests // if(out && print_tests() >= PRINT_BASIC) *out << "\nCheck: alpha*op(op(inv("<<M_name<<"))*op("<<M_name<<"))*v == alpha*v ..."; if(out && print_tests() > PRINT_BASIC) *out << std::endl; VectorSpace::vec_mut_ptr_t v_c1 = M.space_cols().create_member(), v_c2 = M.space_cols().create_member(), v_r1 = M.space_rows().create_member(), v_r2 = M.space_rows().create_member(); // Side of the matrix inverse const BLAS_Cpp::Side a_side[2] = { BLAS_Cpp::left, BLAS_Cpp::right }; // If the matrices are transposed or not const BLAS_Cpp::Transp a_trans[2] = { BLAS_Cpp::no_trans, BLAS_Cpp::trans }; for( int side_i = 0; side_i < 2; ++side_i ) { for( int trans_i = 0; trans_i < 2; ++trans_i ) { const BLAS_Cpp::Side t_side = a_side[side_i]; const BLAS_Cpp::Transp t_trans = a_trans[trans_i]; if(out && print_tests() >= PRINT_MORE) *out << "\n" << side_i+1 << "." << trans_i+1 << ") " << "Check: (t2 = "<<(t_side==left?"inv(":"alpha * ")<< M_name<<(t_trans==trans?"\'":"")<<(t_side==left?")":"") << " * (t1 = "<<(t_side==right?"inv(":"alpha * ")<<M_name<<(t_trans==trans?"\'":"")<<(t_side==right?")":"") << " * v)) == alpha * v ..."; if(out && print_tests() > PRINT_MORE) *out << std::endl; result = true; VectorMutable *v = NULL, *t1 = NULL, *t2 = NULL; if( (t_side == left && t_trans == no_trans) || (t_side == right && t_trans == trans) ) { // (inv(R)*R*v or R'*inv(R')*v v = v_r1.get(); t1 = v_c1.get(); t2 = v_r2.get(); } else { // (inv(R')*R'*v or R*inv(R)*v v = v_c1.get(); t1 = v_r1.get(); t2 = v_c2.get(); } for( int k = 1; k <= num_random_tests(); ++k ) { lresult = true; random_vector( rand_y_l, rand_y_u, v ); if(out && print_tests() >= PRINT_ALL) { *out << "\n"<<side_i+1<<"."<<trans_i+1<<"."<<k<<") random vector " << k << " ( ||v||_1 / n = " << (v->norm_1() / v->dim()) << " )\n"; if(dump_all() && print_tests() >= PRINT_ALL) *out << "\nv =\n" << *v; } // t1 if( t_side == right ) { // t1 = inv(op(M))*v V_InvMtV( t1, M, t_trans, *v ); } else { // t1 = alpha*op(M)*v V_StMtV( t1, alpha, M, t_trans, *v ); } // t2 if( t_side == left ) { // t2 = inv(op(M))*t1 V_InvMtV( t2, M, t_trans, *t1 ); } else { // t2 = alpha*op(M)*t1 V_StMtV( t2, alpha, M, t_trans, *t1 ); } const value_type sum_t2 = sum(*t2), sum_av = alpha*sum(*v); assert_print_nan_inf(sum_t2, "sum(t2)",true,out); assert_print_nan_inf(sum_av, "sum(alpha*t1)",true,out); const value_type calc_err = ::fabs( ( sum_av - sum_t2 ) /( ::fabs(sum_av) + ::fabs(sum_t2) + small_num ) ); if(out && print_tests() >= PRINT_ALL) *out << "\nrel_err(sum(alpha*v),sum(t2)) = " << "rel_err(" << sum_av << "," << sum_t2 << ") = " << calc_err << std::endl; if( calc_err >= warning_tol() ) { if(out && print_tests() >= PRINT_ALL) *out << std::endl << ( calc_err >= error_tol() ? "Error" : "Warning" ) << ", rel_err(sum(alpha*v),sum(t2)) = " << "rel_err(" << sum_av << "," << sum_t2 << ") = " << calc_err << " exceeded " << ( calc_err >= error_tol() ? "error_tol" : "warning_tol" ) << " = " << ( calc_err >= error_tol() ? error_tol() : warning_tol() ) << std::endl; if(calc_err >= error_tol()) { if(dump_all() && print_tests() >= PRINT_ALL) { *out << "\nalpha = " << alpha << std::endl; *out << "\nv =\n" << *v; *out << "\nt1 =\n" << *t2; *out << "\nt2 =\n" << *t2; } lresult = false; } } if(!lresult) result = false; } if(!result) success = false; if( out && print_tests() == PRINT_MORE ) *out << " : " << ( result ? "passed" : "failed" ) << std::endl; } } if( out && print_tests() == PRINT_BASIC ) *out << " : " << ( success ? "passed" : "failed" ); return success; }