// Copyright (C) 2004, 2009 International Business Machines and others. // All Rights Reserved. // This code is published under the Eclipse Public License. // // 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 IPOPTLIB_EXPORT IpoptAdditionalData: public ReferencedObject { public: /**@name Constructors/Destructors */ ///@{ /** Default Constructor */ IpoptAdditionalData() { } /** 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& ); /** Default Assignment 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 prototypes 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 IPOPTLIB_EXPORT IpoptData: public ReferencedObject { public: /**@name Constructors/Destructors */ ///@{ /** Constructor */ IpoptData( SmartPtr add_data = NULL ); /** 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 ); /* 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); /** 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 ); /** 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() { 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. * * Can only be called after beginning of optimization. */ IPOPT_DEPRECATED Number cpu_time_start() const { return timing_statistics_.OverallAlgorithm().StartCpuTime(); } /** @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_; } /** Return Timing Statistics Object * * @since 3.14.11 */ const TimingStatistics& TimingStats() const { 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 ) { // cppcheck-suppress assertWithSideEffect 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_; } 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_; /** 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& ); /** Default Assignment Operator */ void operator=( const IpoptData& ); ///@} #if 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 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 IPOPT_CHECKLEVEL > 0 // verify the correct space DBG_ASSERT(trial_->OwnerSpace() == static_cast(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 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 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 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