OR-Tools  8.1
lp_data.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 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 <cmath>
18 #include <string>
19 #include <utility>
20 
21 #include "absl/container/flat_hash_map.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_format.h"
24 #include "ortools/base/logging.h"
29 
30 namespace operations_research {
31 namespace glop {
32 
33 namespace {
34 
35 // This should be the same as DCHECK(AreBoundsValid()), but the DCHECK() are
36 // split to give more meaningful information to the user in case of failure.
37 void DebugCheckBoundsValid(Fractional lower_bound, Fractional upper_bound) {
38  DCHECK(!std::isnan(lower_bound));
39  DCHECK(!std::isnan(upper_bound));
40  DCHECK(!(lower_bound == kInfinity && upper_bound == kInfinity));
41  DCHECK(!(lower_bound == -kInfinity && upper_bound == -kInfinity));
42  DCHECK_LE(lower_bound, upper_bound);
43  DCHECK(AreBoundsValid(lower_bound, upper_bound));
44 }
45 
46 // Returns true if the bounds are the ones of a free or boxed row. Note that
47 // a fixed row is not counted as boxed.
48 bool AreBoundsFreeOrBoxed(Fractional lower_bound, Fractional upper_bound) {
49  if (lower_bound == -kInfinity && upper_bound == kInfinity) return true;
50  if (lower_bound != -kInfinity && upper_bound != kInfinity &&
51  lower_bound != upper_bound) {
52  return true;
53  }
54  return false;
55 }
56 
57 template <class I, class T>
58 double Average(const absl::StrongVector<I, T>& v) {
59  const size_t size = v.size();
60  DCHECK_LT(0, size);
61  double sum = 0.0;
62  double n = 0.0; // n is used in a calculation involving doubles.
63  for (I i(0); i < size; ++i) {
64  if (v[i] == 0.0) continue;
65  ++n;
66  sum += static_cast<double>(v[i].value());
67  }
68  return n == 0.0 ? 0.0 : sum / n;
69 }
70 
71 template <class I, class T>
72 double StandardDeviation(const absl::StrongVector<I, T>& v) {
73  const size_t size = v.size();
74  double n = 0.0; // n is used in a calculation involving doubles.
75  double sigma_square = 0.0;
76  double sigma = 0.0;
77  for (I i(0); i < size; ++i) {
78  double sample = static_cast<double>(v[i].value());
79  if (sample == 0.0) continue;
80  sigma_square += sample * sample;
81  sigma += sample;
82  ++n;
83  }
84  return n == 0.0 ? 0.0 : sqrt((sigma_square - sigma * sigma / n) / n);
85 }
86 
87 // Returns 0 when the vector is empty.
88 template <class I, class T>
89 T GetMaxElement(const absl::StrongVector<I, T>& v) {
90  const size_t size = v.size();
91  if (size == 0) {
92  return T(0);
93  }
94 
95  T max_index = v[I(0)];
96  for (I i(1); i < size; ++i) {
97  if (max_index < v[i]) {
98  max_index = v[i];
99  }
100  }
101  return max_index;
102 }
103 
104 } // anonymous namespace
105 
106 // --------------------------------------------------------
107 // LinearProgram
108 // --------------------------------------------------------
110  : matrix_(),
111  transpose_matrix_(),
112  constraint_lower_bounds_(),
113  constraint_upper_bounds_(),
114  constraint_names_(),
115  objective_coefficients_(),
116  variable_lower_bounds_(),
117  variable_upper_bounds_(),
118  variable_names_(),
119  variable_types_(),
120  integer_variables_list_(),
121  variable_table_(),
122  constraint_table_(),
123  objective_offset_(0.0),
124  objective_scaling_factor_(1.0),
125  maximize_(false),
126  columns_are_known_to_be_clean_(true),
127  transpose_matrix_is_consistent_(true),
128  integer_variables_list_is_consistent_(true),
129  name_(),
130  first_slack_variable_(kInvalidCol) {}
131 
133  matrix_.Clear();
134  transpose_matrix_.Clear();
135 
136  constraint_lower_bounds_.clear();
137  constraint_upper_bounds_.clear();
138  constraint_names_.clear();
139 
140  objective_coefficients_.clear();
141  variable_lower_bounds_.clear();
142  variable_upper_bounds_.clear();
143  variable_types_.clear();
144  integer_variables_list_.clear();
145  variable_names_.clear();
146 
147  constraint_table_.clear();
148  variable_table_.clear();
149 
150  maximize_ = false;
151  objective_offset_ = 0.0;
152  objective_scaling_factor_ = 1.0;
153  columns_are_known_to_be_clean_ = true;
154  transpose_matrix_is_consistent_ = true;
155  integer_variables_list_is_consistent_ = true;
156  name_.clear();
157  first_slack_variable_ = kInvalidCol;
158 }
159 
161  DCHECK_EQ(kInvalidCol, first_slack_variable_)
162  << "New variables can't be added to programs that already have slack "
163  "variables. Consider calling LinearProgram::DeleteSlackVariables() "
164  "before adding new variables to the problem.";
165  objective_coefficients_.push_back(0.0);
166  variable_lower_bounds_.push_back(0);
167  variable_upper_bounds_.push_back(kInfinity);
168  variable_types_.push_back(VariableType::CONTINUOUS);
169  variable_names_.push_back("");
170  transpose_matrix_is_consistent_ = false;
171  return matrix_.AppendEmptyColumn();
172 }
173 
174 ColIndex LinearProgram::CreateNewSlackVariable(bool is_integer_slack_variable,
175  Fractional lower_bound,
176  Fractional upper_bound,
177  const std::string& name) {
178  objective_coefficients_.push_back(0.0);
179  variable_lower_bounds_.push_back(lower_bound);
180  variable_upper_bounds_.push_back(upper_bound);
181  variable_types_.push_back(is_integer_slack_variable
184  variable_names_.push_back(name);
185  transpose_matrix_is_consistent_ = false;
186  return matrix_.AppendEmptyColumn();
187 }
188 
190  DCHECK_EQ(kInvalidCol, first_slack_variable_)
191  << "New constraints can't be added to programs that already have slack "
192  "variables. Consider calling LinearProgram::DeleteSlackVariables() "
193  "before adding new variables to the problem.";
194  const RowIndex row(constraint_names_.size());
195  matrix_.SetNumRows(row + 1);
196  constraint_lower_bounds_.push_back(Fractional(0.0));
197  constraint_upper_bounds_.push_back(Fractional(0.0));
198  constraint_names_.push_back("");
199  transpose_matrix_is_consistent_ = false;
200  return row;
201 }
202 
203 ColIndex LinearProgram::FindOrCreateVariable(const std::string& variable_id) {
204  const absl::flat_hash_map<std::string, ColIndex>::iterator it =
205  variable_table_.find(variable_id);
206  if (it != variable_table_.end()) {
207  return it->second;
208  } else {
209  const ColIndex col = CreateNewVariable();
210  variable_names_[col] = variable_id;
211  variable_table_[variable_id] = col;
212  return col;
213  }
214 }
215 
217  const std::string& constraint_id) {
218  const absl::flat_hash_map<std::string, RowIndex>::iterator it =
219  constraint_table_.find(constraint_id);
220  if (it != constraint_table_.end()) {
221  return it->second;
222  } else {
223  const RowIndex row = CreateNewConstraint();
224  constraint_names_[row] = constraint_id;
225  constraint_table_[constraint_id] = row;
226  return row;
227  }
228 }
229 
230 void LinearProgram::SetVariableName(ColIndex col, absl::string_view name) {
231  variable_names_[col] = std::string(name);
232 }
233 
235  const bool var_was_integer = IsVariableInteger(col);
236  variable_types_[col] = type;
237  const bool var_is_integer = IsVariableInteger(col);
238  if (var_is_integer != var_was_integer) {
239  integer_variables_list_is_consistent_ = false;
240  }
241 }
242 
243 void LinearProgram::SetConstraintName(RowIndex row, absl::string_view name) {
244  constraint_names_[row] = std::string(name);
245 }
246 
248  Fractional upper_bound) {
249  if (dcheck_bounds_) DebugCheckBoundsValid(lower_bound, upper_bound);
250  const bool var_was_binary = IsVariableBinary(col);
251  variable_lower_bounds_[col] = lower_bound;
252  variable_upper_bounds_[col] = upper_bound;
253  const bool var_is_binary = IsVariableBinary(col);
254  if (var_is_binary != var_was_binary) {
255  integer_variables_list_is_consistent_ = false;
256  }
257 }
258 
259 void LinearProgram::UpdateAllIntegerVariableLists() const {
260  if (integer_variables_list_is_consistent_) return;
261  integer_variables_list_.clear();
262  binary_variables_list_.clear();
263  non_binary_variables_list_.clear();
264  const ColIndex num_cols = num_variables();
265  for (ColIndex col(0); col < num_cols; ++col) {
266  if (IsVariableInteger(col)) {
267  integer_variables_list_.push_back(col);
268  if (IsVariableBinary(col)) {
269  binary_variables_list_.push_back(col);
270  } else {
271  non_binary_variables_list_.push_back(col);
272  }
273  }
274  }
275  integer_variables_list_is_consistent_ = true;
276 }
277 
278 const std::vector<ColIndex>& LinearProgram::IntegerVariablesList() const {
279  UpdateAllIntegerVariableLists();
280  return integer_variables_list_;
281 }
282 
283 const std::vector<ColIndex>& LinearProgram::BinaryVariablesList() const {
284  UpdateAllIntegerVariableLists();
285  return binary_variables_list_;
286 }
287 
288 const std::vector<ColIndex>& LinearProgram::NonBinaryVariablesList() const {
289  UpdateAllIntegerVariableLists();
290  return non_binary_variables_list_;
291 }
292 
293 bool LinearProgram::IsVariableInteger(ColIndex col) const {
294  return variable_types_[col] == VariableType::INTEGER ||
295  variable_types_[col] == VariableType::IMPLIED_INTEGER;
296 }
297 
298 bool LinearProgram::IsVariableBinary(ColIndex col) const {
299  // TODO(user,user): bounds of binary variables (and of integer ones) should
300  // be integer. Add a preprocessor for that.
301  return IsVariableInteger(col) && (variable_lower_bounds_[col] < kEpsilon) &&
302  (variable_lower_bounds_[col] > Fractional(-1)) &&
303  (variable_upper_bounds_[col] > Fractional(1) - kEpsilon) &&
304  (variable_upper_bounds_[col] < 2);
305 }
306 
308  Fractional upper_bound) {
309  if (dcheck_bounds_) DebugCheckBoundsValid(lower_bound, upper_bound);
310  ResizeRowsIfNeeded(row);
311  constraint_lower_bounds_[row] = lower_bound;
312  constraint_upper_bounds_[row] = upper_bound;
313 }
314 
315 void LinearProgram::SetCoefficient(RowIndex row, ColIndex col,
316  Fractional value) {
318  ResizeRowsIfNeeded(row);
319  columns_are_known_to_be_clean_ = false;
320  transpose_matrix_is_consistent_ = false;
322 }
323 
326  objective_coefficients_[col] = value;
327 }
328 
331  objective_offset_ = objective_offset;
332 }
333 
335  Fractional objective_scaling_factor) {
338  objective_scaling_factor_ = objective_scaling_factor;
339 }
340 
342  maximize_ = maximize;
343 }
344 
346  if (columns_are_known_to_be_clean_) return;
347  matrix_.CleanUp();
348  columns_are_known_to_be_clean_ = true;
349  transpose_matrix_is_consistent_ = false;
350 }
351 
353  if (columns_are_known_to_be_clean_) return true;
354  columns_are_known_to_be_clean_ = matrix_.IsCleanedUp();
355  return columns_are_known_to_be_clean_;
356 }
357 
358 std::string LinearProgram::GetVariableName(ColIndex col) const {
359  return col >= variable_names_.size() || variable_names_[col].empty()
360  ? absl::StrFormat("c%d", col.value())
361  : variable_names_[col];
362 }
363 
364 std::string LinearProgram::GetConstraintName(RowIndex row) const {
365  return row >= constraint_names_.size() || constraint_names_[row].empty()
366  ? absl::StrFormat("r%d", row.value())
367  : constraint_names_[row];
368 }
369 
371  return variable_types_[col];
372 }
373 
375  if (!transpose_matrix_is_consistent_) {
376  transpose_matrix_.PopulateFromTranspose(matrix_);
377  transpose_matrix_is_consistent_ = true;
378  }
379  DCHECK_EQ(transpose_matrix_.num_rows().value(), matrix_.num_cols().value());
380  DCHECK_EQ(transpose_matrix_.num_cols().value(), matrix_.num_rows().value());
381  return transpose_matrix_;
382 }
383 
385  if (!transpose_matrix_is_consistent_) {
386  transpose_matrix_.PopulateFromTranspose(matrix_);
387  }
388  // This enables a client to start modifying the matrix and then abort and not
389  // call UseTransposeMatrixAsReference(). Then, the other client of
390  // GetTransposeSparseMatrix() will still see the correct matrix.
391  transpose_matrix_is_consistent_ = false;
392  return &transpose_matrix_;
393 }
394 
396  DCHECK_EQ(transpose_matrix_.num_rows().value(), matrix_.num_cols().value());
397  DCHECK_EQ(transpose_matrix_.num_cols().value(), matrix_.num_rows().value());
398  matrix_.PopulateFromTranspose(transpose_matrix_);
399  transpose_matrix_is_consistent_ = true;
400 }
401 
403  transpose_matrix_.Clear();
404  transpose_matrix_is_consistent_ = false;
405 }
406 
408  return matrix_.column(col);
409 }
410 
412  columns_are_known_to_be_clean_ = false;
413  transpose_matrix_is_consistent_ = false;
414  return matrix_.mutable_column(col);
415 }
416 
418  ColIndex col) const {
419  return maximize_ ? -objective_coefficients()[col]
421 }
422 
424  return absl::StrFormat(
425  "%d rows, %d columns, %d entries", num_constraints().value(),
426  num_variables().value(),
427  // static_cast<int64> is needed because the Android port uses int32.
428  static_cast<int64>(num_entries().value()));
429 }
430 
432  int64 num_non_zeros = 0;
433  Fractional min_value = +kInfinity;
434  Fractional max_value = -kInfinity;
435  for (ColIndex col(0); col < objective_coefficients_.size(); ++col) {
436  const Fractional value = objective_coefficients_[col];
437  if (value == 0) continue;
438  min_value = std::min(min_value, value);
439  max_value = std::max(max_value, value);
440  ++num_non_zeros;
441  }
442  if (num_non_zeros == 0) {
443  return "No objective term. This is a pure feasibility problem.";
444  } else {
445  return absl::StrFormat("%d non-zeros, range [%e, %e]", num_non_zeros,
446  min_value, max_value);
447  }
448 }
449 
451  const DenseRow& solution, Fractional absolute_tolerance) const {
452  DCHECK_EQ(solution.size(), num_variables());
453  if (solution.size() != num_variables()) return false;
454  const ColIndex num_cols = num_variables();
455  for (ColIndex col = ColIndex(0); col < num_cols; ++col) {
456  if (!IsFinite(solution[col])) return false;
457  const Fractional lb_error = variable_lower_bounds()[col] - solution[col];
458  const Fractional ub_error = solution[col] - variable_upper_bounds()[col];
459  if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) {
460  return false;
461  }
462  }
463  return true;
464 }
465 
467  Fractional absolute_tolerance) const {
468  if (!SolutionIsWithinVariableBounds(solution, absolute_tolerance)) {
469  return false;
470  }
471  const SparseMatrix& transpose = GetTransposeSparseMatrix();
472  const RowIndex num_rows = num_constraints();
473  for (RowIndex row = RowIndex(0); row < num_rows; ++row) {
474  const Fractional sum =
475  ScalarProduct(solution, transpose.column(RowToColIndex(row)));
476  if (!IsFinite(sum)) return false;
477  const Fractional lb_error = constraint_lower_bounds()[row] - sum;
478  const Fractional ub_error = sum - constraint_upper_bounds()[row];
479  if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) {
480  return false;
481  }
482  }
483  return true;
484 }
485 
487  Fractional absolute_tolerance) const {
488  DCHECK_EQ(solution.size(), num_variables());
489  if (solution.size() != num_variables()) return false;
490  for (ColIndex col : IntegerVariablesList()) {
491  if (!IsFinite(solution[col])) return false;
492  const Fractional fractionality = fabs(solution[col] - round(solution[col]));
493  if (fractionality > absolute_tolerance) return false;
494  }
495  return true;
496 }
497 
499  Fractional absolute_tolerance) const {
500  return SolutionIsLPFeasible(solution, absolute_tolerance) &&
501  SolutionIsInteger(solution, absolute_tolerance);
502 }
503 
505  CHECK(solution != nullptr);
506  const ColIndex num_cols = GetFirstSlackVariable();
507  const SparseMatrix& transpose = GetTransposeSparseMatrix();
508  const RowIndex num_rows = num_constraints();
509  CHECK_EQ(solution->size(), num_variables());
510  for (RowIndex row = RowIndex(0); row < num_rows; ++row) {
511  const Fractional sum = PartialScalarProduct(
512  *solution, transpose.column(RowToColIndex(row)), num_cols.value());
513  const ColIndex slack_variable = GetSlackVariable(row);
514  CHECK_NE(slack_variable, kInvalidCol);
515  (*solution)[slack_variable] = -sum;
516  }
517 }
518 
520  Fractional value) const {
522 }
523 
525  Fractional value) const {
527 }
528 
529 std::string LinearProgram::Dump() const {
530  // Objective line.
531  std::string output = maximize_ ? "max:" : "min:";
532  if (objective_offset_ != 0.0) {
533  output += Stringify(objective_offset_);
534  }
535  const ColIndex num_cols = num_variables();
536  for (ColIndex col(0); col < num_cols; ++col) {
537  const Fractional coeff = objective_coefficients()[col];
538  if (coeff != 0.0) {
539  output += StringifyMonomial(coeff, GetVariableName(col), false);
540  }
541  }
542  output.append(";\n");
543 
544  // Constraints.
545  const RowIndex num_rows = num_constraints();
546  for (RowIndex row(0); row < num_rows; ++row) {
547  const Fractional lower_bound = constraint_lower_bounds()[row];
548  const Fractional upper_bound = constraint_upper_bounds()[row];
549  output += GetConstraintName(row);
550  output += ":";
551  if (AreBoundsFreeOrBoxed(lower_bound, upper_bound)) {
552  output += " ";
553  output += Stringify(lower_bound);
554  output += " <=";
555  }
556  for (ColIndex col(0); col < num_cols; ++col) {
557  const Fractional coeff = matrix_.LookUpValue(row, col);
558  output += StringifyMonomial(coeff, GetVariableName(col), false);
559  }
560  if (AreBoundsFreeOrBoxed(lower_bound, upper_bound)) {
561  output += " <= ";
562  output += Stringify(upper_bound);
563  } else if (lower_bound == upper_bound) {
564  output += " = ";
565  output += Stringify(upper_bound);
566  } else if (lower_bound != -kInfinity) {
567  output += " >= ";
568  output += Stringify(lower_bound);
569  } else if (lower_bound != kInfinity) {
570  output += " <= ";
571  output += Stringify(upper_bound);
572  }
573  output += ";\n";
574  }
575 
576  // Variables.
577  for (ColIndex col(0); col < num_cols; ++col) {
578  const Fractional lower_bound = variable_lower_bounds()[col];
579  const Fractional upper_bound = variable_upper_bounds()[col];
580  if (AreBoundsFreeOrBoxed(lower_bound, upper_bound)) {
581  output += Stringify(lower_bound);
582  output += " <= ";
583  }
584  output += GetVariableName(col);
585  if (AreBoundsFreeOrBoxed(lower_bound, upper_bound)) {
586  output += " <= ";
587  output += Stringify(upper_bound);
588  } else if (lower_bound == upper_bound) {
589  output += " = ";
590  output += Stringify(upper_bound);
591  } else if (lower_bound != -kInfinity) {
592  output += " >= ";
593  output += Stringify(lower_bound);
594  } else if (lower_bound != kInfinity) {
595  output += " <= ";
596  output += Stringify(upper_bound);
597  }
598  output += ";\n";
599  }
600 
601  // Integer variables.
602  // TODO(user): if needed provide similar output for binary variables.
603  const std::vector<ColIndex>& integer_variables = IntegerVariablesList();
604  if (!integer_variables.empty()) {
605  output += "int";
606  for (ColIndex col : integer_variables) {
607  output += " ";
608  output += GetVariableName(col);
609  }
610  output += ";\n";
611  }
612 
613  return output;
614 }
615 
616 std::string LinearProgram::DumpSolution(const DenseRow& variable_values) const {
617  DCHECK_EQ(variable_values.size(), num_variables());
618  std::string output;
619  for (ColIndex col(0); col < variable_values.size(); ++col) {
620  if (!output.empty()) absl::StrAppend(&output, ", ");
621  absl::StrAppend(&output, GetVariableName(col), " = ",
622  (variable_values[col]));
623  }
624  return output;
625 }
626 
627 std::string LinearProgram::GetProblemStats() const {
628  return ProblemStatFormatter(
629  "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
630  "%d,%d,%d,%d");
631 }
632 
634  return ProblemStatFormatter(
635  "Number of rows : %d\n"
636  "Number of variables in file : %d\n"
637  "Number of entries (non-zeros) : %d\n"
638  "Number of entries in the objective : %d\n"
639  "Number of entries in the right-hand side : %d\n"
640  "Number of <= constraints : %d\n"
641  "Number of >= constraints : %d\n"
642  "Number of = constraints : %d\n"
643  "Number of range constraints : %d\n"
644  "Number of non-negative variables : %d\n"
645  "Number of boxed variables : %d\n"
646  "Number of free variables : %d\n"
647  "Number of fixed variables : %d\n"
648  "Number of other variables : %d\n"
649  "Number of integer variables : %d\n"
650  "Number of binary variables : %d\n"
651  "Number of non-binary integer variables : %d\n"
652  "Number of continuous variables : %d\n");
653 }
654 
655 std::string LinearProgram::GetNonZeroStats() const {
656  return NonZeroStatFormatter("%.2f%%,%d,%.2f,%.2f,%d,%.2f,%.2f");
657 }
658 
660  return NonZeroStatFormatter(
661  "Fill rate : %.2f%%\n"
662  "Entries in row (Max / average / std. dev.) : %d / %.2f / %.2f\n"
663  "Entries in column (Max / average / std. dev.): %d / %.2f / %.2f\n");
664 }
665 
667  bool detect_integer_constraints) {
668  // Clean up the matrix. We're going to add entries, but we'll only be adding
669  // them to new columns, and only one entry per column, which does not
670  // invalidate the "cleanness" of the matrix.
671  CleanUp();
672 
673  // Detect which constraints produce an integer slack variable. A constraint
674  // has an integer slack variable, if it contains only integer variables with
675  // integer coefficients. We do not check the bounds of the constraints,
676  // because in such case, they will be tightened to integer values by the
677  // preprocessors.
678  //
679  // We don't use the transpose, because it might not be valid and it would be
680  // inefficient to update it and invalidate it again at the end of this
681  // preprocessor.
682  DenseBooleanColumn has_integer_slack_variable(num_constraints(),
683  detect_integer_constraints);
684  if (detect_integer_constraints) {
685  for (ColIndex col(0); col < num_variables(); ++col) {
686  const SparseColumn& column = matrix_.column(col);
687  const bool is_integer_variable = IsVariableInteger(col);
688  for (const SparseColumn::Entry& entry : column) {
689  const RowIndex row = entry.row();
690  has_integer_slack_variable[row] =
691  has_integer_slack_variable[row] && is_integer_variable &&
692  round(entry.coefficient()) == entry.coefficient();
693  }
694  }
695  }
696 
697  // Extend the matrix of the problem with an identity matrix.
698  const ColIndex original_num_variables = num_variables();
699  for (RowIndex row(0); row < num_constraints(); ++row) {
700  ColIndex slack_variable_index = GetSlackVariable(row);
701  if (slack_variable_index != kInvalidCol &&
702  slack_variable_index < original_num_variables) {
703  // Slack variable is already present in this constraint.
704  continue;
705  }
706  const ColIndex slack_col = CreateNewSlackVariable(
707  has_integer_slack_variable[row], -constraint_upper_bounds_[row],
708  -constraint_lower_bounds_[row], absl::StrCat("s", row.value()));
709  SetCoefficient(row, slack_col, 1.0);
710  SetConstraintBounds(row, 0.0, 0.0);
711  }
712 
713  columns_are_known_to_be_clean_ = true;
714  transpose_matrix_is_consistent_ = false;
715  if (first_slack_variable_ == kInvalidCol) {
716  first_slack_variable_ = original_num_variables;
717  }
718 }
719 
721  return first_slack_variable_;
722 }
723 
724 ColIndex LinearProgram::GetSlackVariable(RowIndex row) const {
725  DCHECK_GE(row, RowIndex(0));
727  if (first_slack_variable_ == kInvalidCol) {
728  return kInvalidCol;
729  }
730  return first_slack_variable_ + RowToColIndex(row);
731 }
732 
734  RowToColMapping* duplicated_rows) {
735  const ColIndex dual_num_variables = dual.num_variables();
736  const RowIndex dual_num_constraints = dual.num_constraints();
737  Clear();
738 
739  // We always take the dual in its minimization form thanks to the
740  // GetObjectiveCoefficientForMinimizationVersion() below, so this will always
741  // be a maximization problem.
743 
744  // Taking the dual does not change the offset nor the objective scaling
745  // factor.
748 
749  // Create the dual variables y, with bounds depending on the type
750  // of constraints in the primal.
751  for (RowIndex dual_row(0); dual_row < dual_num_constraints; ++dual_row) {
753  const ColIndex col = RowToColIndex(dual_row);
754  const Fractional lower_bound = dual.constraint_lower_bounds()[dual_row];
755  const Fractional upper_bound = dual.constraint_upper_bounds()[dual_row];
756  if (lower_bound == upper_bound) {
758  SetObjectiveCoefficient(col, lower_bound);
759  } else if (upper_bound != kInfinity) {
760  // Note that for a ranged constraint, the loop will be continued here.
761  // This is wanted because we want to deal with the lower_bound afterwards.
763  SetObjectiveCoefficient(col, upper_bound);
764  } else if (lower_bound != -kInfinity) {
766  SetObjectiveCoefficient(col, lower_bound);
767  } else {
768  // This code does not support free rows in linear_program.
769  LOG(DFATAL) << "PopulateFromDual() was called with a program "
770  << "containing free constraints.";
771  }
772  }
773  // Create the dual slack variables v.
774  for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
775  const Fractional lower_bound = dual.variable_lower_bounds()[dual_col];
776  if (lower_bound != -kInfinity) {
777  const ColIndex col = CreateNewVariable();
778  SetObjectiveCoefficient(col, lower_bound);
780  const RowIndex row = ColToRowIndex(dual_col);
782  }
783  }
784  // Create the dual surplus variables w.
785  for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
786  const Fractional upper_bound = dual.variable_upper_bounds()[dual_col];
787  if (upper_bound != kInfinity) {
788  const ColIndex col = CreateNewVariable();
789  SetObjectiveCoefficient(col, upper_bound);
791  const RowIndex row = ColToRowIndex(dual_col);
793  }
794  }
795  // Store the transpose of the matrix.
796  for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
797  const RowIndex row = ColToRowIndex(dual_col);
798  const Fractional row_bound =
800  SetConstraintBounds(row, row_bound, row_bound);
801  for (const SparseColumn::Entry e : dual.GetSparseColumn(dual_col)) {
802  const RowIndex dual_row = e.row();
803  const ColIndex col = RowToColIndex(dual_row);
804  SetCoefficient(row, col, e.coefficient());
805  }
806  }
807 
808  // Take care of ranged constraints.
809  duplicated_rows->assign(dual_num_constraints, kInvalidCol);
810  for (RowIndex dual_row(0); dual_row < dual_num_constraints; ++dual_row) {
811  const Fractional lower_bound = dual.constraint_lower_bounds()[dual_row];
812  const Fractional upper_bound = dual.constraint_upper_bounds()[dual_row];
813  if (AreBoundsFreeOrBoxed(lower_bound, upper_bound)) {
814  DCHECK(upper_bound != kInfinity || lower_bound != -kInfinity);
815 
816  // upper_bound was done in a loop above, now do the lower_bound.
817  const ColIndex col = CreateNewVariable();
819  SetObjectiveCoefficient(col, lower_bound);
821  matrix_.column(RowToColIndex(dual_row)));
822  (*duplicated_rows)[dual_row] = col;
823  }
824  }
825 
826  // We know that the columns are ordered by rows.
827  columns_are_known_to_be_clean_ = true;
828  transpose_matrix_is_consistent_ = false;
829 }
830 
832  const LinearProgram& linear_program) {
833  matrix_.PopulateFromSparseMatrix(linear_program.matrix_);
834  if (linear_program.transpose_matrix_is_consistent_) {
835  transpose_matrix_is_consistent_ = true;
836  transpose_matrix_.PopulateFromSparseMatrix(
837  linear_program.transpose_matrix_);
838  } else {
839  transpose_matrix_is_consistent_ = false;
840  transpose_matrix_.Clear();
841  }
842 
843  constraint_lower_bounds_ = linear_program.constraint_lower_bounds_;
844  constraint_upper_bounds_ = linear_program.constraint_upper_bounds_;
845  constraint_names_ = linear_program.constraint_names_;
846  constraint_table_.clear();
847 
848  PopulateNameObjectiveAndVariablesFromLinearProgram(linear_program);
849  first_slack_variable_ = linear_program.first_slack_variable_;
850 }
851 
853  const LinearProgram& lp, const RowPermutation& row_permutation,
854  const ColumnPermutation& col_permutation) {
855  DCHECK(lp.IsCleanedUp());
856  DCHECK_EQ(row_permutation.size(), lp.num_constraints());
857  DCHECK_EQ(col_permutation.size(), lp.num_variables());
859  Clear();
860 
861  // Populate matrix coefficients.
862  ColumnPermutation inverse_col_permutation;
863  inverse_col_permutation.PopulateFromInverse(col_permutation);
864  matrix_.PopulateFromPermutedMatrix(lp.matrix_, row_permutation,
865  inverse_col_permutation);
867 
868  // Populate constraints.
869  ApplyPermutation(row_permutation, lp.constraint_lower_bounds(),
870  &constraint_lower_bounds_);
871  ApplyPermutation(row_permutation, lp.constraint_upper_bounds(),
872  &constraint_upper_bounds_);
873 
874  // Populate variables.
875  ApplyPermutation(col_permutation, lp.objective_coefficients(),
876  &objective_coefficients_);
877  ApplyPermutation(col_permutation, lp.variable_lower_bounds(),
878  &variable_lower_bounds_);
879  ApplyPermutation(col_permutation, lp.variable_upper_bounds(),
880  &variable_upper_bounds_);
881  ApplyPermutation(col_permutation, lp.variable_types(), &variable_types_);
882  integer_variables_list_is_consistent_ = false;
883 
884  // There is no vector based accessor to names, because they may be created
885  // on the fly.
886  constraint_names_.resize(lp.num_constraints());
887  for (RowIndex old_row(0); old_row < lp.num_constraints(); ++old_row) {
888  const RowIndex new_row = row_permutation[old_row];
889  constraint_names_[new_row] = lp.constraint_names_[old_row];
890  }
891  variable_names_.resize(lp.num_variables());
892  for (ColIndex old_col(0); old_col < lp.num_variables(); ++old_col) {
893  const ColIndex new_col = col_permutation[old_col];
894  variable_names_[new_col] = lp.variable_names_[old_col];
895  }
896 
897  // Populate singular fields.
898  maximize_ = lp.maximize_;
899  objective_offset_ = lp.objective_offset_;
900  objective_scaling_factor_ = lp.objective_scaling_factor_;
901  name_ = lp.name_;
902 }
903 
905  const LinearProgram& linear_program) {
906  matrix_.PopulateFromZero(RowIndex(0), linear_program.num_variables());
907  first_slack_variable_ = kInvalidCol;
908  transpose_matrix_is_consistent_ = false;
909  transpose_matrix_.Clear();
910 
911  constraint_lower_bounds_.clear();
912  constraint_upper_bounds_.clear();
913  constraint_names_.clear();
914  constraint_table_.clear();
915 
916  PopulateNameObjectiveAndVariablesFromLinearProgram(linear_program);
917 }
918 
919 void LinearProgram::PopulateNameObjectiveAndVariablesFromLinearProgram(
920  const LinearProgram& linear_program) {
921  objective_coefficients_ = linear_program.objective_coefficients_;
922  variable_lower_bounds_ = linear_program.variable_lower_bounds_;
923  variable_upper_bounds_ = linear_program.variable_upper_bounds_;
924  variable_names_ = linear_program.variable_names_;
925  variable_types_ = linear_program.variable_types_;
926  integer_variables_list_is_consistent_ =
927  linear_program.integer_variables_list_is_consistent_;
928  integer_variables_list_ = linear_program.integer_variables_list_;
929  binary_variables_list_ = linear_program.binary_variables_list_;
930  non_binary_variables_list_ = linear_program.non_binary_variables_list_;
931  variable_table_.clear();
932 
933  maximize_ = linear_program.maximize_;
934  objective_offset_ = linear_program.objective_offset_;
935  objective_scaling_factor_ = linear_program.objective_scaling_factor_;
936  columns_are_known_to_be_clean_ =
937  linear_program.columns_are_known_to_be_clean_;
938  name_ = linear_program.name_;
939 }
940 
942  const SparseMatrix& coefficients, const DenseColumn& left_hand_sides,
943  const DenseColumn& right_hand_sides,
945  const RowIndex num_new_constraints = coefficients.num_rows();
946  DCHECK_EQ(num_variables(), coefficients.num_cols());
947  DCHECK_EQ(num_new_constraints, left_hand_sides.size());
948  DCHECK_EQ(num_new_constraints, right_hand_sides.size());
949  DCHECK_EQ(num_new_constraints, names.size());
950 
952  transpose_matrix_is_consistent_ = false;
953  transpose_matrix_.Clear();
954  columns_are_known_to_be_clean_ = false;
955 
956  // Copy constraint bounds and names from linear_program.
957  constraint_lower_bounds_.insert(constraint_lower_bounds_.end(),
958  left_hand_sides.begin(),
959  left_hand_sides.end());
960  constraint_upper_bounds_.insert(constraint_upper_bounds_.end(),
961  right_hand_sides.begin(),
962  right_hand_sides.end());
963  constraint_names_.insert(constraint_names_.end(), names.begin(), names.end());
964 }
965 
967  const SparseMatrix& coefficients, const DenseColumn& left_hand_sides,
968  const DenseColumn& right_hand_sides,
970  bool detect_integer_constraints_for_slack) {
971  AddConstraints(coefficients, left_hand_sides, right_hand_sides, names);
972  AddSlackVariablesWhereNecessary(detect_integer_constraints_for_slack);
973 }
974 
976  const DenseRow& variable_lower_bounds,
977  const DenseRow& variable_upper_bounds) {
978  const ColIndex num_vars = num_variables();
979  DCHECK_EQ(variable_lower_bounds.size(), num_vars);
980  DCHECK_EQ(variable_upper_bounds.size(), num_vars);
981 
982  DenseRow new_lower_bounds(num_vars, 0);
983  DenseRow new_upper_bounds(num_vars, 0);
984  for (ColIndex i(0); i < num_vars; ++i) {
985  const Fractional new_lower_bound =
986  std::max(variable_lower_bounds[i], variable_lower_bounds_[i]);
987  const Fractional new_upper_bound =
988  std::min(variable_upper_bounds[i], variable_upper_bounds_[i]);
989  if (new_lower_bound > new_upper_bound) {
990  return false;
991  }
992  new_lower_bounds[i] = new_lower_bound;
993  new_upper_bounds[i] = new_upper_bound;
994  }
995  variable_lower_bounds_.swap(new_lower_bounds);
996  variable_upper_bounds_.swap(new_upper_bounds);
997  return true;
998 }
999 
1000 void LinearProgram::Swap(LinearProgram* linear_program) {
1001  matrix_.Swap(&linear_program->matrix_);
1002  transpose_matrix_.Swap(&linear_program->transpose_matrix_);
1003 
1004  constraint_lower_bounds_.swap(linear_program->constraint_lower_bounds_);
1005  constraint_upper_bounds_.swap(linear_program->constraint_upper_bounds_);
1006  constraint_names_.swap(linear_program->constraint_names_);
1007 
1008  objective_coefficients_.swap(linear_program->objective_coefficients_);
1009  variable_lower_bounds_.swap(linear_program->variable_lower_bounds_);
1010  variable_upper_bounds_.swap(linear_program->variable_upper_bounds_);
1011  variable_names_.swap(linear_program->variable_names_);
1012  variable_types_.swap(linear_program->variable_types_);
1013  integer_variables_list_.swap(linear_program->integer_variables_list_);
1014  binary_variables_list_.swap(linear_program->binary_variables_list_);
1015  non_binary_variables_list_.swap(linear_program->non_binary_variables_list_);
1016 
1017  variable_table_.swap(linear_program->variable_table_);
1018  constraint_table_.swap(linear_program->constraint_table_);
1019 
1020  std::swap(maximize_, linear_program->maximize_);
1021  std::swap(objective_offset_, linear_program->objective_offset_);
1022  std::swap(objective_scaling_factor_,
1023  linear_program->objective_scaling_factor_);
1024  std::swap(columns_are_known_to_be_clean_,
1025  linear_program->columns_are_known_to_be_clean_);
1026  std::swap(transpose_matrix_is_consistent_,
1027  linear_program->transpose_matrix_is_consistent_);
1028  std::swap(integer_variables_list_is_consistent_,
1029  linear_program->integer_variables_list_is_consistent_);
1030  name_.swap(linear_program->name_);
1031  std::swap(first_slack_variable_, linear_program->first_slack_variable_);
1032 }
1033 
1034 void LinearProgram::DeleteColumns(const DenseBooleanRow& columns_to_delete) {
1035  if (columns_to_delete.empty()) return;
1036  integer_variables_list_is_consistent_ = false;
1037  const ColIndex num_cols = num_variables();
1038  ColumnPermutation permutation(num_cols);
1039  ColIndex new_index(0);
1040  for (ColIndex col(0); col < num_cols; ++col) {
1041  permutation[col] = new_index;
1042  if (col >= columns_to_delete.size() || !columns_to_delete[col]) {
1043  objective_coefficients_[new_index] = objective_coefficients_[col];
1044  variable_lower_bounds_[new_index] = variable_lower_bounds_[col];
1045  variable_upper_bounds_[new_index] = variable_upper_bounds_[col];
1046  variable_names_[new_index] = variable_names_[col];
1047  variable_types_[new_index] = variable_types_[col];
1048  ++new_index;
1049  } else {
1050  permutation[col] = kInvalidCol;
1051  }
1052  }
1053 
1054  matrix_.DeleteColumns(columns_to_delete);
1055  objective_coefficients_.resize(new_index, 0.0);
1056  variable_lower_bounds_.resize(new_index, 0.0);
1057  variable_upper_bounds_.resize(new_index, 0.0);
1058  variable_types_.resize(new_index, VariableType::CONTINUOUS);
1059  variable_names_.resize(new_index, "");
1060 
1061  // Remove the id of the deleted columns and adjust the index of the other.
1062  absl::flat_hash_map<std::string, ColIndex>::iterator it =
1063  variable_table_.begin();
1064  while (it != variable_table_.end()) {
1065  const ColIndex col = it->second;
1066  if (col >= columns_to_delete.size() || !columns_to_delete[col]) {
1067  it->second = permutation[col];
1068  ++it;
1069  } else {
1070  // This safely deletes the entry and moves the iterator one step ahead.
1071  variable_table_.erase(it++);
1072  }
1073  }
1074 
1075  // Eventually update transpose_matrix_.
1076  if (transpose_matrix_is_consistent_) {
1077  transpose_matrix_.DeleteRows(
1078  ColToRowIndex(new_index),
1079  reinterpret_cast<const RowPermutation&>(permutation));
1080  }
1081 }
1082 
1084  DCHECK_NE(first_slack_variable_, kInvalidCol);
1085  DenseBooleanRow slack_variables(matrix_.num_cols(), false);
1086  // Restore the bounds on the constraints corresponding to the slack variables.
1087  for (ColIndex slack_variable = first_slack_variable_;
1088  slack_variable < matrix_.num_cols(); ++slack_variable) {
1089  const SparseColumn& column = matrix_.column(slack_variable);
1090  // Slack variables appear only in the constraints for which they were
1091  // created. We can find this constraint by looking at the (only) entry in
1092  // the columnm of the slack variable.
1093  DCHECK_EQ(column.num_entries(), 1);
1094  const RowIndex row = column.EntryRow(EntryIndex(0));
1095  DCHECK_EQ(constraint_lower_bounds_[row], 0.0);
1096  DCHECK_EQ(constraint_upper_bounds_[row], 0.0);
1097  SetConstraintBounds(row, -variable_upper_bounds_[slack_variable],
1098  -variable_lower_bounds_[slack_variable]);
1099  slack_variables[slack_variable] = true;
1100  }
1101 
1102  DeleteColumns(slack_variables);
1103  first_slack_variable_ = kInvalidCol;
1104 }
1105 
1106 namespace {
1107 
1108 // Note that we ignore zeros and infinities because they do not matter from a
1109 // scaling perspective where this function is used.
1110 template <typename FractionalRange>
1111 void UpdateMinAndMaxMagnitude(const FractionalRange& range,
1112  Fractional* min_magnitude,
1113  Fractional* max_magnitude) {
1114  for (const Fractional value : range) {
1115  const Fractional magnitude = std::abs(value);
1116  if (magnitude == 0 || magnitude == kInfinity) continue;
1117  *min_magnitude = std::min(*min_magnitude, magnitude);
1118  *max_magnitude = std::max(*max_magnitude, magnitude);
1119  }
1120 }
1121 
1122 Fractional GetMedianScalingFactor(const DenseRow& range) {
1123  std::vector<Fractional> median;
1124  for (const Fractional value : range) {
1125  if (value == 0.0) continue;
1126  median.push_back(std::abs(value));
1127  }
1128  if (median.empty()) return 1.0;
1129  std::sort(median.begin(), median.end());
1130  return median[median.size() / 2];
1131 }
1132 
1133 Fractional GetMeanScalingFactor(const DenseRow& range) {
1134  Fractional mean = 0.0;
1135  int num_non_zeros = 0;
1136  for (const Fractional value : range) {
1137  if (value == 0.0) continue;
1138  ++num_non_zeros;
1139  mean += std::abs(value);
1140  }
1141  if (num_non_zeros == 0.0) return 1.0;
1142  return mean / static_cast<Fractional>(num_non_zeros);
1143 }
1144 
1145 Fractional ComputeDivisorSoThatRangeContainsOne(Fractional min_magnitude,
1146  Fractional max_magnitude) {
1147  if (min_magnitude > 1.0 && min_magnitude < kInfinity) {
1148  return min_magnitude;
1149  } else if (max_magnitude > 0.0 && max_magnitude < 1.0) {
1150  return max_magnitude;
1151  }
1152  return 1.0;
1153 }
1154 
1155 } // namespace
1156 
1158  GlopParameters::CostScalingAlgorithm method) {
1159  Fractional min_magnitude = kInfinity;
1160  Fractional max_magnitude = 0.0;
1161  UpdateMinAndMaxMagnitude(objective_coefficients(), &min_magnitude,
1162  &max_magnitude);
1163  Fractional cost_scaling_factor = 1.0;
1164  switch (method) {
1165  case GlopParameters::NO_COST_SCALING:
1166  break;
1167  case GlopParameters::CONTAIN_ONE_COST_SCALING:
1168  cost_scaling_factor =
1169  ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1170  break;
1171  case GlopParameters::MEAN_COST_SCALING:
1172  cost_scaling_factor = GetMeanScalingFactor(objective_coefficients());
1173  break;
1174  case GlopParameters::MEDIAN_COST_SCALING:
1175  cost_scaling_factor = GetMedianScalingFactor(objective_coefficients());
1176  break;
1177  }
1178  if (cost_scaling_factor != 1.0) {
1179  for (ColIndex col(0); col < num_variables(); ++col) {
1180  if (objective_coefficients()[col] == 0.0) continue;
1182  col, objective_coefficients()[col] / cost_scaling_factor);
1183  }
1184  SetObjectiveScalingFactor(objective_scaling_factor() * cost_scaling_factor);
1185  SetObjectiveOffset(objective_offset() / cost_scaling_factor);
1186  }
1187  VLOG(1) << "Objective magnitude range is [" << min_magnitude << ", "
1188  << max_magnitude << "] (dividing by " << cost_scaling_factor << ").";
1189  return cost_scaling_factor;
1190 }
1191 
1193  Fractional min_magnitude = kInfinity;
1194  Fractional max_magnitude = 0.0;
1195  UpdateMinAndMaxMagnitude(variable_lower_bounds(), &min_magnitude,
1196  &max_magnitude);
1197  UpdateMinAndMaxMagnitude(variable_upper_bounds(), &min_magnitude,
1198  &max_magnitude);
1199  UpdateMinAndMaxMagnitude(constraint_lower_bounds(), &min_magnitude,
1200  &max_magnitude);
1201  UpdateMinAndMaxMagnitude(constraint_upper_bounds(), &min_magnitude,
1202  &max_magnitude);
1203  const Fractional bound_scaling_factor =
1204  ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1205  if (bound_scaling_factor != 1.0) {
1207  bound_scaling_factor);
1208  SetObjectiveOffset(objective_offset() / bound_scaling_factor);
1209  for (ColIndex col(0); col < num_variables(); ++col) {
1211  variable_lower_bounds()[col] / bound_scaling_factor,
1212  variable_upper_bounds()[col] / bound_scaling_factor);
1213  }
1214  for (RowIndex row(0); row < num_constraints(); ++row) {
1216  row, constraint_lower_bounds()[row] / bound_scaling_factor,
1217  constraint_upper_bounds()[row] / bound_scaling_factor);
1218  }
1219  }
1220 
1221  VLOG(1) << "Bounds magnitude range is [" << min_magnitude << ", "
1222  << max_magnitude << "] (dividing bounds by " << bound_scaling_factor
1223  << ").";
1224  return bound_scaling_factor;
1225 }
1226 
1227 void LinearProgram::DeleteRows(const DenseBooleanColumn& rows_to_delete) {
1228  if (rows_to_delete.empty()) return;
1229 
1230  // Deal with row-indexed data and construct the row mapping that will need to
1231  // be applied to every column entry.
1232  const RowIndex num_rows = num_constraints();
1233  RowPermutation permutation(num_rows);
1234  RowIndex new_index(0);
1235  for (RowIndex row(0); row < num_rows; ++row) {
1236  if (row >= rows_to_delete.size() || !rows_to_delete[row]) {
1237  constraint_lower_bounds_[new_index] = constraint_lower_bounds_[row];
1238  constraint_upper_bounds_[new_index] = constraint_upper_bounds_[row];
1239  constraint_names_[new_index].swap(constraint_names_[row]);
1240  permutation[row] = new_index;
1241  ++new_index;
1242  } else {
1243  permutation[row] = kInvalidRow;
1244  }
1245  }
1246  constraint_lower_bounds_.resize(new_index, 0.0);
1247  constraint_upper_bounds_.resize(new_index, 0.0);
1248  constraint_names_.resize(new_index, "");
1249 
1250  // Remove the rows from the matrix.
1251  matrix_.DeleteRows(new_index, permutation);
1252 
1253  // Remove the id of the deleted rows and adjust the index of the other.
1254  absl::flat_hash_map<std::string, RowIndex>::iterator it =
1255  constraint_table_.begin();
1256  while (it != constraint_table_.end()) {
1257  const RowIndex row = it->second;
1258  if (permutation[row] != kInvalidRow) {
1259  it->second = permutation[row];
1260  ++it;
1261  } else {
1262  // This safely deletes the entry and moves the iterator one step ahead.
1263  constraint_table_.erase(it++);
1264  }
1265  }
1266 
1267  // Eventually update transpose_matrix_.
1268  if (transpose_matrix_is_consistent_) {
1269  transpose_matrix_.DeleteColumns(
1270  reinterpret_cast<const DenseBooleanRow&>(rows_to_delete));
1271  }
1272 }
1273 
1275  if (!IsFinite(objective_offset_)) return false;
1276  if (!IsFinite(objective_scaling_factor_)) return false;
1277  if (objective_scaling_factor_ == 0.0) return false;
1278  const ColIndex num_cols = num_variables();
1279  for (ColIndex col(0); col < num_cols; ++col) {
1281  variable_upper_bounds()[col])) {
1282  return false;
1283  }
1284  if (!IsFinite(objective_coefficients()[col])) {
1285  return false;
1286  }
1287  for (const SparseColumn::Entry e : GetSparseColumn(col)) {
1288  if (!IsFinite(e.coefficient())) return false;
1289  }
1290  }
1291  if (constraint_upper_bounds_.size() != constraint_lower_bounds_.size()) {
1292  return false;
1293  }
1294  for (RowIndex row(0); row < constraint_lower_bounds_.size(); ++row) {
1297  return false;
1298  }
1299  }
1300  return true;
1301 }
1302 
1303 std::string LinearProgram::ProblemStatFormatter(
1304  const absl::string_view format) const {
1305  int num_objective_non_zeros = 0;
1306  int num_non_negative_variables = 0;
1307  int num_boxed_variables = 0;
1308  int num_free_variables = 0;
1309  int num_fixed_variables = 0;
1310  int num_other_variables = 0;
1311  const ColIndex num_cols = num_variables();
1312  for (ColIndex col(0); col < num_cols; ++col) {
1313  if (objective_coefficients()[col] != 0.0) {
1314  ++num_objective_non_zeros;
1315  }
1316 
1317  const Fractional lower_bound = variable_lower_bounds()[col];
1318  const Fractional upper_bound = variable_upper_bounds()[col];
1319  const bool lower_bounded = (lower_bound != -kInfinity);
1320  const bool upper_bounded = (upper_bound != kInfinity);
1321 
1322  if (!lower_bounded && !upper_bounded) {
1323  ++num_free_variables;
1324  } else if (lower_bound == 0.0 && !upper_bounded) {
1325  ++num_non_negative_variables;
1326  } else if (!upper_bounded || !lower_bounded) {
1327  ++num_other_variables;
1328  } else if (lower_bound == upper_bound) {
1329  ++num_fixed_variables;
1330  } else {
1331  ++num_boxed_variables;
1332  }
1333  }
1334 
1335  int num_range_constraints = 0;
1336  int num_less_than_constraints = 0;
1337  int num_greater_than_constraints = 0;
1338  int num_equal_constraints = 0;
1339  int num_rhs_non_zeros = 0;
1340  const RowIndex num_rows = num_constraints();
1341  for (RowIndex row(0); row < num_rows; ++row) {
1342  const Fractional lower_bound = constraint_lower_bounds()[row];
1343  const Fractional upper_bound = constraint_upper_bounds()[row];
1344  if (AreBoundsFreeOrBoxed(lower_bound, upper_bound)) {
1345  // TODO(user): we currently count a free row as a range constraint.
1346  // Add a new category?
1347  ++num_range_constraints;
1348  continue;
1349  }
1350  if (lower_bound == upper_bound) {
1351  ++num_equal_constraints;
1352  if (lower_bound != 0) {
1353  ++num_rhs_non_zeros;
1354  }
1355  continue;
1356  }
1357  if (lower_bound == -kInfinity) {
1358  ++num_less_than_constraints;
1359  if (upper_bound != 0) {
1360  ++num_rhs_non_zeros;
1361  }
1362  continue;
1363  }
1364  if (upper_bound == kInfinity) {
1365  ++num_greater_than_constraints;
1366  if (lower_bound != 0) {
1367  ++num_rhs_non_zeros;
1368  }
1369  continue;
1370  }
1371  LOG(DFATAL) << "There is a bug since all possible cases for the row bounds "
1372  "should have been accounted for. row="
1373  << row;
1374  }
1375 
1376  const int num_integer_variables = IntegerVariablesList().size();
1377  const int num_binary_variables = BinaryVariablesList().size();
1378  const int num_non_binary_variables = NonBinaryVariablesList().size();
1379  const int num_continuous_variables =
1380  ColToIntIndex(num_variables()) - num_integer_variables;
1381  auto format_runtime =
1382  absl::ParsedFormat<'d', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
1383  'd', 'd', 'd', 'd', 'd', 'd', 'd'>::New(format);
1384  CHECK(format_runtime);
1385  return absl::StrFormat(
1386  *format_runtime, RowToIntIndex(num_constraints()),
1387  ColToIntIndex(num_variables()), matrix_.num_entries().value(),
1388  num_objective_non_zeros, num_rhs_non_zeros, num_less_than_constraints,
1389  num_greater_than_constraints, num_equal_constraints,
1390  num_range_constraints, num_non_negative_variables, num_boxed_variables,
1391  num_free_variables, num_fixed_variables, num_other_variables,
1392  num_integer_variables, num_binary_variables, num_non_binary_variables,
1393  num_continuous_variables);
1394 }
1395 
1396 std::string LinearProgram::NonZeroStatFormatter(
1397  const absl::string_view format) const {
1398  StrictITIVector<RowIndex, EntryIndex> num_entries_in_row(num_constraints(),
1399  EntryIndex(0));
1400  StrictITIVector<ColIndex, EntryIndex> num_entries_in_column(num_variables(),
1401  EntryIndex(0));
1402  EntryIndex num_entries(0);
1403  const ColIndex num_cols = num_variables();
1404  for (ColIndex col(0); col < num_cols; ++col) {
1405  const SparseColumn& sparse_column = GetSparseColumn(col);
1406  num_entries += sparse_column.num_entries();
1407  num_entries_in_column[col] = sparse_column.num_entries();
1408  for (const SparseColumn::Entry e : sparse_column) {
1409  ++num_entries_in_row[e.row()];
1410  }
1411  }
1412 
1413  // To avoid division by 0 if there are no columns or no rows, we set
1414  // height and width to be at least one.
1415  const int64 height = std::max(RowToIntIndex(num_constraints()), 1);
1416  const int64 width = std::max(ColToIntIndex(num_variables()), 1);
1417  const double fill_rate = 100.0 * static_cast<double>(num_entries.value()) /
1418  static_cast<double>(height * width);
1419 
1420  auto format_runtime =
1421  absl::ParsedFormat<'f', 'd', 'f', 'f', 'd', 'f', 'f'>::New(format);
1422  return absl::StrFormat(
1423  *format_runtime, fill_rate, GetMaxElement(num_entries_in_row).value(),
1424  Average(num_entries_in_row), StandardDeviation(num_entries_in_row),
1425  GetMaxElement(num_entries_in_column).value(),
1426  Average(num_entries_in_column), StandardDeviation(num_entries_in_column));
1427 }
1428 
1429 void LinearProgram::ResizeRowsIfNeeded(RowIndex row) {
1430  DCHECK_GE(row, 0);
1431  if (row >= num_constraints()) {
1432  transpose_matrix_is_consistent_ = false;
1433  matrix_.SetNumRows(row + 1);
1434  constraint_lower_bounds_.resize(row + 1, Fractional(0.0));
1435  constraint_upper_bounds_.resize(row + 1, Fractional(0.0));
1436  constraint_names_.resize(row + 1, "");
1437  }
1438 }
1439 
1441  for (RowIndex constraint(0); constraint < num_constraints(); ++constraint) {
1442  if (constraint_lower_bounds_[constraint] != 0.0 ||
1443  constraint_upper_bounds_[constraint] != 0.0) {
1444  return false;
1445  }
1446  }
1447  const ColIndex num_slack_variables =
1449  return num_constraints().value() == num_slack_variables.value() &&
1451 }
1452 
1454  Fractional tolerance) const {
1455  for (const ColIndex col : IntegerVariablesList()) {
1456  if ((IsFinite(variable_lower_bounds_[col]) &&
1457  !IsIntegerWithinTolerance(variable_lower_bounds_[col], tolerance)) ||
1458  (IsFinite(variable_upper_bounds_[col]) &&
1459  !IsIntegerWithinTolerance(variable_upper_bounds_[col], tolerance))) {
1460  VLOG(1) << "Bounds of variable " << col.value() << " are non-integer ("
1461  << variable_lower_bounds_[col] << ", "
1462  << variable_upper_bounds_[col] << ").";
1463  return false;
1464  }
1465  }
1466  return true;
1467 }
1468 
1470  Fractional tolerance) const {
1471  // Using transpose for this is faster (complexity = O(number of non zeros in
1472  // matrix)) than directly iterating through entries (complexity = O(number of
1473  // constraints * number of variables)).
1474  const SparseMatrix& transpose = GetTransposeSparseMatrix();
1475  for (RowIndex row = RowIndex(0); row < num_constraints(); ++row) {
1476  bool integer_constraint = true;
1477  for (const SparseColumn::Entry var : transpose.column(RowToColIndex(row))) {
1478  if (!IsVariableInteger(RowToColIndex(var.row()))) {
1479  integer_constraint = false;
1480  break;
1481  }
1482  if (!IsIntegerWithinTolerance(var.coefficient(), tolerance)) {
1483  integer_constraint = false;
1484  break;
1485  }
1486  }
1487  if (integer_constraint) {
1488  if ((IsFinite(constraint_lower_bounds_[row]) &&
1489  !IsIntegerWithinTolerance(constraint_lower_bounds_[row],
1490  tolerance)) ||
1491  (IsFinite(constraint_upper_bounds_[row]) &&
1492  !IsIntegerWithinTolerance(constraint_upper_bounds_[row],
1493  tolerance))) {
1494  VLOG(1) << "Bounds of constraint " << row.value()
1495  << " are non-integer (" << constraint_lower_bounds_[row] << ", "
1496  << constraint_upper_bounds_[row] << ").";
1497  return false;
1498  }
1499  }
1500  }
1501  return true;
1502 }
1503 
1504 // --------------------------------------------------------
1505 // ProblemSolution
1506 // --------------------------------------------------------
1507 std::string ProblemSolution::DebugString() const {
1508  std::string s = "Problem status: " + GetProblemStatusString(status);
1509  for (ColIndex col(0); col < primal_values.size(); ++col) {
1510  absl::StrAppendFormat(&s, "\n Var #%d: %s %g", col.value(),
1512  primal_values[col]);
1513  }
1514  s += "\n------------------------------";
1515  for (RowIndex row(0); row < dual_values.size(); ++row) {
1516  absl::StrAppendFormat(&s, "\n Constraint #%d: %s %g", row.value(),
1518  dual_values[row]);
1519  }
1520  return s;
1521 }
1522 
1523 } // namespace glop
1524 } // namespace operations_research
operations_research::glop::LinearProgram::GetPrettyNonZeroStats
std::string GetPrettyNonZeroStats() const
Definition: lp_data.cc:659
operations_research::glop::LinearProgram::IsVariableBinary
bool IsVariableBinary(ColIndex col) const
Definition: lp_data.cc:298
operations_research::glop::LinearProgram::ApplyObjectiveScalingAndOffset
Fractional ApplyObjectiveScalingAndOffset(Fractional value) const
Definition: lp_data.cc:519
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::glop::LinearProgram::num_constraints
RowIndex num_constraints() const
Definition: lp_data.h:208
absl::StrongVector::end
iterator end()
Definition: strong_vector.h:140
operations_research::glop::SparseMatrix::PopulateFromZero
void PopulateFromZero(RowIndex num_rows, ColIndex num_cols)
Definition: sparse.cc:164
operations_research::glop::LinearProgram::PopulateFromDual
void PopulateFromDual(const LinearProgram &dual, RowToColMapping *duplicated_rows)
Definition: lp_data.cc:733
operations_research::glop::StrictITIVector::resize
void resize(IntType size)
Definition: lp_types.h:269
operations_research::glop::LinearProgram::AddSlackVariablesWhereNecessary
void AddSlackVariablesWhereNecessary(bool detect_integer_constraints)
Definition: lp_data.cc:666
min
int64 min
Definition: alldiff_cst.cc:138
operations_research::glop::DenseRow
StrictITIVector< ColIndex, Fractional > DenseRow
Definition: lp_types.h:299
DCHECK_LT
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:888
VLOG
#define VLOG(verboselevel)
Definition: base/logging.h:978
absl::StrongVector::push_back
void push_back(const value_type &x)
Definition: strong_vector.h:158
operations_research::glop::SparseMatrix::AppendRowsFromSparseMatrix
bool AppendRowsFromSparseMatrix(const SparseMatrix &matrix)
Definition: sparse.cc:302
operations_research::glop::LinearProgram::SolutionIsLPFeasible
bool SolutionIsLPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:466
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::glop::LinearProgram::PopulateFromPermutedLinearProgram
void PopulateFromPermutedLinearProgram(const LinearProgram &lp, const RowPermutation &row_permutation, const ColumnPermutation &col_permutation)
Definition: lp_data.cc:852
coefficients
std::vector< double > coefficients
Definition: sat/lp_utils.cc:497
operations_research::glop::ProblemSolution::status
ProblemStatus status
Definition: lp_data.h:655
operations_research::glop::ApplyPermutation
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
Definition: lp_data/permutation.h:191
LOG
#define LOG(severity)
Definition: base/logging.h:420
operations_research::glop::kInvalidCol
const ColIndex kInvalidCol(-1)
lp_data.h
absl::StrongVector::size
size_type size() const
Definition: strong_vector.h:147
operations_research::glop::LinearProgram::SetVariableType
void SetVariableType(ColIndex col, VariableType type)
Definition: lp_data.cc:234
operations_research::glop::LinearProgram::variable_lower_bounds
const DenseRow & variable_lower_bounds() const
Definition: lp_data.h:229
operations_research::glop::LinearProgram::ScaleObjective
Fractional ScaleObjective(GlopParameters::CostScalingAlgorithm method)
Definition: lp_data.cc:1157
operations_research::glop::Permutation::PopulateFromInverse
void PopulateFromInverse(const Permutation &inverse)
Definition: lp_data/permutation.h:126
operations_research::glop::LinearProgram::GetFirstSlackVariable
ColIndex GetFirstSlackVariable() const
Definition: lp_data.cc:720
operations_research::glop::kEpsilon
const double kEpsilon
Definition: lp_types.h:86
operations_research::glop::ColToIntIndex
Index ColToIntIndex(ColIndex col)
Definition: lp_types.h:54
logging.h
operations_research::glop::LinearProgram::GetPrettyProblemStats
std::string GetPrettyProblemStats() const
Definition: lp_data.cc:633
operations_research::glop::StringifyMonomial
std::string StringifyMonomial(const Fractional a, const std::string &x, bool fraction)
Definition: lp_print_utils.cc:53
operations_research::glop::LinearProgram::GetProblemStats
std::string GetProblemStats() const
Definition: lp_data.cc:627
operations_research::glop::LinearProgram::SetConstraintBounds
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:307
value
int64 value
Definition: demon_profiler.cc:43
lp_utils.h
operations_research::glop::LinearProgram::AddConstraintsWithSlackVariables
void AddConstraintsWithSlackVariables(const SparseMatrix &coefficients, const DenseColumn &left_hand_sides, const DenseColumn &right_hand_sides, const StrictITIVector< RowIndex, std::string > &names, bool detect_integer_constraints_for_slack)
Definition: lp_data.cc:966
operations_research::glop::LinearProgram::GetMutableSparseColumn
SparseColumn * GetMutableSparseColumn(ColIndex col)
Definition: lp_data.cc:411
operations_research::glop::StrictITIVector::size
IntType size() const
Definition: lp_types.h:276
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::glop::SparseMatrix::LookUpValue
Fractional LookUpValue(RowIndex row, ColIndex col) const
Definition: sparse.cc:323
operations_research::glop::SparseMatrix::PopulateFromSparseMatrix
void PopulateFromSparseMatrix(const SparseMatrix &matrix)
Definition: sparse.cc:206
operations_research::glop::LinearProgram::VariableType::CONTINUOUS
@ CONTINUOUS
operations_research::glop::LinearProgram::GetTransposeSparseMatrix
const SparseMatrix & GetTransposeSparseMatrix() const
Definition: lp_data.cc:374
operations_research::glop::SparseMatrix::DeleteRows
void DeleteRows(RowIndex num_rows, const RowPermutation &permutation)
Definition: sparse.cc:289
operations_research::IsIntegerWithinTolerance
bool IsIntegerWithinTolerance(FloatType x, FloatType tolerance)
Definition: fp_utils.h:161
operations_research::glop::SparseColumn
Definition: sparse_column.h:44
int64
int64_t int64
Definition: integral_types.h:34
operations_research::glop::Stringify
std::string Stringify(const Fractional x, bool fraction)
Definition: lp_print_utils.cc:45
operations_research::glop::SparseColumn::EntryRow
RowIndex EntryRow(EntryIndex i) const
Definition: sparse_column.h:51
operations_research::glop::LinearProgram::SetMaximizationProblem
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:341
operations_research::glop::LinearProgram::AddConstraints
void AddConstraints(const SparseMatrix &coefficients, const DenseColumn &left_hand_sides, const DenseColumn &right_hand_sides, const StrictITIVector< RowIndex, std::string > &names)
Definition: lp_data.cc:941
operations_research::glop::LinearProgram::GetMutableTransposeSparseMatrix
SparseMatrix * GetMutableTransposeSparseMatrix()
Definition: lp_data.cc:384
matrix_utils.h
operations_research::glop::Fractional
double Fractional
Definition: lp_types.h:77
operations_research::glop::LinearProgram::ComputeSlackVariableValues
void ComputeSlackVariableValues(DenseRow *solution) const
Definition: lp_data.cc:504
operations_research::glop::AreBoundsValid
bool AreBoundsValid(Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.h:683
operations_research::glop::LinearProgram::CreateNewVariable
ColIndex CreateNewVariable()
Definition: lp_data.cc:160
operations_research::glop::LinearProgram::CreateNewConstraint
RowIndex CreateNewConstraint()
Definition: lp_data.cc:189
operations_research::glop::LinearProgram::LinearProgram
LinearProgram()
Definition: lp_data.cc:109
operations_research::glop::LinearProgram::VariableType
VariableType
Definition: lp_data.h:57
operations_research::glop::LinearProgram::RemoveObjectiveScalingAndOffset
Fractional RemoveObjectiveScalingAndOffset(Fractional value) const
Definition: lp_data.cc:524
operations_research::glop::LinearProgram::Clear
void Clear()
Definition: lp_data.cc:132
DCHECK_NE
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:886
operations_research::glop::LinearProgram::constraint_lower_bounds
const DenseColumn & constraint_lower_bounds() const
Definition: lp_data.h:215
operations_research::glop::kInfinity
const double kInfinity
Definition: lp_types.h:83
operations_research::glop::RowToColIndex
ColIndex RowToColIndex(RowIndex row)
Definition: lp_types.h:48
operations_research::glop::LinearProgram::DeleteRows
void DeleteRows(const DenseBooleanColumn &rows_to_delete)
Definition: lp_data.cc:1227
operations_research::glop::ScalarProduct
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
Definition: lp_data/lp_utils.h:47
operations_research::glop::LinearProgram::PopulateFromLinearProgram
void PopulateFromLinearProgram(const LinearProgram &linear_program)
Definition: lp_data.cc:831
operations_research::glop::LinearProgram::SolutionIsMIPFeasible
bool SolutionIsMIPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:498
operations_research::glop::SparseMatrix::AppendEmptyColumn
ColIndex AppendEmptyColumn()
Definition: sparse.cc:145
operations_research::glop::StrictITIVector::assign
void assign(IntType size, const T &v)
Definition: lp_types.h:274
operations_research::glop::SparseMatrix::num_cols
ColIndex num_cols() const
Definition: sparse.h:177
operations_research::glop::SparseMatrix::DeleteColumns
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
Definition: sparse.cc:276
operations_research::glop::SparseVector::PopulateFromSparseVector
void PopulateFromSparseVector(const SparseVector &sparse_vector)
Definition: sparse_vector.h:592
operations_research::glop::LinearProgram::GetSparseColumn
const SparseColumn & GetSparseColumn(ColIndex col) const
Definition: lp_data.cc:407
operations_research::glop::SparseMatrix::CleanUp
void CleanUp()
Definition: sparse.cc:119
operations_research::glop::LinearProgram::IsValid
bool IsValid() const
Definition: lp_data.cc:1274
operations_research::glop::IsFinite
bool IsFinite(Fractional value)
Definition: lp_types.h:90
operations_research::glop::LinearProgram::SetVariableBounds
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:247
operations_research::glop::LinearProgram::DeleteSlackVariables
void DeleteSlackVariables()
Definition: lp_data.cc:1083
operations_research::glop::LinearProgram::name
const std::string & name() const
Definition: lp_data.h:75
operations_research::glop::SparseMatrix
Definition: sparse.h:61
operations_research::glop::SparseMatrix::mutable_column
SparseColumn * mutable_column(ColIndex col)
Definition: sparse.h:181
operations_research::glop::SparseMatrix::PopulateFromPermutedMatrix
void PopulateFromPermutedMatrix(const Matrix &a, const RowPermutation &row_perm, const ColumnPermutation &inverse_col_perm)
Definition: sparse.cc:212
operations_research::glop::GetVariableStatusString
std::string GetVariableStatusString(VariableStatus status)
Definition: lp_types.cc:71
operations_research::glop::LinearProgram::FindOrCreateVariable
ColIndex FindOrCreateVariable(const std::string &variable_id)
Definition: lp_data.cc:203
operations_research::glop::SparseMatrix::IsCleanedUp
bool IsCleanedUp() const
Definition: sparse.cc:135
operations_research::glop::ProblemSolution::constraint_statuses
ConstraintStatusColumn constraint_statuses
Definition: lp_data.h:676
operations_research::glop::SparseMatrix::num_rows
RowIndex num_rows() const
Definition: sparse.h:176
operations_research::glop::StrictITIVector< ColIndex, Fractional >
operations_research::glop::LinearProgram::BinaryVariablesList
const std::vector< ColIndex > & BinaryVariablesList() const
Definition: lp_data.cc:283
operations_research::glop::SparseMatrix::Clear
void Clear()
Definition: sparse.cc:110
CHECK_EQ
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:697
operations_research::glop::LinearProgram::IsInEquationForm
bool IsInEquationForm() const
Definition: lp_data.cc:1440
operations_research::glop::LinearProgram::num_entries
EntryIndex num_entries() const
Definition: lp_data.h:211
operations_research::glop::SparseMatrix::Swap
void Swap(SparseMatrix *matrix)
Definition: sparse.cc:158
operations_research::glop::LinearProgram::SolutionIsInteger
bool SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:486
operations_research::glop::LinearProgram::GetVariableName
std::string GetVariableName(ColIndex col) const
Definition: lp_data.cc:358
operations_research::glop::LinearProgram::CleanUp
void CleanUp()
Definition: lp_data.cc:345
operations_research::glop::LinearProgram::SetCoefficient
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:315
operations_research::glop::LinearProgram::SetObjectiveScalingFactor
void SetObjectiveScalingFactor(Fractional objective_scaling_factor)
Definition: lp_data.cc:334
operations_research::glop::LinearProgram::UseTransposeMatrixAsReference
void UseTransposeMatrixAsReference()
Definition: lp_data.cc:395
operations_research::glop::LinearProgram::UpdateVariableBoundsToIntersection
bool UpdateVariableBoundsToIntersection(const DenseRow &variable_lower_bounds, const DenseRow &variable_upper_bounds)
Definition: lp_data.cc:975
operations_research::glop::ProblemSolution::dual_values
DenseColumn dual_values
Definition: lp_data.h:660
absl::StrongVector::begin
iterator begin()
Definition: strong_vector.h:138
operations_research::glop::LinearProgram::BoundsOfIntegerVariablesAreInteger
bool BoundsOfIntegerVariablesAreInteger(Fractional tolerance) const
Definition: lp_data.cc:1453
operations_research::glop::LinearProgram::GetConstraintName
std::string GetConstraintName(RowIndex row) const
Definition: lp_data.cc:364
operations_research::glop::GetProblemStatusString
std::string GetProblemStatusString(ProblemStatus problem_status)
Definition: lp_types.cc:19
operations_research::glop::LinearProgram::ClearTransposeMatrix
void ClearTransposeMatrix()
Definition: lp_data.cc:402
operations_research::glop::LinearProgram::objective_scaling_factor
Fractional objective_scaling_factor() const
Definition: lp_data.h:261
operations_research::glop::ProblemSolution::DebugString
std::string DebugString() const
Definition: lp_data.cc:1507
DCHECK
#define DCHECK(condition)
Definition: base/logging.h:884
operations_research::glop::LinearProgram::GetObjectiveCoefficientForMinimizationVersion
Fractional GetObjectiveCoefficientForMinimizationVersion(ColIndex col) const
Definition: lp_data.cc:417
operations_research::glop::LinearProgram::objective_offset
Fractional objective_offset() const
Definition: lp_data.h:260
operations_research::glop::LinearProgram::GetObjectiveStatsString
std::string GetObjectiveStatsString() const
Definition: lp_data.cc:431
operations_research::glop::LinearProgram::SetConstraintName
void SetConstraintName(RowIndex row, absl::string_view name)
Definition: lp_data.cc:243
operations_research::glop::SparseVector::SetCoefficient
void SetCoefficient(Index index, Fractional value)
Definition: sparse_vector.h:680
operations_research::glop::LinearProgram::NonBinaryVariablesList
const std::vector< ColIndex > & NonBinaryVariablesList() const
Definition: lp_data.cc:288
operations_research::glop::SparseMatrix::column
const SparseColumn & column(ColIndex col) const
Definition: sparse.h:180
operations_research::glop::LinearProgram::IsVariableInteger
bool IsVariableInteger(ColIndex col) const
Definition: lp_data.cc:293
operations_research::glop::SparseMatrix::PopulateFromTranspose
void PopulateFromTranspose(const Matrix &input)
Definition: sparse.cc:181
operations_research::glop::Permutation< RowIndex >
operations_research::glop::LinearProgram::ScaleBounds
Fractional ScaleBounds()
Definition: lp_data.cc:1192
operations_research::glop::SparseVector< RowIndex, SparseColumnIterator >::Entry
typename Iterator::Entry Entry
Definition: sparse_vector.h:91
DCHECK_GE
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:889
absl::StrongVector::clear
void clear()
Definition: strong_vector.h:170
operations_research::glop::LinearProgram::variable_types
const StrictITIVector< ColIndex, VariableType > variable_types() const
Definition: lp_data.h:237
operations_research::glop::LinearProgram::SetObjectiveOffset
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:329
operations_research::glop::LinearProgram::VariableType::INTEGER
@ INTEGER
operations_research::glop::LinearProgram::GetDimensionString
std::string GetDimensionString() const
Definition: lp_data.cc:423
lp_print_utils.h
absl::StrongVector
Definition: strong_vector.h:76
col
ColIndex col
Definition: markowitz.cc:176
operations_research::glop::LinearProgram::DeleteColumns
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
Definition: lp_data.cc:1034
operations_research::glop::SparseVector::num_entries
EntryIndex num_entries() const
Definition: sparse_vector.h:270
operations_research::glop::LinearProgram::Swap
void Swap(LinearProgram *linear_program)
Definition: lp_data.cc:1000
operations_research::glop::RowToIntIndex
Index RowToIntIndex(RowIndex row)
Definition: lp_types.h:57
operations_research::glop::LinearProgram::Dump
std::string Dump() const
Definition: lp_data.cc:529
operations_research::glop::LinearProgram::SetVariableName
void SetVariableName(ColIndex col, absl::string_view name)
Definition: lp_data.cc:230
row
RowIndex row
Definition: markowitz.cc:175
operations_research::glop::LinearProgram
Definition: lp_data.h:55
absl::StrongVector::swap
void swap(StrongVector &x)
Definition: strong_vector.h:169
operations_research::glop::LinearProgram::FindOrCreateConstraint
RowIndex FindOrCreateConstraint(const std::string &constraint_id)
Definition: lp_data.cc:216
operations_research::glop::LinearProgram::SetObjectiveCoefficient
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:324
operations_research::glop::LinearProgram::PopulateFromLinearProgramVariables
void PopulateFromLinearProgramVariables(const LinearProgram &linear_program)
Definition: lp_data.cc:904
operations_research::glop::LinearProgram::GetNonZeroStats
std::string GetNonZeroStats() const
Definition: lp_data.cc:655
operations_research::glop::LinearProgram::objective_coefficients
const DenseRow & objective_coefficients() const
Definition: lp_data.h:223
operations_research::glop::Permutation::size
IndexType size() const
Definition: lp_data/permutation.h:49
operations_research::glop::LinearProgram::num_variables
ColIndex num_variables() const
Definition: lp_data.h:205
operations_research::glop::LinearProgram::IsCleanedUp
bool IsCleanedUp() const
Definition: lp_data.cc:352
DCHECK_EQ
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:885
operations_research::glop::LinearProgram::GetSlackVariable
ColIndex GetSlackVariable(RowIndex row) const
Definition: lp_data.cc:724
maximize_
const bool maximize_
Definition: search.cc:2499
operations_research::glop::ProblemSolution::variable_statuses
VariableStatusRow variable_statuses
Definition: lp_data.h:675
CHECK_NE
#define CHECK_NE(val1, val2)
Definition: base/logging.h:698
operations_research::glop::LinearProgram::VariableType::IMPLIED_INTEGER
@ IMPLIED_INTEGER
permutation.h
operations_research::glop::SparseMatrix::num_entries
EntryIndex num_entries() const
Definition: sparse.cc:389
operations_research::glop::kInvalidRow
const RowIndex kInvalidRow(-1)
operations_research::glop::LinearProgram::CreateNewSlackVariable
ColIndex CreateNewSlackVariable(bool is_integer_slack_variable, Fractional lower_bound, Fractional upper_bound, const std::string &name)
Definition: lp_data.cc:174
operations_research::glop::LinearProgram::BoundsOfIntegerConstraintsAreInteger
bool BoundsOfIntegerConstraintsAreInteger(Fractional tolerance) const
Definition: lp_data.cc:1469
operations_research::glop::LinearProgram::IntegerVariablesList
const std::vector< ColIndex > & IntegerVariablesList() const
Definition: lp_data.cc:278
operations_research::glop::ColToRowIndex
RowIndex ColToRowIndex(ColIndex col)
Definition: lp_types.h:51
DCHECK_LE
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:887
absl::StrongVector::empty
bool empty() const
Definition: strong_vector.h:156
operations_research::glop::ProblemSolution::primal_values
DenseRow primal_values
Definition: lp_data.h:659
operations_research::glop::LinearProgram::variable_upper_bounds
const DenseRow & variable_upper_bounds() const
Definition: lp_data.h:232
operations_research::glop::LinearProgram::DumpSolution
std::string DumpSolution(const DenseRow &variable_values) const
Definition: lp_data.cc:616
operations_research::glop::LinearProgram::GetVariableType
VariableType GetVariableType(ColIndex col) const
Definition: lp_data.cc:370
operations_research::glop::PartialScalarProduct
Fractional PartialScalarProduct(const DenseRowOrColumn &u, const SparseColumn &v, int max_index)
Definition: lp_data/lp_utils.h:130
CHECK
#define CHECK(condition)
Definition: base/logging.h:495
name
const std::string name
Definition: default_search.cc:808
operations_research::glop::GetConstraintStatusString
std::string GetConstraintStatusString(ConstraintStatus status)
Definition: lp_types.cc:90
operations_research::glop::LinearProgram::constraint_upper_bounds
const DenseColumn & constraint_upper_bounds() const
Definition: lp_data.h:218
operations_research::glop::SparseMatrix::SetNumRows
void SetNumRows(RowIndex num_rows)
Definition: sparse.cc:143
operations_research::glop::IsRightMostSquareMatrixIdentity
bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix)
Definition: matrix_utils.cc:231
absl::StrongVector::insert
iterator insert(const_iterator pos, const value_type &x)
Definition: strong_vector.h:183
operations_research::glop::LinearProgram::SolutionIsWithinVariableBounds
bool SolutionIsWithinVariableBounds(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:450