// Copyright (C) 2004, 2009 International Business Machines and others. // All Rights Reserved. // This code is published under the Eclipse Public License. // // $Id: IpIpoptData.hpp 2472 2014-04-05 17:47:20Z stefan $ // // Authors: Carl Laird, Andreas Waechter IBM 2004-08-13 #ifndef __IPIPOPTDATA_HPP__ #define __IPIPOPTDATA_HPP__ #include "IpSymMatrix.hpp" #include "IpOptionsList.hpp" #include "IpIteratesVector.hpp" #include "IpRegOptions.hpp" #include "IpTimingStatistics.hpp" namespace Ipopt { /* Forward declaration */ class IpoptNLP; /** Base class for additional data that is special to a particular * type of algorithm, such as the CG penalty function, or using * iterative linear solvers. The regular IpoptData object should * be given a derivation of this base class when it is created. */ class IpoptAdditionalData : public ReferencedObject { public: /**@name Constructors/Destructors */ //@{ /** Default Constructor */ IpoptAdditionalData() {} /** Default destructor */ virtual ~IpoptAdditionalData() {} //@} /** This method is called to initialize the global algorithmic * parameters. The parameters are taken from the OptionsList * object. */ virtual bool Initialize(const Journalist& jnlst, const OptionsList& options, const std::string& prefix) = 0; /** Initialize Data Structures at the beginning. */ virtual bool InitializeDataStructures() = 0; /** Do whatever is necessary to accept a trial point as current * iterate. This is also used to finish an iteration, i.e., to * release memory, and to reset any flags for a new iteration. */ virtual void AcceptTrialPoint() = 0; private: /**@name Default Compiler Generated Methods * (Hidden to avoid implicit creation/calling). * These methods are not implemented and * we do not want the compiler to implement * them for us, so we declare them private * and do not define them. This ensures that * they will not be implicitly created/called. */ //@{ /** Copy Constructor */ IpoptAdditionalData(const IpoptAdditionalData&); /** Overloaded Equals Operator */ void operator=(const IpoptAdditionalData&); //@} }; /** Class to organize all the data required by the algorithm. * Internally, once this Data object has been initialized, all * internal curr_ vectors must always be set (so that prototyes are * available). The current values can only be set from the trial * values. The trial values can be set by copying from a vector or * by adding some fraction of a step to the current values. This * object also stores steps, which allows to easily communicate the * step from the step computation object to the line search object. */ class IpoptData : public ReferencedObject { public: /**@name Constructors/Destructors */ //@{ /** Constructor */ IpoptData(SmartPtr add_data = NULL, Number cpu_time_start = -1.); /** Default destructor */ virtual ~IpoptData(); //@} /** Initialize Data Structures */ bool InitializeDataStructures(IpoptNLP& ip_nlp, bool want_x, bool want_y_c, bool want_y_d, bool want_z_L, bool want_z_U); /** This method must be called to initialize the global * algorithmic parameters. The parameters are taken from the * OptionsList object. */ bool Initialize(const Journalist& jnlst, const OptionsList& options, const std::string& prefix); /** @name Get Methods for Iterates */ //@{ /** Current point */ inline SmartPtr curr() const; /** Get the current point in a copied container that is non-const. The entries in the container cannot be modified, but the container can be modified to point to new entries. */ // SmartPtr curr_container() const; /** Get Trial point */ inline SmartPtr trial() const; /** Get Trial point in a copied container that is non-const. * The entries in the container can not be modified, but * the container can be modified to point to new entries. */ //SmartPtr trial_container() const; /** Set the trial point - this method copies the pointer for * efficiency (no copy and to keep cache tags the same) so * after you call set you cannot modify the data again */ inline void set_trial(SmartPtr& trial); /** Set the values of the primal trial variables (x and s) from * provided Step with step length alpha. */ void SetTrialPrimalVariablesFromStep(Number alpha, const Vector& delta_x, const Vector& delta_s); /** Set the values of the trial values for the equality constraint * multipliers (y_c and y_d) from provided step with step length * alpha. */ void SetTrialEqMultipliersFromStep(Number alpha, const Vector& delta_y_c, const Vector& delta_y_d); /** Set the value of the trial values for the bound multipliers * (z_L, z_U, v_L, v_U) from provided step with step length * alpha. */ void SetTrialBoundMultipliersFromStep(Number alpha, const Vector& delta_z_L, const Vector& delta_z_U, const Vector& delta_v_L, const Vector& delta_v_U); /** ToDo: I may need to add versions of set_trial like the * following, but I am not sure */ // void set_trial(const SmartPtr& trial_iterates); // void set_trial(SmartPtr& trial_iterates); /** get the current delta */ inline SmartPtr delta() const; /** Set the current delta - like the trial point, this method copies * the pointer for efficiency (no copy and to keep cache tags the * same) so after you call set, you cannot modify the data */ inline void set_delta(SmartPtr& delta); /** Set the current delta - like the trial point, this method * copies the pointer for efficiency (no copy and to keep cache * tags the same) so after you call set, you cannot modify the * data. This is the version that is happy with a pointer to * const IteratesVector. */ inline void set_delta(SmartPtr& delta); /** Affine Delta */ inline SmartPtr delta_aff() const; /** Set the affine delta - like the trial point, this method copies * the pointer for efficiency (no copy and to keep cache tags the * same) so after you call set, you cannot modify the data */ inline void set_delta_aff(SmartPtr& delta_aff); /** Hessian or Hessian approximation (do not hold on to it, it might be changed) */ SmartPtr W() { DBG_ASSERT(IsValid(W_)); return W_; } /** Set Hessian approximation */ void Set_W(SmartPtr W) { W_ = W; } /** @name ("Main") Primal-dual search direction. Those fields are * used to store the search directions computed from solving the * primal-dual system, and can be used in the line search. They * are overwritten in every iteration, so do not hold on to the * pointers (make copies instead) */ //@{ /** Returns true, if the primal-dual step have been already * computed for the current iteration. This flag is reset after * every call of AcceptTrialPoint(). If the search direction is * computed during the computation of the barrier parameter, the * method computing the barrier parameter should call * SetHaveDeltas(true) to tell the IpoptAlgorithm object that it * doesn't need to recompute the primal-dual step. */ bool HaveDeltas() const { return have_deltas_; } /** Method for setting the HaveDeltas flag. This method should be * called if some method computes the primal-dual step (and * stores it in the delta_ fields of IpoptData) at an early part * of the iteration. If that flag is set to true, the * IpoptAlgorithm object will not recompute the step. */ void SetHaveDeltas(bool have_deltas) { have_deltas_ = have_deltas; } //@} /** @name Affine-scaling step. Those fields can be used to store * the affine scaling step. For example, if the method for * computing the current barrier parameter computes the affine * scaling steps, then the corrector step in the line search does * not have to recompute those solutions of the linear system. */ //@{ /** Returns true, if the affine-scaling step have been already * computed for the current iteration. This flag is reset after * every call of AcceptTrialPoint(). If the search direction is * computed during the computation of the barrier parameter, the * method computing the barrier parameter should call * SetHaveDeltas(true) to tell the line search does not have to * recompute them in case it wants to do a corrector step. */ bool HaveAffineDeltas() const { return have_affine_deltas_; } /** Method for setting the HaveDeltas flag. This method should be * called if some method computes the primal-dual step (and * stores it in the delta_ fields of IpoptData) at an early part * of the iteration. If that flag is set to true, the * IpoptAlgorithm object will not recompute the step. */ void SetHaveAffineDeltas(bool have_affine_deltas) { have_affine_deltas_ = have_affine_deltas; } //@} /** @name Public Methods for updating iterates */ //@{ /** Copy the trial values to the current values */ inline void CopyTrialToCurrent(); /** Set the current iterate values from the * trial values. */ void AcceptTrialPoint(); //@} /** @name General algorithmic data */ //@{ Index iter_count() const { return iter_count_; } void Set_iter_count(Index iter_count) { iter_count_ = iter_count; } Number curr_mu() const { DBG_ASSERT(mu_initialized_); return curr_mu_; } void Set_mu(Number mu) { curr_mu_ = mu; mu_initialized_ = true; } bool MuInitialized() const { return mu_initialized_; } Number curr_tau() const { DBG_ASSERT(tau_initialized_); return curr_tau_; } void Set_tau(Number tau) { curr_tau_ = tau; tau_initialized_ = true; } bool TauInitialized() const { return tau_initialized_; } void SetFreeMuMode(bool free_mu_mode) { free_mu_mode_ = free_mu_mode; } bool FreeMuMode() const { return free_mu_mode_; } /** Setting the flag that indicates if a tiny step (below machine * precision) has been detected */ void Set_tiny_step_flag(bool flag) { tiny_step_flag_ = flag; } bool tiny_step_flag() { return tiny_step_flag_; } //@} /** Overall convergence tolerance. It is used in the convergence * test, but also in some other parts of the algorithm that * depend on the specified tolerance, such as the minimum value * for the barrier parameter. */ //@{ /** Obtain the tolerance. */ Number tol() const { DBG_ASSERT(initialize_called_); return tol_; } /** Set a new value for the tolerance. One should be very careful * when using this, since changing the predefined tolerance might * have unexpected consequences. This method is for example used * in the restoration convergence checker to tighten the * restoration phase convergence tolerance, if the restoration * phase converged to a point that has not a large value for the * constraint violation. */ void Set_tol(Number tol) { tol_ = tol; } //@} /** Cpu time counter at the beginning of the optimization. This * is useful to see how much CPU time has been spent in this * optimization run. */ Number cpu_time_start() const { return cpu_time_start_; } /** @name Information gathered for iteration output */ //@{ Number info_regu_x() const { return info_regu_x_; } void Set_info_regu_x(Number regu_x) { info_regu_x_ = regu_x; } Number info_alpha_primal() const { return info_alpha_primal_; } void Set_info_alpha_primal(Number alpha_primal) { info_alpha_primal_ = alpha_primal; } char info_alpha_primal_char() const { return info_alpha_primal_char_; } void Set_info_alpha_primal_char(char info_alpha_primal_char) { info_alpha_primal_char_ = info_alpha_primal_char; } Number info_alpha_dual() const { return info_alpha_dual_; } void Set_info_alpha_dual(Number alpha_dual) { info_alpha_dual_ = alpha_dual; } Index info_ls_count() const { return info_ls_count_; } void Set_info_ls_count(Index ls_count) { info_ls_count_ = ls_count; } bool info_skip_output() const { return info_skip_output_; } void Append_info_string(const std::string& add_str) { info_string_ += add_str; } const std::string& info_string() const { return info_string_; } /** Set this to true, if the next time when output is written, the * summary line should not be printed. */ void Set_info_skip_output(bool info_skip_output) { info_skip_output_ = info_skip_output; } /** gives time when the last summary output line was printed */ Number info_last_output() { return info_last_output_; } /** sets time when the last summary output line was printed */ void Set_info_last_output(Number info_last_output) { info_last_output_ = info_last_output; } /** gives number of iteration summaries actually printed * since last summary header was printed */ int info_iters_since_header() { return info_iters_since_header_; } /** increases number of iteration summaries actually printed * since last summary header was printed */ void Inc_info_iters_since_header() { info_iters_since_header_++; } /** sets number of iteration summaries actually printed * since last summary header was printed */ void Set_info_iters_since_header(int info_iters_since_header) { info_iters_since_header_ = info_iters_since_header; } /** Reset all info fields */ void ResetInfo() { info_regu_x_ = 0; info_alpha_primal_ = 0; info_alpha_dual_ = 0.; info_alpha_primal_char_ = ' '; info_skip_output_ = false; info_string_.erase(); } //@} /** Return Timing Statistics Object */ TimingStatistics& TimingStats() { return timing_statistics_; } /** Check if additional data has been set */ bool HaveAddData() { return IsValid(add_data_); } /** Get access to additional data object */ IpoptAdditionalData& AdditionalData() { return *add_data_; } /** Set a new pointer for additional Ipopt data */ void SetAddData(SmartPtr add_data) { DBG_ASSERT(!HaveAddData()); add_data_ = add_data; } /** Set the perturbation of the primal-dual system */ void setPDPert(Number pd_pert_x, Number pd_pert_s, Number pd_pert_c, Number pd_pert_d) { pd_pert_x_ = pd_pert_x; pd_pert_s_ = pd_pert_s; pd_pert_c_ = pd_pert_c; pd_pert_d_ = pd_pert_d; } /** Get the current perturbation of the primal-dual system */ void getPDPert(Number& pd_pert_x, Number& pd_pert_s, Number& pd_pert_c, Number& pd_pert_d) { pd_pert_x = pd_pert_x_; pd_pert_s = pd_pert_s_; pd_pert_c = pd_pert_c_; pd_pert_d = pd_pert_d_; } /** Methods for IpoptType */ //@{ static void RegisterOptions(const SmartPtr& roptions); //@} private: /** @name Iterates */ //@{ /** Main iteration variables * (current iteration) */ SmartPtr curr_; /** Main iteration variables * (trial calculations) */ SmartPtr trial_; /** Hessian (approximation) - might be changed elsewhere! */ SmartPtr W_; /** @name Primal-dual Step */ //@{ SmartPtr delta_; /** The following flag is set to true, if some other part of the * algorithm (like the method for computing the barrier * parameter) has already computed the primal-dual search * direction. This flag is reset when the AcceptTrialPoint * method is called. * ToDo: we could cue off of a null delta_; */ bool have_deltas_; //@} /** @name Affine-scaling step. This used to transfer the * information about the affine-scaling step from the computation * of the barrier parameter to the corrector (in the line * search). */ //@{ SmartPtr delta_aff_; /** The following flag is set to true, if some other part of the * algorithm (like the method for computing the barrier * parameter) has already computed the affine-scaling step. This * flag is reset when the AcceptTrialPoint method is called. * ToDo: we could cue off of a null delta_aff_; */ bool have_affine_deltas_; //@} /** iteration count */ Index iter_count_; /** current barrier parameter */ Number curr_mu_; bool mu_initialized_; /** current fraction to the boundary parameter */ Number curr_tau_; bool tau_initialized_; /** flag indicating if Initialize method has been called (for * debugging) */ bool initialize_called_; /** flag for debugging whether we have already curr_ values * available (from which new Vectors can be generated */ bool have_prototypes_; /** @name Global algorithm parameters. Those are options that can * be modified by the user and appear at different places in the * algorithm. They are set using an OptionsList object in the * Initialize method. */ //@{ /** Overall convergence tolerance */ Number tol_; //@} /** @name Status data **/ //@{ /** flag indicating whether the algorithm is in the free mu mode */ bool free_mu_mode_; /** flag indicating if a tiny step has been detected */ bool tiny_step_flag_; //@} /** @name Gathered information for iteration output */ //@{ /** Size of regularization for the Hessian */ Number info_regu_x_; /** Primal step size */ Number info_alpha_primal_; /** Info character for primal step size */ char info_alpha_primal_char_; /** Dual step size */ Number info_alpha_dual_; /** Number of backtracking trial steps */ Index info_ls_count_; /** true, if next summary output line should not be printed (eg * after restoration phase. */ bool info_skip_output_; /** any string of characters for the end of the output line */ std::string info_string_; /** time when the last summary output line was printed */ Number info_last_output_; /** number of iteration summaries actually printed since last * summary header was printed */ int info_iters_since_header_; //@} /** VectorSpace for all the iterates */ SmartPtr iterates_space_; /** TimingStatistics object collecting all Ipopt timing * statistics */ TimingStatistics timing_statistics_; /** CPU time counter at initialization. */ Number cpu_time_start_; /** Object for the data specific for the Chen-Goldfarb penalty * method algorithm */ SmartPtr add_data_; /** @name Information about the perturbation of the primal-dual * system */ //@{ Number pd_pert_x_; Number pd_pert_s_; Number pd_pert_c_; Number pd_pert_d_; //@} /**@name Default Compiler Generated Methods * (Hidden to avoid implicit creation/calling). * These methods are not implemented and * we do not want the compiler to implement * them for us, so we declare them private * and do not define them. This ensures that * they will not be implicitly created/called. */ //@{ /** Copy Constructor */ IpoptData(const IpoptData&); /** Overloaded Equals Operator */ void operator=(const IpoptData&); //@} #if COIN_IPOPT_CHECKLEVEL > 0 /** Some debug flags to make sure vectors are not changed * behind the IpoptData's back */ //@{ TaggedObject::Tag debug_curr_tag_; TaggedObject::Tag debug_trial_tag_; TaggedObject::Tag debug_delta_tag_; TaggedObject::Tag debug_delta_aff_tag_; TaggedObject::Tag debug_curr_tag_sum_; TaggedObject::Tag debug_trial_tag_sum_; TaggedObject::Tag debug_delta_tag_sum_; TaggedObject::Tag debug_delta_aff_tag_sum_; //@} #endif }; inline SmartPtr IpoptData::curr() const { DBG_ASSERT(IsNull(curr_) || (curr_->GetTag() == debug_curr_tag_ && curr_->GetTagSum() == debug_curr_tag_sum_) ); return curr_; } inline SmartPtr IpoptData::trial() const { DBG_ASSERT(IsNull(trial_) || (trial_->GetTag() == debug_trial_tag_ && trial_->GetTagSum() == debug_trial_tag_sum_) ); return trial_; } inline SmartPtr IpoptData::delta() const { DBG_ASSERT(IsNull(delta_) || (delta_->GetTag() == debug_delta_tag_ && delta_->GetTagSum() == debug_delta_tag_sum_) ); return delta_; } inline SmartPtr IpoptData::delta_aff() const { DBG_ASSERT(IsNull(delta_aff_) || (delta_aff_->GetTag() == debug_delta_aff_tag_ && delta_aff_->GetTagSum() == debug_delta_aff_tag_sum_) ); return delta_aff_; } inline void IpoptData::CopyTrialToCurrent() { curr_ = trial_; #if COIN_IPOPT_CHECKLEVEL > 0 if (IsValid(curr_)) { debug_curr_tag_ = curr_->GetTag(); debug_curr_tag_sum_ = curr_->GetTagSum(); } else { debug_curr_tag_ = 0; debug_curr_tag_sum_ = 0; } #endif } inline void IpoptData::set_trial(SmartPtr& trial) { trial_ = ConstPtr(trial); #if COIN_IPOPT_CHECKLEVEL > 0 // verify the correct space DBG_ASSERT(trial_->OwnerSpace() == (VectorSpace*)GetRawPtr(iterates_space_)); if (IsValid(trial)) { debug_trial_tag_ = trial->GetTag(); debug_trial_tag_sum_ = trial->GetTagSum(); } else { debug_trial_tag_ = 0; debug_trial_tag_sum_ = 0; } #endif trial = NULL; } inline void IpoptData::set_delta(SmartPtr& delta) { delta_ = ConstPtr(delta); #if COIN_IPOPT_CHECKLEVEL > 0 if (IsValid(delta)) { debug_delta_tag_ = delta->GetTag(); debug_delta_tag_sum_ = delta->GetTagSum(); } else { debug_delta_tag_ = 0; debug_delta_tag_sum_ = 0; } #endif delta = NULL; } inline void IpoptData::set_delta(SmartPtr& delta) { delta_ = delta; #if COIN_IPOPT_CHECKLEVEL > 0 if (IsValid(delta)) { debug_delta_tag_ = delta->GetTag(); debug_delta_tag_sum_ = delta->GetTagSum(); } else { debug_delta_tag_ = 0; debug_delta_tag_sum_ = 0; } #endif delta = NULL; } inline void IpoptData::set_delta_aff(SmartPtr& delta_aff) { delta_aff_ = ConstPtr(delta_aff); #if COIN_IPOPT_CHECKLEVEL > 0 if (IsValid(delta_aff)) { debug_delta_aff_tag_ = delta_aff->GetTag(); debug_delta_aff_tag_sum_ = delta_aff->GetTagSum(); } else { debug_delta_aff_tag_ = 0; debug_delta_aff_tag_sum_ = delta_aff->GetTagSum(); } #endif delta_aff = NULL; } } // namespace Ipopt #endif