OR-Tools  9.3
variable_values.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_VARIABLE_VALUES_H_
15#define OR_TOOLS_GLOP_VARIABLE_VALUES_H_
16
23#include "ortools/util/stats.h"
24
25namespace operations_research {
26namespace glop {
27
28// Class holding all the variable values and responsible for updating them. The
29// variable values 'x' are such that 'A.x = 0' where A is the linear program
30// matrix. This is because slack variables with bounds corresponding to the
31// constraints bounds were added to the linear program matrix A.
32//
33// Some remarks:
34// - For convenience, the variable values are stored in a DenseRow and indexed
35// by ColIndex, like the variables and the columns of A.
36// - During the dual-simplex, all non-basic variable values are at their exact
37// bounds or exactly at 0.0 for a free variable.
38// - During the primal-simplex, the non-basic variable values may not be exactly
39// at their bounds because of bound-shifting during degenerate simplex
40// pivoting which is implemented by not setting the variable values exactly at
41// their bounds to have a lower primal residual error.
43 public:
44 VariableValues(const GlopParameters& parameters,
45 const CompactSparseMatrix& matrix,
46 const RowToColMapping& basis,
47 const VariablesInfo& variables_info,
48 const BasisFactorization& basis_factorization,
49 DualEdgeNorms* dual_edge_norms,
50 DynamicMaximum<RowIndex>* dual_prices);
51
52 // Getters for the variable values.
53 const Fractional Get(ColIndex col) const { return variable_values_[col]; }
54 const DenseRow& GetDenseRow() const { return variable_values_; }
55
56 // Sets the value of a non-basic variable to the exact value implied by its
57 // current status. Note that the basic variable values are NOT updated by this
58 // function and it is up to the client to call RecomputeBasicVariableValues().
60
61 // Calls SetNonBasicVariableValueFromStatus() on all non-basic variables. We
62 // accept any size for free_initial_values, for columns col that are valid
63 // indices, free_initial_values[col] will be used instead of 0.0 for a free
64 // column. If free_initial_values is empty, then we have the default behavior
65 // of starting at zero for all FREE variables.
66 //
67 // Note(user): It is okay to always use the same value to reset a FREE
68 // variable because as soon as a FREE variable value is modified, this
69 // variable shouldn't be FREE anymore. It will either move to a bound or enter
70 // the basis, these are the only options.
71 void ResetAllNonBasicVariableValues(const DenseRow& free_initial_values);
72
73 // Recomputes the value of the basic variables from the non-basic ones knowing
74 // that the linear program matrix A times the variable values vector must be
75 // zero. It is better to call this when the basis is refactorized. This
76 // is checked in debug mode.
78
79 // Computes the infinity norm of A.x where A is the linear_program matrix and
80 // x is the variable values column.
82
83 // Computes the maximum bound error for all the variables, defined as the
84 // distance of the current value of the variable to its interval
85 // [lower bound, upper bound]. The infeasibility is thus equal to 0.0 if the
86 // current value falls within the bounds, to the distance to lower_bound
87 // (resp. upper_bound), if the current value is below (resp. above)
88 // lower_bound (resp. upper_bound).
91
92 // Updates the variable during a simplex pivot:
93 // - step * direction is substracted from the basic variables value.
94 // - step is added to the entering column value.
95 void UpdateOnPivoting(const ScatteredColumn& direction, ColIndex entering_col,
96 Fractional step);
97
98 // Batch version of SetNonBasicVariableValueFromStatus(). This function also
99 // updates the basic variable values and infeasibility statuses if
100 // update_basic_variables is true. The update is done in an incremental way
101 // and is thus more efficient than calling afterwards
102 // RecomputeBasicVariableValues() and RecomputeDualPrices().
103 void UpdateGivenNonBasicVariables(const std::vector<ColIndex>& cols_to_update,
104 bool update_basic_variables);
105
106 // Functions dealing with the primal-infeasible basic variables. A basic
107 // variable is primal-infeasible if its infeasibility is stricly greater than
108 // the primal feasibility tolerance. These are exactly the dual "prices" and
109 // are just used during the dual simplex.
110 //
111 // This information is only available after a call to RecomputeDualPrices()
112 // and has to be kept in sync by calling UpdateDualPrices() for the rows that
113 // changed values.
114 void RecomputeDualPrices();
115 void UpdateDualPrices(const std::vector<RowIndex>& row);
116
117 // The primal phase I objective is related to the primal infeasible
118 // information above. The cost of a basic column will be 1 if the variable is
119 // above its upper bound by strictly more than the primal tolerance, and -1 if
120 // it is lower than its lower bound by strictly less than the same tolerance.
121 //
122 // Returns true iff some cost changed.
123 template <typename Rows>
124 bool UpdatePrimalPhaseICosts(const Rows& rows, DenseRow* objective);
125
126 // Sets the variable value of a given column.
127 void Set(ColIndex col, Fractional value) { variable_values_[col] = value; }
128
129 // Parameters and stats functions.
130 std::string StatString() const { return stats_.StatString(); }
131
132 private:
133 // It is important that the infeasibility is always computed in the same
134 // way. So the code should always use these functions that returns a positive
135 // value when the variable is out of bounds.
136 Fractional GetUpperBoundInfeasibility(ColIndex col) const {
137 return variable_values_[col] -
138 variables_info_.GetVariableUpperBounds()[col];
139 }
140 Fractional GetLowerBoundInfeasibility(ColIndex col) const {
141 return variables_info_.GetVariableLowerBounds()[col] -
142 variable_values_[col];
143 }
144
145 // Input problem data.
146 const GlopParameters& parameters_;
147 const CompactSparseMatrix& matrix_;
148 const RowToColMapping& basis_;
149 const VariablesInfo& variables_info_;
150 const BasisFactorization& basis_factorization_;
151
152 // The dual prices are a normalized version of the primal infeasibility.
153 DualEdgeNorms* dual_edge_norms_;
154 DynamicMaximum<RowIndex>* dual_prices_;
155
156 // Values of the variables.
157 DenseRow variable_values_;
158
159 mutable StatsGroup stats_;
160 mutable ScatteredColumn scratchpad_;
161
162 // A temporary scattered column that is always reset to all zero after use.
163 ScatteredColumn initially_all_zero_scratchpad_;
164
165 DISALLOW_COPY_AND_ASSIGN(VariableValues);
166};
167
168template <typename Rows>
170 DenseRow* objective) {
171 SCOPED_TIME_STAT(&stats_);
172 bool changed = false;
173 const Fractional tolerance = parameters_.primal_feasibility_tolerance();
174 for (const RowIndex row : rows) {
175 const ColIndex col = basis_[row];
176 Fractional new_cost = 0.0;
177 if (GetUpperBoundInfeasibility(col) > tolerance) {
178 new_cost = 1.0;
179 } else if (GetLowerBoundInfeasibility(col) > tolerance) {
180 new_cost = -1.0;
181 }
182 if (new_cost != (*objective)[col]) {
183 changed = true;
184 (*objective)[col] = new_cost;
185 }
186 }
187 return changed;
188}
189
190} // namespace glop
191} // namespace operations_research
192
193#endif // OR_TOOLS_GLOP_VARIABLE_VALUES_H_
std::string StatString() const
Definition: stats.cc:71
void Set(ColIndex col, Fractional value)
void UpdateGivenNonBasicVariables(const std::vector< ColIndex > &cols_to_update, bool update_basic_variables)
void ResetAllNonBasicVariableValues(const DenseRow &free_initial_values)
void UpdateDualPrices(const std::vector< RowIndex > &row)
void UpdateOnPivoting(const ScatteredColumn &direction, ColIndex entering_col, Fractional step)
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)
const Fractional Get(ColIndex col) const
bool UpdatePrimalPhaseICosts(const Rows &rows, DenseRow *objective)
const DenseRow & GetVariableLowerBounds() const
const DenseRow & GetVariableUpperBounds() const
SatParameters parameters
int64_t value
ColIndex col
Definition: markowitz.cc:183
RowIndex row
Definition: markowitz.cc:182
StrictITIVector< ColIndex, Fractional > DenseRow
Definition: lp_types.h:303
StrictITIVector< RowIndex, ColIndex > RowToColMapping
Definition: lp_types.h:346
Collection of objects used to extend the Constraint Solver library.
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:438