Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
variable_values.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_VARIABLE_VALUES_H_
15#define OR_TOOLS_GLOP_VARIABLE_VALUES_H_
16
17#include <algorithm>
18#include <string>
19#include <vector>
20
21#include "absl/types/span.h"
24#include "ortools/glop/parameters.pb.h"
30#include "ortools/util/stats.h"
31
32namespace operations_research {
33namespace glop {
34
35// Class holding all the variable values and responsible for updating them. The
36// variable values 'x' are such that 'A.x = 0' where A is the linear program
37// matrix. This is because slack variables with bounds corresponding to the
38// constraints bounds were added to the linear program matrix A.
39//
40// Some remarks:
41// - For convenience, the variable values are stored in a DenseRow and indexed
42// by ColIndex, like the variables and the columns of A.
43// - During the dual-simplex, all non-basic variable values are at their exact
44// bounds or exactly at 0.0 for a free variable.
45// - During the primal-simplex, the non-basic variable values may not be exactly
46// at their bounds because of bound-shifting during degenerate simplex
47// pivoting which is implemented by not setting the variable values exactly at
48// their bounds to have a lower primal residual error.
50 public:
51 VariableValues(const GlopParameters& parameters,
52 const CompactSparseMatrix& matrix,
53 const RowToColMapping& basis,
54 const VariablesInfo& variables_info,
55 const BasisFactorization& basis_factorization,
56 DualEdgeNorms* dual_edge_norms,
57 DynamicMaximum<RowIndex>* dual_prices);
58
59 // This type is neither copyable nor movable.
62
63 // Getters for the variable values.
64 Fractional Get(ColIndex col) const { return variable_values_[col]; }
65 const DenseRow& GetDenseRow() const { return variable_values_; }
66
67 // Sets the value of a non-basic variable to the exact value implied by its
68 // current status. Note that the basic variable values are NOT updated by this
69 // function and it is up to the client to call RecomputeBasicVariableValues().
71
72 // Calls SetNonBasicVariableValueFromStatus() on all non-basic variables. We
73 // accept any size for free_initial_values, for columns col that are valid
74 // indices, free_initial_values[col] will be used instead of 0.0 for a free
75 // column. If free_initial_values is empty, then we have the default behavior
76 // of starting at zero for all FREE variables.
77 //
78 // Note(user): It is okay to always use the same value to reset a FREE
79 // variable because as soon as a FREE variable value is modified, this
80 // variable shouldn't be FREE anymore. It will either move to a bound or enter
81 // the basis, these are the only options.
82 void ResetAllNonBasicVariableValues(const DenseRow& free_initial_values);
83
84 // Recomputes the value of the basic variables from the non-basic ones knowing
85 // that the linear program matrix A times the variable values vector must be
86 // zero. It is better to call this when the basis is refactorized. This
87 // is checked in debug mode.
89
90 // Computes the infinity norm of A.x where A is the linear_program matrix and
91 // x is the variable values column.
93
94 // Computes the maximum bound error for all the variables, defined as the
95 // distance of the current value of the variable to its interval
96 // [lower bound, upper bound]. The infeasibility is thus equal to 0.0 if the
97 // current value falls within the bounds, to the distance to lower_bound
98 // (resp. upper_bound), if the current value is below (resp. above)
99 // lower_bound (resp. upper_bound).
102
103 // Updates the variable during a simplex pivot:
104 // - step * direction is subtracted from the basic variables value.
105 // - step is added to the entering column value.
106 void UpdateOnPivoting(const ScatteredColumn& direction, ColIndex entering_col,
107 Fractional step);
108
109 // Batch version of SetNonBasicVariableValueFromStatus(). This function also
110 // updates the basic variable values and infeasibility statuses if
111 // update_basic_variables is true. The update is done in an incremental way
112 // and is thus more efficient than calling afterwards
113 // RecomputeBasicVariableValues() and RecomputeDualPrices().
114 void UpdateGivenNonBasicVariables(absl::Span<const ColIndex> cols_to_update,
115 bool update_basic_variables);
116
117 // Functions dealing with the primal-infeasible basic variables. A basic
118 // variable is primal-infeasible if its infeasibility is stricly greater than
119 // the primal feasibility tolerance. These are exactly the dual "prices" once
120 // recalled by the norms. This is only used during the dual simplex.
121 //
122 // This information is only available after a call to RecomputeDualPrices()
123 // and has to be kept in sync by calling UpdateDualPrices() for the rows that
124 // changed values.
125 //
126 // TODO(user): On some problem like stp3d.mps or pds-100.mps, using different
127 // price like abs(infeasibility) / squared_norms give better result. Some
128 // solver switch according to a criteria like all entry are +1/-1, the column
129 // have no more than 24 non-zero and the average column size is no more than
130 // 6! Understand and implement some variant of this? I think the gain is
131 // mainly because of using sparser vectors?
132 void RecomputeDualPrices(bool put_more_importance_on_norm = false);
133 void UpdateDualPrices(absl::Span<const RowIndex> row);
134
135 // The primal phase I objective is related to the primal infeasible
136 // information above. The cost of a basic column will be 1 if the variable is
137 // above its upper bound by strictly more than the primal tolerance, and -1 if
138 // it is lower than its lower bound by strictly less than the same tolerance.
139 //
140 // Returns true iff some cost changed.
141 template <typename Rows>
142 bool UpdatePrimalPhaseICosts(const Rows& rows, DenseRow* objective);
143
144 // Sets the variable value of a given column.
145 void Set(ColIndex col, Fractional value) { variable_values_[col] = value; }
146
147 // Parameters and stats functions.
148 std::string StatString() const { return stats_.StatString(); }
149
150 private:
151 // It is important that the infeasibility is always computed in the same
152 // way. So the code should always use these functions that returns a positive
153 // value when the variable is out of bounds.
154 Fractional GetColInfeasibility(ColIndex col,
155 DenseRow::ConstView variable_values,
158 return std::max(variable_values[col] - upper_bounds[col],
159 lower_bounds[col] - variable_values[col]);
160 }
161
162 // Input problem data.
163 const GlopParameters& parameters_;
164 const CompactSparseMatrix& matrix_;
165 const RowToColMapping& basis_;
166 const VariablesInfo& variables_info_;
167 const BasisFactorization& basis_factorization_;
168
169 // This is set by RecomputeDualPrices() so that UpdateDualPrices() use
170 // the same formula.
171 bool put_more_importance_on_norm_ = false;
172
173 // The dual prices are a normalized version of the primal infeasibility.
174 DualEdgeNorms* dual_edge_norms_;
175 DynamicMaximum<RowIndex>* dual_prices_;
176
177 // Values of the variables.
178 DenseRow variable_values_;
179
180 mutable StatsGroup stats_;
181 mutable ScatteredColumn scratchpad_;
182
183 // A temporary scattered column that is always reset to all zero after use.
184 ScatteredColumn initially_all_zero_scratchpad_;
185};
186
187template <typename Rows>
189 DenseRow* objective) {
190 SCOPED_TIME_STAT(&stats_);
191 bool changed = false;
192 const Fractional tolerance = parameters_.primal_feasibility_tolerance();
193 const DenseRow::ConstView variable_values = variable_values_.const_view();
195 variables_info_.GetVariableLowerBounds().const_view();
197 variables_info_.GetVariableUpperBounds().const_view();
198 for (const RowIndex row : rows) {
199 const ColIndex col = basis_[row];
200 Fractional new_cost = 0.0;
201 if (variable_values[col] - upper_bounds[col] > tolerance) {
202 new_cost = 1.0;
203 } else if (lower_bounds[col] - variable_values[col] > tolerance) {
204 new_cost = -1.0;
205 }
206 if (new_cost != (*objective)[col]) {
207 changed = true;
208 (*objective)[col] = new_cost;
209 }
210 }
211 return changed;
212}
213
214} // namespace glop
215} // namespace operations_research
216
217#endif // OR_TOOLS_GLOP_VARIABLE_VALUES_H_
Base class to print a nice summary of a group of statistics.
Definition stats.h:128
std::string StatString() const
Definition stats.cc:77
bool UpdatePrimalPhaseICosts(const Rows &rows, DenseRow *objective)
VariableValues(const VariableValues &)=delete
This type is neither copyable nor movable.
void Set(ColIndex col, Fractional value)
Sets the variable value of a given column.
std::string StatString() const
Parameters and stats functions.
void UpdateOnPivoting(const ScatteredColumn &direction, ColIndex entering_col, Fractional step)
void UpdateGivenNonBasicVariables(absl::Span< const ColIndex > cols_to_update, bool update_basic_variables)
VariableValues(const GlopParameters &parameters, const CompactSparseMatrix &matrix, const RowToColMapping &basis, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization, DualEdgeNorms *dual_edge_norms, DynamicMaximum< RowIndex > *dual_prices)
void ResetAllNonBasicVariableValues(const DenseRow &free_initial_values)
VariableValues & operator=(const VariableValues &)=delete
void RecomputeDualPrices(bool put_more_importance_on_norm=false)
void UpdateDualPrices(absl::Span< const RowIndex > row)
Fractional Get(ColIndex col) const
Getters for the variable values.
const DenseRow & GetVariableLowerBounds() const
Returns the variable bounds.
const DenseRow & GetVariableUpperBounds() const
SatParameters parameters
int64_t value
ColIndex col
Definition markowitz.cc:187
RowIndex row
Definition markowitz.cc:186
StrictITIVector< RowIndex, ColIndex > RowToColMapping
Definition lp_types.h:396
StrictITIVector< ColIndex, Fractional > DenseRow
Row-vector types. Row-vector types are indexed by a column index.
Definition lp_types.h:353
In SWIG mode, we don't want anything besides these top-level includes.
std::vector< double > lower_bounds
Definition lp_utils.cc:746
std::vector< double > upper_bounds
Definition lp_utils.cc:747
#define SCOPED_TIME_STAT(stats)
Definition stats.h:418