// Run one step of nonlinear CG. virtual void run( Vector<Real> &s , const Vector<Real> &g, const Vector<Real> &x, Objective<Real> &obj ) { // Initialize vector storage if ( state_->iter == 0 ) { if ( state_->nlcg_type != NONLINEARCG_FLETCHER_REEVES && state_->nlcg_type != NONLINEARCG_FLETCHER_CONJDESC ) { y_ = g.clone(); } if ( state_->nlcg_type == NONLINEARCG_HAGAR_ZHANG || state_->nlcg_type == NONLINEARCG_OREN_LUENBERGER ) { yd_ = g.clone(); } } s.set(g.dual()); if ((state_->iter % state_->restart) != 0) { Real beta = 0.0; switch(state_->nlcg_type) { case NONLINEARCG_HESTENES_STIEFEL: { y_->set(g); y_->axpy(-1.0, *(state_->grad[0])); beta = - g.dot(*y_) / (state_->pstep[0]->dot(y_->dual())); beta = std::max(beta, 0.0); break; } case NONLINEARCG_FLETCHER_REEVES: { beta = g.dot(g) / (state_->grad[0])->dot(*(state_->grad[0])); break; } case NONLINEARCG_DANIEL: { Real htol = 0.0; obj.hessVec( *y_, *(state_->pstep[0]), x, htol ); beta = - g.dot(*y_) / (state_->pstep[0])->dot(y_->dual()); beta = std::max(beta, 0.0); break; } case NONLINEARCG_POLAK_RIBIERE: { y_->set(g); y_->axpy(-1.0, *(state_->grad[0])); beta = g.dot(*y_) / (state_->grad[0])->dot(*(state_->grad[0])); beta = std::max(beta, 0.0); break; } case NONLINEARCG_FLETCHER_CONJDESC: { beta = g.dot(g) / (state_->pstep[0])->dot((state_->grad[0])->dual()); break; } case NONLINEARCG_LIU_STOREY: { y_->set(g); y_->axpy(-1.0, *(state_->grad[0])); beta = g.dot(*y_) / (state_->pstep[0])->dot((state_->grad[0])->dual()); //beta = std::max(beta, 0.0); // Is this needed? May need research. break; } case NONLINEARCG_DAI_YUAN: { y_->set(g); y_->axpy(-1.0, *(state_->grad[0])); beta = - g.dot(g) / (state_->pstep[0])->dot(y_->dual()); break; } case NONLINEARCG_HAGAR_ZHANG: { Real eta_0 = 1e-2; y_->set(g); y_->axpy(-1.0, *(state_->grad[0])); yd_->set(*y_); Real mult = 2.0 * ( y_->dot(*y_) / (state_->pstep[0])->dot(y_->dual()) ); yd_->axpy(-mult, (state_->pstep[0])->dual()); beta = - yd_->dot(g) / (state_->pstep[0])->dot(y_->dual()); Real eta = -1.0 / ((state_->pstep[0])->norm()*std::min(eta_0,(state_->grad[0])->norm())); beta = std::max(beta, eta); break; } case NONLINEARCG_OREN_LUENBERGER: { Real eta_0 = 1e-2; y_->set(g); y_->axpy(-1.0, *(state_->grad[0])); yd_->set(*y_); Real mult = ( y_->dot(*y_) / (state_->pstep[0])->dot(y_->dual()) ); yd_->axpy(-mult, (state_->pstep[0])->dual()); beta = - yd_->dot(g) / (state_->pstep[0])->dot(y_->dual()); Real eta = -1.0 / ((state_->pstep[0])->norm()*std::min(eta_0,(state_->grad[0])->norm())); beta = std::max(beta, eta); break; } default: TEUCHOS_TEST_FOR_EXCEPTION(!(isValidNonlinearCG(state_->nlcg_type)), std::invalid_argument, ">>> ERROR (ROL_NonlinearCG.hpp): Invalid nonlinear CG type in the 'run' method!"); } s.axpy(beta, *(state_->pstep[0])); } // Update storage. if (state_->iter == 0) { (state_->grad[0]) = g.clone(); (state_->pstep[0]) = s.clone(); } (state_->grad[0])->set(g); (state_->pstep[0])->set(s); state_->iter++; }
/** \brief Compute step. Given \f$x_k\f$, this function first builds the primal-dual active sets \f$\mathcal{A}_k^-\f$ and \f$\mathcal{A}_k^+\f$. Next, it uses CR to compute the inactive components of the step by solving \f[ \nabla^2 f(x_k)_{\mathcal{I}_k,\mathcal{I}_k}(s_k)_{\mathcal{I}_k} = -\nabla f(x_k)_{\mathcal{I}_k} -\nabla^2 f(x_k)_{\mathcal{I}_k,\mathcal{A}_k} (s_k)_{\mathcal{A}_k}. \f] Finally, it updates the active components of the dual variables as \f[ \lambda_{k+1} = -\nabla f(x_k)_{\mathcal{A}_k} -(\nabla^2 f(x_k) s_k)_{\mathcal{A}_k}. \f] @param[out] s is the step computed via PDAS @param[in] x is the current iterate @param[in] obj is the objective function @param[in] con are the bound constraints @param[in] algo_state is the current state of the algorithm */ void compute( Vector<Real> &s, const Vector<Real> &x, Objective<Real> &obj, BoundConstraint<Real> &con, AlgorithmState<Real> &algo_state ) { Teuchos::RCP<StepState<Real> > step_state = Step<Real>::getState(); s.zero(); x0_->set(x); res_->set(*(step_state->gradientVec)); for ( iter_ = 0; iter_ < maxit_; iter_++ ) { /********************************************************************/ // MODIFY ITERATE VECTOR TO CHECK ACTIVE SET /********************************************************************/ xlam_->set(*x0_); // xlam = x0 xlam_->axpy(scale_,*(lambda_)); // xlam = x0 + c*lambda /********************************************************************/ // PROJECT x ONTO PRIMAL DUAL FEASIBLE SET /********************************************************************/ As_->zero(); // As = 0 con.setVectorToUpperBound(*xbnd_); // xbnd = u xbnd_->axpy(-1.0,x); // xbnd = u - x xtmp_->set(*xbnd_); // tmp = u - x con.pruneUpperActive(*xtmp_,*xlam_,neps_); // tmp = I(u - x) xbnd_->axpy(-1.0,*xtmp_); // xbnd = A(u - x) As_->plus(*xbnd_); // As += A(u - x) con.setVectorToLowerBound(*xbnd_); // xbnd = l xbnd_->axpy(-1.0,x); // xbnd = l - x xtmp_->set(*xbnd_); // tmp = l - x con.pruneLowerActive(*xtmp_,*xlam_,neps_); // tmp = I(l - x) xbnd_->axpy(-1.0,*xtmp_); // xbnd = A(l - x) As_->plus(*xbnd_); // As += A(l - x) /********************************************************************/ // APPLY HESSIAN TO ACTIVE COMPONENTS OF s AND REMOVE INACTIVE /********************************************************************/ itol_ = std::sqrt(ROL_EPSILON); if ( useSecantHessVec_ && secant_ != Teuchos::null ) { // IHAs = H*As secant_->applyB(*gtmp_,*As_,x); } else { obj.hessVec(*gtmp_,*As_,x,itol_); } con.pruneActive(*gtmp_,*xlam_,neps_); // IHAs = I(H*As) /********************************************************************/ // SEPARATE ACTIVE AND INACTIVE COMPONENTS OF THE GRADIENT /********************************************************************/ rtmp_->set(*(step_state->gradientVec)); // Inactive components con.pruneActive(*rtmp_,*xlam_,neps_); Ag_->set(*(step_state->gradientVec)); // Active components Ag_->axpy(-1.0,*rtmp_); /********************************************************************/ // SOLVE REDUCED NEWTON SYSTEM /********************************************************************/ rtmp_->plus(*gtmp_); rtmp_->scale(-1.0); // rhs = -Ig - I(H*As) s.zero(); if ( rtmp_->norm() > 0.0 ) { //solve(s,*rtmp_,*xlam_,x,obj,con); // Call conjugate residuals krylov_->run(s,*hessian_,*rtmp_,*precond_,iterCR_,flagCR_); con.pruneActive(s,*xlam_,neps_); // s <- Is } s.plus(*As_); // s = Is + As /********************************************************************/ // UPDATE MULTIPLIER /********************************************************************/ if ( useSecantHessVec_ && secant_ != Teuchos::null ) { secant_->applyB(*rtmp_,s,x); } else { obj.hessVec(*rtmp_,s,x,itol_); } gtmp_->set(*rtmp_); con.pruneActive(*gtmp_,*xlam_,neps_); lambda_->set(*rtmp_); lambda_->axpy(-1.0,*gtmp_); lambda_->plus(*Ag_); lambda_->scale(-1.0); /********************************************************************/ // UPDATE STEP /********************************************************************/ x0_->set(x); x0_->plus(s); res_->set(*(step_state->gradientVec)); res_->plus(*rtmp_); // Compute criticality measure xtmp_->set(*x0_); xtmp_->axpy(-1.0,res_->dual()); con.project(*xtmp_); xtmp_->axpy(-1.0,*x0_); // std::cout << s.norm() << " " // << tmp->norm() << " " // << res_->norm() << " " // << lambda_->norm() << " " // << flagCR_ << " " // << iterCR_ << "\n"; if ( xtmp_->norm() < gtol_*algo_state.gnorm ) { flag_ = 0; break; } if ( s.norm() < stol_*x.norm() ) { flag_ = 2; break; } } if ( iter_ == maxit_ ) { flag_ = 1; } else { iter_++; } }