OR-Tools  9.6
reduced_costs.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
15 
16 #include <algorithm>
17 #include <random>
18 
19 #ifdef OMP
20 #include <omp.h>
21 #endif
22 
24 
25 namespace operations_research {
26 namespace glop {
27 
29  const DenseRow& objective,
30  const RowToColMapping& basis,
31  const VariablesInfo& variables_info,
32  const BasisFactorization& basis_factorization,
33  absl::BitGenRef random)
34  : matrix_(matrix),
35  objective_(objective),
36  basis_(basis),
37  variables_info_(variables_info),
38  basis_factorization_(basis_factorization),
39  random_(random),
40  parameters_(),
41  stats_(),
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),
48  basic_objective_(),
49  reduced_costs_(),
50  basic_objective_left_inverse_(),
51  dual_feasibility_tolerance_() {}
52 
54  return must_refactorize_basis_;
55 }
56 
58  ColIndex entering_col, const ScatteredColumn& direction) {
59  SCOPED_TIME_STAT(&stats_);
60  if (recompute_basic_objective_) {
61  ComputeBasicObjective();
62  }
63  const Fractional old_reduced_cost = reduced_costs_[entering_col];
64  const Fractional precise_reduced_cost =
65  objective_[entering_col] + cost_perturbations_[entering_col] -
66  ScalarProduct(basic_objective_, direction);
67 
68  // Update the reduced cost of the entering variable with the precise version.
69  reduced_costs_[entering_col] = precise_reduced_cost;
70 
71  // At this point, we have an entering variable that will move the objective in
72  // the good direction. We check the precision of the reduced cost and edges
73  // norm, but even if they are imprecise, we finish this pivot and will
74  // recompute them during the next call to ChooseEnteringColumn().
75 
76  // Estimate the accuracy of the reduced costs using the entering variable.
77  if (!recompute_reduced_costs_) {
78  const Fractional estimated_reduced_costs_accuracy =
79  old_reduced_cost - precise_reduced_cost;
80  const Fractional scale =
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
86  << " error = "
87  << std::abs(precise_reduced_cost - old_reduced_cost);
89  }
90  }
91 
92  return precise_reduced_cost;
93 }
94 
96  SCOPED_TIME_STAT(&stats_);
97  Fractional dual_residual_error(0.0);
98  const RowIndex num_rows = matrix_.num_rows();
99  const DenseRow& dual_values = Transpose(GetDualValues());
100  for (RowIndex row(0); row < num_rows; ++row) {
101  const ColIndex basic_col = basis_[row];
102  const Fractional residual =
103  objective_[basic_col] + cost_perturbations_[basic_col] -
104  matrix_.ColumnScalarProduct(basic_col, dual_values);
105  dual_residual_error = std::max(dual_residual_error, std::abs(residual));
106  }
107  return dual_residual_error;
108 }
109 
111  SCOPED_TIME_STAT(&stats_);
112 
113  // Trigger a recomputation if needed so that reduced_costs_ is valid.
114  GetReducedCosts();
115 
116  Fractional maximum_dual_infeasibility = 0.0;
117  const DenseBitRow& can_decrease = variables_info_.GetCanDecreaseBitRow();
118  const DenseBitRow& can_increase = variables_info_.GetCanIncreaseBitRow();
119  for (const ColIndex col : variables_info_.GetIsRelevantBitRow()) {
120  const Fractional rc = reduced_costs_[col];
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));
125  }
126  }
127  return maximum_dual_infeasibility;
128 }
129 
131  SCOPED_TIME_STAT(&stats_);
132 
133  // Trigger a recomputation if needed so that reduced_costs_ is valid.
134  GetReducedCosts();
135 
136  Fractional maximum_dual_infeasibility = 0.0;
137  const DenseBitRow& can_decrease = variables_info_.GetCanDecreaseBitRow();
138  const DenseBitRow& can_increase = variables_info_.GetCanIncreaseBitRow();
139  const DenseBitRow& is_boxed = variables_info_.GetNonBasicBoxedVariables();
140  for (const ColIndex col : variables_info_.GetNotBasicBitRow()) {
141  if (is_boxed[col]) continue;
142  const Fractional rc = reduced_costs_[col];
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));
147  }
148  }
149  return maximum_dual_infeasibility;
150 }
151 
153  SCOPED_TIME_STAT(&stats_);
154 
155  // Trigger a recomputation if needed so that reduced_costs_ is valid.
156  GetReducedCosts();
157 
158  Fractional dual_infeasibility_sum = 0.0;
159  const DenseBitRow& can_decrease = variables_info_.GetCanDecreaseBitRow();
160  const DenseBitRow& can_increase = variables_info_.GetCanIncreaseBitRow();
161  for (const ColIndex col : variables_info_.GetIsRelevantBitRow()) {
162  const Fractional rc = reduced_costs_[col];
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));
166  }
167  }
168  return dual_infeasibility_sum;
169 }
170 
171 void ReducedCosts::UpdateBeforeBasisPivot(ColIndex entering_col,
172  RowIndex leaving_row,
173  const ScatteredColumn& direction,
174  UpdateRow* update_row) {
175  SCOPED_TIME_STAT(&stats_);
176  const ColIndex leaving_col = basis_[leaving_row];
177  DCHECK(!variables_info_.GetIsBasicBitRow().IsSet(entering_col));
178  DCHECK(variables_info_.GetIsBasicBitRow().IsSet(leaving_col));
179 
180  // If we are recomputing everything when requested, no need to update.
181  if (!recompute_reduced_costs_) {
182  UpdateReducedCosts(entering_col, leaving_col, leaving_row,
183  direction[leaving_row], update_row);
184  }
185 
186  // Note that it is important to update basic_objective_ AFTER calling
187  // UpdateReducedCosts().
188  UpdateBasicObjective(entering_col, leaving_row);
189 }
190 
192  Fractional* current_cost) {
193  DCHECK_NE(variables_info_.GetStatusRow()[col], VariableStatus::BASIC);
194  DCHECK_EQ(current_cost, &objective_[col]);
195  reduced_costs_[col] -= objective_[col];
196  *current_cost = 0.0;
197 }
198 
199 void ReducedCosts::SetParameters(const GlopParameters& parameters) {
200  parameters_ = parameters;
201 }
202 
204  SCOPED_TIME_STAT(&stats_);
205  recompute_basic_objective_ = true;
206  recompute_basic_objective_left_inverse_ = true;
207  are_reduced_costs_precise_ = false;
208  SetRecomputeReducedCostsAndNotifyWatchers();
209 }
210 
212  SCOPED_TIME_STAT(&stats_);
213  recompute_basic_objective_ = true;
214  recompute_basic_objective_left_inverse_ = true;
215 }
216 
218  SCOPED_TIME_STAT(&stats_);
219  if (are_reduced_costs_precise_) return;
220  must_refactorize_basis_ = true;
221  recompute_basic_objective_left_inverse_ = true;
222  SetRecomputeReducedCostsAndNotifyWatchers();
223 }
224 
226  SCOPED_TIME_STAT(&stats_);
227  VLOG(1) << "Perturbing the costs ... ";
228 
229  Fractional max_cost_magnitude = 0.0;
230  const ColIndex structural_size =
231  matrix_.num_cols() - RowToColIndex(matrix_.num_rows());
232  for (ColIndex col(0); col < structural_size; ++col) {
233  max_cost_magnitude =
234  std::max(max_cost_magnitude, std::abs(objective_[col]));
235  }
236 
237  cost_perturbations_.AssignToZero(matrix_.num_cols());
238  for (ColIndex col(0); col < structural_size; ++col) {
239  const Fractional objective = objective_[col];
240  const Fractional magnitude =
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);
245 
246  // The perturbation direction is such that a dual-feasible solution stays
247  // feasible. This is important.
248  const VariableType type = variables_info_.GetTypeRow()[col];
249  switch (type) {
251  break;
253  break;
255  cost_perturbations_[col] = magnitude;
256  break;
258  cost_perturbations_[col] = -magnitude;
259  break;
261  // Here we don't necessarily maintain the dual-feasibility of a dual
262  // feasible solution, however we can always shift the variable to its
263  // other bound (because it is boxed) to restore dual-feasiblity. This is
264  // done by MakeBoxedVariableDualFeasible() at the end of the dual
265  // phase-I algorithm.
266  if (objective > 0.0) {
267  cost_perturbations_[col] = magnitude;
268  } else if (objective < 0.0) {
269  cost_perturbations_[col] = -magnitude;
270  }
271  break;
272  }
273  }
274 }
275 
276 void ReducedCosts::ShiftCostIfNeeded(bool increasing_rc_is_needed,
277  ColIndex col) {
278  SCOPED_TIME_STAT(&stats_);
279 
280  // We always want a minimum step size, so if we have a negative step or
281  // a step that is really small, we will shift the cost of the given column.
282  const Fractional minimum_delta =
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;
286 
287  const Fractional delta =
288  increasing_rc_is_needed ? minimum_delta : -minimum_delta;
289  IF_STATS_ENABLED(stats_.cost_shift.Add(reduced_costs_[col] + delta));
290  cost_perturbations_[col] -= reduced_costs_[col] + delta;
291  reduced_costs_[col] = -delta;
292  has_cost_shift_ = true;
293 }
294 
295 bool ReducedCosts::StepIsDualDegenerate(bool increasing_rc_is_needed,
296  ColIndex col) {
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;
299  return false;
300 }
301 
303  SCOPED_TIME_STAT(&stats_);
304  has_cost_shift_ = false;
305  cost_perturbations_.AssignToZero(matrix_.num_cols());
306  recompute_basic_objective_ = true;
307  recompute_basic_objective_left_inverse_ = true;
308  are_reduced_costs_precise_ = false;
309  SetRecomputeReducedCostsAndNotifyWatchers();
310 }
311 
313  SCOPED_TIME_STAT(&stats_);
314  if (!are_reduced_costs_recomputed_) {
315  SetRecomputeReducedCostsAndNotifyWatchers();
316  }
317  return GetReducedCosts();
318 }
319 
321  SCOPED_TIME_STAT(&stats_);
322  if (basis_factorization_.IsRefactorized()) {
323  must_refactorize_basis_ = false;
324  }
325  if (recompute_reduced_costs_) {
326  ComputeReducedCosts();
327  }
328  return reduced_costs_;
329 }
330 
332  SCOPED_TIME_STAT(&stats_);
333  ComputeBasicObjectiveLeftInverse();
334  return Transpose(basic_objective_left_inverse_.values);
335 }
336 
337 void ReducedCosts::ComputeBasicObjective() {
338  SCOPED_TIME_STAT(&stats_);
339  const ColIndex num_cols_in_basis = RowToColIndex(matrix_.num_rows());
340  cost_perturbations_.resize(matrix_.num_cols(), 0.0);
341  basic_objective_.resize(num_cols_in_basis, 0.0);
342  for (ColIndex col(0); col < num_cols_in_basis; ++col) {
343  const ColIndex basis_col = basis_[ColToRowIndex(col)];
344  basic_objective_[col] =
345  objective_[basis_col] + cost_perturbations_[basis_col];
346  }
347  recompute_basic_objective_ = false;
348  recompute_basic_objective_left_inverse_ = true;
349 }
350 
351 void ReducedCosts::ComputeReducedCosts() {
352  SCOPED_TIME_STAT(&stats_);
353  if (recompute_basic_objective_left_inverse_) {
354  ComputeBasicObjectiveLeftInverse();
355  }
356  Fractional dual_residual_error(0.0);
357  const ColIndex num_cols = matrix_.num_cols();
358 
359  reduced_costs_.resize(num_cols, 0.0);
360  const DenseBitRow& is_basic = variables_info_.GetIsBasicBitRow();
361 #ifdef OMP
362  const int num_omp_threads = parameters_.num_omp_threads();
363 #else
364  const int num_omp_threads = 1;
365 #endif
366  if (num_omp_threads == 1) {
367  for (ColIndex col(0); col < num_cols; ++col) {
368  reduced_costs_[col] = objective_[col] + cost_perturbations_[col] -
369  matrix_.ColumnScalarProduct(
370  col, basic_objective_left_inverse_.values);
371 
372  // We also compute the dual residual error y.B - c_B.
373  if (is_basic.IsSet(col)) {
374  dual_residual_error =
375  std::max(dual_residual_error, std::abs(reduced_costs_[col]));
376  }
377  }
378  } else {
379 #ifdef OMP
380  // In the multi-threaded case, perform the same computation as in the
381  // single-threaded case above.
382  std::vector<Fractional> thread_local_dual_residual_error(num_omp_threads,
383  0.0);
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] -
389  matrix_.ColumnScalarProduct(
390  col, basic_objective_left_inverse_.values);
391 
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]));
396  }
397  }
398  // end of omp parallel for
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]);
402  }
403 #endif // OMP
404  }
405 
406  deterministic_time_ +=
408  recompute_reduced_costs_ = false;
409  are_reduced_costs_recomputed_ = true;
410  are_reduced_costs_precise_ = basis_factorization_.IsRefactorized();
411 
412  // It is not resonable to have a dual tolerance lower than the current
413  // dual_residual_error, otherwise we may never terminate (This is happening on
414  // dfl001.mps with a low dual_feasibility_tolerance). Note that since we
415  // recompute the reduced costs with maximum precision before really exiting,
416  // it is fine to do a couple of iterations with a high zero tolerance.
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;
421  }
422 }
423 
424 void ReducedCosts::ComputeBasicObjectiveLeftInverse() {
425  SCOPED_TIME_STAT(&stats_);
426  if (recompute_basic_objective_) {
427  ComputeBasicObjective();
428  }
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;
433  IF_STATS_ENABLED(stats_.basic_objective_left_inverse_density.Add(
434  Density(basic_objective_left_inverse_.values)));
435 
436  // TODO(user): Estimate its accuracy by a few scalar products, and refactorize
437  // if it is above a threshold?
438 }
439 
440 // Note that the update is such than the entering reduced cost is always set to
441 // 0.0. In particular, because of this we can step in the wrong direction for
442 // the dual method if the reduced cost is slightly infeasible.
443 void ReducedCosts::UpdateReducedCosts(ColIndex entering_col,
444  ColIndex leaving_col,
445  RowIndex leaving_row, Fractional pivot,
446  UpdateRow* update_row) {
447  DCHECK_NE(entering_col, leaving_col);
448  DCHECK_NE(pivot, 0.0);
449  if (recompute_reduced_costs_) return;
450 
451  // Note that this is precise because of the CheckPrecision().
452  const Fractional entering_reduced_cost = reduced_costs_[entering_col];
453 
454  // Nothing to do if the entering reduced cost is 0.0.
455  // This correspond to a dual degenerate pivot.
456  if (entering_reduced_cost == 0.0) {
457  VLOG(2) << "Reduced costs didn't change.";
458 
459  // TODO(user): the reduced costs may still be "precise" in this case, but
460  // other parts of the code assume that if they are precise then the basis
461  // was just refactorized in order to recompute them which is not the case
462  // here. Clean this up.
463  are_reduced_costs_precise_ = false;
464  return;
465  }
466 
467  are_reduced_costs_recomputed_ = false;
468  are_reduced_costs_precise_ = false;
469  update_row->ComputeUpdateRow(leaving_row);
470  SCOPED_TIME_STAT(&stats_);
471 
472  // Update the leaving variable reduced cost.
473  // '-pivot' is the value of the entering_edge at 'leaving_row'.
474  // The edge of the 'leaving_col' in the new basis is equal to
475  // 'entering_edge / -pivot'.
476  const Fractional new_leaving_reduced_cost = entering_reduced_cost / -pivot;
477  for (const ColIndex col : update_row->GetNonZeroPositions()) {
478  const Fractional coeff = update_row->GetCoefficient(col);
479  reduced_costs_[col] += new_leaving_reduced_cost * coeff;
480  }
481  reduced_costs_[leaving_col] = new_leaving_reduced_cost;
482 
483  // In the dual, since we compute the update before selecting the entering
484  // variable, this cost is still in the update_position_list, so we make sure
485  // it is 0 here.
486  reduced_costs_[entering_col] = 0.0;
487 }
488 
490  const Fractional reduced_cost = reduced_costs_[col];
491  const DenseBitRow& can_decrease = variables_info_.GetCanDecreaseBitRow();
492  const DenseBitRow& can_increase = variables_info_.GetCanIncreaseBitRow();
493  const Fractional tolerance = dual_feasibility_tolerance_;
494  return (can_increase.IsSet(col) && (reduced_cost < -tolerance)) ||
495  (can_decrease.IsSet(col) && (reduced_cost > tolerance));
496 }
497 
498 void ReducedCosts::UpdateBasicObjective(ColIndex entering_col,
499  RowIndex leaving_row) {
500  SCOPED_TIME_STAT(&stats_);
501  basic_objective_[RowToColIndex(leaving_row)] =
502  objective_[entering_col] + cost_perturbations_[entering_col];
503  recompute_basic_objective_left_inverse_ = true;
504 }
505 
506 void ReducedCosts::SetRecomputeReducedCostsAndNotifyWatchers() {
507  recompute_reduced_costs_ = true;
508  for (bool* watcher : watchers_) *watcher = true;
509 }
510 
511 PrimalPrices::PrimalPrices(absl::BitGenRef random,
512  const VariablesInfo& variables_info,
513  PrimalEdgeNorms* primal_edge_norms,
514  ReducedCosts* reduced_costs)
515  : prices_(random),
516  variables_info_(variables_info),
517  primal_edge_norms_(primal_edge_norms),
518  reduced_costs_(reduced_costs) {
519  reduced_costs_->AddRecomputationWatcher(&recompute_);
520  primal_edge_norms->AddRecomputationWatcher(&recompute_);
521 }
522 
523 void PrimalPrices::UpdateBeforeBasisPivot(ColIndex entering_col,
524  UpdateRow* update_row) {
525  // If we are recomputing everything when requested, no need to update.
526  if (recompute_) return;
527 
528  // Note that the set of positions works because both the reduced costs
529  // and the primal edge norms are updated on the same positions which are
530  // given by the update_row.
531  UpdateEnteringCandidates</*from_clean_state=*/false>(
532  update_row->GetNonZeroPositions());
533 }
534 
536  if (recompute_) return;
537  if (reduced_costs_->IsValidPrimalEnteringCandidate(col)) {
538  const DenseRow& squared_norms = primal_edge_norms_->GetSquaredNorms();
539  const DenseRow& reduced_costs = reduced_costs_->GetReducedCosts();
540  DCHECK_NE(0.0, squared_norms[col]);
541  prices_.AddOrUpdate(col, Square(reduced_costs[col]) / squared_norms[col]);
542  } else {
543  prices_.Remove(col);
544  }
545 }
546 
548  // If we need a recomputation, we cannot assumes that the reduced costs are
549  // valid until we are about to recompute the prices.
550  if (recompute_) return;
551 
552  DCHECK(!reduced_costs_->IsValidPrimalEnteringCandidate(col));
553  prices_.Remove(col);
554 }
555 
557  if (recompute_) {
558  const DenseRow& reduced_costs = reduced_costs_->GetReducedCosts();
559  prices_.ClearAndResize(reduced_costs.size());
560  UpdateEnteringCandidates</*from_clean_state=*/true>(
561  variables_info_.GetIsRelevantBitRow());
562  recompute_ = false;
563  }
564  return prices_.GetMaximum();
565 }
566 
567 // A variable is an entering candidate if it can move in a direction that
568 // minimizes the objective. That is, its value needs to increase if its
569 // reduced cost is negative or it needs to decrease if its reduced cost is
570 // positive (see the IsValidPrimalEnteringCandidate() function). Note that
571 // this is the same as a dual-infeasible variable.
572 template <bool from_clean_state, typename ColumnsToUpdate>
573 void PrimalPrices::UpdateEnteringCandidates(const ColumnsToUpdate& cols) {
574  const Fractional tolerance = reduced_costs_->GetDualFeasibilityTolerance();
575  const DenseBitRow& can_decrease = variables_info_.GetCanDecreaseBitRow();
576  const DenseBitRow& can_increase = variables_info_.GetCanIncreaseBitRow();
577  const DenseRow& squared_norms = primal_edge_norms_->GetSquaredNorms();
578  const DenseRow& reduced_costs = reduced_costs_->GetReducedCosts();
579  for (const ColIndex col : cols) {
580  const Fractional reduced_cost = reduced_costs[col];
581 
582  // Optimization for speed (The function is about 30% faster than the code in
583  // IsValidPrimalEnteringCandidate() or a switch() on variable_status[col]).
584  // This relies on the fact that (double1 > double2) returns a 1 or 0 result
585  // when converted to an int. It also uses an XOR (which appears to be
586  // faster) since the two conditions on the reduced cost are exclusive.
587  const bool is_dual_infeasible = Bitset64<ColIndex>::ConditionalXorOfTwoBits(
588  col, reduced_cost > tolerance, can_decrease, reduced_cost < -tolerance,
589  can_increase);
590  if (is_dual_infeasible) {
591  DCHECK(reduced_costs_->IsValidPrimalEnteringCandidate(col));
592  const Fractional price = Square(reduced_cost) / squared_norms[col];
593  prices_.AddOrUpdate(col, price);
594  } else {
595  DCHECK(!reduced_costs_->IsValidPrimalEnteringCandidate(col));
596  if (!from_clean_state) prices_.Remove(col);
597  }
598  }
599 }
600 
601 } // namespace glop
602 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
bool IsSet(IndexType i) const
Definition: bitset.h:504
static uint64_t ConditionalXorOfTwoBits(IndexType i, uint64_t use1, const Bitset64< IndexType > &set1, uint64_t use2, const Bitset64< IndexType > &set2)
Definition: bitset.h:631
Fractional ColumnScalarProduct(ColIndex col, const DenseRow &vector) const
Definition: sparse.h:421
void AddOrUpdate(Index position, Fractional value)
Definition: pricing.h:188
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)
ReducedCosts(const CompactSparseMatrix &matrix_, const DenseRow &objective, const RowToColMapping &basis, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization, absl::BitGenRef random)
Fractional TestEnteringReducedCostPrecision(ColIndex entering_col, const ScatteredColumn &direction)
bool IsValidPrimalEnteringCandidate(ColIndex col) const
void SetNonBasicVariableCostToZero(ColIndex col, Fractional *current_cost)
Fractional ComputeMaximumDualInfeasibilityOnNonBoxedVariables()
bool StepIsDualDegenerate(bool increasing_rc_is_needed, ColIndex col)
void UpdateBeforeBasisPivot(ColIndex entering_col, RowIndex leaving_row, const ScatteredColumn &direction, UpdateRow *update_row)
Fractional GetDualFeasibilityTolerance() const
void ShiftCostIfNeeded(bool increasing_rc_is_needed, ColIndex col)
void SetParameters(const GlopParameters &parameters)
const ColIndexVector & GetNonZeroPositions() const
Definition: update_row.cc:185
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
SatParameters parameters
ColIndex col
Definition: markowitz.cc:186
RowIndex row
Definition: markowitz.cc:185
Fractional Square(Fractional f)
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
double Density(const DenseRow &row)
ColIndex RowToColIndex(RowIndex row)
Definition: lp_types.h:53
const DenseRow & Transpose(const DenseColumn &col)
Bitset64< ColIndex > DenseBitRow
Definition: lp_types.h:365
RowIndex ColToRowIndex(ColIndex col)
Definition: lp_types.h:56
static double DeterministicTimeForFpOperations(int64_t n)
Definition: lp_types.h:421
Collection of objects used to extend the Constraint Solver library.
int64_t delta
Definition: resource.cc:1695
IntVar *const objective_
Definition: search.cc:3068
#define IF_STATS_ENABLED(instructions)
Definition: stats.h:438
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:439
StrictITIVector< Index, Fractional > values
#define VLOG(verboselevel)
Definition: vlog.h:39