23 #include "absl/container/flat_hash_map.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/str_format.h"
60 template <
class I,
class T>
62 const size_t size = v.
size();
66 for (I i(0); i < size; ++i) {
67 if (v[i] == 0.0)
continue;
69 sum +=
static_cast<double>(v[i].value());
71 return n == 0.0 ? 0.0 : sum / n;
74 template <
class I,
class T>
76 const size_t size = v.
size();
78 double sigma_square = 0.0;
80 for (I i(0); i < size; ++i) {
81 double sample =
static_cast<double>(v[i].value());
82 if (sample == 0.0)
continue;
83 sigma_square += sample * sample;
87 return n == 0.0 ? 0.0 : sqrt((sigma_square - sigma * sigma / n) / n);
91 template <
class I,
class T>
93 const size_t size = v.
size();
98 T max_index = v[I(0)];
99 for (I i(1); i < size; ++i) {
100 if (max_index < v[i]) {
115 constraint_lower_bounds_(),
116 constraint_upper_bounds_(),
118 objective_coefficients_(),
119 variable_lower_bounds_(),
120 variable_upper_bounds_(),
123 integer_variables_list_(),
126 objective_offset_(0.0),
127 objective_scaling_factor_(1.0),
129 columns_are_known_to_be_clean_(true),
130 transpose_matrix_is_consistent_(true),
131 integer_variables_list_is_consistent_(true),
137 transpose_matrix_.
Clear();
139 constraint_lower_bounds_.
clear();
140 constraint_upper_bounds_.
clear();
141 constraint_names_.
clear();
143 objective_coefficients_.
clear();
144 variable_lower_bounds_.
clear();
145 variable_upper_bounds_.
clear();
146 variable_types_.
clear();
147 integer_variables_list_.clear();
148 variable_names_.
clear();
150 constraint_table_.clear();
151 variable_table_.clear();
154 objective_offset_ = 0.0;
155 objective_scaling_factor_ = 1.0;
156 columns_are_known_to_be_clean_ =
true;
157 transpose_matrix_is_consistent_ =
true;
158 integer_variables_list_is_consistent_ =
true;
165 <<
"New variables can't be added to programs that already have slack "
166 "variables. Consider calling LinearProgram::DeleteSlackVariables() "
167 "before adding new variables to the problem.";
173 transpose_matrix_is_consistent_ =
false;
180 const std::string&
name) {
184 variable_types_.
push_back(is_integer_slack_variable
188 transpose_matrix_is_consistent_ =
false;
194 <<
"New constraints can't be added to programs that already have slack "
195 "variables. Consider calling LinearProgram::DeleteSlackVariables() "
196 "before adding new variables to the problem.";
197 const RowIndex
row(constraint_names_.
size());
202 transpose_matrix_is_consistent_ =
false;
207 const absl::flat_hash_map<std::string, ColIndex>::iterator it =
208 variable_table_.find(variable_id);
209 if (it != variable_table_.end()) {
213 variable_names_[
col] = variable_id;
214 variable_table_[variable_id] =
col;
220 const std::string& constraint_id) {
221 const absl::flat_hash_map<std::string, RowIndex>::iterator it =
222 constraint_table_.find(constraint_id);
223 if (it != constraint_table_.end()) {
227 constraint_names_[
row] = constraint_id;
228 constraint_table_[constraint_id] =
row;
234 variable_names_[
col] = std::string(
name);
239 variable_types_[
col] = type;
241 if (var_is_integer != var_was_integer) {
242 integer_variables_list_is_consistent_ =
false;
247 constraint_names_[
row] = std::string(
name);
257 if (var_is_binary != var_was_binary) {
258 integer_variables_list_is_consistent_ =
false;
262 void LinearProgram::UpdateAllIntegerVariableLists()
const {
263 if (integer_variables_list_is_consistent_)
return;
264 integer_variables_list_.clear();
265 binary_variables_list_.clear();
266 non_binary_variables_list_.clear();
268 for (ColIndex
col(0);
col < num_cols; ++
col) {
270 integer_variables_list_.push_back(
col);
272 binary_variables_list_.push_back(
col);
274 non_binary_variables_list_.push_back(
col);
278 integer_variables_list_is_consistent_ =
true;
282 UpdateAllIntegerVariableLists();
283 return integer_variables_list_;
287 UpdateAllIntegerVariableLists();
288 return binary_variables_list_;
292 UpdateAllIntegerVariableLists();
293 return non_binary_variables_list_;
307 (variable_upper_bounds_[
col] < 2);
313 ResizeRowsIfNeeded(
row);
321 ResizeRowsIfNeeded(
row);
322 columns_are_known_to_be_clean_ =
false;
323 transpose_matrix_is_consistent_ =
false;
329 objective_coefficients_[
col] =
value;
345 maximize_ = maximize;
349 if (columns_are_known_to_be_clean_)
return;
351 columns_are_known_to_be_clean_ =
true;
352 transpose_matrix_is_consistent_ =
false;
356 if (columns_are_known_to_be_clean_)
return true;
357 columns_are_known_to_be_clean_ = matrix_.
IsCleanedUp();
358 return columns_are_known_to_be_clean_;
363 ? absl::StrFormat(
"c%d",
col.value())
364 : variable_names_[
col];
368 return row >= constraint_names_.
size() || constraint_names_[
row].
empty()
369 ? absl::StrFormat(
"r%d",
row.value())
370 : constraint_names_[
row];
374 return variable_types_[
col];
378 if (!transpose_matrix_is_consistent_) {
380 transpose_matrix_is_consistent_ =
true;
382 DCHECK_EQ(transpose_matrix_.
num_rows().value(), matrix_.
num_cols().value());
383 DCHECK_EQ(transpose_matrix_.
num_cols().value(), matrix_.
num_rows().value());
384 return transpose_matrix_;
388 if (!transpose_matrix_is_consistent_) {
394 transpose_matrix_is_consistent_ =
false;
395 return &transpose_matrix_;
399 DCHECK_EQ(transpose_matrix_.
num_rows().value(), matrix_.
num_cols().value());
400 DCHECK_EQ(transpose_matrix_.
num_cols().value(), matrix_.
num_rows().value());
402 transpose_matrix_is_consistent_ =
true;
406 transpose_matrix_.
Clear();
407 transpose_matrix_is_consistent_ =
false;
415 columns_are_known_to_be_clean_ =
false;
416 transpose_matrix_is_consistent_ =
false;
421 ColIndex
col)
const {
430 return absl::StrFormat(
431 "%d rows, %d columns, %d entries with magnitude in [%e, %e]",
440 template <
typename FractionalValues>
441 void UpdateStats(
const FractionalValues& values, int64_t* num_non_zeros,
445 *min_value =
std::min(*min_value, v);
446 *max_value =
std::max(*max_value, v);
454 int64_t num_non_zeros = 0;
457 UpdateStats(objective_coefficients_, &num_non_zeros, &min_value, &max_value);
458 if (num_non_zeros == 0) {
459 return "No objective term. This is a pure feasibility problem.";
461 return absl::StrFormat(
"%d non-zeros, range [%e, %e]", num_non_zeros,
462 min_value, max_value);
467 int64_t num_non_zeros = 0;
470 UpdateStats(variable_lower_bounds_, &num_non_zeros, &min_value, &max_value);
471 UpdateStats(variable_upper_bounds_, &num_non_zeros, &min_value, &max_value);
472 UpdateStats(constraint_lower_bounds_, &num_non_zeros, &min_value, &max_value);
473 UpdateStats(constraint_upper_bounds_, &num_non_zeros, &min_value, &max_value);
474 if (num_non_zeros == 0) {
475 return "All variables/constraints bounds are zero or +/- infinity.";
477 return absl::StrFormat(
"%d non-zeros, range [%e, %e]", num_non_zeros,
478 min_value, max_value);
487 for (ColIndex
col = ColIndex(0);
col < num_cols; ++
col) {
491 if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) {
505 for (RowIndex
row = RowIndex(0);
row < num_rows; ++
row) {
511 if (lb_error > absolute_tolerance || ub_error > absolute_tolerance) {
524 const Fractional fractionality = fabs(solution[
col] - round(solution[
col]));
525 if (fractionality > absolute_tolerance)
return false;
537 CHECK(solution !=
nullptr);
542 for (RowIndex
row = RowIndex(0);
row < num_rows; ++
row) {
547 (*solution)[slack_variable] = -sum;
563 std::string output = maximize_ ?
"max:" :
"min:";
564 if (objective_offset_ != 0.0) {
568 for (ColIndex
col(0);
col < num_cols; ++
col) {
574 output.append(
";\n");
578 for (RowIndex
row(0);
row < num_rows; ++
row) {
588 for (ColIndex
col(0);
col < num_cols; ++
col) {
609 for (ColIndex
col(0);
col < num_cols; ++
col) {
636 if (!integer_variables.empty()) {
638 for (ColIndex
col : integer_variables) {
652 if (!output.empty()) absl::StrAppend(&output,
", ");
654 (variable_values[
col]));
660 return ProblemStatFormatter(
661 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
666 return ProblemStatFormatter(
667 "Number of rows : %d\n"
668 "Number of variables in file : %d\n"
669 "Number of entries (non-zeros) : %d\n"
670 "Number of entries in the objective : %d\n"
671 "Number of entries in the right-hand side : %d\n"
672 "Number of <= constraints : %d\n"
673 "Number of >= constraints : %d\n"
674 "Number of = constraints : %d\n"
675 "Number of range constraints : %d\n"
676 "Number of non-negative variables : %d\n"
677 "Number of boxed variables : %d\n"
678 "Number of free variables : %d\n"
679 "Number of fixed variables : %d\n"
680 "Number of other variables : %d\n"
681 "Number of integer variables : %d\n"
682 "Number of binary variables : %d\n"
683 "Number of non-binary integer variables : %d\n"
684 "Number of continuous variables : %d\n");
688 return NonZeroStatFormatter(
"%.2f%%,%d,%.2f,%.2f,%d,%.2f,%.2f");
692 return NonZeroStatFormatter(
693 "Fill rate : %.2f%%\n"
694 "Entries in row (Max / average / std. dev.) : %d / %.2f / %.2f\n"
695 "Entries in column (Max / average / std. dev.): %d / %.2f / %.2f\n");
699 bool detect_integer_constraints) {
715 detect_integer_constraints);
716 if (detect_integer_constraints) {
721 const RowIndex
row = entry.row();
722 has_integer_slack_variable[
row] =
723 has_integer_slack_variable[
row] && is_integer_variable &&
724 round(entry.coefficient()) == entry.coefficient();
734 slack_variable_index < original_num_variables) {
739 has_integer_slack_variable[
row], -constraint_upper_bounds_[
row],
740 -constraint_lower_bounds_[
row], absl::StrCat(
"s",
row.value()));
745 columns_are_known_to_be_clean_ =
true;
746 transpose_matrix_is_consistent_ =
false;
748 first_slack_variable_ = original_num_variables;
753 return first_slack_variable_;
757 DCHECK_GE(
row, RowIndex(0));
783 for (RowIndex dual_row(0); dual_row < dual_num_constraints; ++dual_row) {
801 LOG(DFATAL) <<
"PopulateFromDual() was called with a program "
802 <<
"containing free constraints.";
806 for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
817 for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
828 for (ColIndex dual_col(0); dual_col < dual_num_variables; ++dual_col) {
834 const RowIndex dual_row = e.row();
842 for (RowIndex dual_row(0); dual_row < dual_num_constraints; ++dual_row) {
854 (*duplicated_rows)[dual_row] =
col;
859 columns_are_known_to_be_clean_ =
true;
860 transpose_matrix_is_consistent_ =
false;
866 if (linear_program.transpose_matrix_is_consistent_) {
867 transpose_matrix_is_consistent_ =
true;
869 linear_program.transpose_matrix_);
871 transpose_matrix_is_consistent_ =
false;
872 transpose_matrix_.
Clear();
875 constraint_lower_bounds_ = linear_program.constraint_lower_bounds_;
876 constraint_upper_bounds_ = linear_program.constraint_upper_bounds_;
877 constraint_names_ = linear_program.constraint_names_;
878 constraint_table_.clear();
880 PopulateNameObjectiveAndVariablesFromLinearProgram(linear_program);
881 first_slack_variable_ = linear_program.first_slack_variable_;
897 inverse_col_permutation);
902 &constraint_lower_bounds_);
904 &constraint_upper_bounds_);
908 &objective_coefficients_);
910 &variable_lower_bounds_);
912 &variable_upper_bounds_);
914 integer_variables_list_is_consistent_ =
false;
920 const RowIndex new_row = row_permutation[old_row];
921 constraint_names_[new_row] = lp.constraint_names_[old_row];
924 for (ColIndex old_col(0); old_col < lp.
num_variables(); ++old_col) {
925 const ColIndex new_col = col_permutation[old_col];
926 variable_names_[new_col] = lp.variable_names_[old_col];
930 maximize_ = lp.maximize_;
931 objective_offset_ = lp.objective_offset_;
932 objective_scaling_factor_ = lp.objective_scaling_factor_;
940 transpose_matrix_is_consistent_ =
false;
941 transpose_matrix_.
Clear();
943 constraint_lower_bounds_.
clear();
944 constraint_upper_bounds_.
clear();
945 constraint_names_.
clear();
946 constraint_table_.clear();
948 PopulateNameObjectiveAndVariablesFromLinearProgram(linear_program);
951 void LinearProgram::PopulateNameObjectiveAndVariablesFromLinearProgram(
953 objective_coefficients_ = linear_program.objective_coefficients_;
954 variable_lower_bounds_ = linear_program.variable_lower_bounds_;
955 variable_upper_bounds_ = linear_program.variable_upper_bounds_;
956 variable_names_ = linear_program.variable_names_;
957 variable_types_ = linear_program.variable_types_;
958 integer_variables_list_is_consistent_ =
959 linear_program.integer_variables_list_is_consistent_;
960 integer_variables_list_ = linear_program.integer_variables_list_;
961 binary_variables_list_ = linear_program.binary_variables_list_;
962 non_binary_variables_list_ = linear_program.non_binary_variables_list_;
963 variable_table_.clear();
965 maximize_ = linear_program.maximize_;
966 objective_offset_ = linear_program.objective_offset_;
967 objective_scaling_factor_ = linear_program.objective_scaling_factor_;
968 columns_are_known_to_be_clean_ =
969 linear_program.columns_are_known_to_be_clean_;
970 name_ = linear_program.name_;
977 const RowIndex num_new_constraints =
coefficients.num_rows();
979 DCHECK_EQ(num_new_constraints, left_hand_sides.
size());
980 DCHECK_EQ(num_new_constraints, right_hand_sides.
size());
981 DCHECK_EQ(num_new_constraints, names.
size());
984 transpose_matrix_is_consistent_ =
false;
985 transpose_matrix_.
Clear();
986 columns_are_known_to_be_clean_ =
false;
989 constraint_lower_bounds_.
insert(constraint_lower_bounds_.
end(),
990 left_hand_sides.
begin(),
991 left_hand_sides.
end());
992 constraint_upper_bounds_.
insert(constraint_upper_bounds_.
end(),
993 right_hand_sides.
begin(),
994 right_hand_sides.
end());
1002 bool detect_integer_constraints_for_slack) {
1014 DenseRow new_lower_bounds(num_vars, 0);
1015 DenseRow new_upper_bounds(num_vars, 0);
1016 for (ColIndex i(0); i < num_vars; ++i) {
1021 if (new_lower_bound > new_upper_bound) {
1024 new_lower_bounds[i] = new_lower_bound;
1025 new_upper_bounds[i] = new_upper_bound;
1027 variable_lower_bounds_.
swap(new_lower_bounds);
1028 variable_upper_bounds_.
swap(new_upper_bounds);
1033 matrix_.
Swap(&linear_program->matrix_);
1034 transpose_matrix_.
Swap(&linear_program->transpose_matrix_);
1036 constraint_lower_bounds_.
swap(linear_program->constraint_lower_bounds_);
1037 constraint_upper_bounds_.
swap(linear_program->constraint_upper_bounds_);
1038 constraint_names_.
swap(linear_program->constraint_names_);
1040 objective_coefficients_.
swap(linear_program->objective_coefficients_);
1041 variable_lower_bounds_.
swap(linear_program->variable_lower_bounds_);
1042 variable_upper_bounds_.
swap(linear_program->variable_upper_bounds_);
1043 variable_names_.
swap(linear_program->variable_names_);
1044 variable_types_.
swap(linear_program->variable_types_);
1045 integer_variables_list_.swap(linear_program->integer_variables_list_);
1046 binary_variables_list_.swap(linear_program->binary_variables_list_);
1047 non_binary_variables_list_.swap(linear_program->non_binary_variables_list_);
1049 variable_table_.swap(linear_program->variable_table_);
1050 constraint_table_.swap(linear_program->constraint_table_);
1052 std::swap(maximize_, linear_program->maximize_);
1053 std::swap(objective_offset_, linear_program->objective_offset_);
1055 linear_program->objective_scaling_factor_);
1056 std::swap(columns_are_known_to_be_clean_,
1057 linear_program->columns_are_known_to_be_clean_);
1058 std::swap(transpose_matrix_is_consistent_,
1059 linear_program->transpose_matrix_is_consistent_);
1060 std::swap(integer_variables_list_is_consistent_,
1061 linear_program->integer_variables_list_is_consistent_);
1062 name_.swap(linear_program->name_);
1063 std::swap(first_slack_variable_, linear_program->first_slack_variable_);
1067 if (columns_to_delete.
empty())
return;
1068 integer_variables_list_is_consistent_ =
false;
1071 ColIndex new_index(0);
1072 for (ColIndex
col(0);
col < num_cols; ++
col) {
1073 permutation[
col] = new_index;
1074 if (
col >= columns_to_delete.
size() || !columns_to_delete[
col]) {
1075 objective_coefficients_[new_index] = objective_coefficients_[
col];
1076 variable_lower_bounds_[new_index] = variable_lower_bounds_[
col];
1077 variable_upper_bounds_[new_index] = variable_upper_bounds_[
col];
1078 variable_names_[new_index] = variable_names_[
col];
1079 variable_types_[new_index] = variable_types_[
col];
1087 objective_coefficients_.
resize(new_index, 0.0);
1088 variable_lower_bounds_.
resize(new_index, 0.0);
1089 variable_upper_bounds_.
resize(new_index, 0.0);
1091 variable_names_.
resize(new_index,
"");
1094 absl::flat_hash_map<std::string, ColIndex>::iterator it =
1095 variable_table_.begin();
1096 while (it != variable_table_.end()) {
1097 const ColIndex
col = it->second;
1098 if (
col >= columns_to_delete.
size() || !columns_to_delete[
col]) {
1099 it->second = permutation[
col];
1103 variable_table_.erase(it++);
1108 if (transpose_matrix_is_consistent_) {
1119 for (ColIndex slack_variable = first_slack_variable_;
1120 slack_variable < matrix_.
num_cols(); ++slack_variable) {
1125 DCHECK_EQ(
column.num_entries(), 1);
1126 const RowIndex
row =
column.EntryRow(EntryIndex(0));
1127 DCHECK_EQ(constraint_lower_bounds_[
row], 0.0);
1128 DCHECK_EQ(constraint_upper_bounds_[
row], 0.0);
1130 -variable_lower_bounds_[slack_variable]);
1131 slack_variables[slack_variable] =
true;
1142 template <
typename FractionalRange>
1143 void UpdateMinAndMaxMagnitude(
const FractionalRange&
range,
1148 if (magnitude == 0 || magnitude ==
kInfinity)
continue;
1149 *min_magnitude =
std::min(*min_magnitude, magnitude);
1150 *max_magnitude =
std::max(*max_magnitude, magnitude);
1155 std::vector<Fractional> median;
1157 if (
value == 0.0)
continue;
1158 median.push_back(std::abs(
value));
1160 if (median.empty())
return 1.0;
1161 std::sort(median.begin(), median.end());
1162 return median[median.size() / 2];
1167 int num_non_zeros = 0;
1169 if (
value == 0.0)
continue;
1171 mean += std::abs(
value);
1173 if (num_non_zeros == 0.0)
return 1.0;
1174 return mean /
static_cast<Fractional>(num_non_zeros);
1179 if (min_magnitude > 1.0 && min_magnitude <
kInfinity) {
1180 return min_magnitude;
1181 }
else if (max_magnitude > 0.0 && max_magnitude < 1.0) {
1182 return max_magnitude;
1190 GlopParameters::CostScalingAlgorithm method) {
1197 case GlopParameters::NO_COST_SCALING:
1199 case GlopParameters::CONTAIN_ONE_COST_SCALING:
1200 cost_scaling_factor =
1201 ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1203 case GlopParameters::MEAN_COST_SCALING:
1206 case GlopParameters::MEDIAN_COST_SCALING:
1210 if (cost_scaling_factor != 1.0) {
1219 VLOG(1) <<
"Objective magnitude range is [" << min_magnitude <<
", "
1220 << max_magnitude <<
"] (dividing by " << cost_scaling_factor <<
").";
1221 return cost_scaling_factor;
1236 ComputeDivisorSoThatRangeContainsOne(min_magnitude, max_magnitude);
1237 if (bound_scaling_factor != 1.0) {
1239 bound_scaling_factor);
1253 VLOG(1) <<
"Bounds magnitude range is [" << min_magnitude <<
", "
1254 << max_magnitude <<
"] (dividing bounds by " << bound_scaling_factor
1256 return bound_scaling_factor;
1260 if (rows_to_delete.
empty())
return;
1266 RowIndex new_index(0);
1267 for (RowIndex
row(0);
row < num_rows; ++
row) {
1268 if (
row >= rows_to_delete.
size() || !rows_to_delete[
row]) {
1269 constraint_lower_bounds_[new_index] = constraint_lower_bounds_[
row];
1270 constraint_upper_bounds_[new_index] = constraint_upper_bounds_[
row];
1271 constraint_names_[new_index].
swap(constraint_names_[
row]);
1272 permutation[
row] = new_index;
1278 constraint_lower_bounds_.
resize(new_index, 0.0);
1279 constraint_upper_bounds_.
resize(new_index, 0.0);
1280 constraint_names_.
resize(new_index,
"");
1286 absl::flat_hash_map<std::string, RowIndex>::iterator it =
1287 constraint_table_.begin();
1288 while (it != constraint_table_.end()) {
1289 const RowIndex
row = it->second;
1291 it->second = permutation[
row];
1295 constraint_table_.erase(it++);
1300 if (transpose_matrix_is_consistent_) {
1307 if (!
IsFinite(objective_offset_))
return false;
1308 if (std::abs(objective_offset_) > max_valid_magnitude)
return false;
1310 if (!
IsFinite(objective_scaling_factor_))
return false;
1311 if (objective_scaling_factor_ == 0.0)
return false;
1312 if (std::abs(objective_scaling_factor_) > max_valid_magnitude)
return false;
1315 for (ColIndex
col(0);
col < num_cols; ++
col) {
1319 if (
IsFinite(lb) && std::abs(lb) > max_valid_magnitude)
return false;
1320 if (
IsFinite(ub) && std::abs(ub) > max_valid_magnitude)
return false;
1330 if (!
IsFinite(e.coefficient()))
return false;
1331 if (std::abs(e.coefficient()) > max_valid_magnitude)
return false;
1334 if (constraint_upper_bounds_.
size() != constraint_lower_bounds_.
size()) {
1337 for (RowIndex
row(0);
row < constraint_lower_bounds_.
size(); ++
row) {
1341 if (
IsFinite(lb) && std::abs(lb) > max_valid_magnitude)
return false;
1342 if (
IsFinite(ub) && std::abs(ub) > max_valid_magnitude)
return false;
1347 std::string LinearProgram::ProblemStatFormatter(
1348 const absl::string_view format)
const {
1349 int num_objective_non_zeros = 0;
1350 int num_non_negative_variables = 0;
1351 int num_boxed_variables = 0;
1352 int num_free_variables = 0;
1353 int num_fixed_variables = 0;
1354 int num_other_variables = 0;
1356 for (ColIndex
col(0);
col < num_cols; ++
col) {
1358 ++num_objective_non_zeros;
1366 if (!lower_bounded && !upper_bounded) {
1367 ++num_free_variables;
1368 }
else if (
lower_bound == 0.0 && !upper_bounded) {
1369 ++num_non_negative_variables;
1370 }
else if (!upper_bounded || !lower_bounded) {
1371 ++num_other_variables;
1373 ++num_fixed_variables;
1375 ++num_boxed_variables;
1379 int num_range_constraints = 0;
1380 int num_less_than_constraints = 0;
1381 int num_greater_than_constraints = 0;
1382 int num_equal_constraints = 0;
1383 int num_rhs_non_zeros = 0;
1385 for (RowIndex
row(0);
row < num_rows; ++
row) {
1391 ++num_range_constraints;
1395 ++num_equal_constraints;
1397 ++num_rhs_non_zeros;
1402 ++num_less_than_constraints;
1404 ++num_rhs_non_zeros;
1409 ++num_greater_than_constraints;
1411 ++num_rhs_non_zeros;
1415 LOG(DFATAL) <<
"There is a bug since all possible cases for the row bounds "
1416 "should have been accounted for. row="
1423 const int num_continuous_variables =
1425 auto format_runtime =
1426 absl::ParsedFormat<
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
'd',
1427 'd',
'd',
'd',
'd',
'd',
'd',
'd'>::New(format);
1428 CHECK(format_runtime);
1429 return absl::StrFormat(
1432 num_objective_non_zeros, num_rhs_non_zeros, num_less_than_constraints,
1433 num_greater_than_constraints, num_equal_constraints,
1434 num_range_constraints, num_non_negative_variables, num_boxed_variables,
1435 num_free_variables, num_fixed_variables, num_other_variables,
1436 num_integer_variables, num_binary_variables, num_non_binary_variables,
1437 num_continuous_variables);
1440 std::string LinearProgram::NonZeroStatFormatter(
1441 const absl::string_view format)
const {
1442 StrictITIVector<RowIndex, EntryIndex> num_entries_in_row(
num_constraints(),
1444 StrictITIVector<ColIndex, EntryIndex> num_entries_in_column(
num_variables(),
1448 for (ColIndex
col(0);
col < num_cols; ++
col) {
1451 num_entries_in_column[
col] = sparse_column.num_entries();
1453 ++num_entries_in_row[e.row()];
1461 const double fill_rate = 100.0 *
static_cast<double>(
num_entries.value()) /
1464 auto format_runtime =
1465 absl::ParsedFormat<'f', 'd', 'f', 'f', 'd', 'f', 'f'>::New(format);
1466 return absl::StrFormat(
1467 *format_runtime, fill_rate, GetMaxElement(num_entries_in_row).
value(),
1468 Average(num_entries_in_row), StandardDeviation(num_entries_in_row),
1469 GetMaxElement(num_entries_in_column).
value(),
1470 Average(num_entries_in_column), StandardDeviation(num_entries_in_column));
1473 void LinearProgram::ResizeRowsIfNeeded(RowIndex
row) {
1476 transpose_matrix_is_consistent_ =
false;
1485 for (RowIndex constraint(0); constraint <
num_constraints(); ++constraint) {
1486 if (constraint_lower_bounds_[constraint] != 0.0 ||
1487 constraint_upper_bounds_[constraint] != 0.0) {
1491 const ColIndex num_slack_variables =
1504 VLOG(1) <<
"Bounds of variable " <<
col.value() <<
" are non-integer ("
1505 << variable_lower_bounds_[
col] <<
", "
1506 << variable_upper_bounds_[
col] <<
").";
1520 bool integer_constraint =
true;
1523 integer_constraint =
false;
1529 if (std::round(
var.coefficient()) !=
var.coefficient()) {
1530 integer_constraint =
false;
1534 if (integer_constraint) {
1541 VLOG(1) <<
"Bounds of constraint " <<
row.value()
1542 <<
" are non-integer (" << constraint_lower_bounds_[
row] <<
", "
1543 << constraint_upper_bounds_[
row] <<
").";
1557 absl::StrAppendFormat(&s,
"\n Var #%d: %s %g",
col.value(),
1561 s +=
"\n------------------------------";
1563 absl::StrAppendFormat(&s,
"\n Constraint #%d: %s %g",
row.value(),
iterator insert(const_iterator pos, const value_type &x)
void push_back(const value_type &x)
void swap(StrongVector &x)
SparseMatrix * GetMutableTransposeSparseMatrix()
std::string GetObjectiveStatsString() const
void SetObjectiveScalingFactor(Fractional objective_scaling_factor)
void PopulateFromPermutedLinearProgram(const LinearProgram &lp, const RowPermutation &row_permutation, const ColumnPermutation &col_permutation)
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
std::string GetVariableName(ColIndex col) const
void SetConstraintName(RowIndex row, absl::string_view name)
const SparseMatrix & GetTransposeSparseMatrix() const
bool SolutionIsWithinVariableBounds(const DenseRow &solution, Fractional absolute_tolerance) const
bool BoundsOfIntegerConstraintsAreInteger(Fractional tolerance) const
bool IsInEquationForm() const
void SetObjectiveOffset(Fractional objective_offset)
void PopulateFromLinearProgram(const LinearProgram &linear_program)
std::string GetPrettyProblemStats() const
bool SolutionIsMIPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
std::string GetNonZeroStats() const
ColIndex GetFirstSlackVariable() const
bool BoundsOfIntegerVariablesAreInteger(Fractional tolerance) const
void ClearTransposeMatrix()
void SetVariableName(ColIndex col, absl::string_view name)
std::string DumpSolution(const DenseRow &variable_values) const
ColIndex GetSlackVariable(RowIndex row) const
const DenseRow & variable_lower_bounds() const
ColIndex FindOrCreateVariable(const std::string &variable_id)
const DenseColumn & constraint_lower_bounds() const
std::string GetBoundsStatsString() const
Fractional ScaleObjective(GlopParameters::CostScalingAlgorithm method)
bool IsValid(Fractional max_valid_magnitude=kInfinity) const
const std::vector< ColIndex > & BinaryVariablesList() const
const DenseRow & objective_coefficients() const
Fractional RemoveObjectiveScalingAndOffset(Fractional value) const
const std::vector< ColIndex > & IntegerVariablesList() const
Fractional GetObjectiveCoefficientForMinimizationVersion(ColIndex col) const
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
ColIndex CreateNewVariable()
ColIndex CreateNewSlackVariable(bool is_integer_slack_variable, Fractional lower_bound, Fractional upper_bound, const std::string &name)
VariableType GetVariableType(ColIndex col) const
RowIndex FindOrCreateConstraint(const std::string &constraint_id)
void Swap(LinearProgram *linear_program)
void AddConstraints(const SparseMatrix &coefficients, const DenseColumn &left_hand_sides, const DenseColumn &right_hand_sides, const StrictITIVector< RowIndex, std::string > &names)
std::string GetPrettyNonZeroStats() const
void SetVariableType(ColIndex col, VariableType type)
Fractional objective_offset() const
const std::vector< ColIndex > & NonBinaryVariablesList() const
bool SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const
SparseColumn * GetMutableSparseColumn(ColIndex col)
std::string GetConstraintName(RowIndex row) const
void UseTransposeMatrixAsReference()
void AddSlackVariablesWhereNecessary(bool detect_integer_constraints)
const DenseColumn & constraint_upper_bounds() const
void ComputeSlackVariableValues(DenseRow *solution) const
bool SolutionIsLPFeasible(const DenseRow &solution, Fractional absolute_tolerance) const
bool IsVariableInteger(ColIndex col) const
void SetObjectiveCoefficient(ColIndex col, Fractional value)
bool IsVariableBinary(ColIndex col) const
Fractional ApplyObjectiveScalingAndOffset(Fractional value) const
void DeleteRows(const DenseBooleanColumn &rows_to_delete)
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
const DenseRow & variable_upper_bounds() const
std::string GetProblemStats() const
ColIndex num_variables() const
bool UpdateVariableBoundsToIntersection(const DenseRow &variable_lower_bounds, const DenseRow &variable_upper_bounds)
void PopulateFromDual(const LinearProgram &dual, RowToColMapping *duplicated_rows)
void DeleteSlackVariables()
const std::string & name() const
RowIndex CreateNewConstraint()
void PopulateFromLinearProgramVariables(const LinearProgram &linear_program)
std::string GetDimensionString() const
Fractional objective_scaling_factor() const
void SetMaximizationProblem(bool maximize)
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 StrictITIVector< ColIndex, VariableType > variable_types() const
const SparseColumn & GetSparseColumn(ColIndex col) const
EntryIndex num_entries() const
RowIndex num_constraints() const
void PopulateFromInverse(const Permutation &inverse)
SparseColumn * mutable_column(ColIndex col)
void PopulateFromPermutedMatrix(const Matrix &a, const RowPermutation &row_perm, const ColumnPermutation &inverse_col_perm)
void PopulateFromTranspose(const Matrix &input)
ColIndex num_cols() const
void SetNumRows(RowIndex num_rows)
Fractional LookUpValue(RowIndex row, ColIndex col) const
void Swap(SparseMatrix *matrix)
void ComputeMinAndMaxMagnitudes(Fractional *min_magnitude, Fractional *max_magnitude) const
void DeleteRows(RowIndex num_rows, const RowPermutation &permutation)
ColIndex AppendEmptyColumn()
RowIndex num_rows() const
bool AppendRowsFromSparseMatrix(const SparseMatrix &matrix)
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
void PopulateFromSparseMatrix(const SparseMatrix &matrix)
const SparseColumn & column(ColIndex col) const
void PopulateFromZero(RowIndex num_rows, ColIndex num_cols)
EntryIndex num_entries() const
typename Iterator::Entry Entry
void SetCoefficient(Index index, Fractional value)
void PopulateFromSparseVector(const SparseVector &sparse_vector)
void resize(IntType size)
void assign(IntType size, const T &v)
absl::Span< const double > coefficients
constexpr ColIndex kInvalidCol(-1)
std::string StringifyMonomial(const Fractional a, const std::string &x, bool fraction)
bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix)
bool AreBoundsValid(Fractional lower_bound, Fractional upper_bound)
constexpr double kEpsilon
std::string Stringify(const Fractional x, bool fraction)
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
StrictITIVector< ColIndex, Fractional > DenseRow
std::string GetProblemStatusString(ProblemStatus problem_status)
Index ColToIntIndex(ColIndex col)
constexpr double kInfinity
std::string GetConstraintStatusString(ConstraintStatus status)
ColIndex RowToColIndex(RowIndex row)
bool IsFinite(Fractional value)
constexpr RowIndex kInvalidRow(-1)
RowIndex ColToRowIndex(ColIndex col)
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
Fractional PartialScalarProduct(const DenseRowOrColumn &u, const SparseColumn &v, int max_index)
std::string GetVariableStatusString(VariableStatus status)
Index RowToIntIndex(RowIndex row)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Collection of objects used to extend the Constraint Solver library.
bool IsIntegerWithinTolerance(FloatType x, FloatType tolerance)
const std::optional< Range > & range
std::string DebugString() const
VariableStatusRow variable_statuses
ConstraintStatusColumn constraint_statuses
VectorXd variable_lower_bounds
VectorXd variable_upper_bounds
#define VLOG(verboselevel)