OR-Tools  9.3
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
19
20namespace operations_research {
21namespace 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.
35struct 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 // Same for an LP not in equation form.
73 const DenseColumn& constraint_lower_bounds,
74 const DenseColumn& constraint_upper_bounds);
75
76 // Initializes the status according to the given BasisState. Incompatible
77 // statuses will be corrected, and we transform the state correctly if new
78 // columns / rows were added. Note however that one will need to update the
79 // BasisState with deletions to preserve the status of unchanged columns.
80 void InitializeFromBasisState(ColIndex first_slack, ColIndex num_new_cols,
81 const BasisState& state);
82
83 // Changes to the FREE status any column with a BASIC status not listed in
84 // the basis. Returns their number. Also makes sure all the columns listed in
85 // basis are marked as basic. Note that if a variable is fixed, we set its
86 // status to FIXED_VALUE not FREE.
88
89 // Loops over all the free variables, and if such a variable has bounds and
90 // its starting value is closer to its closest bound than the given distance,
91 // change the status to move this variable to that bound. Returns the number
92 // of changes. The variable for which starting_values is not provided are
93 // considered at zero.
94 //
95 // This is mainly useful if non-zero starting values are provided. It allows
96 // to move all the variables close to their bounds at once instead of having
97 // to move them one by one with simplex pivots later. Of course, by doing that
98 // we usually introduce a small primal infeasibility that might need
99 // correction.
100 //
101 // If one uses a large distance, then all such variables will start at their
102 // bound if they have one.
104 const DenseRow& starting_values);
105
106 // Sets all variables status to their lowest magnitude bounds. Note that there
107 // will be no basic variable after this is called.
109
110 // Updates the information of the given variable. Note that it is not needed
111 // to call this if the status or the bound of a variable didn't change.
112 void UpdateToBasicStatus(ColIndex col);
114
115 // Various getter, see the corresponding member declaration below for more
116 // information.
117 const VariableTypeRow& GetTypeRow() const;
118 const VariableStatusRow& GetStatusRow() const;
119 const DenseBitRow& GetCanIncreaseBitRow() const;
120 const DenseBitRow& GetCanDecreaseBitRow() const;
121 const DenseBitRow& GetIsRelevantBitRow() const;
122 const DenseBitRow& GetIsBasicBitRow() const;
123 const DenseBitRow& GetNotBasicBitRow() const;
125
126 // Returns the variable bounds.
127 const DenseRow& GetVariableLowerBounds() const { return lower_bounds_; }
128 const DenseRow& GetVariableUpperBounds() const { return upper_bounds_; }
129
130 const ColIndex GetNumberOfColumns() const { return matrix_.num_cols(); }
131
132 // Changes whether or not a non-basic boxed variable is 'relevant' and will be
133 // returned as such by GetIsRelevantBitRow().
135
136 // This is used in UpdateRow to decide whether to compute it using the
137 // row-wise or column-wise representation.
138 EntryIndex GetNumEntriesInRelevantColumns() const;
139
140 // Returns the distance between the upper and lower bound of the given column.
142 return upper_bounds_[col] - lower_bounds_[col];
143 }
144
145 // This is used for the (SP) method of "Progress in the dual simplex method
146 // for large scale LP problems: practical dual phase I algorithms". Achim
147 // Koberstein & Uwe H. Suhl.
148 //
149 // This just set the bounds according to the variable types:
150 // - Boxed variables get fixed at [0,0].
151 // - Upper bounded variables get [-1, 0] bounds
152 // - Lower bounded variables get [0, 1] bounds
153 // - Free variables get [-1000, 1000] to heuristically move them to the basis.
154 // I.e. they cost in the dual infeasibility minimization problem is
155 // multiplied by 1000.
156 //
157 // It then update the status to get an initial dual feasible solution, and
158 // then one just have to apply the phase II algo on this problem to try to
159 // find a feasible solution to the original problem.
160 //
161 // Optimization: When a variable become basic, its non-zero bounds are
162 // relaxed. This is a bit hacky as it requires that the status is updated
163 // before the bounds are read (which is the case). It is however an important
164 // optimization.
165 //
166 // TODO(user): Shall we re-add the bound when the variable is moved out of
167 // the base? it is not needed, but might allow for more bound flips?
168 void TransformToDualPhaseIProblem(Fractional dual_feasibility_tolerance,
169 const DenseRow& reduced_costs);
170 void EndDualPhaseI(Fractional dual_feasibility_tolerance,
171 const DenseRow& reduced_costs);
172
173 private:
174 // Computes the initial/default variable status from its type. A constrained
175 // variable is set to the lowest of its 2 bounds in absolute value.
176 VariableStatus DefaultVariableStatus(ColIndex col) const;
177
178 // Resizes all status related vectors.
179 void ResetStatusInfo();
180
181 // Computes the variable type from its lower and upper bound.
182 VariableType ComputeVariableType(ColIndex col) const;
183
184 // Sets the column relevance and updates num_entries_in_relevant_columns_.
185 void SetRelevance(ColIndex col, bool relevance);
186
187 // Used by TransformToDualPhaseIProblem()/EndDualPhaseI().
188 void UpdateStatusForNewType(ColIndex col);
189
190 // Problem data that should be updated from outside.
191 const CompactSparseMatrix& matrix_;
192
193 // The variables bounds of the current problem. Like everything here, it
194 // include the slacks.
195 DenseRow lower_bounds_;
196 DenseRow upper_bounds_;
197
198 // This is just used temporarily by the dual phase I algo to save the original
199 // bounds.
200 DenseRow saved_lower_bounds_;
201 DenseRow saved_upper_bounds_;
202
203 // Array of variable statuses, indexed by column index.
204 VariableStatusRow variable_status_;
205
206 // Array of variable types, indexed by column index.
207 VariableTypeRow variable_type_;
208
209 // Indicates if a non-basic variable can move up or down while not increasing
210 // the primal infeasibility. Note that all combinaisons are possible for a
211 // variable according to its status: fixed, free, upper or lower bounded. This
212 // is always false for basic variable.
213 DenseBitRow can_increase_;
214 DenseBitRow can_decrease_;
215
216 // Indicates if we should consider this variable for entering the basis during
217 // the simplex algorithm. We never consider fixed variables and in the dual
218 // feasibility phase, we don't consider boxed variable.
219 DenseBitRow relevance_;
220
221 // Indicates if a variable is BASIC or not. There are currently two members
222 // because the DenseBitRow class only supports a nice range-based iteration on
223 // the non-zero positions and not on the others.
224 DenseBitRow is_basic_;
225 DenseBitRow not_basic_;
226
227 // Set of boxed variables that are non-basic.
228 DenseBitRow non_basic_boxed_variables_;
229
230 // Number of entries for the relevant matrix columns (see relevance_).
231 EntryIndex num_entries_in_relevant_columns_;
232
233 // Whether or not a boxed variable should be considered relevant.
234 bool boxed_variables_are_relevant_ = true;
235
236 // Whether we are between the calls TransformToDualPhaseIProblem() and
237 // EndDualPhaseI().
238 bool in_dual_phase_one_ = false;
239
240 DISALLOW_COPY_AND_ASSIGN(VariablesInfo);
241};
242
243} // namespace glop
244} // namespace operations_research
245
246#endif // OR_TOOLS_GLOP_VARIABLES_INFO_H_
bool empty() const
const DenseBitRow & GetIsBasicBitRow() const
int SnapFreeVariablesToBound(Fractional distance, const DenseRow &starting_values)
const DenseRow & GetVariableLowerBounds() const
int ChangeUnusedBasicVariablesToFree(const RowToColMapping &basis)
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 DenseBitRow & GetNotBasicBitRow() const
VariablesInfo(const CompactSparseMatrix &matrix)
const VariableStatusRow & GetStatusRow() const
const DenseRow & GetVariableUpperBounds() 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
absl::Status status
Definition: g_gurobi.cc:35
ColIndex col
Definition: markowitz.cc:183
Collection of objects used to extend the Constraint Solver library.
double distance
VectorXd variable_lower_bounds
VectorXd variable_upper_bounds