33 : max_scaled_abs_cost_(0.0),
34 bixby_column_comparator_(*this),
35 triangular_column_comparator_(*this),
36 compact_matrix_(compact_matrix),
40 variable_type_(variable_type) {}
46 const RowIndex num_rows = compact_matrix_.
num_rows();
49 DCHECK_EQ(num_rows, basis->
size());
51 for (RowIndex
row(0);
row < num_rows; ++
row) {
53 can_be_replaced[
row] =
true;
54 has_zero_coefficient[
row] =
true;
63 std::vector<ColIndex> candidates;
68 for (
int i = 0; i < candidates.size(); ++i) {
69 bool enter_basis =
false;
70 const ColIndex candidate_col_index = candidates[i];
71 const auto& candidate_col = compact_matrix_.
column(candidate_col_index);
79 RowIndex candidate_row;
81 candidate_col, has_zero_coefficient, &candidate_row);
83 if (candidate_coeff > kBixbyHighThreshold) {
85 }
else if (
IsDominated(candidate_col, scaled_diagonal_abs)) {
88 if (candidate_coeff != 0.0) {
94 can_be_replaced[candidate_row] =
false;
97 scaled_diagonal_abs[candidate_row] =
98 kBixbyLowThreshold * std::abs(candidate_coeff);
99 (*basis)[candidate_row] = candidate_col_index;
106 return GetMarosBasis<false>(num_cols, basis);
111 return GetMarosBasis<true>(num_cols, basis);
116 return CompleteTriangularBasis<false>(num_cols, basis);
121 return CompleteTriangularBasis<true>(num_cols, basis);
124 template <
bool only_allow_zero_cost_column>
125 void InitialBasis::CompleteTriangularBasis(ColIndex num_cols,
128 const RowIndex num_rows = compact_matrix_.
num_rows();
130 DCHECK_EQ(num_rows, basis->
size());
132 for (RowIndex
row(0);
row < num_rows; ++
row) {
134 can_be_replaced[
row] =
true;
139 MatrixNonZeroPattern residual_pattern;
140 residual_pattern.Reset(num_rows, num_cols);
141 for (ColIndex
col(0);
col < num_cols; ++
col) {
142 if (only_allow_zero_cost_column && objective_[
col] != 0.0)
continue;
144 if (can_be_replaced[e.row()]) {
145 residual_pattern.AddEntry(e.row(),
col);
152 std::vector<ColIndex> residual_singleton_column;
153 max_scaled_abs_cost_ = 0.0;
154 for (ColIndex
col(0);
col < num_cols; ++
col) {
155 max_scaled_abs_cost_ =
156 std::max(max_scaled_abs_cost_, std::abs(objective_[
col]));
157 if (residual_pattern.ColDegree(
col) == 1) {
158 residual_singleton_column.push_back(
col);
162 max_scaled_abs_cost_ =
163 (max_scaled_abs_cost_ == 0.0) ? 1.0 : kBixbyWeight * max_scaled_abs_cost_;
164 std::priority_queue<ColIndex, std::vector<ColIndex>,
165 InitialBasis::TriangularColumnComparator>
166 queue(residual_singleton_column.begin(), residual_singleton_column.end(),
167 triangular_column_comparator_);
171 while (!queue.empty()) {
172 const ColIndex candidate = queue.top();
174 if (residual_pattern.ColDegree(candidate) != 1)
continue;
182 max_magnitude =
std::max(max_magnitude, std::abs(e.coefficient()));
183 if (can_be_replaced[e.row()]) {
185 coeff = e.coefficient();
190 if (std::abs(coeff) < kStabilityThreshold * max_magnitude)
continue;
194 (*basis)[
row] = candidate;
195 can_be_replaced[
row] =
false;
196 residual_pattern.DeleteRowAndColumn(
row, candidate);
197 for (
const ColIndex
col : residual_pattern.RowNonZero(
row)) {
198 if (
col == candidate)
continue;
199 residual_pattern.DecreaseColDegree(
col);
200 if (residual_pattern.ColDegree(
col) == 1) {
207 int InitialBasis::GetMarosPriority(ColIndex
col)
const {
209 switch (variable_type_[
col]) {
223 int InitialBasis::GetMarosPriority(RowIndex
row)
const {
229 return GetMarosPriority(slack_index);
232 template <
bool only_allow_zero_cost_column>
233 void InitialBasis::GetMarosBasis(ColIndex num_cols,
RowToColMapping* basis) {
234 VLOG(1) <<
"Starting Maros crash procedure.";
237 const RowIndex num_rows = compact_matrix_.
num_rows();
238 const ColIndex first_slack = num_cols -
RowToColIndex(num_rows);
239 DCHECK_EQ(num_rows, basis->size());
240 basis->resize(num_rows);
241 for (RowIndex
row(0);
row < num_rows;
row++) {
247 for (ColIndex
col(0);
col < first_slack; ++
col) {
249 (only_allow_zero_cost_column && objective_[
col] != 0.0)) {
250 available[
col] =
false;
253 for (ColIndex
col = first_slack;
col < num_cols; ++
col) {
255 available[
col] =
false;
260 MatrixNonZeroPattern residual_pattern;
261 residual_pattern.Reset(num_rows, num_cols);
262 for (ColIndex
col(0);
col < first_slack; ++
col) {
265 residual_pattern.AddEntry(e.row(),
col);
271 for (RowIndex
row(0);
row < num_rows;
row++) {
272 if (residual_pattern.RowDegree(
row) == 0) {
282 for (RowIndex
row(0);
row < num_rows;
row++) {
285 10 * (3 - GetMarosPriority(
row)) - residual_pattern.RowDegree(
row);
286 if (rpf > max_row_priority_function) {
287 max_row_priority_function = rpf;
300 for (
const ColIndex
col : residual_pattern.RowNonZero(max_rpf_row)) {
301 if (!available[
col])
continue;
303 10 * GetMarosPriority(
col) - residual_pattern.ColDegree(
col);
304 if (cpf > max_col_priority_function) {
307 pivot_absolute_value = 0.0;
308 const auto& column_values = compact_matrix_.
column(
col);
310 const Fractional absolute_value = std::fabs(e.coefficient());
311 if (e.row() == max_rpf_row) pivot_absolute_value = absolute_value;
312 max_magnitude =
std::max(max_magnitude, absolute_value);
314 if (pivot_absolute_value >= kStabilityThreshold * max_magnitude) {
315 max_col_priority_function = cpf;
329 const int row_priority = GetMarosPriority(max_rpf_row);
330 const int column_priority = GetMarosPriority(max_cpf_col);
331 if (row_priority >= column_priority) {
338 (*basis)[max_rpf_row] = max_cpf_col;
340 VLOG(2) <<
"Slack variable " << max_rpf_row <<
" replaced by column "
342 <<
". Pivot coefficient magnitude: " << pivot_absolute_value <<
".";
344 available[max_cpf_col] =
false;
350 residual_pattern.DeleteRowAndColumn(max_rpf_row, max_cpf_col);
351 for (
const ColIndex
col : residual_pattern.RowNonZero(max_rpf_row)) {
352 available[
col] =
false;
358 std::vector<ColIndex>* candidates) {
360 max_scaled_abs_cost_ = 0.0;
361 for (ColIndex
col(0);
col < num_cols; ++
col) {
364 candidates->push_back(
col);
365 max_scaled_abs_cost_ =
366 std::max(max_scaled_abs_cost_, std::abs(objective_[
col]));
370 max_scaled_abs_cost_ =
371 (max_scaled_abs_cost_ == 0.0) ? 1.0 : kBixbyWeight * max_scaled_abs_cost_;
372 std::sort(candidates->begin(), candidates->end(), bixby_column_comparator_);
375 int InitialBasis::GetColumnCategory(ColIndex
col)
const {
378 switch (variable_type_[
col]) {
392 Fractional InitialBasis::GetColumnPenalty(ColIndex
col)
const {
396 penalty = lower_bound_[
col];
399 penalty = -upper_bound_[
col];
402 penalty = lower_bound_[
col] - upper_bound_[
col];
404 return penalty + std::abs(objective_[
col]) / max_scaled_abs_cost_;
407 bool InitialBasis::BixbyColumnComparator::operator()(ColIndex col_a,
408 ColIndex col_b)
const {
409 if (col_a == col_b)
return false;
410 const int category_a = initial_basis_.GetColumnCategory(col_a);
411 const int category_b = initial_basis_.GetColumnCategory(col_b);
412 if (category_a != category_b) {
413 return category_a < category_b;
415 return initial_basis_.GetColumnPenalty(col_a) <
416 initial_basis_.GetColumnPenalty(col_b);
420 bool InitialBasis::TriangularColumnComparator::operator()(
421 ColIndex col_a, ColIndex col_b)
const {
422 if (col_a == col_b)
return false;
423 const int category_a = initial_basis_.GetColumnCategory(col_a);
424 const int category_b = initial_basis_.GetColumnCategory(col_b);
425 if (category_a != category_b) {
426 return category_a > category_b;
435 if (initial_basis_.compact_matrix_.column(col_a).num_entries() !=
436 initial_basis_.compact_matrix_.column(col_b).num_entries()) {
437 return initial_basis_.compact_matrix_.column(col_a).num_entries() >
438 initial_basis_.compact_matrix_.column(col_b).num_entries();
440 return initial_basis_.GetColumnPenalty(col_a) >
441 initial_basis_.GetColumnPenalty(col_b);
EntryIndex num_entries() const
ColIndex num_cols() const
RowIndex num_rows() const
ColumnView column(ColIndex col) const
void CompleteTriangularPrimalBasis(ColIndex num_cols, RowToColMapping *basis)
void CompleteTriangularDualBasis(ColIndex num_cols, RowToColMapping *basis)
InitialBasis(const CompactSparseMatrix &compact_matrix, const DenseRow &objective, const DenseRow &lower_bound, const DenseRow &upper_bound, const VariableTypeRow &variable_type)
void CompleteBixbyBasis(ColIndex num_cols, RowToColMapping *basis)
void GetDualMarosBasis(ColIndex num_cols, RowToColMapping *basis)
void GetPrimalMarosBasis(ColIndex num_cols, RowToColMapping *basis)
void ComputeCandidates(ColIndex num_cols, std::vector< ColIndex > *candidates)
typename Iterator::Entry Entry
void resize(IntType size)
constexpr ColIndex kInvalidCol(-1)
Fractional InfinityNorm(const DenseColumn &v)
@ UPPER_AND_LOWER_BOUNDED
constexpr double kInfinity
void SetSupportToFalse(const ColumnView &column, DenseBooleanColumn *b)
ColIndex RowToColIndex(RowIndex row)
bool IsDominated(const ColumnView &column, const DenseColumn &radius)
constexpr RowIndex kInvalidRow(-1)
StrictITIVector< ColIndex, bool > DenseBooleanRow
StrictITIVector< RowIndex, ColIndex > RowToColMapping
Fractional RestrictedInfinityNorm(const ColumnView &column, const DenseBooleanColumn &rows_to_consider, RowIndex *row_index)
Collection of objects used to extend the Constraint Solver library.
#define VLOG(verboselevel)