19#include "absl/log/check.h"
20#include "absl/types/span.h"
23#include "ortools/glop/parameters.pb.h"
40 transposed_matrix_(transposed_matrix),
41 variables_info_(variables_info),
43 basis_factorization_(basis_factorization),
44 unit_row_left_inverse_(),
45 non_zero_position_list_(),
46 non_zero_position_set_(),
59 return unit_row_left_inverse_;
63 RowIndex leaving_row) {
65 basis_factorization_.TemporaryLeftSolveForUnitRow(
RowToColIndex(leaving_row),
66 &unit_row_left_inverse_);
67 return unit_row_left_inverse_;
71 if (left_inverse_computed_for_ == leaving_row)
return;
72 left_inverse_computed_for_ = leaving_row;
75 basis_factorization_.LeftSolveForUnitRow(
RowToColIndex(leaving_row),
76 &unit_row_left_inverse_);
80 matrix_.ColumnScalarProduct(basis_[leaving_row],
81 unit_row_left_inverse_.values) -
84 Density(unit_row_left_inverse_.values)));
88 if (update_row_computed_for_ == leaving_row)
return;
89 update_row_computed_for_ = leaving_row;
93 if (parameters_.use_transposed_matrix()) {
95 EntryIndex num_row_wise_entries(0);
107 const Fractional drop_tolerance = parameters_.drop_tolerance();
108 unit_row_left_inverse_filtered_non_zeros_.clear();
109 const auto matrix_view = transposed_matrix_.view();
110 if (unit_row_left_inverse_.non_zeros.empty()) {
111 const ColIndex size = unit_row_left_inverse_.values.size();
112 const auto values = unit_row_left_inverse_.values.view();
113 for (ColIndex col(0); col < size; ++col) {
114 if (std::abs(values[col]) > drop_tolerance) {
115 unit_row_left_inverse_filtered_non_zeros_.push_back(col);
116 num_row_wise_entries += matrix_view.ColumnNumEntries(col);
120 for (
const auto e : unit_row_left_inverse_) {
121 if (std::abs(e.coefficient()) > drop_tolerance) {
122 unit_row_left_inverse_filtered_non_zeros_.push_back(e.column());
123 num_row_wise_entries += matrix_view.ColumnNumEntries(e.column());
132 if (unit_row_left_inverse_filtered_non_zeros_.size() == 1) {
133 ComputeUpdatesForSingleRow(
134 unit_row_left_inverse_filtered_non_zeros_.front());
135 num_operations_ += num_row_wise_entries.value();
137 static_cast<double>(num_non_zeros_) /
138 static_cast<double>(matrix_.num_cols().value())));
143 const EntryIndex num_col_wise_entries =
144 variables_info_.GetNumEntriesInRelevantColumns();
149 const double row_wise =
static_cast<double>(num_row_wise_entries.value());
150 if (row_wise < 0.5 *
static_cast<double>(num_col_wise_entries.value())) {
151 if (row_wise < 1.1 *
static_cast<double>(matrix_.num_cols().value())) {
152 ComputeUpdatesRowWiseHypersparse();
157 5 * num_row_wise_entries.value() + matrix_.num_cols().value() / 64;
159 ComputeUpdatesRowWise();
161 num_row_wise_entries.value() + matrix_.num_rows().value();
164 ComputeUpdatesColumnWise();
166 num_col_wise_entries.value() + matrix_.num_cols().value();
169 ComputeUpdatesColumnWise();
171 variables_info_.GetNumEntriesInRelevantColumns().value() +
172 matrix_.num_cols().value();
175 static_cast<double>(num_non_zeros_) /
176 static_cast<double>(matrix_.num_cols().value())));
180 const std::string& algorithm) {
181 unit_row_left_inverse_.values = lhs;
183 if (algorithm ==
"column") {
184 ComputeUpdatesColumnWise();
185 }
else if (algorithm ==
"row") {
186 ComputeUpdatesRowWise();
187 }
else if (algorithm ==
"row_hypersparse") {
188 ComputeUpdatesRowWiseHypersparse();
190 LOG(DFATAL) <<
"Unknown algorithm in ComputeUpdateRowForBenchmark(): '"
198 return absl::MakeSpan(non_zero_position_list_.data(), num_non_zeros_);
202 parameters_ = parameters;
207void UpdateRow::ComputeUpdatesRowWise() {
210 const auto output_coeffs = coefficient_.
view();
211 const auto view = transposed_matrix_.
view();
212 for (
const ColIndex col : unit_row_left_inverse_filtered_non_zeros_) {
213 const Fractional multiplier = unit_row_left_inverse_[col];
214 for (
const EntryIndex i : view.Column(col)) {
216 output_coeffs[pos] += multiplier * view.EntryCoefficient(i);
220 non_zero_position_list_.resize(matrix_.
num_cols().value());
221 auto* non_zeros = non_zero_position_list_.data();
222 const Fractional drop_tolerance = parameters_.drop_tolerance();
224 if (std::abs(output_coeffs[col]) > drop_tolerance) {
228 num_non_zeros_ = non_zeros - non_zero_position_list_.data();
233void UpdateRow::ComputeUpdatesRowWiseHypersparse() {
235 const ColIndex num_cols = matrix_.num_cols();
236 non_zero_position_set_.ClearAndResize(num_cols);
237 coefficient_.resize(num_cols, 0.0);
239 const auto output_coeffs = coefficient_.view();
240 const auto view = transposed_matrix_.view();
241 const auto nz_set = non_zero_position_set_.const_view();
242 for (
const ColIndex col : unit_row_left_inverse_filtered_non_zeros_) {
243 const Fractional multiplier = unit_row_left_inverse_[col];
244 for (
const EntryIndex i : view.Column(col)) {
246 const Fractional v = multiplier * view.EntryCoefficient(i);
252 output_coeffs[pos] = v;
253 non_zero_position_set_.Set(pos);
255 output_coeffs[pos] += v;
261 non_zero_position_set_.Intersection(variables_info_.GetIsRelevantBitRow());
262 non_zero_position_list_.resize(matrix_.num_cols().value());
263 auto* non_zeros = non_zero_position_list_.data();
264 const Fractional drop_tolerance = parameters_.drop_tolerance();
265 for (
const ColIndex col : non_zero_position_set_) {
270 if (std::abs(output_coeffs[col]) > drop_tolerance) {
274 num_non_zeros_ = non_zeros - non_zero_position_list_.data();
277void UpdateRow::ComputeUpdatesForSingleRow(ColIndex row_as_col) {
278 coefficient_.resize(matrix_.num_cols(), 0.0);
279 non_zero_position_list_.resize(matrix_.num_cols().value());
280 auto* non_zeros = non_zero_position_list_.data();
282 const DenseBitRow& is_relevant = variables_info_.GetIsRelevantBitRow();
283 const Fractional drop_tolerance = parameters_.drop_tolerance();
284 const Fractional multiplier = unit_row_left_inverse_[row_as_col];
285 const auto output_coeffs = coefficient_.
view();
286 const auto view = transposed_matrix_.view();
287 for (
const EntryIndex i : view.Column(row_as_col)) {
289 if (!is_relevant[pos])
continue;
291 const Fractional v = multiplier * view.EntryCoefficient(i);
292 if (std::abs(v) > drop_tolerance) {
293 output_coeffs[pos] = v;
297 num_non_zeros_ = non_zeros - non_zero_position_list_.data();
300void UpdateRow::ComputeUpdatesColumnWise() {
303 coefficient_.resize(matrix_.num_cols(), 0.0);
304 non_zero_position_list_.resize(matrix_.num_cols().value());
305 auto* non_zeros = non_zero_position_list_.data();
307 const Fractional drop_tolerance = parameters_.drop_tolerance();
308 const auto output_coeffs = coefficient_.view();
309 const auto view = matrix_.view();
310 const auto unit_row_left_inverse = unit_row_left_inverse_.values.const_view();
311 for (
const ColIndex col : variables_info_.GetIsRelevantBitRow()) {
314 view.ColumnScalarProduct(col, unit_row_left_inverse);
320 if (std::abs(coeff) > drop_tolerance) {
322 output_coeffs[col] = coeff;
325 num_non_zeros_ = non_zeros - non_zero_position_list_.data();
333 CHECK_EQ(leaving_row, left_inverse_computed_for_);
335 const ColIndex num_cols = matrix_.num_cols();
339 (*output)[basis_[leaving_row]] = 1.0;
342 const Fractional drop_tolerance = parameters_.drop_tolerance();
343 const auto view = matrix_.view();
344 const auto unit_row_left_inverse = unit_row_left_inverse_.values.const_view();
345 for (
const ColIndex col : variables_info_.GetNotBasicBitRow()) {
347 view.ColumnScalarProduct(col, unit_row_left_inverse);
348 if (std::abs(coeff) > drop_tolerance) {
349 (*output)[col] = coeff;
ColIndex num_cols() const
void AssignToZero(IntType size)
const DenseRow & GetCoefficients() const
const ScatteredRow & ComputeAndGetUnitRowLeftInverse(RowIndex leaving_row)
void SetParameters(const GlopParameters ¶meters)
Sets the algorithm parameters.
void ComputeFullUpdateRow(RowIndex leaving_row, DenseRow *output) const
const ScatteredRow & GetUnitRowLeftInverse() const
void ComputeUnitRowLeftInverse(RowIndex leaving_row)
void ComputeUpdateRow(RowIndex leaving_row)
UpdateRow(const CompactSparseMatrix &matrix, const CompactSparseMatrix &transposed_matrix, const VariablesInfo &variables_info, const RowToColMapping &basis, const BasisFactorization &basis_factorization)
Takes references to the linear program data we need.
void ComputeUpdateRowForBenchmark(const DenseRow &lhs, const std::string &algorithm)
absl::Span< const ColIndex > GetNonZeroPositions() const
const DenseBitRow & GetIsRelevantBitRow() const
double Density(const DenseRow &row)
StrictITIVector< RowIndex, ColIndex > RowToColMapping
void ComputeNonZeros(const StrictITIVector< IndexType, Fractional > &input, std::vector< IndexType > *non_zeros)
Computes the positions of the non-zeros of a dense vector.
Bitset64< ColIndex > DenseBitRow
Row of bits.
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
constexpr RowIndex kInvalidRow(-1)
StrictITIVector< ColIndex, Fractional > DenseRow
Row-vector types. Row-vector types are indexed by a column index.
In SWIG mode, we don't want anything besides these top-level includes.
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)