// Copyright (C) 2000, International Business Machines // Corporation and others. All Rights Reserved. #ifndef _BCP_CUT_H #define _BCP_CUT_H // This file is fully docified. //############################################################################# #include "CoinSmartPtr.hpp" #include "BCP_math.hpp" #include "BCP_error.hpp" #include "BCP_enum.hpp" #include "BCP_vector.hpp" #include "BCP_obj_change.hpp" //############################################################################# // Generic cut definition /** Abstract base class that defines members common to all types of cuts. Classes describing the three types of cuts (core and algorithmic) are derived from this class. No object of type BCP_cut can exist (having purely virtual members in the class enforces this restriction). */ class BCP_cut : public Coin::ReferencedObject { private: /**@name Disabled methods */ /*@{*/ /** The default constructor is declared but not defined to disable it. */ BCP_cut(); /** The copy constructor is declared but not defined to disable it. */ BCP_cut(const BCP_cut&); /** The assignment operator is declared but not defined to disable it. */ BCP_cut& operator=(const BCP_cut&); /*@}*/ private: /** These data members are used only by BCP, the user need not worry about them. */ /*@{*/ /** The internal, unique index of the cut. */ int _bcpind; /** The status of the cut. */ BCP_obj_status _status; /** Effectiveness counter (used only in the LP process). */ int _eff_cnt; /*@}*/ protected: /*@{*/ /** Lower bound of the cut. */ double _lb; /** Upper bound of the cut. */ double _ub; /*@}*/ public: /**@name Constructor and destructor Note that there is no default constructor. There is no such thing as "default cut". */ /*@{*/ /** The constructor sets the internal index of the cut to zero and the other data members to the given arguments. */ BCP_cut(const double lb, const double ub) : _bcpind(0), _status(BCP_ObjNoInfo), _eff_cnt(0), _lb(lb), _ub(ub) {} /** The destructor is virtual so that the appropriate destructor is invoked for every cut. */ virtual ~BCP_cut() {} /*@}*/ /**@name Query methods */ /*@{*/ /** Return the type of the variable. */ virtual BCP_object_t obj_type() const = 0; /** Return the effectiveness count of the cut (only in LP process). */ inline int effective_count() const { return _eff_cnt; } /** Return the lower bound on the cut. */ inline double lb() const { return _lb; } /** Return the upper bound on the cut. */ inline double ub() const { return _ub; } /** Return the internal index of the cut. */ inline int bcpind() const { return _bcpind; } /* *@name Query methods about the status of the variable */ /* @{*/ /** Return the status of the cut. */ inline BCP_obj_status status() const { return _status; } /** Return whether the cut should be sent to the Cut Pool process. (Assuming that it stays in the formulation long enough to qualify to be sent to the Cut Pool at all. */ inline bool dont_send_to_pool() const { return _status & BCP_ObjDoNotSendToPool ? true : false; } /** Return whether the cut marked as NotRemovable. Such cuts are, e.g., the branching cuts. */ inline bool is_non_removable() const { return (_status & BCP_ObjNotRemovable) ? true : false; } /** Return whether the cut must be removed from the formulation. There are very few circumstances when this flag is set; all of them are completely internal to BCP. */ inline bool is_to_be_removed() const { return (_status & BCP_ObjToBeRemoved) != 0; } /* @}*/ /*@}*/ /**@name Modifying methods */ /*@{*/ /** Set the effectiveness count to the given value. */ inline void set_effective_count(const int cnt) { _eff_cnt = cnt; } /** Increase the effectiveness count by 1 (or to 1 if it was negative). Return the new effectiveness count. */ inline int increase_effective_count() { _eff_cnt = _eff_cnt <= 0 ? 1 : _eff_cnt + 1; return _eff_cnt; } /** Decrease the effectiveness count by 1 (or to -1 if it was positive). Return the new effectiveness count. */ inline int decrease_effective_count() { _eff_cnt = _eff_cnt >= 0 ? -1 : _eff_cnt - 1; return _eff_cnt; } /** Set the lower bound on the cut. */ inline void set_lb(const double lb) { _lb = lb; } /** Set the upper bound on the cut. */ inline void set_ub(const double ub) { _ub = ub; } /** Set the lower/upper bounds and the status of the cut simultaneously to the values given in the data members of the argument. */ inline void change_lb_ub_st(const BCP_obj_change& change) { _lb = change.lb; _ub = change.ub; _status = change.stat; if (_lb < -BCP_DBL_MAX/10 && _ub > BCP_DBL_MAX/10) _status = static_cast(_status | BCP_ObjInactive); } /** Change just the lower/upper bounds. */ inline void change_bounds(const double lb, const double ub) { _lb = lb; _ub = ub; if (lb < BCP_DBL_MAX/10 && ub > BCP_DBL_MAX/10) _status = static_cast(_status | BCP_ObjInactive); } /** Set the internal index of the cut. */ inline void set_bcpind(const int bcpind) { _bcpind = bcpind; } /** Flip the internal index of the variable to its negative */ inline void set_bcpind_flip() { _bcpind = -_bcpind; } /* *@name Status modifying methods */ /* @{*/ /** Set the status of the cut. */ inline void set_status(const BCP_obj_status stat) { _status = stat; } /** Set/unset the flag controlling whether the cut could be sent to the Cut Pool process. */ inline void dont_send_to_pool(bool flag) { _status = static_cast(flag ? _status | BCP_ObjDoNotSendToPool : _status & ~BCP_ObjDoNotSendToPool); } /** Mark the cut as active. Note that when this method is invoked the lp formulation must be modified as well: the original bounds of the cut must be reset. */ inline void make_active() { _status = static_cast(_status & ~BCP_ObjInactive); } /** Mark the cut as NotRemovable. */ inline void make_non_removable() { _status = static_cast ((_status & ~BCP_ObjToBeRemoved) | BCP_ObjNotRemovable); } /** Mark the cut as ToBeRemoved. It will actually be removed immediately after all cuts that have to be marked this way are marked. */ inline void make_to_be_removed() { _status = BCP_ObjToBeRemoved; } /* @}*/ /*@}*/ }; //############################################################################# //############################################################################# /** Core cuts are the cuts that always stay in the LP formulation. Therefore the data members in the base class are quite sufficient to describe the cut. The only thing that has to be done here is overriding the pure virtual method obj_type(). */ class BCP_cut_core : public BCP_cut { private: /**@name Disabled methods */ /*@{*/ /** The default constructor is declared but not defined to disable it. */ BCP_cut_core(); /** The assignment operator is declared but not defined to disable it. */ BCP_cut_core& operator=(const BCP_cut_core&); /*@}*/ public: /**@name Constructors and desctructor */ /*@{*/ /** The copy constructor makes a replica of the argument. */ BCP_cut_core(const BCP_cut_core& x) : BCP_cut(x._lb, x._ub) { set_bcpind(x.bcpind()); set_status(x.status()); set_effective_count(x.effective_count()); } /** This constructor just sets the data members to the given values. See also the constructor of BCP_cut. */ BCP_cut_core(const double lb, const double ub) : BCP_cut(lb, ub) {} /** The destructor deletes the object. */ ~BCP_cut_core() {} /*@}*/ /**@name Query methods */ /*@{*/ /** Return BCP_CoreObj indicating that the object is a core cut. */ inline BCP_object_t obj_type() const { return BCP_CoreObj; } /*@}*/ }; //############################################################################# // This is the class the user should derive his/her own algorithmic cuts /** This is the class from which the user should derive her own algorithmic cuts. Note that such an object cannot be constructed (it has pure virtual methods), only objects with types derived from BCP_cut_algo can be created. Such objects are constructed either directly by the user or by the unpacking functions of the \c BCP_xx_user classes. */ class BCP_cut_algo : public BCP_cut { private: /**@name Disabled methods */ /*@{*/ /** The default constructor is declared but not defined to disable it. */ BCP_cut_algo(); /** The copy constructor is declared but not defined to disable it. */ BCP_cut_algo(const BCP_cut_algo&); /** The assignment operator is declared but not defined to disable it. */ BCP_cut_algo& operator=(const BCP_cut_algo&); /*@}*/ public: /**@name Constructor and destructor */ /*@{*/ /** This constructor just sets the data members to the given values. See also the constructor of BCP_cut. */ BCP_cut_algo(const double lb, const double ub) : BCP_cut(lb, ub) {} /** The destructor deletes the object. */ virtual ~BCP_cut_algo() = 0; /*@}*/ /**@name Query methods */ /*@{*/ /** Return \c BCP_AlgoObj indicating that the object is an algorithmic cut. */ inline BCP_object_t obj_type() const { return BCP_AlgoObj; } /*@}*/ }; //############################################################################# //############################################################################# /** This class is just a collection of pointers to cuts with a number of methods to manipulate these cuts and/or select certain entries. */ class BCP_cut_set : public BCP_vec { private: /**@name Disabled methods */ /*@{*/ /** The copy constructor is declared but not defined to disable it. */ BCP_cut_set(const BCP_cut_set&); /** The assignment operator is declared but not defined to disable it. */ BCP_cut_set& operator=(const BCP_cut_set&); /*@}*/ public: /**@name Constructor and destructor */ /*@{*/ /** The default constructor creates a cut set with no cuts in it. */ BCP_cut_set() {} /** The destructor empties the cut set. NOTE: the destructor does NOT delete the cuts the members of the cut set point to. */ ~BCP_cut_set() {} /*@}*/ /**@name Modifying methods */ /*@{*/ /** Append the cuts in the vector x to the end of the cut set. */ inline void append(const BCP_vec& x) { BCP_vec::append(x); } /** Append the cuts in [first, last) to the end of the cut set. */ inline void append(BCP_cut_set::const_iterator first, BCP_cut_set::const_iterator last){ BCP_vec::append(first, last); } /** Set the lower/upper bound pairs of the entries given by the contents of pos to the values in [bounds, bounds + pos. size()). */ void set_lb_ub(const BCP_vec& pos, BCP_vec::const_iterator bounds); /** Set the lower/upper bound pairs and the stati of the first cc. size() entries to the triplets given in the vector. This method is invoked when the cut set is all the cuts in the current formulation and we want to change the triplets for the core cuts, which are at the beginning of that cut set. */ void set_lb_ub_st(const BCP_vec& cc); /** Set the lower/upper bound pairs and the stati of the entries given by the content of [pos, pos + cc. size()) to the triplets contained in cc. */ void set_lb_ub_st(BCP_vec::const_iterator pos, const BCP_vec& cc); /*@}*/ #if 0 //-------------------------------------------------------------------------- /**@name Methods that select a subset of the cuts These methods fill up coll with the indices of the selected cuts. A cut is selected if it
  1. is not already free
  2. is not non-removable
  3. has been ineffective for at least ineff_limit iterations
  4. is ineffective now according to the criteria of the method.
The first cut tested is the first_to_check-th one. (This argument is there so that we can skip the core cuts easily.) Also, for ineffective cuts the effectiveness count is decreased, for effective cuts it is increased. */ /*@{*/ /** Those cuts are considered ineffective whose corresponding slack value is nonzero (greater than etol). */ void nonzero_slack(int first_to_check, const double * slacks, const double etol, const int ineff_limit, BCP_vec& coll); /** Those cuts are considered ineffective whose corresponding dual value is zero (its absolute value is less than etol). */ void zero_dual(int first_to_check, const double * duals, const double etol, const int ineff_limit, BCP_vec& coll); /*@}*/ #endif /**@name Methods related to deleting cuts from the cut set */ /*@{*/ #if 0 /** Collect the indices of the cuts marked to be removed. Since core cuts are never removed, we pass the number of core cuts in the first argument to speed up things a little. */ void deletable(const int bcutnum, BCP_vec& collection) const; #endif /** Move the cut pointers whose indices are listed in deletable_cuts into the pool. Note that this method does NOT compress the cut set, it merely replaces the cut pointers with 0 pointers. */ void move_deletable_to_pool(const BCP_vec& deletable_cuts, BCP_vec& pool); /*@}*/ //----------------------------------------------------------------------- }; #endif