OR-Tools  9.0
variables_info.h
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_GLOP_VARIABLES_INFO_H_
15 #define OR_TOOLS_GLOP_VARIABLES_INFO_H_
16 
18 #include "ortools/lp_data/sparse.h"
19 
20 namespace operations_research {
21 namespace glop {
22 
23 // Holds the statuses of all the variables, including slack variables. There
24 // is no point storing constraint statuses since internally all constraints are
25 // always fixed to zero.
26 //
27 // Note that this is the minimal amount of information needed to perform a "warm
28 // start". Using this information and the original linear program, the basis can
29 // be refactorized and all the needed quantities derived.
30 //
31 // TODO(user): Introduce another state class to store a complete state of the
32 // solver. Using this state and the original linear program, the solver can be
33 // restarted with as little time overhead as possible. This is especially useful
34 // for strong branching in a MIP context.
35 struct BasisState {
36  // TODO(user): A MIP solver will potentially store a lot of BasisStates so
37  // memory usage is important. It is possible to use only 2 bits for one
38  // VariableStatus enum. To achieve this, the FIXED_VALUE status can be
39  // converted to either AT_LOWER_BOUND or AT_UPPER_BOUND and decoded properly
40  // later since this will be used with a given linear program. This way we can
41  // even encode more information by using the reduced cost sign to choose to
42  // which bound the fixed status correspond.
44 
45  // Returns true if this state is empty.
46  bool IsEmpty() const { return statuses.empty(); }
47 };
48 
49 // Class responsible for maintaining diverse information for each variable that
50 // depend on its bounds and status.
51 //
52 // Note(user): Not all information is needed at all time, but it is cheap to
53 // maintain it since it only requires a few calls to Update() per simplex
54 // iteration.
56  public:
57  // Takes references to the linear program data we need.
58  explicit VariablesInfo(const CompactSparseMatrix& matrix);
59 
60  // Updates the internal bounds and recomputes the variable types from the
61  // bounds (this is the only function that changes them).
62  //
63  // Returns true iff the existing bounds didn't change. Except if the bounds
64  // AND underlying matrix didn't change, one will need to call one of the two
65  // Initialize*() methods below before using this class.
66  bool LoadBoundsAndReturnTrueIfUnchanged(const DenseRow& new_lower_bounds,
67  const DenseRow& new_upper_bounds);
68 
69  // Initializes the status according to the given BasisState. Incompatible
70  // statuses will be corrected, and we transfrom the state correctly if new
71  // columns / rows were added. Note however that one will need to update the
72  // BasisState with deletions to preserve the status of unchanged columns.
73  void InitializeFromBasisState(ColIndex first_slack, ColIndex num_new_cols,
74  const BasisState& state);
75 
76  // Sets all variables status to their lowest magnitude bounds. Note that there
77  // will be no basic variable after this is called.
79 
80  // Updates the information of the given variable. Note that it is not needed
81  // to call this if the status or the bound of a variable didn't change.
82  void UpdateToBasicStatus(ColIndex col);
83  void UpdateToNonBasicStatus(ColIndex col, VariableStatus status);
84 
85  // Various getter, see the corresponding member declaration below for more
86  // information.
87  const VariableTypeRow& GetTypeRow() const;
88  const VariableStatusRow& GetStatusRow() const;
89  const DenseBitRow& GetCanIncreaseBitRow() const;
90  const DenseBitRow& GetCanDecreaseBitRow() const;
91  const DenseBitRow& GetIsRelevantBitRow() const;
92  const DenseBitRow& GetIsBasicBitRow() const;
93  const DenseBitRow& GetNotBasicBitRow() const;
95 
96  // Returns the variable bounds.
97  const DenseRow& GetVariableLowerBounds() const { return lower_bounds_; }
98  const DenseRow& GetVariableUpperBounds() const { return upper_bounds_; }
99 
100  const ColIndex GetNumberOfColumns() const { return matrix_.num_cols(); }
101 
102  // Changes whether or not a non-basic boxed variable is 'relevant' and will be
103  // returned as such by GetIsRelevantBitRow().
104  void MakeBoxedVariableRelevant(bool value);
105 
106  // This is used in UpdateRow to decide whether to compute it using the
107  // row-wise or column-wise representation.
108  EntryIndex GetNumEntriesInRelevantColumns() const;
109 
110  // Returns the distance between the upper and lower bound of the given column.
112  return upper_bounds_[col] - lower_bounds_[col];
113  }
114 
115  // This is used for the (SP) method of "Progress in the dual simplex method
116  // for large scale LP problems: practical dual phase I algorithms". Achim
117  // Koberstein & Uwe H. Suhl.
118  //
119  // This just set the bounds according to the variable types:
120  // - Boxed variables get fixed at [0,0].
121  // - Upper bounded variables get [-1, 0] bounds
122  // - Lower bounded variables get [0, 1] bounds
123  // - Free variables get [-1000, 1000] to heuristically move them to the basis.
124  // I.e. they cost in the dual infeasibility minimization problem is
125  // multiplied by 1000.
126  //
127  // It then update the status to get an inital dual feasible solution, and
128  // then one just have to apply the phase II algo on this problem to try to
129  // find a feasible solution to the original problem.
130  //
131  // Optimization: When a variable become basic, its non-zero bounds are
132  // relaxed. This is a bit hacky as it requires that the status is updated
133  // before the bounds are read (which is the case). It is however an important
134  // optimization.
135  //
136  // TODO(user): Shall we re-add the bound when the variable is moved out of
137  // the base? it is not needed, but might allow for more bound flips?
138  void TransformToDualPhaseIProblem(Fractional dual_feasibility_tolerance,
139  const DenseRow& reduced_costs);
140  void EndDualPhaseI(Fractional dual_feasibility_tolerance,
141  const DenseRow& reduced_costs);
142 
143  private:
144  // Computes the initial/default variable status from its type. A constrained
145  // variable is set to the lowest of its 2 bounds in absolute value.
146  VariableStatus DefaultVariableStatus(ColIndex col) const;
147 
148  // Resizes all status related vectors.
149  void ResetStatusInfo();
150 
151  // Computes the variable type from its lower and upper bound.
152  VariableType ComputeVariableType(ColIndex col) const;
153 
154  // Sets the column relevance and updates num_entries_in_relevant_columns_.
155  void SetRelevance(ColIndex col, bool relevance);
156 
157  // Used by TransformToDualPhaseIProblem()/EndDualPhaseI().
158  void UpdateStatusForNewType(ColIndex col);
159 
160  // Problem data that should be updated from outside.
161  const CompactSparseMatrix& matrix_;
162 
163  // The variables bounds of the current problem. Like everything here, it
164  // include the slacks.
165  DenseRow lower_bounds_;
166  DenseRow upper_bounds_;
167 
168  // This is just used temporarily by the dual phase I algo to save the original
169  // bounds.
170  DenseRow saved_lower_bounds_;
171  DenseRow saved_upper_bounds_;
172 
173  // Array of variable statuses, indexed by column index.
174  VariableStatusRow variable_status_;
175 
176  // Array of variable types, indexed by column index.
177  VariableTypeRow variable_type_;
178 
179  // Indicates if a non-basic variable can move up or down while not increasing
180  // the primal infeasibility. Note that all combinaisons are possible for a
181  // variable according to its status: fixed, free, upper or lower bounded. This
182  // is always false for basic variable.
183  DenseBitRow can_increase_;
184  DenseBitRow can_decrease_;
185 
186  // Indicates if we should consider this variable for entering the basis during
187  // the simplex algorithm. We never consider fixed variables and in the dual
188  // feasibility phase, we don't consider boxed variable.
189  DenseBitRow relevance_;
190 
191  // Indicates if a variable is BASIC or not. There are currently two members
192  // because the DenseBitRow class only supports a nice range-based iteration on
193  // the non-zero positions and not on the others.
194  DenseBitRow is_basic_;
195  DenseBitRow not_basic_;
196 
197  // Set of boxed variables that are non-basic.
198  DenseBitRow non_basic_boxed_variables_;
199 
200  // Number of entries for the relevant matrix columns (see relevance_).
201  EntryIndex num_entries_in_relevant_columns_;
202 
203  // Whether or not a boxed variable should be considered relevant.
204  bool boxed_variables_are_relevant_ = true;
205 
206  // Whether we are between the calls TransformToDualPhaseIProblem() and
207  // EndDualPhaseI().
208  bool in_dual_phase_one_ = false;
209 
210  DISALLOW_COPY_AND_ASSIGN(VariablesInfo);
211 };
212 
213 } // namespace glop
214 } // namespace operations_research
215 
216 #endif // OR_TOOLS_GLOP_VARIABLES_INFO_H_
bool empty() const
const DenseBitRow & GetIsBasicBitRow() const
const DenseRow & GetVariableUpperBounds() const
const DenseBitRow & GetNonBasicBoxedVariables() const
Fractional GetBoundDifference(ColIndex col) const
const DenseBitRow & GetCanIncreaseBitRow() const
const DenseBitRow & GetCanDecreaseBitRow() const
const VariableTypeRow & GetTypeRow() const
void EndDualPhaseI(Fractional dual_feasibility_tolerance, const DenseRow &reduced_costs)
void UpdateToNonBasicStatus(ColIndex col, VariableStatus status)
const DenseRow & GetVariableLowerBounds() const
const DenseBitRow & GetNotBasicBitRow() const
VariablesInfo(const CompactSparseMatrix &matrix)
const VariableStatusRow & GetStatusRow() const
const DenseBitRow & GetIsRelevantBitRow() const
void InitializeFromBasisState(ColIndex first_slack, ColIndex num_new_cols, const BasisState &state)
bool LoadBoundsAndReturnTrueIfUnchanged(const DenseRow &new_lower_bounds, const DenseRow &new_upper_bounds)
void TransformToDualPhaseIProblem(Fractional dual_feasibility_tolerance, const DenseRow &reduced_costs)
int64_t value
ColIndex col
Definition: markowitz.cc:183
Collection of objects used to extend the Constraint Solver library.