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