33 absl::BitGenRef random)
37 variables_info_(variables_info),
38 basis_factorization_(basis_factorization),
42 must_refactorize_basis_(false),
43 recompute_basic_objective_left_inverse_(true),
44 recompute_basic_objective_(true),
45 recompute_reduced_costs_(true),
46 are_reduced_costs_precise_(false),
47 are_reduced_costs_recomputed_(false),
50 basic_objective_left_inverse_(),
51 dual_feasibility_tolerance_() {}
54 return must_refactorize_basis_;
60 if (recompute_basic_objective_) {
61 ComputeBasicObjective();
63 const Fractional old_reduced_cost = reduced_costs_[entering_col];
65 objective_[entering_col] + cost_perturbations_[entering_col] -
69 reduced_costs_[entering_col] = precise_reduced_cost;
77 if (!recompute_reduced_costs_) {
78 const Fractional estimated_reduced_costs_accuracy =
79 old_reduced_cost - precise_reduced_cost;
81 (std::abs(precise_reduced_cost) <= 1.0) ? 1.0 : precise_reduced_cost;
82 stats_.reduced_costs_accuracy.Add(estimated_reduced_costs_accuracy / scale);
83 if (std::abs(estimated_reduced_costs_accuracy) / scale >
84 parameters_.recompute_reduced_costs_threshold()) {
85 VLOG(1) <<
"Recomputing reduced costs, value = " << precise_reduced_cost
87 << std::abs(precise_reduced_cost - old_reduced_cost);
92 return precise_reduced_cost;
98 const RowIndex num_rows = matrix_.
num_rows();
100 for (RowIndex
row(0);
row < num_rows; ++
row) {
101 const ColIndex basic_col = basis_[
row];
103 objective_[basic_col] + cost_perturbations_[basic_col] -
105 dual_residual_error =
std::max(dual_residual_error, std::abs(residual));
107 return dual_residual_error;
121 if ((can_increase.
IsSet(
col) && rc < 0.0) ||
122 (can_decrease.
IsSet(
col) && rc > 0.0)) {
123 maximum_dual_infeasibility =
124 std::max(maximum_dual_infeasibility, std::abs(rc));
127 return maximum_dual_infeasibility;
141 if (is_boxed[
col])
continue;
143 if ((can_increase.
IsSet(
col) && rc < 0.0) ||
144 (can_decrease.
IsSet(
col) && rc > 0.0)) {
145 maximum_dual_infeasibility =
146 std::max(maximum_dual_infeasibility, std::abs(rc));
149 return maximum_dual_infeasibility;
163 if ((can_increase.
IsSet(
col) && rc < 0.0) ||
164 (can_decrease.
IsSet(
col) && rc > 0.0)) {
165 dual_infeasibility_sum += std::abs(std::abs(rc));
168 return dual_infeasibility_sum;
172 RowIndex leaving_row,
176 const ColIndex leaving_col = basis_[leaving_row];
181 if (!recompute_reduced_costs_) {
182 UpdateReducedCosts(entering_col, leaving_col, leaving_row,
183 direction[leaving_row], update_row);
188 UpdateBasicObjective(entering_col, leaving_row);
194 DCHECK_EQ(current_cost, &objective_[
col]);
195 reduced_costs_[
col] -= objective_[
col];
205 recompute_basic_objective_ =
true;
206 recompute_basic_objective_left_inverse_ =
true;
207 are_reduced_costs_precise_ =
false;
208 SetRecomputeReducedCostsAndNotifyWatchers();
213 recompute_basic_objective_ =
true;
214 recompute_basic_objective_left_inverse_ =
true;
219 if (are_reduced_costs_precise_)
return;
220 must_refactorize_basis_ =
true;
221 recompute_basic_objective_left_inverse_ =
true;
222 SetRecomputeReducedCostsAndNotifyWatchers();
227 VLOG(1) <<
"Perturbing the costs ... ";
230 const ColIndex structural_size =
232 for (ColIndex
col(0);
col < structural_size; ++
col) {
234 std::max(max_cost_magnitude, std::abs(objective_[
col]));
238 for (ColIndex
col(0);
col < structural_size; ++
col) {
241 (1.0 + std::uniform_real_distribution<double>()(random_)) *
242 (parameters_.relative_cost_perturbation() * std::abs(objective) +
243 parameters_.relative_max_cost_perturbation() * max_cost_magnitude);
244 DCHECK_GE(magnitude, 0.0);
255 cost_perturbations_[
col] = magnitude;
258 cost_perturbations_[
col] = -magnitude;
266 if (objective > 0.0) {
267 cost_perturbations_[
col] = magnitude;
268 }
else if (objective < 0.0) {
269 cost_perturbations_[
col] = -magnitude;
283 parameters_.degenerate_ministep_factor() * dual_feasibility_tolerance_;
284 if (increasing_rc_is_needed && reduced_costs_[
col] <= -minimum_delta)
return;
285 if (!increasing_rc_is_needed && reduced_costs_[
col] >= minimum_delta)
return;
288 increasing_rc_is_needed ? minimum_delta : -minimum_delta;
290 cost_perturbations_[
col] -= reduced_costs_[
col] +
delta;
292 has_cost_shift_ =
true;
297 if (increasing_rc_is_needed && reduced_costs_[
col] >= 0.0)
return true;
298 if (!increasing_rc_is_needed && reduced_costs_[
col] <= 0.0)
return true;
304 has_cost_shift_ =
false;
306 recompute_basic_objective_ =
true;
307 recompute_basic_objective_left_inverse_ =
true;
308 are_reduced_costs_precise_ =
false;
309 SetRecomputeReducedCostsAndNotifyWatchers();
314 if (!are_reduced_costs_recomputed_) {
315 SetRecomputeReducedCostsAndNotifyWatchers();
323 must_refactorize_basis_ =
false;
325 if (recompute_reduced_costs_) {
326 ComputeReducedCosts();
328 return reduced_costs_;
333 ComputeBasicObjectiveLeftInverse();
337 void ReducedCosts::ComputeBasicObjective() {
341 basic_objective_.
resize(num_cols_in_basis, 0.0);
342 for (ColIndex
col(0);
col < num_cols_in_basis; ++
col) {
344 basic_objective_[
col] =
345 objective_[basis_col] + cost_perturbations_[basis_col];
347 recompute_basic_objective_ =
false;
348 recompute_basic_objective_left_inverse_ =
true;
351 void ReducedCosts::ComputeReducedCosts() {
353 if (recompute_basic_objective_left_inverse_) {
354 ComputeBasicObjectiveLeftInverse();
357 const ColIndex num_cols = matrix_.
num_cols();
359 reduced_costs_.
resize(num_cols, 0.0);
362 const int num_omp_threads = parameters_.num_omp_threads();
364 const int num_omp_threads = 1;
366 if (num_omp_threads == 1) {
367 for (ColIndex
col(0);
col < num_cols; ++
col) {
368 reduced_costs_[
col] = objective_[
col] + cost_perturbations_[
col] -
370 col, basic_objective_left_inverse_.
values);
373 if (is_basic.IsSet(
col)) {
374 dual_residual_error =
375 std::max(dual_residual_error, std::abs(reduced_costs_[
col]));
382 std::vector<Fractional> thread_local_dual_residual_error(num_omp_threads,
384 const int parallel_loop_size = num_cols.value();
385 #pragma omp parallel for num_threads(num_omp_threads)
386 for (
int i = 0; i < parallel_loop_size; i++) {
387 const ColIndex
col(i);
388 reduced_costs_[
col] = objective_[
col] + objective_perturbation_[
col] -
390 col, basic_objective_left_inverse_.
values);
392 if (is_basic.IsSet(
col)) {
393 thread_local_dual_residual_error[omp_get_thread_num()] =
394 std::max(thread_local_dual_residual_error[omp_get_thread_num()],
395 std::abs(reduced_costs_[
col]));
399 for (
int i = 0; i < num_omp_threads; i++) {
400 dual_residual_error =
401 std::max(dual_residual_error, thread_local_dual_residual_error[i]);
406 deterministic_time_ +=
408 recompute_reduced_costs_ =
false;
409 are_reduced_costs_recomputed_ =
true;
410 are_reduced_costs_precise_ = basis_factorization_.
IsRefactorized();
417 dual_feasibility_tolerance_ = parameters_.dual_feasibility_tolerance();
418 if (dual_residual_error > dual_feasibility_tolerance_) {
419 VLOG(2) <<
"Changing dual_feasibility_tolerance to " << dual_residual_error;
420 dual_feasibility_tolerance_ = dual_residual_error;
424 void ReducedCosts::ComputeBasicObjectiveLeftInverse() {
426 if (recompute_basic_objective_) {
427 ComputeBasicObjective();
429 basic_objective_left_inverse_.
values = basic_objective_;
430 basic_objective_left_inverse_.
non_zeros.clear();
431 basis_factorization_.
LeftSolve(&basic_objective_left_inverse_);
432 recompute_basic_objective_left_inverse_ =
false;
443 void ReducedCosts::UpdateReducedCosts(ColIndex entering_col,
444 ColIndex leaving_col,
446 UpdateRow* update_row) {
447 DCHECK_NE(entering_col, leaving_col);
448 DCHECK_NE(pivot, 0.0);
449 if (recompute_reduced_costs_)
return;
452 const Fractional entering_reduced_cost = reduced_costs_[entering_col];
456 if (entering_reduced_cost == 0.0) {
457 VLOG(2) <<
"Reduced costs didn't change.";
463 are_reduced_costs_precise_ =
false;
467 are_reduced_costs_recomputed_ =
false;
468 are_reduced_costs_precise_ =
false;
469 update_row->ComputeUpdateRow(leaving_row);
476 const Fractional new_leaving_reduced_cost = entering_reduced_cost / -pivot;
477 for (
const ColIndex
col : update_row->GetNonZeroPositions()) {
479 reduced_costs_[
col] += new_leaving_reduced_cost * coeff;
481 reduced_costs_[leaving_col] = new_leaving_reduced_cost;
486 reduced_costs_[entering_col] = 0.0;
493 const Fractional tolerance = dual_feasibility_tolerance_;
494 return (can_increase.
IsSet(
col) && (reduced_cost < -tolerance)) ||
495 (can_decrease.
IsSet(
col) && (reduced_cost > tolerance));
498 void ReducedCosts::UpdateBasicObjective(ColIndex entering_col,
499 RowIndex leaving_row) {
502 objective_[entering_col] + cost_perturbations_[entering_col];
503 recompute_basic_objective_left_inverse_ =
true;
506 void ReducedCosts::SetRecomputeReducedCostsAndNotifyWatchers() {
507 recompute_reduced_costs_ =
true;
508 for (
bool* watcher : watchers_) *watcher =
true;
516 variables_info_(variables_info),
517 primal_edge_norms_(primal_edge_norms),
518 reduced_costs_(reduced_costs) {
526 if (recompute_)
return;
531 UpdateEnteringCandidates<
false>(
536 if (recompute_)
return;
540 DCHECK_NE(0.0, squared_norms[
col]);
550 if (recompute_)
return;
560 UpdateEnteringCandidates<
true>(
572 template <
bool from_clean_state,
typename ColumnsToUpdate>
573 void PrimalPrices::UpdateEnteringCandidates(
const ColumnsToUpdate& cols) {
579 for (
const ColIndex
col : cols) {
588 col, reduced_cost > tolerance, can_decrease, reduced_cost < -tolerance,
590 if (is_dual_infeasible) {
596 if (!from_clean_state) prices_.
Remove(
col);
bool IsSet(IndexType i) const
static uint64_t ConditionalXorOfTwoBits(IndexType i, uint64_t use1, const Bitset64< IndexType > &set1, uint64_t use2, const Bitset64< IndexType > &set2)
bool IsRefactorized() const
void LeftSolve(ScatteredRow *y) const
ColIndex num_cols() const
RowIndex num_rows() const
Fractional ColumnScalarProduct(ColIndex col, const DenseRow &vector) const
EntryIndex num_entries() const
void AddOrUpdate(Index position, Fractional value)
void Remove(Index position)
void ClearAndResize(Index n)
const DenseRow & GetSquaredNorms()
void AddRecomputationWatcher(bool *watcher)
void SetAndDebugCheckThatColumnIsDualFeasible(ColIndex col)
void UpdateBeforeBasisPivot(ColIndex entering_col, UpdateRow *update_row)
PrimalPrices(absl::BitGenRef random, const VariablesInfo &variables_info, PrimalEdgeNorms *primal_edge_norms, ReducedCosts *reduced_costs)
void RecomputePriceAt(ColIndex col)
ColIndex GetBestEnteringColumn()
ReducedCosts(const CompactSparseMatrix &matrix_, const DenseRow &objective, const RowToColMapping &basis, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization, absl::BitGenRef random)
void AddRecomputationWatcher(bool *watcher)
void ResetForNewObjective()
Fractional TestEnteringReducedCostPrecision(ColIndex entering_col, const ScatteredColumn &direction)
void MakeReducedCostsPrecise()
bool IsValidPrimalEnteringCandidate(ColIndex col) const
void SetNonBasicVariableCostToZero(ColIndex col, Fractional *current_cost)
Fractional ComputeMaximumDualInfeasibilityOnNonBoxedVariables()
bool StepIsDualDegenerate(bool increasing_rc_is_needed, ColIndex col)
Fractional ComputeSumOfDualInfeasibilities()
const DenseRow & GetFullReducedCosts()
void UpdateBeforeBasisPivot(ColIndex entering_col, RowIndex leaving_row, const ScatteredColumn &direction, UpdateRow *update_row)
const DenseRow & GetReducedCosts()
Fractional GetDualFeasibilityTolerance() const
const DenseColumn & GetDualValues()
void ClearAndRemoveCostShifts()
Fractional ComputeMaximumDualResidual()
void UpdateDataOnBasisPermutation()
void ShiftCostIfNeeded(bool increasing_rc_is_needed, ColIndex col)
Fractional ComputeMaximumDualInfeasibility()
void SetParameters(const GlopParameters ¶meters)
bool NeedsBasisRefactorization() const
void AssignToZero(IntType size)
void resize(IntType size)
const ColIndexVector & GetNonZeroPositions() const
const DenseBitRow & GetIsBasicBitRow() const
const DenseBitRow & GetNonBasicBoxedVariables() const
const DenseBitRow & GetCanIncreaseBitRow() const
const DenseBitRow & GetCanDecreaseBitRow() const
const VariableTypeRow & GetTypeRow() const
const DenseBitRow & GetNotBasicBitRow() const
const VariableStatusRow & GetStatusRow() const
const DenseBitRow & GetIsRelevantBitRow() const
Fractional Square(Fractional f)
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
@ UPPER_AND_LOWER_BOUNDED
double Density(const DenseRow &row)
ColIndex RowToColIndex(RowIndex row)
const DenseRow & Transpose(const DenseColumn &col)
Bitset64< ColIndex > DenseBitRow
RowIndex ColToRowIndex(ColIndex col)
static double DeterministicTimeForFpOperations(int64_t n)
Collection of objects used to extend the Constraint Solver library.
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
std::vector< Index > non_zeros
StrictITIVector< Index, Fractional > values
#define VLOG(verboselevel)