44 #ifndef OPTIPACK_NONLINEAR_CG_DEF_HPP
45 #define OPTIPACK_NONLINEAR_CG_DEF_HPP
50 #include "OptiPack_UnconstrainedOptMeritFunc1D.hpp"
51 #include "Thyra_ModelEvaluatorHelpers.hpp"
52 #include "Thyra_VectorStdOps.hpp"
53 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
54 #include "Teuchos_StandardParameterEntryValidators.hpp"
55 #include "Teuchos_Tuple.hpp"
61 template<
typename Scalar>
62 RCP<Teuchos::ParameterEntryValidator>
69 template<
typename Scalar>
86 template<
typename Scalar>
90 const int responseIndex,
95 model_ = model.assert_not_null();
96 paramIndex_ = paramIndex;
97 responseIndex_ = responseIndex;
98 linesearch_ = linesearch.assert_not_null();
102 template<
typename Scalar>
109 template<
typename Scalar>
117 template<
typename Scalar>
120 return alpha_reinit_;
124 template<
typename Scalar>
127 return and_conv_tests_;
131 template<
typename Scalar>
138 template<
typename Scalar>
145 template<
typename Scalar>
149 return g_reduct_tol_;
153 template<
typename Scalar>
161 template<
typename Scalar>
172 template<
typename Scalar>
177 namespace NCGU = NonlinearCGUtils;
178 using Teuchos::getParameter;
179 using Teuchos::getIntegralValue;
185 minIters_ = getParameter<int>(*paramList, NCGU::minIters_name);
186 maxIters_ = getParameter<int>(*paramList, NCGU::maxIters_name);
191 TEUCHOS_ASSERT_INEQUALITY( minIters_, >=, 0 );
192 TEUCHOS_ASSERT_INEQUALITY( minIters_, <, maxIters_ );
193 TEUCHOS_ASSERT_INEQUALITY( g_reduct_tol_, >=, SMT::zero() );
194 TEUCHOS_ASSERT_INEQUALITY( g_grad_tol_, >=, SMT::zero() );
195 TEUCHOS_ASSERT_INEQUALITY( g_mag_, >, SMT::zero() );
196 Teuchos::readVerboseObjectSublist(&*paramList,
this);
197 setMyParamList(paramList);
201 template<
typename Scalar>
205 using Teuchos::tuple;
206 namespace NCGU = NonlinearCGUtils;
211 solverType_validator_ =
212 Teuchos::stringToIntegralParameterEntryValidator<NCGU::ESolverTypes>(
220 "Fletcher-Reeves Method",
221 "Polak-Ribiere Method",
222 "Fletcher-Reeves Polak-Ribiere Hybrid Method",
223 "Hestenes-Stiefel Method"
225 tuple<NCGU::ESolverTypes>(
234 "Set the type of nonlinear CG solver algorithm to use.",
235 solverType_validator_ );
239 pl->
set( NCGU::minIters_name, NCGU::minIters_default );
240 pl->
set( NCGU::maxIters_name, NCGU::maxIters_default );
244 Teuchos::setupVerboseObjectSublist(&*pl);
255 template<
typename Scalar>
258 const Ptr<Thyra::VectorBase<Scalar> > &p_inout,
272 using Teuchos::tuple;
273 using Teuchos::rcpFromPtr;
274 using Teuchos::optInArg;
275 using Teuchos::inOutArg;
276 using GlobiPack::computeValue;
278 using Thyra::VectorSpaceBase;
279 using Thyra::VectorBase;
280 using Thyra::MultiVectorBase;
281 using Thyra::scalarProd;
282 using Thyra::createMember;
283 using Thyra::createMembers;
284 using Thyra::get_ele;
288 using Thyra::eval_g_DgDp;
289 typedef Thyra::Ordinal
Ordinal;
290 typedef Thyra::ModelEvaluatorBase MEB;
291 namespace NCGU = NonlinearCGUtils;
301 linesearch_->setOStream(out);
305 const bool compute_beta_PR =
319 pointEvaluator = defaultPolyLineSearchPointEvaluator<Scalar>();
322 meritFunc = unconstrainedOptMeritFunc1D<Scalar>(
323 model_, paramIndex_, responseIndex_ );
326 p_space = model_->get_p_space(paramIndex_),
327 g_space = model_->get_g_space(responseIndex_);
331 p_k = rcpFromPtr(p_inout),
332 p_kp1 = createMember(p_space),
333 g_vec = createMember(g_space),
334 g_grad_k = createMember(p_space),
335 d_k = createMember(p_space),
336 g_grad_k_diff_km1 = null;
343 alpha_km1 = SMT::zero(),
345 g_grad_km1_inner_g_grad_km1 = SMT::zero();
347 if (compute_beta_PR || compute_beta_HS) {
348 g_grad_km1 = createMember(p_space);
349 g_grad_k_diff_km1 = createMember(p_space);
352 if (compute_beta_HS) {
353 d_km1 = createMember(p_space);
360 *out <<
"\nStarting nonlinear CG iterations ...\n";
362 if (and_conv_tests_) {
363 *out <<
"\nNOTE: Using AND of convergence tests!\n";
366 *out <<
"\nNOTE: Using OR of convergence tests!\n";
369 const Scalar alpha_init =
370 ( !
is_null(alpha_init_in) ? *alpha_init_in : alpha_init_ );
371 const Scalar g_reduct_tol =
372 ( !
is_null(g_reduct_tol_in) ? *g_reduct_tol_in : g_reduct_tol_ );
373 const Scalar g_grad_tol =
374 ( !
is_null(g_grad_tol_in) ? *g_grad_tol_in : g_grad_tol_ );
376 const Ordinal globalDim = p_space->dim();
378 bool foundSolution =
false;
379 bool fatalLinesearchFailure =
false;
381 int numConsecutiveLineSearchFailures = 0;
383 int numConsecutiveIters = 0;
385 for (numIters_ = 0; numIters_ < maxIters_; ++numIters_, ++numConsecutiveIters) {
389 *out <<
"\nNonlinear CG Iteration k = " << numIters_ <<
"\n";
398 *model_, paramIndex_, *p_k, responseIndex_,
399 numIters_ == 0 ? g_vec.
ptr() : null,
400 MEB::Derivative<Scalar>(g_grad_k, MEB::DERIV_MV_GRADIENT_FORM) );
402 const ScalarMag g_k = get_ele(*g_vec, 0);
411 bool g_reduct_converged =
false;
417 *out <<
"\ng_k - g_km1 = "<<g_reduct<<
"\n";
420 SMT::magnitude(g_reduct / SMT::magnitude(g_k + g_mag_));
422 g_reduct_converged = (g_reduct_err <= g_reduct_tol);
424 *out <<
"\nCheck convergence: |g_k - g_km1| / |g_k + g_mag| = "<<g_reduct_err
425 << (g_reduct_converged ?
" <= " :
" > ")
426 <<
"g_reduct_tol = "<<g_reduct_tol<<
"\n";
432 const Scalar g_grad_k_inner_g_grad_k = scalarProd<Scalar>(*g_grad_k, *g_grad_k);
433 const ScalarMag norm_g_grad_k = ST::magnitude(ST::squareroot(g_grad_k_inner_g_grad_k));
435 *out <<
"\n||g_grad_k|| = "<<norm_g_grad_k <<
"\n";
437 const ScalarMag g_grad_err = norm_g_grad_k / g_mag_;
439 const bool g_grad_converged = (g_grad_err <= g_grad_tol);
441 *out <<
"\nCheck convergence: ||g_grad_k|| / g_mag = "<<g_grad_err
442 << (g_grad_converged ?
" <= " :
" > ")
443 <<
"g_grad_tol = "<<g_grad_tol<<
"\n";
447 bool isConverged =
false;
448 if (and_conv_tests_) {
449 isConverged = g_reduct_converged && g_grad_converged;
452 isConverged = g_reduct_converged || g_grad_converged;
456 if (numIters_ < minIters_) {
457 *out <<
"\nnumIters="<<numIters_<<
" < minIters="<<minIters_
458 <<
", continuing on!\n";
461 *out <<
"\nFound solution, existing algorithm!\n";
462 foundSolution =
true;
466 *out <<
"\nNot converged!\n";
477 if (numConsecutiveIters == globalDim) {
479 *out <<
"\nThe number of consecutive iterations exceeds the"
480 <<
" global dimension so restarting!\n";
488 *out <<
"\nResetting search direction back to steppest descent!\n";
491 V_StV( d_k.ptr(), as<Scalar>(-1.0), *g_grad_k );
499 if (!
is_null(g_grad_k_diff_km1)) {
500 V_VmV( g_grad_k_diff_km1.ptr(), *g_grad_k, *g_grad_km1 );
504 const Scalar beta_FR =
505 g_grad_k_inner_g_grad_k / g_grad_km1_inner_g_grad_km1;
506 *out <<
"\nbeta_FR = " << beta_FR <<
"\n";
511 Scalar beta_PR = ST::zero();
512 if (compute_beta_PR) {
514 inner(*g_grad_k, *g_grad_k_diff_km1) / g_grad_km1_inner_g_grad_km1;
515 *out <<
"\nbeta_PR = " << beta_PR <<
"\n";
520 Scalar beta_HS = ST::zero();
521 if (compute_beta_HS) {
523 inner(*g_grad_k, *g_grad_k_diff_km1) / inner(*g_grad_k_diff_km1, *d_km1);
524 *out <<
"\nbeta_HS = " << beta_HS <<
"\n";
527 Scalar beta_k = ST::zero();
528 switch(solverType_) {
534 beta_k = max(beta_PR, ST::zero());
539 if (numConsecutiveIters < 2) {
542 else if (beta_PR < -beta_FR)
544 else if (ST::magnitude(beta_PR) <= beta_FR)
557 *out <<
"\nbeta_k = " << beta_k <<
"\n";
561 V_StV( d_k.ptr(), beta_k, *d_km1 );
563 Vt_S( d_k.ptr(), beta_k );
564 Vp_StV( d_k.ptr(), as<Scalar>(-1.0), *g_grad_k );
574 Scalar alpha_k = as<Scalar>(-1.0);
576 if (numIters_ == 0) {
577 alpha_k = alpha_init;
581 alpha_k = alpha_init;
592 pointEvaluator->initialize(tuple<
RCP<
const VectorBase<Scalar> > >(p_k, d_k)());
594 ScalarMag g_grad_k_inner_d_k = ST::zero();
597 meritFunc->setEvaluationQuantities(pointEvaluator, p_kp1, g_vec, null);
599 PointEval1D<ScalarMag> point_k(ST::zero(), g_k);
600 if (linesearch_->requiresBaseDeriv()) {
601 g_grad_k_inner_d_k = scalarProd(*g_grad_k, *d_k);
602 point_k.Dphi = g_grad_k_inner_d_k;
605 ScalarMag g_kp1 = computeValue(*meritFunc, alpha_k);
608 PointEval1D<ScalarMag> point_kp1(alpha_k, g_kp1);
610 const bool linesearchResult = linesearch_->doLineSearch(
611 *meritFunc, point_k, inOutArg(point_kp1), null );
613 alpha_k = point_kp1.alpha;
614 g_kp1 = point_kp1.phi;
616 if (linesearchResult) {
617 numConsecutiveLineSearchFailures = 0;
620 if (numConsecutiveLineSearchFailures==0) {
621 *out <<
"\nLine search failure, resetting the search direction!\n";
624 if (numConsecutiveLineSearchFailures==1) {
625 *out <<
"\nLine search failure on last iteration also, terminating algorithm!\n";
626 fatalLinesearchFailure =
true;
628 ++numConsecutiveLineSearchFailures;
631 if (fatalLinesearchFailure) {
641 g_grad_km1_inner_g_grad_km1 = g_grad_k_inner_g_grad_k;
642 std::swap(p_k, p_kp1);
644 std::swap(g_grad_km1, g_grad_k);
646 std::swap(d_k, d_km1);
650 V_S(g_grad_k.ptr(), ST::nan());
651 V_S(p_kp1.ptr(), ST::nan());
661 *g_opt_out = get_ele(*g_vec, 0);
664 V_V( p_inout, *p_k );
667 *numIters_out = numIters_;
670 if (numIters_ == maxIters_) {
671 *out <<
"\nMax nonlinear CG iterations exceeded!\n";
677 else if(fatalLinesearchFailure) {
690 #endif // OPTIPACK_NONLINEAR_CG_DEF_HPP
const std::string and_conv_tests_name
bool get_and_conv_tests() const
const std::string alpha_init_name
bool is_null(const boost::shared_ptr< T > &p)
bool get_alpha_reinit() const
const bool and_conv_tests_default
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
#define TEUCHOS_ASSERT_INEQUALITY(val1, comp, val2)
const double g_mag_default
const std::string solverType_name
RCP< const ParameterList > getValidParameters() const
const int maxIters_default
NonlinearCGUtils::ESolverTypes get_solverType() const
const double g_grad_tol_default
const std::string g_reduct_tol_name
const double g_reduct_tol_default
ScalarMag get_alpha_init() const
void setParameterList(RCP< ParameterList > const ¶mList)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
const double alpha_init_default
NonlinearCG()
Construct with default parameters.
ScalarMag get_g_reduct_tol() const
const std::string g_mag_name
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
const ESolverTypes solverType_default_integral_val
TypeTo as(const TypeFrom &t)
const Ptr< T > & assert_not_null() const
ScalarMag get_g_grad_tol() const
ScalarMag get_g_mag() const
void initialize(const RCP< const Thyra::ModelEvaluator< Scalar > > &model, const int paramIndex, const int responseIndex, const RCP< GlobiPack::LineSearchBase< Scalar > > &linesearch)
Initialize.
const int minIters_default
Fletcher-Reeves Polak-Ribiere Hybrid Method.
const std::string alpha_reinit_name
const std::string solverType_default
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
NonlinearCGUtils::ESolveReturn doSolve(const Ptr< Thyra::VectorBase< Scalar > > &p, const Ptr< ScalarMag > &g_opt, const Ptr< const ScalarMag > &g_reduct_tol=Teuchos::null, const Ptr< const ScalarMag > &g_grad_tol=Teuchos::null, const Ptr< const ScalarMag > &alpha_init=Teuchos::null, const Ptr< int > &numIters=Teuchos::null)
Perform a solve.
const bool alpha_reinit_default
const std::string g_grad_tol_name