32 absl::BitGenRef random)
36 variables_info_(variables_info),
37 basis_factorization_(basis_factorization),
41 must_refactorize_basis_(false),
42 recompute_basic_objective_left_inverse_(true),
43 recompute_basic_objective_(true),
44 recompute_reduced_costs_(true),
45 are_reduced_costs_precise_(false),
46 are_reduced_costs_recomputed_(false),
49 basic_objective_left_inverse_(),
50 dual_feasibility_tolerance_() {}
53 return must_refactorize_basis_;
59 if (recompute_basic_objective_) {
60 ComputeBasicObjective();
62 const Fractional old_reduced_cost = reduced_costs_[entering_col];
64 objective_[entering_col] + cost_perturbations_[entering_col] -
68 reduced_costs_[entering_col] = precise_reduced_cost;
76 if (!recompute_reduced_costs_) {
77 const Fractional estimated_reduced_costs_accuracy =
78 old_reduced_cost - precise_reduced_cost;
80 (std::abs(precise_reduced_cost) <= 1.0) ? 1.0 : precise_reduced_cost;
81 stats_.reduced_costs_accuracy.Add(estimated_reduced_costs_accuracy / scale);
82 if (std::abs(estimated_reduced_costs_accuracy) / scale >
83 parameters_.recompute_reduced_costs_threshold()) {
84 VLOG(1) <<
"Recomputing reduced costs, value = " << precise_reduced_cost
86 << std::abs(precise_reduced_cost - old_reduced_cost);
91 return precise_reduced_cost;
97 const RowIndex num_rows = matrix_.
num_rows();
99 for (RowIndex
row(0);
row < num_rows; ++
row) {
100 const ColIndex basic_col = basis_[
row];
102 objective_[basic_col] + cost_perturbations_[basic_col] -
104 dual_residual_error =
std::max(dual_residual_error, std::abs(residual));
106 return dual_residual_error;
120 if ((can_increase.
IsSet(
col) && rc < 0.0) ||
121 (can_decrease.
IsSet(
col) && rc > 0.0)) {
122 maximum_dual_infeasibility =
123 std::max(maximum_dual_infeasibility, std::abs(rc));
126 return maximum_dual_infeasibility;
140 if (is_boxed[
col])
continue;
142 if ((can_increase.
IsSet(
col) && rc < 0.0) ||
143 (can_decrease.
IsSet(
col) && rc > 0.0)) {
144 maximum_dual_infeasibility =
145 std::max(maximum_dual_infeasibility, std::abs(rc));
148 return maximum_dual_infeasibility;
162 if ((can_increase.
IsSet(
col) && rc < 0.0) ||
163 (can_decrease.
IsSet(
col) && rc > 0.0)) {
164 dual_infeasibility_sum += std::abs(std::abs(rc));
167 return dual_infeasibility_sum;
171 RowIndex leaving_row,
175 const ColIndex leaving_col = basis_[leaving_row];
180 if (!recompute_reduced_costs_) {
181 UpdateReducedCosts(entering_col, leaving_col, leaving_row,
182 direction[leaving_row], update_row);
187 UpdateBasicObjective(entering_col, leaving_row);
194 reduced_costs_[
col] -= objective_[
col];
204 recompute_basic_objective_ =
true;
205 recompute_basic_objective_left_inverse_ =
true;
206 are_reduced_costs_precise_ =
false;
207 SetRecomputeReducedCostsAndNotifyWatchers();
212 recompute_basic_objective_ =
true;
213 recompute_basic_objective_left_inverse_ =
true;
218 if (are_reduced_costs_precise_)
return;
219 must_refactorize_basis_ =
true;
220 recompute_basic_objective_left_inverse_ =
true;
221 SetRecomputeReducedCostsAndNotifyWatchers();
226 VLOG(1) <<
"Perturbing the costs ... ";
229 const ColIndex structural_size =
231 for (ColIndex
col(0);
col < structural_size; ++
col) {
233 std::max(max_cost_magnitude, std::abs(objective_[
col]));
237 for (ColIndex
col(0);
col < structural_size; ++
col) {
240 (1.0 + std::uniform_real_distribution<double>()(random_)) *
241 (parameters_.relative_cost_perturbation() * std::abs(objective) +
242 parameters_.relative_max_cost_perturbation() * max_cost_magnitude);
254 cost_perturbations_[
col] = magnitude;
257 cost_perturbations_[
col] = -magnitude;
265 if (objective > 0.0) {
266 cost_perturbations_[
col] = magnitude;
267 }
else if (objective < 0.0) {
268 cost_perturbations_[
col] = -magnitude;
282 parameters_.degenerate_ministep_factor() * dual_feasibility_tolerance_;
283 if (increasing_rc_is_needed && reduced_costs_[
col] <= -minimum_delta)
return;
284 if (!increasing_rc_is_needed && reduced_costs_[
col] >= minimum_delta)
return;
287 increasing_rc_is_needed ? minimum_delta : -minimum_delta;
289 cost_perturbations_[
col] -= reduced_costs_[
col] +
delta;
291 has_cost_shift_ =
true;
296 if (increasing_rc_is_needed && reduced_costs_[
col] >= 0.0)
return true;
297 if (!increasing_rc_is_needed && reduced_costs_[
col] <= 0.0)
return true;
303 has_cost_shift_ =
false;
305 recompute_basic_objective_ =
true;
306 recompute_basic_objective_left_inverse_ =
true;
307 are_reduced_costs_precise_ =
false;
308 SetRecomputeReducedCostsAndNotifyWatchers();
313 if (!are_reduced_costs_recomputed_) {
314 SetRecomputeReducedCostsAndNotifyWatchers();
322 must_refactorize_basis_ =
false;
324 if (recompute_reduced_costs_) {
325 ComputeReducedCosts();
327 return reduced_costs_;
332 ComputeBasicObjectiveLeftInverse();
336void ReducedCosts::ComputeBasicObjective() {
340 basic_objective_.
resize(num_cols_in_basis, 0.0);
341 for (ColIndex
col(0);
col < num_cols_in_basis; ++
col) {
343 basic_objective_[
col] =
344 objective_[basis_col] + cost_perturbations_[basis_col];
346 recompute_basic_objective_ =
false;
347 recompute_basic_objective_left_inverse_ =
true;
350void ReducedCosts::ComputeReducedCosts() {
352 if (recompute_basic_objective_left_inverse_) {
353 ComputeBasicObjectiveLeftInverse();
356 const ColIndex num_cols = matrix_.
num_cols();
358 reduced_costs_.
resize(num_cols, 0.0);
361 const int num_omp_threads = parameters_.num_omp_threads();
363 const int num_omp_threads = 1;
365 if (num_omp_threads == 1) {
366 for (ColIndex
col(0);
col < num_cols; ++
col) {
367 reduced_costs_[
col] = objective_[
col] + cost_perturbations_[
col] -
369 col, basic_objective_left_inverse_.
values);
372 if (is_basic.IsSet(
col)) {
373 dual_residual_error =
374 std::max(dual_residual_error, std::abs(reduced_costs_[
col]));
381 std::vector<Fractional> thread_local_dual_residual_error(num_omp_threads,
383 const int parallel_loop_size = num_cols.value();
384#pragma omp parallel for num_threads(num_omp_threads)
385 for (
int i = 0; i < parallel_loop_size; i++) {
386 const ColIndex
col(i);
387 reduced_costs_[
col] = objective_[
col] + objective_perturbation_[
col] -
389 col, basic_objective_left_inverse_.
values);
391 if (is_basic.IsSet(
col)) {
392 thread_local_dual_residual_error[omp_get_thread_num()] =
393 std::max(thread_local_dual_residual_error[omp_get_thread_num()],
394 std::abs(reduced_costs_[
col]));
398 for (
int i = 0; i < num_omp_threads; i++) {
399 dual_residual_error =
400 std::max(dual_residual_error, thread_local_dual_residual_error[i]);
405 deterministic_time_ +=
407 recompute_reduced_costs_ =
false;
408 are_reduced_costs_recomputed_ =
true;
409 are_reduced_costs_precise_ = basis_factorization_.
IsRefactorized();
416 dual_feasibility_tolerance_ = parameters_.dual_feasibility_tolerance();
417 if (dual_residual_error > dual_feasibility_tolerance_) {
418 VLOG(2) <<
"Changing dual_feasibility_tolerance to " << dual_residual_error;
419 dual_feasibility_tolerance_ = dual_residual_error;
423void ReducedCosts::ComputeBasicObjectiveLeftInverse() {
425 if (recompute_basic_objective_) {
426 ComputeBasicObjective();
428 basic_objective_left_inverse_.
values = basic_objective_;
429 basic_objective_left_inverse_.
non_zeros.clear();
430 basis_factorization_.
LeftSolve(&basic_objective_left_inverse_);
431 recompute_basic_objective_left_inverse_ =
false;
442void ReducedCosts::UpdateReducedCosts(ColIndex entering_col,
443 ColIndex leaving_col,
445 UpdateRow* update_row) {
448 if (recompute_reduced_costs_)
return;
451 const Fractional entering_reduced_cost = reduced_costs_[entering_col];
455 if (entering_reduced_cost == 0.0) {
456 VLOG(2) <<
"Reduced costs didn't change.";
462 are_reduced_costs_precise_ =
false;
466 are_reduced_costs_recomputed_ =
false;
467 are_reduced_costs_precise_ =
false;
468 update_row->ComputeUpdateRow(leaving_row);
475 const Fractional new_leaving_reduced_cost = entering_reduced_cost / -pivot;
476 for (
const ColIndex
col : update_row->GetNonZeroPositions()) {
478 reduced_costs_[
col] += new_leaving_reduced_cost *
coeff;
480 reduced_costs_[leaving_col] = new_leaving_reduced_cost;
485 reduced_costs_[entering_col] = 0.0;
492 const Fractional tolerance = dual_feasibility_tolerance_;
493 return (can_increase.
IsSet(
col) && (reduced_cost < -tolerance)) ||
494 (can_decrease.
IsSet(
col) && (reduced_cost > tolerance));
497void ReducedCosts::UpdateBasicObjective(ColIndex entering_col,
498 RowIndex leaving_row) {
501 objective_[entering_col] + cost_perturbations_[entering_col];
502 recompute_basic_objective_left_inverse_ =
true;
505void ReducedCosts::SetRecomputeReducedCostsAndNotifyWatchers() {
506 recompute_reduced_costs_ =
true;
507 for (
bool* watcher : watchers_) *watcher =
true;
515 variables_info_(variables_info),
516 primal_edge_norms_(primal_edge_norms),
517 reduced_costs_(reduced_costs) {
525 if (recompute_)
return;
530 UpdateEnteringCandidates<
false>(
535 if (recompute_)
return;
549 if (recompute_)
return;
559 UpdateEnteringCandidates<
true>(
571template <
bool from_clean_state,
typename ColumnsToUpdate>
572void PrimalPrices::UpdateEnteringCandidates(
const ColumnsToUpdate& cols) {
578 for (
const ColIndex
col : cols) {
587 col, reduced_cost > tolerance, can_decrease, reduced_cost < -tolerance,
589 if (is_dual_infeasible) {
595 if (!from_clean_state) prices_.
Remove(
col);
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
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)
@ UPPER_AND_LOWER_BOUNDED
Fractional PreciseScalarProduct(const DenseRowOrColumn &u, const DenseRowOrColumn2 &v)
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