20#include "absl/log/check.h"
21#include "absl/log/log.h"
38 : compact_matrix_(compact_matrix),
39 variables_info_(variables_info),
40 basis_factorization_(basis_factorization),
42 recompute_edge_squared_norms_(true),
43 reset_devex_weights_(true),
44 edge_squared_norms_(),
45 matrix_column_norms_(),
47 direction_left_inverse_(),
52 matrix_column_norms_.clear();
53 recompute_edge_squared_norms_ =
true;
54 reset_devex_weights_ =
true;
55 for (
bool* watcher : watchers_) *watcher =
true;
59 if (pricing_rule_ != GlopParameters ::STEEPEST_EDGE)
return false;
60 return recompute_edge_squared_norms_;
64 switch (pricing_rule_) {
72 LOG(FATAL) <<
"Invalid pricing rule: " << pricing_rule_;
76 if (recompute_edge_squared_norms_) ComputeEdgeSquaredNorms();
77 return edge_squared_norms_;
81 if (reset_devex_weights_) ResetDevexWeights();
82 return devex_weights_;
86 if (matrix_column_norms_.empty()) ComputeMatrixColumnNorms();
87 return matrix_column_norms_;
92 if (!recompute_edge_squared_norms_) {
96 const Fractional old_squared_norm = edge_squared_norms_[entering_col];
98 edge_squared_norms_[entering_col] = precise_squared_norm;
100 const Fractional precise_norm = sqrt(precise_squared_norm);
101 const Fractional estimated_edges_norm_accuracy =
102 (precise_norm - sqrt(old_squared_norm)) / precise_norm;
103 stats_.edges_norm_accuracy.Add(estimated_edges_norm_accuracy);
104 if (std::abs(estimated_edges_norm_accuracy) >
105 parameters_.recompute_edges_norm_threshold()) {
106 VLOG(1) <<
"Recomputing edge norms: " << sqrt(precise_squared_norm)
107 <<
" vs " << sqrt(old_squared_norm);
108 recompute_edge_squared_norms_ =
true;
109 for (
bool* watcher : watchers_) *watcher =
true;
112 if (old_squared_norm < 0.25 * precise_squared_norm) {
113 VLOG(1) <<
"Imprecise norm, reprice. old=" << old_squared_norm
114 <<
" new=" << precise_squared_norm;
122 ColIndex leaving_col,
123 RowIndex leaving_row,
127 DCHECK_NE(entering_col, leaving_col);
128 if (!recompute_edge_squared_norms_) {
130 ComputeDirectionLeftInverse(entering_col, direction);
131 UpdateEdgeSquaredNorms(entering_col, leaving_col, leaving_row,
132 direction.
values, *update_row);
134 if (!reset_devex_weights_) {
137 ++num_devex_updates_since_reset_;
138 if (num_devex_updates_since_reset_ >
139 parameters_.devex_weights_reset_period()) {
140 reset_devex_weights_ =
true;
143 UpdateDevexWeights(entering_col, leaving_col, leaving_row,
144 direction.
values, *update_row);
149void PrimalEdgeNorms::ComputeMatrixColumnNorms() {
152 for (ColIndex col(0); col < compact_matrix_.
num_cols(); ++col) {
158void PrimalEdgeNorms::ComputeEdgeSquaredNorms() {
163 const bool test_limit = (time_limit_ !=
nullptr) &&
174 compact_matrix_.
column(col));
182 recompute_edge_squared_norms_ =
false;
188void PrimalEdgeNorms::ComputeDirectionLeftInverse(
195 const ColIndex size =
RowToColIndex(direction.values.size());
196 const double kThreshold = 0.05 * size.value();
197 if (!direction_left_inverse_.non_zeros.empty() &&
198 (direction_left_inverse_.non_zeros.size() + direction.non_zeros.size() <
201 for (
const auto e : direction) {
202 direction_left_inverse_[
RowToColIndex(e.row())] = e.coefficient();
205 direction_left_inverse_.values =
Transpose(direction.values);
206 direction_left_inverse_.non_zeros.clear();
209 if (direction.non_zeros.size() < kThreshold) {
212 basis_factorization_.LeftSolve(&direction_left_inverse_);
216 compact_matrix_.ColumnScalarProduct(entering_col,
217 direction_left_inverse_.values) -
220 Density(direction_left_inverse_.values)));
230void PrimalEdgeNorms::UpdateEdgeSquaredNorms(ColIndex entering_col,
231 ColIndex leaving_col,
232 RowIndex leaving_row,
240 const Fractional pivot = -direction[leaving_row];
241 DCHECK_NE(pivot, 0.0);
243 const ColIndex first_slack =
244 compact_matrix_.num_cols() -
RowToColIndex(compact_matrix_.num_rows());
248 const Fractional entering_squared_norm = edge_squared_norms_[entering_col];
252 int stat_lower_bounded_norms = 0;
254 const auto view = compact_matrix_.view();
255 auto output = edge_squared_norms_.view();
256 const auto direction_left_inverse =
257 direction_left_inverse_.values.const_view();
258 for (
const ColIndex col : update_row.GetNonZeroPositions()) {
259 const Fractional coeff = update_row.GetCoefficient(col);
262 ? direction_left_inverse_[col - first_slack]
263 : view.ColumnScalarProduct(col, direction_left_inverse);
264 num_operations_ += view.ColumnNumEntries(col).value();
270 coeff * (coeff * leaving_squared_norm + factor * scalar_product);
278 if (output[col] < lower_bound) {
279 output[col] = lower_bound;
280 ++stat_lower_bounded_norms;
283 output[leaving_col] = leaving_squared_norm;
284 stats_.lower_bounded_norms.Add(stat_lower_bounded_norms);
287void PrimalEdgeNorms::UpdateDevexWeights(
288 ColIndex entering_col ,
289 ColIndex leaving_col , RowIndex leaving_row,
296 const Fractional pivot_magnitude = std::abs(direction[leaving_row]);
298 std::max(
Fractional(1.0), entering_norm / pivot_magnitude);
299 for (
const ColIndex col : update_row.GetNonZeroPositions()) {
300 const Fractional coeff = update_row.GetCoefficient(col);
301 const Fractional update_vector_norm = std::abs(coeff) * leaving_norm;
302 devex_weights_[col] =
303 std::max(devex_weights_[col],
Square(update_vector_norm));
305 devex_weights_[leaving_col] =
Square(leaving_norm);
308void PrimalEdgeNorms::ResetDevexWeights() {
310 if (parameters_.initialize_devex_with_column_norms()) {
313 devex_weights_.assign(compact_matrix_.num_cols(), 1.0);
315 num_devex_updates_since_reset_ = 0;
316 reset_devex_weights_ =
false;
StrictITISpan< ColIndex, const Fractional > ConstView
bool IsRefactorized() const
Fractional RightSolveSquaredNorm(const ColumnView &a) const
EntryIndex NumberOfEntriesInLU() const
EntryIndex num_entries() const
ColIndex num_cols() const
ColumnView column(ColIndex col) const
static constexpr PricingRule DEVEX
static constexpr PricingRule DANTZIG
static constexpr PricingRule STEEPEST_EDGE
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
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)
ColIndex RowToColIndex(RowIndex row)
void ClearAndResizeVectorWithNonZeros(IndexType size, ScatteredRowOrCol *v)
Fractional PreciseSquaredNorm(const SparseColumn &v)
Fractional SquaredNorm(const SparseColumn &v)
StrictITIVector< RowIndex, Fractional > DenseColumn
StrictITIVector< ColIndex, Fractional > DenseRow
const ScatteredRow & TransposedView(const ScatteredColumn &c)
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
StrictITIVector< Index, Fractional > values
std::vector< Index > non_zeros