// Copyright 2010-2018 Google LLC // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef OR_TOOLS_GLOP_ENTERING_VARIABLE_H_ #define OR_TOOLS_GLOP_ENTERING_VARIABLE_H_ #include "ortools/glop/basis_representation.h" #include "ortools/glop/parameters.pb.h" #include "ortools/glop/primal_edge_norms.h" #include "ortools/glop/reduced_costs.h" #include "ortools/glop/status.h" #include "ortools/glop/update_row.h" #include "ortools/glop/variables_info.h" #include "ortools/lp_data/lp_data.h" #include "ortools/lp_data/lp_types.h" #include "ortools/util/bitset.h" #include "ortools/util/random_engine.h" #include "ortools/util/stats.h" #if !SWIG namespace operations_research { namespace glop { // This class contains the primal and dual algorithms that choose the entering // column (i.e. variable) during a simplex iteration. // // The goal of this component is, given a matrix A (matrix_), a subset of // columns (basis_) that form a basis B and a cost (objective_) associated to // each column of A, to choose a "good" non-basic column to enter the basis // B. Note that this choice does not depend on the current variable values // (except for the direction in which each variable is allowed to change given // by variable_status_). // // Terminology: // - The entering edge is the edge we are following during a simplex step, // and we call "direction" the reverse of this edge restricted to the // basic variables, i.e. the right inverse of the entering column. // // Papers: // - Ping-Qi Pan, "Efficient nested pricing in the simplex algorithm", // http://www.optimization-online.org/DB_FILE/2007/10/1810.pdf class EnteringVariable { public: // Takes references to the linear program data we need. EnteringVariable(const VariablesInfo& variables_info, random_engine_t* random, ReducedCosts* reduced_costs, PrimalEdgeNorms* primal_edge_norms); // Returns the index of a valid primal entering column (see // IsValidPrimalEnteringCandidate() for more details) or kInvalidCol if no // such column exists. This latter case means that the primal algorithm has // terminated: the optimal has been reached. ABSL_MUST_USE_RESULT Status PrimalChooseEnteringColumn(ColIndex* entering_col); // Dual optimization phase (i.e. phase II) ratio test. // Returns the index of the entering column given that we want to move along // the "update" row vector in the direction given by the sign of // cost_variation. Computes the smallest step that keeps the dual feasibility // for all the columns. ABSL_MUST_USE_RESULT Status DualChooseEnteringColumn( const UpdateRow& update_row, Fractional cost_variation, std::vector* bound_flip_candidates, ColIndex* entering_col, Fractional* step); // Dual feasibility phase (i.e. phase I) ratio test. // Similar to the optimization phase test, but allows a step that increases // the infeasibility of an already infeasible column. The step magnitude is // the one that minimize the sum of infeasibilities when applied. ABSL_MUST_USE_RESULT Status DualPhaseIChooseEnteringColumn( const UpdateRow& update_row, Fractional cost_variation, ColIndex* entering_col, Fractional* step); // Sets the pricing parameters. This does not change the pricing rule. void SetParameters(const GlopParameters& parameters); // Sets the pricing rule. void SetPricingRule(GlopParameters::PricingRule rule); // Stats related functions. std::string StatString() const { return stats_.StatString(); } // Recomputes the set of unused columns used during nested pricing. // Visible for testing (the returns value is also there for testing). DenseBitRow* ResetUnusedColumns(); private: // Dantzig selection rule: choose the variable with the best reduced cost. // If normalize is true, we normalize the costs by the column norms. // If nested_pricing is true, we use nested pricing (see parameters.proto). template void DantzigChooseEnteringColumn(ColIndex* entering_col); // Steepest edge rule: the reduced costs are normalized by the edges norm. // Devex rule: the reduced costs are normalized by an approximation of the // edges norm. template void NormalizedChooseEnteringColumn(ColIndex* entering_col); // Problem data that should be updated from outside. const VariablesInfo& variables_info_; random_engine_t* random_; ReducedCosts* reduced_costs_; PrimalEdgeNorms* primal_edge_norms_; // Internal data. GlopParameters parameters_; GlopParameters::PricingRule rule_; // Stats. struct Stats : public StatsGroup { Stats() : StatsGroup("EnteringVariable"), num_perfect_ties("num_perfect_ties", this) {} IntegerDistribution num_perfect_ties; }; Stats stats_; // This is used for nested pricing. It is denoted J in Ping-Qi Pan's paper. // At a given step, it is true for the variable that should be considered for // entering the basis. DenseBitRow unused_columns_; // Temporary vector used to hold the best entering column candidates that are // tied using the current choosing criteria. We actually only store the tied // candidate #2, #3, ...; because the first tied candidate is remembered // anyway. std::vector equivalent_entering_choices_; // Store a column with its update coefficient and ratio. // This is used during the dual phase I & II ratio tests. struct ColWithRatio { ColWithRatio(ColIndex _col, Fractional reduced_cost, Fractional coeff_m) : col(_col), ratio(reduced_cost / coeff_m), coeff_magnitude(coeff_m) {} // Returns false if "this" is before "other" in a priority queue. bool operator<(const ColWithRatio& other) const { if (ratio == other.ratio) { if (coeff_magnitude == other.coeff_magnitude) { return col > other.col; } return coeff_magnitude < other.coeff_magnitude; } return ratio > other.ratio; } ColIndex col; Fractional ratio; Fractional coeff_magnitude; }; // Temporary vector used to hold breakpoints. std::vector breakpoints_; DISALLOW_COPY_AND_ASSIGN(EnteringVariable); }; } // namespace glop } // namespace operations_research #endif // SWIG #endif // OR_TOOLS_GLOP_ENTERING_VARIABLE_H_