OR-Tools  8.0
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 gtl::ITIVector<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 gtl::ITIVector<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 gtl::ITIVector<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, const std::string& name) {
231  variable_names_[col] = 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, const std::string& name) {
244  constraint_names_[row] = 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) {
317  DCHECK(IsFinite(value));
318  ResizeRowsIfNeeded(row);
319  columns_are_known_to_be_clean_ = false;
320  transpose_matrix_is_consistent_ = false;
322 }
323 
325  DCHECK(IsFinite(value));
326  objective_coefficients_[col] = value;
327 }
328 
330  DCHECK(IsFinite(objective_offset));
331  objective_offset_ = objective_offset;
332 }
333 
335  Fractional objective_scaling_factor) {
337  DCHECK_NE(0.0, 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));
726  DCHECK_LT(row, num_constraints());
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());
858  DCHECK_EQ(lp.GetFirstSlackVariable(), kInvalidCol);
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 ComputeDivisorSoThatRangeContainsOne(Fractional min_magnitude,
1123  Fractional max_magnitude) {
1124  if (min_magnitude > 1.0 && min_magnitude < kInfinity) {
1125  return min_magnitude;
1126  } else if (max_magnitude > 0.0 && max_magnitude < 1.0) {
1127  return max_magnitude;
1128  }
1129  return 1.0;
1130 }
1131 
1132 } // namespace
1133 
1135  Fractional min_magnitude = kInfinity;
1136  Fractional max_magnitude = 0.0;
1137  UpdateMinAndMaxMagnitude(objective_coefficients(), &min_magnitude,
1138  &max_magnitude);
1139  const Fractional cost_scaling_factor =
1140  ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1141  if (cost_scaling_factor != 1.0) {
1142  for (ColIndex col(0); col < num_variables(); ++col) {
1144  col, objective_coefficients()[col] / cost_scaling_factor);
1145  }
1146  SetObjectiveScalingFactor(objective_scaling_factor() * cost_scaling_factor);
1147  SetObjectiveOffset(objective_offset() / cost_scaling_factor);
1148  }
1149 
1150  VLOG(1) << "Objective magnitude range is [" << min_magnitude << ", "
1151  << max_magnitude << "] (dividing by " << cost_scaling_factor << ").";
1152  return cost_scaling_factor;
1153 }
1154 
1156  Fractional min_magnitude = kInfinity;
1157  Fractional max_magnitude = 0.0;
1158  UpdateMinAndMaxMagnitude(variable_lower_bounds(), &min_magnitude,
1159  &max_magnitude);
1160  UpdateMinAndMaxMagnitude(variable_upper_bounds(), &min_magnitude,
1161  &max_magnitude);
1162  UpdateMinAndMaxMagnitude(constraint_lower_bounds(), &min_magnitude,
1163  &max_magnitude);
1164  UpdateMinAndMaxMagnitude(constraint_upper_bounds(), &min_magnitude,
1165  &max_magnitude);
1166  const Fractional bound_scaling_factor =
1167  ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1168  if (bound_scaling_factor != 1.0) {
1170  bound_scaling_factor);
1171  SetObjectiveOffset(objective_offset() / bound_scaling_factor);
1172  for (ColIndex col(0); col < num_variables(); ++col) {
1174  variable_lower_bounds()[col] / bound_scaling_factor,
1175  variable_upper_bounds()[col] / bound_scaling_factor);
1176  }
1177  for (RowIndex row(0); row < num_constraints(); ++row) {
1179  row, constraint_lower_bounds()[row] / bound_scaling_factor,
1180  constraint_upper_bounds()[row] / bound_scaling_factor);
1181  }
1182  }
1183 
1184  VLOG(1) << "Bounds magnitude range is [" << min_magnitude << ", "
1185  << max_magnitude << "] (dividing bounds by " << bound_scaling_factor
1186  << ").";
1187  return bound_scaling_factor;
1188 }
1189 
1190 void LinearProgram::DeleteRows(const DenseBooleanColumn& rows_to_delete) {
1191  if (rows_to_delete.empty()) return;
1192 
1193  // Deal with row-indexed data and construct the row mapping that will need to
1194  // be applied to every column entry.
1195  const RowIndex num_rows = num_constraints();
1196  RowPermutation permutation(num_rows);
1197  RowIndex new_index(0);
1198  for (RowIndex row(0); row < num_rows; ++row) {
1199  if (row >= rows_to_delete.size() || !rows_to_delete[row]) {
1200  constraint_lower_bounds_[new_index] = constraint_lower_bounds_[row];
1201  constraint_upper_bounds_[new_index] = constraint_upper_bounds_[row];
1202  constraint_names_[new_index].swap(constraint_names_[row]);
1203  permutation[row] = new_index;
1204  ++new_index;
1205  } else {
1206  permutation[row] = kInvalidRow;
1207  }
1208  }
1209  constraint_lower_bounds_.resize(new_index, 0.0);
1210  constraint_upper_bounds_.resize(new_index, 0.0);
1211  constraint_names_.resize(new_index, "");
1212 
1213  // Remove the rows from the matrix.
1214  matrix_.DeleteRows(new_index, permutation);
1215 
1216  // Remove the id of the deleted rows and adjust the index of the other.
1217  absl::flat_hash_map<std::string, RowIndex>::iterator it =
1218  constraint_table_.begin();
1219  while (it != constraint_table_.end()) {
1220  const RowIndex row = it->second;
1221  if (permutation[row] != kInvalidRow) {
1222  it->second = permutation[row];
1223  ++it;
1224  } else {
1225  // This safely deletes the entry and moves the iterator one step ahead.
1226  constraint_table_.erase(it++);
1227  }
1228  }
1229 
1230  // Eventually update transpose_matrix_.
1231  if (transpose_matrix_is_consistent_) {
1232  transpose_matrix_.DeleteColumns(
1233  reinterpret_cast<const DenseBooleanRow&>(rows_to_delete));
1234  }
1235 }
1236 
1238  if (!IsFinite(objective_offset_)) return false;
1239  if (!IsFinite(objective_scaling_factor_)) return false;
1240  if (objective_scaling_factor_ == 0.0) return false;
1241  const ColIndex num_cols = num_variables();
1242  for (ColIndex col(0); col < num_cols; ++col) {
1244  variable_upper_bounds()[col])) {
1245  return false;
1246  }
1247  if (!IsFinite(objective_coefficients()[col])) {
1248  return false;
1249  }
1250  for (const SparseColumn::Entry e : GetSparseColumn(col)) {
1251  if (!IsFinite(e.coefficient())) return false;
1252  }
1253  }
1254  if (constraint_upper_bounds_.size() != constraint_lower_bounds_.size()) {
1255  return false;
1256  }
1257  for (RowIndex row(0); row < constraint_lower_bounds_.size(); ++row) {
1260  return false;
1261  }
1262  }
1263  return true;
1264 }
1265 
1266 std::string LinearProgram::ProblemStatFormatter(
1267  const absl::string_view format) const {
1268  int num_objective_non_zeros = 0;
1269  int num_non_negative_variables = 0;
1270  int num_boxed_variables = 0;
1271  int num_free_variables = 0;
1272  int num_fixed_variables = 0;
1273  int num_other_variables = 0;
1274  const ColIndex num_cols = num_variables();
1275  for (ColIndex col(0); col < num_cols; ++col) {
1276  if (objective_coefficients()[col] != 0.0) {
1277  ++num_objective_non_zeros;
1278  }
1279 
1280  const Fractional lower_bound = variable_lower_bounds()[col];
1281  const Fractional upper_bound = variable_upper_bounds()[col];
1282  const bool lower_bounded = (lower_bound != -kInfinity);
1283  const bool upper_bounded = (upper_bound != kInfinity);
1284 
1285  if (!lower_bounded && !upper_bounded) {
1286  ++num_free_variables;
1287  } else if (lower_bound == 0.0 && !upper_bounded) {
1288  ++num_non_negative_variables;
1289  } else if (!upper_bounded || !lower_bounded) {
1290  ++num_other_variables;
1291  } else if (lower_bound == upper_bound) {
1292  ++num_fixed_variables;
1293  } else {
1294  ++num_boxed_variables;
1295  }
1296  }
1297 
1298  int num_range_constraints = 0;
1299  int num_less_than_constraints = 0;
1300  int num_greater_than_constraints = 0;
1301  int num_equal_constraints = 0;
1302  int num_rhs_non_zeros = 0;
1303  const RowIndex num_rows = num_constraints();
1304  for (RowIndex row(0); row < num_rows; ++row) {
1305  const Fractional lower_bound = constraint_lower_bounds()[row];
1306  const Fractional upper_bound = constraint_upper_bounds()[row];
1307  if (AreBoundsFreeOrBoxed(lower_bound, upper_bound)) {
1308  // TODO(user): we currently count a free row as a range constraint.
1309  // Add a new category?
1310  ++num_range_constraints;
1311  continue;
1312  }
1313  if (lower_bound == upper_bound) {
1314  ++num_equal_constraints;
1315  if (lower_bound != 0) {
1316  ++num_rhs_non_zeros;
1317  }
1318  continue;
1319  }
1320  if (lower_bound == -kInfinity) {
1321  ++num_less_than_constraints;
1322  if (upper_bound != 0) {
1323  ++num_rhs_non_zeros;
1324  }
1325  continue;
1326  }
1327  if (upper_bound == kInfinity) {
1328  ++num_greater_than_constraints;
1329  if (lower_bound != 0) {
1330  ++num_rhs_non_zeros;
1331  }
1332  continue;
1333  }
1334  LOG(DFATAL) << "There is a bug since all possible cases for the row bounds "
1335  "should have been accounted for. row="
1336  << row;
1337  }
1338 
1339  const int num_integer_variables = IntegerVariablesList().size();
1340  const int num_binary_variables = BinaryVariablesList().size();
1341  const int num_non_binary_variables = NonBinaryVariablesList().size();
1342  const int num_continuous_variables =
1343  ColToIntIndex(num_variables()) - num_integer_variables;
1344  auto format_runtime =
1345  absl::ParsedFormat<'d', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
1346  'd', 'd', 'd', 'd', 'd', 'd', 'd'>::New(format);
1347  CHECK(format_runtime);
1348  return absl::StrFormat(
1349  *format_runtime, RowToIntIndex(num_constraints()),
1350  ColToIntIndex(num_variables()), matrix_.num_entries().value(),
1351  num_objective_non_zeros, num_rhs_non_zeros, num_less_than_constraints,
1352  num_greater_than_constraints, num_equal_constraints,
1353  num_range_constraints, num_non_negative_variables, num_boxed_variables,
1354  num_free_variables, num_fixed_variables, num_other_variables,
1355  num_integer_variables, num_binary_variables, num_non_binary_variables,
1356  num_continuous_variables);
1357 }
1358 
1359 std::string LinearProgram::NonZeroStatFormatter(
1360  const absl::string_view format) const {
1361  StrictITIVector<RowIndex, EntryIndex> num_entries_in_row(num_constraints(),
1362  EntryIndex(0));
1363  StrictITIVector<ColIndex, EntryIndex> num_entries_in_column(num_variables(),
1364  EntryIndex(0));
1365  EntryIndex num_entries(0);
1366  const ColIndex num_cols = num_variables();
1367  for (ColIndex col(0); col < num_cols; ++col) {
1368  const SparseColumn& sparse_column = GetSparseColumn(col);
1369  num_entries += sparse_column.num_entries();
1370  num_entries_in_column[col] = sparse_column.num_entries();
1371  for (const SparseColumn::Entry e : sparse_column) {
1372  ++num_entries_in_row[e.row()];
1373  }
1374  }
1375 
1376  // To avoid division by 0 if there are no columns or no rows, we set
1377  // height and width to be at least one.
1378  const int64 height = std::max(RowToIntIndex(num_constraints()), 1);
1379  const int64 width = std::max(ColToIntIndex(num_variables()), 1);
1380  const double fill_rate = 100.0 * static_cast<double>(num_entries.value()) /
1381  static_cast<double>(height * width);
1382 
1383  auto format_runtime =
1384  absl::ParsedFormat<'f', 'd', 'f', 'f', 'd', 'f', 'f'>::New(format);
1385  return absl::StrFormat(
1386  *format_runtime, fill_rate, GetMaxElement(num_entries_in_row).value(),
1387  Average(num_entries_in_row), StandardDeviation(num_entries_in_row),
1388  GetMaxElement(num_entries_in_column).value(),
1389  Average(num_entries_in_column), StandardDeviation(num_entries_in_column));
1390 }
1391 
1392 void LinearProgram::ResizeRowsIfNeeded(RowIndex row) {
1393  DCHECK_GE(row, 0);
1394  if (row >= num_constraints()) {
1395  transpose_matrix_is_consistent_ = false;
1396  matrix_.SetNumRows(row + 1);
1397  constraint_lower_bounds_.resize(row + 1, Fractional(0.0));
1398  constraint_upper_bounds_.resize(row + 1, Fractional(0.0));
1399  constraint_names_.resize(row + 1, "");
1400  }
1401 }
1402 
1404  for (RowIndex constraint(0); constraint < num_constraints(); ++constraint) {
1405  if (constraint_lower_bounds_[constraint] != 0.0 ||
1406  constraint_upper_bounds_[constraint] != 0.0) {
1407  return false;
1408  }
1409  }
1410  const ColIndex num_slack_variables =
1412  return num_constraints().value() == num_slack_variables.value() &&
1414 }
1415 
1417  Fractional tolerance) const {
1418  for (const ColIndex col : IntegerVariablesList()) {
1419  if ((IsFinite(variable_lower_bounds_[col]) &&
1420  !IsIntegerWithinTolerance(variable_lower_bounds_[col], tolerance)) ||
1421  (IsFinite(variable_upper_bounds_[col]) &&
1422  !IsIntegerWithinTolerance(variable_upper_bounds_[col], tolerance))) {
1423  VLOG(1) << "Bounds of variable " << col.value() << " are non-integer ("
1424  << variable_lower_bounds_[col] << ", "
1425  << variable_upper_bounds_[col] << ").";
1426  return false;
1427  }
1428  }
1429  return true;
1430 }
1431 
1433  Fractional tolerance) const {
1434  // Using transpose for this is faster (complexity = O(number of non zeros in
1435  // matrix)) than directly iterating through entries (complexity = O(number of
1436  // constraints * number of variables)).
1437  const SparseMatrix& transpose = GetTransposeSparseMatrix();
1438  for (RowIndex row = RowIndex(0); row < num_constraints(); ++row) {
1439  bool integer_constraint = true;
1440  for (const SparseColumn::Entry var : transpose.column(RowToColIndex(row))) {
1441  if (!IsVariableInteger(RowToColIndex(var.row()))) {
1442  integer_constraint = false;
1443  break;
1444  }
1445  if (!IsIntegerWithinTolerance(var.coefficient(), tolerance)) {
1446  integer_constraint = false;
1447  break;
1448  }
1449  }
1450  if (integer_constraint) {
1451  if ((IsFinite(constraint_lower_bounds_[row]) &&
1452  !IsIntegerWithinTolerance(constraint_lower_bounds_[row],
1453  tolerance)) ||
1454  (IsFinite(constraint_upper_bounds_[row]) &&
1455  !IsIntegerWithinTolerance(constraint_upper_bounds_[row],
1456  tolerance))) {
1457  VLOG(1) << "Bounds of constraint " << row.value()
1458  << " are non-integer (" << constraint_lower_bounds_[row] << ", "
1459  << constraint_upper_bounds_[row] << ").";
1460  return false;
1461  }
1462  }
1463  }
1464  return true;
1465 }
1466 
1467 // --------------------------------------------------------
1468 // ProblemSolution
1469 // --------------------------------------------------------
1470 std::string ProblemSolution::DebugString() const {
1471  std::string s = "Problem status: " + GetProblemStatusString(status);
1472  for (ColIndex col(0); col < primal_values.size(); ++col) {
1473  absl::StrAppendFormat(&s, "\n Var #%d: %s %g", col.value(),
1475  primal_values[col]);
1476  }
1477  s += "\n------------------------------";
1478  for (RowIndex row(0); row < dual_values.size(); ++row) {
1479  absl::StrAppendFormat(&s, "\n Constraint #%d: %s %g", row.value(),
1481  dual_values[row]);
1482  }
1483  return s;
1484 }
1485 
1486 } // namespace glop
1487 } // namespace operations_research
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::glop::SparseMatrix::CleanUp
void CleanUp()
Definition: sparse.cc:119
operations_research::glop::LinearProgram::BoundsOfIntegerVariablesAreInteger
bool BoundsOfIntegerVariablesAreInteger(Fractional tolerance) const
Definition: lp_data.cc:1416
min
int64 min
Definition: alldiff_cst.cc:138
operations_research::glop::LinearProgram::UpdateVariableBoundsToIntersection
bool UpdateVariableBoundsToIntersection(const DenseRow &variable_lower_bounds, const DenseRow &variable_upper_bounds)
Definition: lp_data.cc:975
max
int64 max
Definition: alldiff_cst.cc:139
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
gtl::ITIVector::begin
iterator begin()
Definition: int_type_indexed_vector.h:137
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::LinearProgram::name
const std::string & name() const
Definition: lp_data.h:75
coefficients
std::vector< double > coefficients
Definition: sat/lp_utils.cc:287
gtl::ITIVector::end
iterator end()
Definition: int_type_indexed_vector.h:139
operations_research::glop::LinearProgram::constraint_upper_bounds
const DenseColumn & constraint_upper_bounds() const
Definition: lp_data.h:218
operations_research::glop::LinearProgram::SetVariableName
void SetVariableName(ColIndex col, const std::string &name)
Definition: lp_data.cc:230
operations_research::glop::StrictITIVector< ColIndex, Fractional >
operations_research::glop::ApplyPermutation
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
Definition: lp_data/permutation.h:191
operations_research::glop::kInvalidCol
const ColIndex kInvalidCol(-1)
lp_data.h
gtl::ITIVector::swap
void swap(ITIVector &x)
Definition: int_type_indexed_vector.h:168
operations_research::glop::LinearProgram::GetPrettyProblemStats
std::string GetPrettyProblemStats() const
Definition: lp_data.cc:633
operations_research::glop::LinearProgram::variable_lower_bounds
const DenseRow & variable_lower_bounds() const
Definition: lp_data.h:229
operations_research::glop::LinearProgram::CreateNewConstraint
RowIndex CreateNewConstraint()
Definition: lp_data.cc:189
operations_research::glop::LinearProgram::variable_upper_bounds
const DenseRow & variable_upper_bounds() const
Definition: lp_data.h:232
operations_research::glop::LinearProgram::CleanUp
void CleanUp()
Definition: lp_data.cc:345
operations_research::glop::LinearProgram::GetMutableTransposeSparseMatrix
SparseMatrix * GetMutableTransposeSparseMatrix()
Definition: lp_data.cc:384
operations_research::glop::LinearProgram::VariableType
VariableType
Definition: lp_data.h:57
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::ComputeSlackVariableValues
void ComputeSlackVariableValues(DenseRow *solution) const
Definition: lp_data.cc:504
operations_research::glop::SparseMatrix::AppendEmptyColumn
ColIndex AppendEmptyColumn()
Definition: sparse.cc:145
operations_research::glop::SparseMatrix
Definition: sparse.h:61
operations_research::glop::LinearProgram::GetVariableName
std::string GetVariableName(ColIndex col) const
Definition: lp_data.cc:358
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::SetObjectiveCoefficient
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:324
operations_research::glop::StrictITIVector::assign
void assign(IntType size, const T &v)
Definition: lp_types.h:274
gtl::ITIVector::clear
void clear()
Definition: int_type_indexed_vector.h:169
operations_research::glop::SparseMatrix::PopulateFromTranspose
void PopulateFromTranspose(const Matrix &input)
Definition: sparse.cc:181
operations_research::glop::LinearProgram::RemoveObjectiveScalingAndOffset
Fractional RemoveObjectiveScalingAndOffset(Fractional value) const
Definition: lp_data.cc:524
operations_research::glop::LinearProgram::GetSlackVariable
ColIndex GetSlackVariable(RowIndex row) const
Definition: lp_data.cc:724
value
int64 value
Definition: demon_profiler.cc:43
operations_research::glop::LinearProgram::SetConstraintName
void SetConstraintName(RowIndex row, const std::string &name)
Definition: lp_data.cc:243
lp_utils.h
operations_research::glop::SparseMatrix::num_rows
RowIndex num_rows() const
Definition: sparse.h:176
operations_research::glop::LinearProgram::IsValid
bool IsValid() const
Definition: lp_data.cc:1237
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::LinearProgram::GetProblemStats
std::string GetProblemStats() const
Definition: lp_data.cc:627
operations_research::glop::LinearProgram::PopulateFromLinearProgramVariables
void PopulateFromLinearProgramVariables(const LinearProgram &linear_program)
Definition: lp_data.cc:904
operations_research::glop::LinearProgram::constraint_lower_bounds
const DenseColumn & constraint_lower_bounds() const
Definition: lp_data.h:215
operations_research::glop::LinearProgram::IsCleanedUp
bool IsCleanedUp() const
Definition: lp_data.cc:352
operations_research::glop::LinearProgram::VariableType::CONTINUOUS
@ CONTINUOUS
operations_research::glop::LinearProgram::num_entries
EntryIndex num_entries() const
Definition: lp_data.h:211
operations_research::glop::LinearProgram::IntegerVariablesList
const std::vector< ColIndex > & IntegerVariablesList() const
Definition: lp_data.cc:278
operations_research::glop::LinearProgram::IsInEquationForm
bool IsInEquationForm() const
Definition: lp_data.cc:1403
operations_research::glop::LinearProgram
Definition: lp_data.h:55
operations_research::glop::LinearProgram::BoundsOfIntegerConstraintsAreInteger
bool BoundsOfIntegerConstraintsAreInteger(Fractional tolerance) const
Definition: lp_data.cc:1432
operations_research::glop::StrictITIVector::resize
void resize(IntType size)
Definition: lp_types.h:269
operations_research::IsIntegerWithinTolerance
bool IsIntegerWithinTolerance(FloatType x, FloatType tolerance)
Definition: fp_utils.h:160
operations_research::glop::SparseMatrix::Swap
void Swap(SparseMatrix *matrix)
Definition: sparse.cc:158
operations_research::glop::LinearProgram::SolutionIsMIPFeasible
bool SolutionIsMIPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:498
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
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
gtl::ITIVector::size
size_type size() const
Definition: int_type_indexed_vector.h:146
gtl::ITIVector::empty
bool empty() const
Definition: int_type_indexed_vector.h:155
operations_research::glop::SparseVector::PopulateFromSparseVector
void PopulateFromSparseVector(const SparseVector &sparse_vector)
Definition: sparse_vector.h:592
operations_research::glop::LinearProgram::SolutionIsWithinVariableBounds
bool SolutionIsWithinVariableBounds(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:450
operations_research::glop::LinearProgram::SetConstraintBounds
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:307
operations_research::glop::LinearProgram::GetObjectiveStatsString
std::string GetObjectiveStatsString() const
Definition: lp_data.cc:431
operations_research::glop::LinearProgram::num_variables
ColIndex num_variables() const
Definition: lp_data.h:205
operations_research::glop::LinearProgram::ScaleBounds
Fractional ScaleBounds()
Definition: lp_data.cc:1155
operations_research::glop::LinearProgram::ApplyObjectiveScalingAndOffset
Fractional ApplyObjectiveScalingAndOffset(Fractional value) const
Definition: lp_data.cc:519
matrix_utils.h
operations_research::glop::SparseMatrix::AppendRowsFromSparseMatrix
bool AppendRowsFromSparseMatrix(const SparseMatrix &matrix)
Definition: sparse.cc:302
operations_research::glop::LinearProgram::SetMaximizationProblem
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:341
operations_research::glop::Fractional
double Fractional
Definition: lp_types.h:77
operations_research::glop::AreBoundsValid
bool AreBoundsValid(Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.h:683
operations_research::glop::SparseVector< RowIndex, SparseColumnIterator >::Entry
typename Iterator::Entry Entry
Definition: sparse_vector.h:91
operations_research::glop::LinearProgram::PopulateFromLinearProgram
void PopulateFromLinearProgram(const LinearProgram &linear_program)
Definition: lp_data.cc:831
operations_research::glop::kInfinity
const double kInfinity
Definition: lp_types.h:83
operations_research::glop::LinearProgram::GetDimensionString
std::string GetDimensionString() const
Definition: lp_data.cc:423
operations_research::glop::RowToColIndex
ColIndex RowToColIndex(RowIndex row)
Definition: lp_types.h:48
operations_research::glop::ScalarProduct
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
Definition: lp_data/lp_utils.h:47
operations_research::glop::LinearProgram::DeleteColumns
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
Definition: lp_data.cc:1034
gtl::ITIVector::insert
iterator insert(const_iterator pos, const value_type &x)
Definition: int_type_indexed_vector.h:182
operations_research::glop::SparseMatrix::LookUpValue
Fractional LookUpValue(RowIndex row, ColIndex col) const
Definition: sparse.cc:323
operations_research::glop::LinearProgram::SetCoefficient
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:315
operations_research::glop::LinearProgram::variable_types
const StrictITIVector< ColIndex, VariableType > variable_types() const
Definition: lp_data.h:237
operations_research::glop::ProblemSolution::primal_values
DenseRow primal_values
Definition: lp_data.h:659
operations_research::glop::IsFinite
bool IsFinite(Fractional value)
Definition: lp_types.h:90
operations_research::glop::SparseMatrix::DeleteRows
void DeleteRows(RowIndex num_rows, const RowPermutation &permutation)
Definition: sparse.cc:289
operations_research::glop::SparseMatrix::PopulateFromZero
void PopulateFromZero(RowIndex num_rows, ColIndex num_cols)
Definition: sparse.cc:164
operations_research::glop::GetVariableStatusString
std::string GetVariableStatusString(VariableStatus status)
Definition: lp_types.cc:71
operations_research::glop::SparseMatrix::num_cols
ColIndex num_cols() const
Definition: sparse.h:177
operations_research::glop::SparseMatrix::num_entries
EntryIndex num_entries() const
Definition: sparse.cc:389
operations_research::glop::LinearProgram::NonBinaryVariablesList
const std::vector< ColIndex > & NonBinaryVariablesList() const
Definition: lp_data.cc:288
operations_research::glop::StrictITIVector::size
IntType size() const
Definition: lp_types.h:276
operations_research::glop::ProblemSolution::DebugString
std::string DebugString() const
Definition: lp_data.cc:1470
operations_research::glop::LinearProgram::DeleteSlackVariables
void DeleteSlackVariables()
Definition: lp_data.cc:1083
operations_research::glop::LinearProgram::ClearTransposeMatrix
void ClearTransposeMatrix()
Definition: lp_data.cc:402
operations_research::glop::LinearProgram::SetVariableBounds
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:247
operations_research::glop::LinearProgram::Dump
std::string Dump() const
Definition: lp_data.cc:529
operations_research::glop::ProblemSolution::dual_values
DenseColumn dual_values
Definition: lp_data.h:660
operations_research::glop::LinearProgram::AddSlackVariablesWhereNecessary
void AddSlackVariablesWhereNecessary(bool detect_integer_constraints)
Definition: lp_data.cc:666
operations_research::glop::LinearProgram::GetNonZeroStats
std::string GetNonZeroStats() const
Definition: lp_data.cc:655
operations_research::glop::LinearProgram::GetMutableSparseColumn
SparseColumn * GetMutableSparseColumn(ColIndex col)
Definition: lp_data.cc:411
operations_research::glop::GetProblemStatusString
std::string GetProblemStatusString(ProblemStatus problem_status)
Definition: lp_types.cc:19
operations_research::glop::SparseMatrix::column
const SparseColumn & column(ColIndex col) const
Definition: sparse.h:180
operations_research::glop::LinearProgram::BinaryVariablesList
const std::vector< ColIndex > & BinaryVariablesList() const
Definition: lp_data.cc:283
operations_research::glop::LinearProgram::IsVariableBinary
bool IsVariableBinary(ColIndex col) const
Definition: lp_data.cc:298
operations_research::glop::LinearProgram::objective_offset
Fractional objective_offset() const
Definition: lp_data.h:260
operations_research::glop::ProblemSolution::variable_statuses
VariableStatusRow variable_statuses
Definition: lp_data.h:675
operations_research::glop::SparseMatrix::DeleteColumns
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
Definition: sparse.cc:276
operations_research::glop::LinearProgram::GetTransposeSparseMatrix
const SparseMatrix & GetTransposeSparseMatrix() const
Definition: lp_data.cc:374
operations_research::glop::LinearProgram::VariableType::IMPLIED_INTEGER
@ IMPLIED_INTEGER
operations_research::glop::Permutation::size
IndexType size() const
Definition: lp_data/permutation.h:49
operations_research::glop::SparseMatrix::PopulateFromSparseMatrix
void PopulateFromSparseMatrix(const SparseMatrix &matrix)
Definition: sparse.cc:206
operations_research::glop::SparseMatrix::IsCleanedUp
bool IsCleanedUp() const
Definition: sparse.cc:135
operations_research::glop::LinearProgram::num_constraints
RowIndex num_constraints() const
Definition: lp_data.h:208
lp_print_utils.h
operations_research::glop::LinearProgram::DumpSolution
std::string DumpSolution(const DenseRow &variable_values) const
Definition: lp_data.cc:616
operations_research::glop::LinearProgram::Swap
void Swap(LinearProgram *linear_program)
Definition: lp_data.cc:1000
operations_research::glop::LinearProgram::objective_scaling_factor
Fractional objective_scaling_factor() const
Definition: lp_data.h:261
operations_research::glop::LinearProgram::objective_coefficients
const DenseRow & objective_coefficients() const
Definition: lp_data.h:223
col
ColIndex col
Definition: markowitz.cc:176
operations_research::glop::RowToIntIndex
Index RowToIntIndex(RowIndex row)
Definition: lp_types.h:57
row
RowIndex row
Definition: markowitz.cc:175
operations_research::glop::LinearProgram::VariableType::INTEGER
@ INTEGER
operations_research::glop::Permutation< RowIndex >
operations_research::glop::SparseMatrix::mutable_column
SparseColumn * mutable_column(ColIndex col)
Definition: sparse.h:181
operations_research::glop::SparseMatrix::Clear
void Clear()
Definition: sparse.cc:110
operations_research::glop::LinearProgram::PopulateFromDual
void PopulateFromDual(const LinearProgram &dual, RowToColMapping *duplicated_rows)
Definition: lp_data.cc:733
operations_research::glop::LinearProgram::UseTransposeMatrixAsReference
void UseTransposeMatrixAsReference()
Definition: lp_data.cc:395
operations_research::glop::LinearProgram::LinearProgram
LinearProgram()
Definition: lp_data.cc:109
maximize_
const bool maximize_
Definition: search.cc:2493
operations_research::glop::LinearProgram::FindOrCreateConstraint
RowIndex FindOrCreateConstraint(const std::string &constraint_id)
Definition: lp_data.cc:216
operations_research::glop::Permutation::PopulateFromInverse
void PopulateFromInverse(const Permutation &inverse)
Definition: lp_data/permutation.h:126
operations_research::glop::LinearProgram::DeleteRows
void DeleteRows(const DenseBooleanColumn &rows_to_delete)
Definition: lp_data.cc:1190
operations_research::glop::LinearProgram::FindOrCreateVariable
ColIndex FindOrCreateVariable(const std::string &variable_id)
Definition: lp_data.cc:203
operations_research::glop::LinearProgram::SolutionIsInteger
bool SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:486
operations_research::glop::SparseColumn::EntryRow
RowIndex EntryRow(EntryIndex i) const
Definition: sparse_column.h:51
gtl::ITIVector
Definition: int_type_indexed_vector.h:76
operations_research::glop::LinearProgram::IsVariableInteger
bool IsVariableInteger(ColIndex col) const
Definition: lp_data.cc:293
operations_research::glop::LinearProgram::SetObjectiveOffset
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:329
gtl::ITIVector::push_back
void push_back(const value_type &x)
Definition: int_type_indexed_vector.h:157
permutation.h
operations_research::glop::LinearProgram::GetVariableType
VariableType GetVariableType(ColIndex col) const
Definition: lp_data.cc:370
operations_research::glop::SparseColumn
Definition: sparse_column.h:44
operations_research::glop::SparseVector::num_entries
EntryIndex num_entries() const
Definition: sparse_vector.h:270
operations_research::glop::LinearProgram::PopulateFromPermutedLinearProgram
void PopulateFromPermutedLinearProgram(const LinearProgram &lp, const RowPermutation &row_permutation, const ColumnPermutation &col_permutation)
Definition: lp_data.cc:852
operations_research::glop::ProblemSolution::status
ProblemStatus status
Definition: lp_data.h:655
operations_research::glop::SparseMatrix::SetNumRows
void SetNumRows(RowIndex num_rows)
Definition: sparse.cc:143
operations_research::glop::kInvalidRow
const RowIndex kInvalidRow(-1)
operations_research::glop::ColToRowIndex
RowIndex ColToRowIndex(ColIndex col)
Definition: lp_types.h:51
operations_research::glop::LinearProgram::SolutionIsLPFeasible
bool SolutionIsLPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
Definition: lp_data.cc:466
operations_research::glop::SparseVector::SetCoefficient
void SetCoefficient(Index index, Fractional value)
Definition: sparse_vector.h:680
operations_research::glop::ProblemSolution::constraint_statuses
ConstraintStatusColumn constraint_statuses
Definition: lp_data.h:676
operations_research::glop::LinearProgram::GetFirstSlackVariable
ColIndex GetFirstSlackVariable() const
Definition: lp_data.cc:720
operations_research::glop::LinearProgram::GetPrettyNonZeroStats
std::string GetPrettyNonZeroStats() const
Definition: lp_data.cc:659
operations_research::glop::PartialScalarProduct
Fractional PartialScalarProduct(const DenseRowOrColumn &u, const SparseColumn &v, int max_index)
Definition: lp_data/lp_utils.h:130
operations_research::glop::LinearProgram::CreateNewVariable
ColIndex CreateNewVariable()
Definition: lp_data.cc:160
operations_research::glop::LinearProgram::GetSparseColumn
const SparseColumn & GetSparseColumn(ColIndex col) const
Definition: lp_data.cc:407
operations_research::glop::LinearProgram::GetConstraintName
std::string GetConstraintName(RowIndex row) const
Definition: lp_data.cc:364
operations_research::glop::LinearProgram::SetVariableType
void SetVariableType(ColIndex col, VariableType type)
Definition: lp_data.cc:234
operations_research::glop::LinearProgram::SetObjectiveScalingFactor
void SetObjectiveScalingFactor(Fractional objective_scaling_factor)
Definition: lp_data.cc:334
operations_research::glop::LinearProgram::GetObjectiveCoefficientForMinimizationVersion
Fractional GetObjectiveCoefficientForMinimizationVersion(ColIndex col) const
Definition: lp_data.cc:417
name
const std::string name
Definition: default_search.cc:807
operations_research::glop::GetConstraintStatusString
std::string GetConstraintStatusString(ConstraintStatus status)
Definition: lp_types.cc:90
operations_research::glop::LinearProgram::ScaleObjective
Fractional ScaleObjective()
Definition: lp_data.cc:1134
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::IsRightMostSquareMatrixIdentity
bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix)
Definition: matrix_utils.cc:231
operations_research::glop::LinearProgram::Clear
void Clear()
Definition: lp_data.cc:132