24#include "absl/container/flat_hash_map.h"
25#include "absl/log/check.h"
26#include "absl/strings/str_cat.h"
27#include "absl/strings/str_format.h"
30#include "ortools/glop/parameters.pb.h"
67template <
class I,
class T>
69 const size_t size = v.size();
73 if (v[i] == 0.0)
continue;
75 sum +=
static_cast<double>(v[
i].value());
77 return n == 0.0 ? 0.0 : sum / n;
80template <
class I,
class T>
82 const size_t size = v.size();
84 double sigma_square = 0.0;
87 double sample =
static_cast<double>(v[
i].value());
88 if (sample == 0.0)
continue;
89 sigma_square += sample * sample;
93 return n == 0.0 ? 0.0 : sqrt((sigma_square - sigma * sigma / n) / n);
97template <
class I,
class T>
99 const size_t size = v.size();
104 T max_index = v[I(0)];
106 if (max_index < v[i]) {
121 constraint_lower_bounds_(),
122 constraint_upper_bounds_(),
124 objective_coefficients_(),
125 variable_lower_bounds_(),
126 variable_upper_bounds_(),
129 integer_variables_list_(),
132 objective_offset_(0.0),
133 objective_scaling_factor_(1.0),
135 columns_are_known_to_be_clean_(true),
136 transpose_matrix_is_consistent_(true),
137 integer_variables_list_is_consistent_(true),
145 constraint_lower_bounds_.clear();
146 constraint_upper_bounds_.clear();
147 constraint_names_.clear();
149 objective_coefficients_.clear();
150 variable_lower_bounds_.clear();
151 variable_upper_bounds_.clear();
152 variable_types_.clear();
153 integer_variables_list_.clear();
154 variable_names_.clear();
156 constraint_table_.clear();
157 variable_table_.clear();
160 objective_offset_ = 0.0;
161 objective_scaling_factor_ = 1.0;
162 columns_are_known_to_be_clean_ =
true;
163 transpose_matrix_is_consistent_ =
true;
164 integer_variables_list_is_consistent_ =
true;
171 <<
"New variables can't be added to programs that already have slack "
172 "variables. Consider calling LinearProgram::DeleteSlackVariables() "
173 "before adding new variables to the problem.";
176 variable_upper_bounds_.
push_back(kInfinity);
179 transpose_matrix_is_consistent_ =
false;
186 const std::string&
name) {
190 variable_types_.
push_back(is_integer_slack_variable
194 transpose_matrix_is_consistent_ =
false;
200 <<
"New constraints can't be added to programs that already have slack "
201 "variables. Consider calling LinearProgram::DeleteSlackVariables() "
202 "before adding new variables to the problem.";
203 const RowIndex
row(constraint_names_.
size());
208 transpose_matrix_is_consistent_ =
false;
213 const absl::flat_hash_map<std::string, ColIndex>::iterator it =
214 variable_table_.find(variable_id);
215 if (it != variable_table_.end()) {
219 variable_names_[
col] = variable_id;
220 variable_table_[variable_id] =
col;
226 absl::string_view constraint_id) {
227 const absl::flat_hash_map<std::string, RowIndex>::iterator it =
228 constraint_table_.find(constraint_id);
229 if (it != constraint_table_.end()) {
233 constraint_names_[
row] = constraint_id;
234 constraint_table_[constraint_id] =
row;
240 variable_names_[
col] = std::string(
name);
245 variable_types_[
col] = type;
247 if (var_is_integer != var_was_integer) {
248 integer_variables_list_is_consistent_ =
false;
253 constraint_names_[
row] = std::string(
name);
263 if (var_is_binary != var_was_binary) {
264 integer_variables_list_is_consistent_ =
false;
268void LinearProgram::UpdateAllIntegerVariableLists()
const {
269 if (integer_variables_list_is_consistent_)
return;
270 integer_variables_list_.clear();
271 binary_variables_list_.clear();
272 non_binary_variables_list_.clear();
274 for (ColIndex
col(0);
col < num_cols; ++
col) {
276 integer_variables_list_.push_back(
col);
278 binary_variables_list_.push_back(
col);
280 non_binary_variables_list_.push_back(
col);
284 integer_variables_list_is_consistent_ =
true;
288 UpdateAllIntegerVariableLists();
289 return integer_variables_list_;
293 UpdateAllIntegerVariableLists();
294 return binary_variables_list_;
298 UpdateAllIntegerVariableLists();
299 return non_binary_variables_list_;
313 (variable_upper_bounds_[
col] < 2);
319 ResizeRowsIfNeeded(
row);
327 ResizeRowsIfNeeded(
row);
328 columns_are_known_to_be_clean_ =
false;
329 transpose_matrix_is_consistent_ =
false;
351 maximize_ = maximize;
355 if (columns_are_known_to_be_clean_)
return;
357 columns_are_known_to_be_clean_ =
true;
358 transpose_matrix_is_consistent_ =
false;
362 if (columns_are_known_to_be_clean_)
return true;
364 return columns_are_known_to_be_clean_;
368 return col >= variable_names_.
size() || variable_names_[
col].empty()
369 ? absl::StrFormat(
"c%d",
col.value())
370 : variable_names_[
col];
374 return row >= constraint_names_.
size() || constraint_names_[
row].empty()
375 ? absl::StrFormat(
"r%d",
row.value())
376 : constraint_names_[
row];
380 return variable_types_[
col];
384 if (!transpose_matrix_is_consistent_) {
386 transpose_matrix_is_consistent_ =
true;
388 DCHECK_EQ(transpose_matrix_.
num_rows().value(), matrix_.
num_cols().value());
389 DCHECK_EQ(transpose_matrix_.
num_cols().value(), matrix_.
num_rows().value());
390 return transpose_matrix_;
394 if (!transpose_matrix_is_consistent_) {
400 transpose_matrix_is_consistent_ =
false;
401 return &transpose_matrix_;
405 DCHECK_EQ(transpose_matrix_.
num_rows().value(), matrix_.
num_cols().value());
408 transpose_matrix_is_consistent_ =
true;
412 transpose_matrix_.
Clear();
413 transpose_matrix_is_consistent_ =
false;
421 columns_are_known_to_be_clean_ =
false;
422 transpose_matrix_is_consistent_ =
false;
427 ColIndex
col)
const {
436 return absl::StrFormat(
437 "%d rows, %d columns, %d entries with magnitude in [%e, %e]",
446template <
typename FractionalValues>
447void UpdateStats(
const FractionalValues& values, int64_t* num_non_zeros,
450 if (v == 0 || v == kInfinity || v == -kInfinity)
continue;
451 *min_value = std::min(*min_value, v);
452 *max_value = std::max(*max_value, v);
460 int64_t num_non_zeros = 0;
463 UpdateStats(objective_coefficients_, &num_non_zeros, &min_value, &max_value);
464 if (num_non_zeros == 0) {
465 return "No objective term. This is a pure feasibility problem.";
467 return absl::StrFormat(
"%d non-zeros, range [%e, %e]", num_non_zeros,
468 min_value, max_value);
473 int64_t num_non_zeros = 0;
476 UpdateStats(variable_lower_bounds_, &num_non_zeros, &min_value, &max_value);
477 UpdateStats(variable_upper_bounds_, &num_non_zeros, &min_value, &max_value);
478 UpdateStats(constraint_lower_bounds_, &num_non_zeros, &min_value, &max_value);
479 UpdateStats(constraint_upper_bounds_, &num_non_zeros, &min_value, &max_value);
480 if (num_non_zeros == 0) {
481 return "All variables/constraints bounds are zero or +/- infinity.";
483 return absl::StrFormat(
"%d non-zeros, range [%e, %e]", num_non_zeros,
484 min_value, max_value);
493 for (ColIndex
col = ColIndex(0);
col < num_cols; ++
col) {
497 if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) {
511 for (RowIndex
row = RowIndex(0);
row < num_rows; ++
row) {
517 if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) {
531 if (fractionality > absolute_tolerance)
return false;
548 for (RowIndex
row = RowIndex(0);
row < num_rows; ++
row) {
553 (*solution)[slack_variable] = -sum;
569 std::string output = maximize_ ?
"max:" :
"min:";
570 if (objective_offset_ != 0.0) {
574 for (ColIndex
col(0);
col < num_cols; ++
col) {
580 output.append(
";\n");
585 for (RowIndex
row(0);
row < num_rows; ++
row) {
617 for (ColIndex
col(0);
col < num_cols; ++
col) {
644 if (!integer_variables.empty()) {
646 for (ColIndex
col : integer_variables) {
659 for (ColIndex
col(0);
col < variable_values.size(); ++
col) {
660 if (!output.empty()) absl::StrAppend(&output,
", ");
662 (variable_values[
col]));
668 return ProblemStatFormatter(
669 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
674 return ProblemStatFormatter(
675 "Number of rows : %d\n"
676 "Number of variables in file : %d\n"
677 "Number of entries (non-zeros) : %d\n"
678 "Number of entries in the objective : %d\n"
679 "Number of entries in the right-hand side : %d\n"
680 "Number of <= constraints : %d\n"
681 "Number of >= constraints : %d\n"
682 "Number of = constraints : %d\n"
683 "Number of range constraints : %d\n"
684 "Number of non-negative variables : %d\n"
685 "Number of boxed variables : %d\n"
686 "Number of free variables : %d\n"
687 "Number of fixed variables : %d\n"
688 "Number of other variables : %d\n"
689 "Number of integer variables : %d\n"
690 "Number of binary variables : %d\n"
691 "Number of non-binary integer variables : %d\n"
692 "Number of continuous variables : %d\n");
696 return NonZeroStatFormatter(
"%.2f%%,%d,%.2f,%.2f,%d,%.2f,%.2f");
700 return NonZeroStatFormatter(
701 "Fill rate : %.2f%%\n"
702 "Entries in row (Max / average / std. dev.) : %d / %.2f / %.2f\n"
703 "Entries in column (Max / average / std. dev.): %d / %.2f / %.2f\n");
707 bool detect_integer_constraints) {
723 detect_integer_constraints);
724 if (detect_integer_constraints) {
728 for (
const SparseColumn::Entry& entry :
column) {
729 const RowIndex
row = entry.row();
730 has_integer_slack_variable[
row] =
731 has_integer_slack_variable[
row] && is_integer_variable &&
732 round(entry.coefficient()) == entry.coefficient();
742 slack_variable_index < original_num_variables) {
747 has_integer_slack_variable[
row], -constraint_upper_bounds_[
row],
748 -constraint_lower_bounds_[
row], absl::StrCat(
"s",
row.value()));
753 columns_are_known_to_be_clean_ =
true;
754 transpose_matrix_is_consistent_ =
false;
756 first_slack_variable_ = original_num_variables;
761 return first_slack_variable_;
765 DCHECK_GE(
row, RowIndex(0));
775 const ColIndex dual_num_variables = dual.num_variables();
776 const RowIndex dual_num_constraints = dual.num_constraints();
791 for (RowIndex dual_row(0); dual_row < dual_num_constraints; ++dual_row) {
809 LOG(DFATAL) <<
"PopulateFromDual() was called with a program "
810 <<
"containing free constraints.";
814 for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
825 for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
836 for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
839 dual.GetObjectiveCoefficientForMinimizationVersion(dual_col);
841 for (
const SparseColumn::Entry e : dual.GetSparseColumn(dual_col)) {
842 const RowIndex dual_row = e.row();
849 duplicated_rows->assign(dual_num_constraints,
kInvalidCol);
850 for (RowIndex dual_row(0); dual_row < dual_num_constraints; ++dual_row) {
862 (*duplicated_rows)[dual_row] =
col;
867 columns_are_known_to_be_clean_ =
true;
868 transpose_matrix_is_consistent_ =
false;
872 const LinearProgram& linear_program) {
874 if (linear_program.transpose_matrix_is_consistent_) {
875 transpose_matrix_is_consistent_ =
true;
877 linear_program.transpose_matrix_);
879 transpose_matrix_is_consistent_ =
false;
880 transpose_matrix_.
Clear();
883 constraint_lower_bounds_ = linear_program.constraint_lower_bounds_;
884 constraint_upper_bounds_ = linear_program.constraint_upper_bounds_;
885 constraint_names_ = linear_program.constraint_names_;
886 constraint_table_.clear();
888 PopulateNameObjectiveAndVariablesFromLinearProgram(linear_program);
889 first_slack_variable_ = linear_program.first_slack_variable_;
895 DCHECK(lp.IsCleanedUp());
896 DCHECK_EQ(row_permutation.size(), lp.num_constraints());
897 DCHECK_EQ(col_permutation.
size(), lp.num_variables());
898 DCHECK_EQ(lp.GetFirstSlackVariable(),
kInvalidCol);
905 inverse_col_permutation);
910 &constraint_lower_bounds_);
912 &constraint_upper_bounds_);
916 &objective_coefficients_);
918 &variable_lower_bounds_);
920 &variable_upper_bounds_);
922 integer_variables_list_is_consistent_ =
false;
926 constraint_names_.
resize(lp.num_constraints());
927 for (RowIndex old_row(0); old_row < lp.num_constraints(); ++old_row) {
928 const RowIndex new_row = row_permutation[old_row];
929 constraint_names_[new_row] = lp.constraint_names_[old_row];
931 variable_names_.
resize(lp.num_variables());
932 for (ColIndex old_col(0); old_col < lp.num_variables(); ++old_col) {
933 const ColIndex new_col = col_permutation[old_col];
934 variable_names_[new_col] = lp.variable_names_[old_col];
938 maximize_ = lp.maximize_;
939 objective_offset_ = lp.objective_offset_;
940 objective_scaling_factor_ = lp.objective_scaling_factor_;
948 transpose_matrix_is_consistent_ =
false;
949 transpose_matrix_.
Clear();
951 constraint_lower_bounds_.clear();
952 constraint_upper_bounds_.clear();
953 constraint_names_.clear();
954 constraint_table_.clear();
956 PopulateNameObjectiveAndVariablesFromLinearProgram(linear_program);
959void LinearProgram::PopulateNameObjectiveAndVariablesFromLinearProgram(
961 objective_coefficients_ = linear_program.objective_coefficients_;
962 variable_lower_bounds_ = linear_program.variable_lower_bounds_;
963 variable_upper_bounds_ = linear_program.variable_upper_bounds_;
964 variable_names_ = linear_program.variable_names_;
965 variable_types_ = linear_program.variable_types_;
966 integer_variables_list_is_consistent_ =
967 linear_program.integer_variables_list_is_consistent_;
968 integer_variables_list_ = linear_program.integer_variables_list_;
969 binary_variables_list_ = linear_program.binary_variables_list_;
970 non_binary_variables_list_ = linear_program.non_binary_variables_list_;
971 variable_table_.clear();
973 maximize_ = linear_program.maximize_;
974 objective_offset_ = linear_program.objective_offset_;
975 objective_scaling_factor_ = linear_program.objective_scaling_factor_;
976 columns_are_known_to_be_clean_ =
977 linear_program.columns_are_known_to_be_clean_;
978 name_ = linear_program.name_;
985 const RowIndex num_new_constraints =
coefficients.num_rows();
987 DCHECK_EQ(num_new_constraints, left_hand_sides.size());
988 DCHECK_EQ(num_new_constraints, right_hand_sides.
size());
989 DCHECK_EQ(num_new_constraints, names.
size());
992 transpose_matrix_is_consistent_ =
false;
993 transpose_matrix_.
Clear();
994 columns_are_known_to_be_clean_ =
false;
997 constraint_lower_bounds_.
insert(constraint_lower_bounds_.end(),
998 left_hand_sides.begin(),
999 left_hand_sides.end());
1000 constraint_upper_bounds_.
insert(constraint_upper_bounds_.end(),
1001 right_hand_sides.begin(),
1002 right_hand_sides.end());
1003 constraint_names_.
insert(constraint_names_.end(), names.begin(), names.end());
1010 bool detect_integer_constraints_for_slack) {
1016 const DenseRow& variable_lower_bounds,
1022 DenseRow new_lower_bounds(num_vars, 0);
1023 DenseRow new_upper_bounds(num_vars, 0);
1024 for (ColIndex i(0); i < num_vars; ++i) {
1029 if (new_lower_bound > new_upper_bound) {
1032 new_lower_bounds[i] = new_lower_bound;
1033 new_upper_bounds[i] = new_upper_bound;
1035 variable_lower_bounds_.
swap(new_lower_bounds);
1036 variable_upper_bounds_.
swap(new_upper_bounds);
1041 matrix_.
Swap(&linear_program->matrix_);
1042 transpose_matrix_.
Swap(&linear_program->transpose_matrix_);
1044 constraint_lower_bounds_.
swap(linear_program->constraint_lower_bounds_);
1045 constraint_upper_bounds_.
swap(linear_program->constraint_upper_bounds_);
1046 constraint_names_.
swap(linear_program->constraint_names_);
1048 objective_coefficients_.
swap(linear_program->objective_coefficients_);
1049 variable_lower_bounds_.
swap(linear_program->variable_lower_bounds_);
1050 variable_upper_bounds_.
swap(linear_program->variable_upper_bounds_);
1051 variable_names_.
swap(linear_program->variable_names_);
1052 variable_types_.
swap(linear_program->variable_types_);
1053 integer_variables_list_.swap(linear_program->integer_variables_list_);
1054 binary_variables_list_.swap(linear_program->binary_variables_list_);
1055 non_binary_variables_list_.swap(linear_program->non_binary_variables_list_);
1057 variable_table_.swap(linear_program->variable_table_);
1058 constraint_table_.swap(linear_program->constraint_table_);
1060 std::swap(maximize_, linear_program->maximize_);
1061 std::swap(objective_offset_, linear_program->objective_offset_);
1062 std::swap(objective_scaling_factor_,
1063 linear_program->objective_scaling_factor_);
1064 std::swap(columns_are_known_to_be_clean_,
1065 linear_program->columns_are_known_to_be_clean_);
1066 std::swap(transpose_matrix_is_consistent_,
1067 linear_program->transpose_matrix_is_consistent_);
1068 std::swap(integer_variables_list_is_consistent_,
1069 linear_program->integer_variables_list_is_consistent_);
1070 name_.swap(linear_program->name_);
1071 std::swap(first_slack_variable_, linear_program->first_slack_variable_);
1075 if (columns_to_delete.empty())
return;
1076 integer_variables_list_is_consistent_ =
false;
1079 ColIndex new_index(0);
1080 for (ColIndex
col(0);
col < num_cols; ++
col) {
1081 permutation[
col] = new_index;
1082 if (
col >= columns_to_delete.
size() || !columns_to_delete[
col]) {
1083 objective_coefficients_[new_index] = objective_coefficients_[
col];
1084 variable_lower_bounds_[new_index] = variable_lower_bounds_[
col];
1085 variable_upper_bounds_[new_index] = variable_upper_bounds_[
col];
1086 variable_names_[new_index] = variable_names_[
col];
1087 variable_types_[new_index] = variable_types_[
col];
1095 objective_coefficients_.
resize(new_index, 0.0);
1096 variable_lower_bounds_.
resize(new_index, 0.0);
1097 variable_upper_bounds_.
resize(new_index, 0.0);
1099 variable_names_.
resize(new_index,
"");
1102 absl::flat_hash_map<std::string, ColIndex>::iterator it =
1103 variable_table_.begin();
1104 while (it != variable_table_.end()) {
1105 const ColIndex
col = it->second;
1106 if (
col >= columns_to_delete.
size() || !columns_to_delete[
col]) {
1107 it->second = permutation[
col];
1111 variable_table_.erase(it++);
1116 if (transpose_matrix_is_consistent_) {
1127 for (ColIndex slack_variable = first_slack_variable_;
1128 slack_variable < matrix_.
num_cols(); ++slack_variable) {
1133 DCHECK_EQ(
column.num_entries(), 1);
1134 const RowIndex
row =
column.EntryRow(EntryIndex(0));
1135 DCHECK_EQ(constraint_lower_bounds_[
row], 0.0);
1136 DCHECK_EQ(constraint_upper_bounds_[
row], 0.0);
1138 -variable_lower_bounds_[slack_variable]);
1139 slack_variables[slack_variable] =
true;
1150template <
typename FractionalRange>
1151void UpdateMinAndMaxMagnitude(
const FractionalRange&
range,
1156 if (magnitude == 0 || magnitude == kInfinity)
continue;
1157 *min_magnitude = std::min(*min_magnitude, magnitude);
1158 *max_magnitude = std::max(*max_magnitude, magnitude);
1163 std::vector<Fractional> median;
1165 if (
value == 0.0)
continue;
1166 median.push_back(std::abs(
value));
1168 if (median.empty())
return 1.0;
1169 std::sort(median.begin(), median.end());
1170 return median[median.size() / 2];
1175 int num_non_zeros = 0;
1177 if (
value == 0.0)
continue;
1179 mean += std::abs(
value);
1181 if (num_non_zeros == 0.0)
return 1.0;
1182 return mean /
static_cast<Fractional>(num_non_zeros);
1187 if (min_magnitude > 1.0 && min_magnitude < kInfinity) {
1188 return min_magnitude;
1189 }
else if (max_magnitude > 0.0 && max_magnitude < 1.0) {
1190 return max_magnitude;
1198 GlopParameters::CostScalingAlgorithm method) {
1205 case GlopParameters::NO_COST_SCALING:
1207 case GlopParameters::CONTAIN_ONE_COST_SCALING:
1208 cost_scaling_factor =
1209 ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1211 case GlopParameters::MEAN_COST_SCALING:
1214 case GlopParameters::MEDIAN_COST_SCALING:
1218 if (cost_scaling_factor != 1.0) {
1227 VLOG(1) <<
"Objective magnitude range is [" << min_magnitude <<
", "
1228 << max_magnitude <<
"] (dividing by " << cost_scaling_factor <<
").";
1229 return cost_scaling_factor;
1244 ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1245 if (bound_scaling_factor != 1.0) {
1247 bound_scaling_factor);
1261 VLOG(1) <<
"Bounds magnitude range is [" << min_magnitude <<
", "
1262 << max_magnitude <<
"] (dividing bounds by " << bound_scaling_factor
1264 return bound_scaling_factor;
1268 if (rows_to_delete.empty())
return;
1274 RowIndex new_index(0);
1275 for (RowIndex
row(0);
row < num_rows; ++
row) {
1276 if (
row >= rows_to_delete.size() || !rows_to_delete[
row]) {
1277 constraint_lower_bounds_[new_index] = constraint_lower_bounds_[
row];
1278 constraint_upper_bounds_[new_index] = constraint_upper_bounds_[
row];
1279 constraint_names_[new_index].
swap(constraint_names_[
row]);
1280 permutation[
row] = new_index;
1286 constraint_lower_bounds_.
resize(new_index, 0.0);
1287 constraint_upper_bounds_.
resize(new_index, 0.0);
1288 constraint_names_.
resize(new_index,
"");
1294 absl::flat_hash_map<std::string, RowIndex>::iterator it =
1295 constraint_table_.begin();
1296 while (it != constraint_table_.end()) {
1297 const RowIndex
row = it->second;
1299 it->second = permutation[
row];
1303 constraint_table_.erase(it++);
1308 if (transpose_matrix_is_consistent_) {
1315 if (!
IsFinite(objective_offset_))
return false;
1316 if (std::abs(objective_offset_) > max_valid_magnitude)
return false;
1318 if (!
IsFinite(objective_scaling_factor_))
return false;
1319 if (objective_scaling_factor_ == 0.0)
return false;
1320 if (std::abs(objective_scaling_factor_) > max_valid_magnitude)
return false;
1323 for (ColIndex
col(0);
col < num_cols; ++
col) {
1327 if (
IsFinite(lb) && std::abs(lb) > max_valid_magnitude)
return false;
1328 if (
IsFinite(ub) && std::abs(ub) > max_valid_magnitude)
return false;
1338 if (!
IsFinite(e.coefficient()))
return false;
1339 if (std::abs(e.coefficient()) > max_valid_magnitude)
return false;
1342 if (constraint_upper_bounds_.
size() != constraint_lower_bounds_.
size()) {
1345 for (RowIndex
row(0);
row < constraint_lower_bounds_.
size(); ++
row) {
1349 if (
IsFinite(lb) && std::abs(lb) > max_valid_magnitude)
return false;
1350 if (
IsFinite(ub) && std::abs(ub) > max_valid_magnitude)
return false;
1355std::string LinearProgram::ProblemStatFormatter(
1356 const absl::string_view format)
const {
1357 int num_objective_non_zeros = 0;
1358 int num_non_negative_variables = 0;
1359 int num_boxed_variables = 0;
1360 int num_free_variables = 0;
1361 int num_fixed_variables = 0;
1362 int num_other_variables = 0;
1364 for (ColIndex
col(0);
col < num_cols; ++
col) {
1366 ++num_objective_non_zeros;
1374 if (!lower_bounded && !upper_bounded) {
1375 ++num_free_variables;
1376 }
else if (
lower_bound == 0.0 && !upper_bounded) {
1377 ++num_non_negative_variables;
1378 }
else if (!upper_bounded || !lower_bounded) {
1379 ++num_other_variables;
1381 ++num_fixed_variables;
1383 ++num_boxed_variables;
1387 int num_range_constraints = 0;
1388 int num_less_than_constraints = 0;
1389 int num_greater_than_constraints = 0;
1390 int num_equal_constraints = 0;
1391 int num_rhs_non_zeros = 0;
1393 for (RowIndex
row(0);
row < num_rows; ++
row) {
1399 ++num_range_constraints;
1403 ++num_equal_constraints;
1405 ++num_rhs_non_zeros;
1410 ++num_less_than_constraints;
1412 ++num_rhs_non_zeros;
1417 ++num_greater_than_constraints;
1419 ++num_rhs_non_zeros;
1423 LOG(DFATAL) <<
"There is a bug since all possible cases for the row bounds "
1424 "should have been accounted for. row="
1431 const int num_continuous_variables =
1433 auto format_runtime =
1434 absl::ParsedFormat<
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
1435 'd',
'd',
'd',
'd',
'd',
'd',
'd'>::New(format);
1436 CHECK(format_runtime);
1437 return absl::StrFormat(
1440 num_objective_non_zeros, num_rhs_non_zeros, num_less_than_constraints,
1441 num_greater_than_constraints, num_equal_constraints,
1442 num_range_constraints, num_non_negative_variables, num_boxed_variables,
1443 num_free_variables, num_fixed_variables, num_other_variables,
1444 num_integer_variables, num_binary_variables, num_non_binary_variables,
1445 num_continuous_variables);
1448std::string LinearProgram::NonZeroStatFormatter(
1449 const absl::string_view format)
const {
1450 StrictITIVector<RowIndex, EntryIndex> num_entries_in_row(
num_constraints(),
1452 StrictITIVector<ColIndex, EntryIndex> num_entries_in_column(
num_variables(),
1456 for (ColIndex
col(0);
col < num_cols; ++
col) {
1459 num_entries_in_column[
col] = sparse_column.num_entries();
1460 for (
const SparseColumn::Entry e : sparse_column) {
1461 ++num_entries_in_row[e.row()];
1469 const double fill_rate = 100.0 *
static_cast<double>(
num_entries.value()) /
1472 auto format_runtime =
1473 absl::ParsedFormat<'f', 'd', 'f', 'f', 'd', 'f', 'f'>::New(format);
1474 return absl::StrFormat(
1475 *format_runtime, fill_rate, GetMaxElement(num_entries_in_row).
value(),
1476 Average(num_entries_in_row), StandardDeviation(num_entries_in_row),
1477 GetMaxElement(num_entries_in_column).
value(),
1478 Average(num_entries_in_column), StandardDeviation(num_entries_in_column));
1481void LinearProgram::ResizeRowsIfNeeded(RowIndex
row) {
1484 transpose_matrix_is_consistent_ =
false;
1493 for (RowIndex constraint(0); constraint <
num_constraints(); ++constraint) {
1494 if (constraint_lower_bounds_[constraint] != 0.0 ||
1495 constraint_upper_bounds_[constraint] != 0.0) {
1499 const ColIndex num_slack_variables =
1512 VLOG(1) <<
"Bounds of variable " <<
col.value() <<
" are non-integer ("
1513 << variable_lower_bounds_[
col] <<
", "
1514 << variable_upper_bounds_[
col] <<
").";
1528 bool integer_constraint =
true;
1531 integer_constraint =
false;
1537 if (std::round(
var.coefficient()) !=
var.coefficient()) {
1538 integer_constraint =
false;
1542 if (integer_constraint) {
1549 VLOG(1) <<
"Bounds of constraint " <<
row.value()
1550 <<
" are non-integer (" << constraint_lower_bounds_[
row] <<
", "
1551 << constraint_upper_bounds_[
row] <<
").";
1560 int64_t num_removed_objective_entries = 0;
1561 int64_t num_removed_matrix_entries = 0;
1565 num_removed_matrix_entries +=
1567 if (std::abs(objective_coefficients_[
col]) <= threshold) {
1568 objective_coefficients_[
col] = 0.0;
1569 ++num_removed_objective_entries;
1572 if (num_removed_matrix_entries > 0) {
1573 transpose_matrix_is_consistent_ =
false;
1574 VLOG(1) <<
"Removed " << num_removed_matrix_entries <<
" matrix entries.";
1576 if (num_removed_objective_entries > 0) {
1577 VLOG(1) <<
"Removed " << num_removed_objective_entries
1578 <<
" objective coefficients.";
1588 absl::StrAppendFormat(&s,
"\n Var #%d: %s %g",
col.value(),
1592 s +=
"\n------------------------------";
1594 absl::StrAppendFormat(&s,
"\n Constraint #%d: %s %g",
row.value(),
bool BoundsOfIntegerConstraintsAreInteger(Fractional tolerance) const
std::string GetDimensionString() const
A short string with the problem dimension.
const DenseRow & objective_coefficients() const
Returns the objective coefficients (or cost) of variables as a row vector.
void Clear()
Clears, i.e. reset the object to its initial value.
void SetConstraintName(RowIndex row, absl::string_view name)
const std::vector< ColIndex > & NonBinaryVariablesList() const
@ INTEGER
The variable must only take integer values.
std::string GetPrettyNonZeroStats() const
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
void RemoveNearZeroEntries(Fractional threshold)
Removes objective and coefficient with magnitude <= threshold.
bool BoundsOfIntegerVariablesAreInteger(Fractional tolerance) const
void ComputeSlackVariableValues(DenseRow *solution) const
bool IsValid(Fractional max_valid_magnitude=kInfinity) const
Fractional GetObjectiveCoefficientForMinimizationVersion(ColIndex col) const
void PopulateFromPermutedLinearProgram(const LinearProgram &lp, const RowPermutation &row_permutation, const ColumnPermutation &col_permutation)
void PopulateFromLinearProgramVariables(const LinearProgram &linear_program)
bool SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const
void SetObjectiveOffset(Fractional objective_offset)
std::string GetConstraintName(RowIndex row) const
void SetObjectiveCoefficient(ColIndex col, Fractional value)
bool SolutionIsLPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
std::string GetPrettyProblemStats() const
const std::string & name() const
bool SolutionIsWithinVariableBounds(const DenseRow &solution, Fractional absolute_tolerance) const
Checks if each variable respects its bounds, nothing else.
Fractional RemoveObjectiveScalingAndOffset(Fractional value) const
void SetObjectiveScalingFactor(Fractional objective_scaling_factor)
bool IsInEquationForm() const
const DenseColumn & constraint_lower_bounds() const
const SparseMatrix & GetTransposeSparseMatrix() const
void AddSlackVariablesWhereNecessary(bool detect_integer_constraints)
void ClearTransposeMatrix()
Release the memory used by the transpose matrix.
const DenseRow & variable_lower_bounds() const
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
ColIndex GetSlackVariable(RowIndex row) const
const std::vector< ColIndex > & BinaryVariablesList() const
EntryIndex num_entries() const
Returns the number of entries in the linear program matrix.
SparseMatrix * GetMutableTransposeSparseMatrix()
void DeleteSlackVariables()
SparseColumn * GetMutableSparseColumn(ColIndex col)
Gets a pointer to the underlying SparseColumn with the given index.
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)
const std::vector< ColIndex > & IntegerVariablesList() const
std::string GetProblemStats() const
bool IsVariableBinary(ColIndex col) const
Returns whether the variable at column col must take binary values or not.
Fractional ScaleObjective(GlopParameters::CostScalingAlgorithm method)
void Swap(LinearProgram *linear_program)
void DeleteRows(const DenseBooleanColumn &rows_to_delete)
void SetVariableType(ColIndex col, VariableType type)
Set the type of the variable.
ColIndex FindOrCreateVariable(absl::string_view variable_id)
std::string DumpSolution(const DenseRow &variable_values) const
bool SolutionIsMIPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
Tests if the solution is both LP-feasible and integer within the tolerance.
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Defines the coefficient for col / row.
void UseTransposeMatrixAsReference()
std::string GetVariableName(ColIndex col) const
const DenseRow & variable_upper_bounds() const
void AddConstraints(const SparseMatrix &coefficients, const DenseColumn &left_hand_sides, const DenseColumn &right_hand_sides, const StrictITIVector< RowIndex, std::string > &names)
void SetVariableName(ColIndex col, absl::string_view name)
ColIndex CreateNewSlackVariable(bool is_integer_slack_variable, Fractional lower_bound, Fractional upper_bound, const std::string &name)
VariableType GetVariableType(ColIndex col) const
Returns the type of variable.
const DenseColumn & constraint_upper_bounds() const
std::string GetNonZeroStats() const
RowIndex CreateNewConstraint()
const SparseColumn & GetSparseColumn(ColIndex col) const
bool IsVariableInteger(ColIndex col) const
Returns whether the variable at column col is constrained to be integer.
void PopulateFromLinearProgram(const LinearProgram &linear_program)
Populates the calling object with the given LinearProgram.
bool UpdateVariableBoundsToIntersection(const DenseRow &variable_lower_bounds, const DenseRow &variable_upper_bounds)
Fractional objective_scaling_factor() const
Fractional ApplyObjectiveScalingAndOffset(Fractional value) const
ColIndex num_variables() const
Returns the number of variables.
ColIndex GetFirstSlackVariable() const
std::string GetObjectiveStatsString() const
A short line with some stats on the problem coefficients.
ColIndex CreateNewVariable()
Fractional objective_offset() const
Returns the objective offset and scaling factor.
RowIndex num_constraints() const
Returns the number of constraints.
std::string GetBoundsStatsString() const
RowIndex FindOrCreateConstraint(absl::string_view constraint_id)
void PopulateFromDual(const LinearProgram &dual, RowToColMapping *duplicated_rows)
void SetMaximizationProblem(bool maximize)
void PopulateFromInverse(const Permutation &inverse)
void ComputeMinAndMaxMagnitudes(Fractional *min_magnitude, Fractional *max_magnitude) const
void PopulateFromPermutedMatrix(const Matrix &a, const RowPermutation &row_perm, const ColumnPermutation &inverse_col_perm)
const SparseColumn & column(ColIndex col) const
Access the underlying sparse columns.
void PopulateFromTranspose(const Matrix &input)
Instantiate needed templates.
SparseColumn * mutable_column(ColIndex col)
void Swap(SparseMatrix *matrix)
bool IsCleanedUp() const
Call IsCleanedUp() on all columns, useful for doing a DCHECK.
void DeleteRows(RowIndex num_rows, const RowPermutation &permutation)
RowIndex num_rows() const
Return the matrix dimension.
void PopulateFromZero(RowIndex num_rows, ColIndex num_cols)
bool AppendRowsFromSparseMatrix(const SparseMatrix &matrix)
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
void PopulateFromSparseMatrix(const SparseMatrix &matrix)
ColIndex num_cols() const
ColIndex AppendEmptyColumn()
Appends an empty column and returns its index.
void SetNumRows(RowIndex num_rows)
Change the number of row of this matrix.
EntryIndex num_entries() const
void RemoveNearZeroEntries(Fractional threshold)
EntryIndex num_entries() const
Note this method can only be used when the vector has no duplicates.
void PopulateFromSparseVector(const SparseVector &sparse_vector)
void SetCoefficient(Index index, Fractional value)
Defines the coefficient at index, i.e. vector[index] = value;.
void resize(IntType size)
void swap(StrongVector &x) noexcept
void push_back(const value_type &val)
iterator insert(const_iterator pos, const value_type &x)
const std::string name
A name for logging purposes.
absl::Span< const double > coefficients
constexpr ColIndex kInvalidCol(-1)
constexpr double kInfinity
Infinity for type Fractional.
StrictITIVector< RowIndex, ColIndex > RowToColMapping
bool AreBoundsValid(Fractional lower_bound, Fractional upper_bound)
StrictITIVector< RowIndex, bool > DenseBooleanColumn
Column of booleans.
std::string Stringify(const Fractional x, bool fraction)
Permutation< RowIndex > RowPermutation
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
std::string GetVariableStatusString(VariableStatus status)
Returns the string representation of the VariableStatus enum.
Index ColToIntIndex(ColIndex col)
Get the integer index corresponding to the col.
bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix)
Returns true iff the rightmost square matrix is an identity matrix.
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
bool IsFinite(Fractional value)
constexpr RowIndex kInvalidRow(-1)
VariableType
Different types of variables.
RowIndex ColToRowIndex(ColIndex col)
Get the RowIndex corresponding to the row # col.
std::string GetConstraintStatusString(ConstraintStatus status)
Returns the string representation of the ConstraintStatus enum.
std::string StringifyMonomial(const Fractional a, absl::string_view x, bool fraction)
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
constexpr double kEpsilon
Epsilon for type Fractional, i.e. the smallest e such that 1.0 + e != 1.0 .
Fractional PartialScalarProduct(const DenseRowOrColumn &u, const SparseColumn &v, int max_index)
Computes a scalar product for entries with index not greater than max_index.
StrictITIVector< RowIndex, Fractional > DenseColumn
Column-vector types. Column-vector types are indexed by a row index.
StrictITIVector< ColIndex, Fractional > DenseRow
Row-vector types. Row-vector types are indexed by a column index.
StrictITIVector< ColIndex, bool > DenseBooleanRow
Row of booleans.
std::string GetProblemStatusString(ProblemStatus problem_status)
Returns the string representation of the ProblemStatus enum.
Index RowToIntIndex(RowIndex row)
Get the integer index corresponding to the row.
In SWIG mode, we don't want anything besides these top-level includes.
bool IsIntegerWithinTolerance(FloatType x, FloatType tolerance)
util_intops::StrongVector< ColumnEntryIndex, ElementIndex, ElementAllocator > SparseColumn
const std::optional< Range > & range
ConstraintStatusColumn constraint_statuses
std::string DebugString() const
VariableStatusRow variable_statuses
ProblemStatus status
The solution status.