19#include "absl/log/check.h"
22#include "ortools/glop/parameters.pb.h"
37 : compact_matrix_(compact_matrix),
38 variables_info_(variables_info),
39 basis_factorization_(basis_factorization),
41 recompute_edge_squared_norms_(true),
42 reset_devex_weights_(true),
43 edge_squared_norms_(),
44 matrix_column_norms_(),
46 direction_left_inverse_(),
51 matrix_column_norms_.clear();
52 recompute_edge_squared_norms_ =
true;
53 reset_devex_weights_ =
true;
54 for (
bool* watcher : watchers_) *watcher =
true;
58 if (pricing_rule_ != GlopParameters ::STEEPEST_EDGE)
return false;
59 return recompute_edge_squared_norms_;
63 switch (pricing_rule_) {
64 case GlopParameters::DANTZIG:
66 case GlopParameters::STEEPEST_EDGE:
68 case GlopParameters::DEVEX:
74 if (recompute_edge_squared_norms_) ComputeEdgeSquaredNorms();
75 return edge_squared_norms_;
79 if (reset_devex_weights_) ResetDevexWeights();
80 return devex_weights_;
84 if (matrix_column_norms_.empty()) ComputeMatrixColumnNorms();
85 return matrix_column_norms_;
90 if (!recompute_edge_squared_norms_) {
94 const Fractional old_squared_norm = edge_squared_norms_[entering_col];
96 edge_squared_norms_[entering_col] = precise_squared_norm;
98 const Fractional precise_norm = sqrt(precise_squared_norm);
99 const Fractional estimated_edges_norm_accuracy =
100 (precise_norm - sqrt(old_squared_norm)) / precise_norm;
101 stats_.edges_norm_accuracy.
Add(estimated_edges_norm_accuracy);
102 if (std::abs(estimated_edges_norm_accuracy) >
103 parameters_.recompute_edges_norm_threshold()) {
104 VLOG(1) <<
"Recomputing edge norms: " << sqrt(precise_squared_norm)
105 <<
" vs " << sqrt(old_squared_norm);
106 recompute_edge_squared_norms_ =
true;
107 for (
bool* watcher : watchers_) *watcher =
true;
110 if (old_squared_norm < 0.25 * precise_squared_norm) {
111 VLOG(1) <<
"Imprecise norm, reprice. old=" << old_squared_norm
112 <<
" new=" << precise_squared_norm;
120 ColIndex leaving_col,
121 RowIndex leaving_row,
125 DCHECK_NE(entering_col, leaving_col);
126 if (!recompute_edge_squared_norms_) {
128 ComputeDirectionLeftInverse(entering_col, direction);
129 UpdateEdgeSquaredNorms(entering_col, leaving_col, leaving_row,
130 direction.
values, *update_row);
132 if (!reset_devex_weights_) {
135 ++num_devex_updates_since_reset_;
136 if (num_devex_updates_since_reset_ >
137 parameters_.devex_weights_reset_period()) {
138 reset_devex_weights_ =
true;
141 UpdateDevexWeights(entering_col, leaving_col, leaving_row,
142 direction.
values, *update_row);
147void PrimalEdgeNorms::ComputeMatrixColumnNorms() {
156void PrimalEdgeNorms::ComputeEdgeSquaredNorms() {
169 recompute_edge_squared_norms_ =
false;
175void PrimalEdgeNorms::ComputeDirectionLeftInverse(
176 ColIndex entering_col,
const ScatteredColumn& direction) {
183 const double kThreshold = 0.05 *
size.value();
184 if (!direction_left_inverse_.
non_zeros.empty() &&
185 (direction_left_inverse_.
non_zeros.size() + direction.non_zeros.size() <
188 for (
const auto e : direction) {
189 direction_left_inverse_[
RowToColIndex(e.row())] = e.coefficient();
193 direction_left_inverse_.
non_zeros.clear();
196 if (direction.non_zeros.size() < kThreshold) {
199 basis_factorization_.
LeftSolve(&direction_left_inverse_);
204 direction_left_inverse_.
values) -
217void PrimalEdgeNorms::UpdateEdgeSquaredNorms(ColIndex entering_col,
218 ColIndex leaving_col,
219 RowIndex leaving_row,
221 const UpdateRow& update_row) {
227 const Fractional pivot = -direction[leaving_row];
228 DCHECK_NE(pivot, 0.0);
232 const Fractional entering_squared_norm = edge_squared_norms_[entering_col];
234 std::max(1.0, entering_squared_norm /
Square(pivot));
236 int stat_lower_bounded_norms = 0;
238 const auto view = compact_matrix_.
view();
239 auto output = edge_squared_norms_.
view();
240 const auto direction_left_inverse =
242 for (
const ColIndex
col : update_row.GetNonZeroPositions()) {
245 view.ColumnScalarProduct(
col, direction_left_inverse);
246 num_operations_ += view.ColumnNumEntries(
col).value();
252 coeff * (coeff * leaving_squared_norm + factor * scalar_product);
262 ++stat_lower_bounded_norms;
265 output[leaving_col] = leaving_squared_norm;
266 stats_.lower_bounded_norms.
Add(stat_lower_bounded_norms);
269void PrimalEdgeNorms::UpdateDevexWeights(
270 ColIndex entering_col ,
271 ColIndex leaving_col , RowIndex leaving_row,
272 const DenseColumn& direction,
const UpdateRow& update_row) {
278 const Fractional pivot_magnitude = std::abs(direction[leaving_row]);
280 std::max(1.0, entering_norm / pivot_magnitude);
281 for (
const ColIndex
col : update_row.GetNonZeroPositions()) {
283 const Fractional update_vector_norm = std::abs(coeff) * leaving_norm;
284 devex_weights_[
col] =
285 std::max(devex_weights_[
col],
Square(update_vector_norm));
287 devex_weights_[leaving_col] =
Square(leaving_norm);
290void PrimalEdgeNorms::ResetDevexWeights() {
292 if (parameters_.initialize_devex_with_column_norms()) {
297 num_devex_updates_since_reset_ = 0;
298 reset_devex_weights_ =
false;
bool IsRefactorized() const
Returns true if the factorization was just recomputed.
Fractional RightSolveSquaredNorm(const ColumnView &a) const
void LeftSolve(ScatteredRow *y) const
Left solves the system y.B = rhs, where y initially contains rhs.
EntryIndex num_entries() const
ColIndex num_cols() const
Fractional ColumnScalarProduct(ColIndex col, const DenseRow &vector) const
ColumnView column(ColIndex col) const
const DenseRow & GetMatrixColumnNorms()
DenseRow::ConstView GetSquaredNorms()
void UpdateBeforeBasisPivot(ColIndex entering_col, ColIndex leaving_col, RowIndex leaving_row, const ScatteredColumn &direction, UpdateRow *update_row)
const DenseRow & GetDevexWeights()
bool TestEnteringEdgeNormPrecision(ColIndex entering_col, const ScatteredColumn &direction)
PrimalEdgeNorms(const CompactSparseMatrix &compact_matrix, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization)
const DenseRow & GetEdgeSquaredNorms()
bool NeedsBasisRefactorization() const
void assign(IntType size, const T &v)
ConstView const_view() const
void resize(IntType size)
void ComputeUpdateRow(RowIndex leaving_row)
const DenseBitRow & GetIsRelevantBitRow() const
double Density(const DenseRow &row)
Fractional Square(Fractional f)
const DenseRow & Transpose(const DenseColumn &col)
Similar comment as the other Transpose() implementation above.
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
void ClearAndResizeVectorWithNonZeros(IndexType size, ScatteredRowOrCol *v)
Sets a dense vector for which the non zeros are known to be non_zeros.
Fractional PreciseSquaredNorm(const SparseColumn &v)
Fractional SquaredNorm(const SparseColumn &v)
StrictITIVector< RowIndex, Fractional > DenseColumn
Column-vector types. Column-vector types are indexed by a row index.
const ScatteredRow & TransposedView(const ScatteredColumn &c)
In SWIG mode, we don't want anything besides these top-level includes.
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
StrictITIVector< Index, Fractional > values
std::vector< Index > non_zeros