25 #include "absl/strings/str_cat.h"
46 using operations_research::MPConstraintProto;
47 using operations_research::MPModelProto;
48 using operations_research::MPVariableProto;
52 void ScaleConstraint(
const std::vector<double>& var_scaling,
53 MPConstraintProto* mp_constraint) {
54 const int num_terms = mp_constraint->coefficient_size();
55 for (
int i = 0; i < num_terms; ++i) {
56 const int var_index = mp_constraint->var_index(i);
57 mp_constraint->set_coefficient(
58 i, mp_constraint->coefficient(i) / var_scaling[var_index]);
62 void ApplyVarScaling(
const std::vector<double> var_scaling,
63 MPModelProto* mp_model) {
64 const int num_variables = mp_model->variable_size();
65 for (
int i = 0; i < num_variables; ++i) {
66 const double scaling = var_scaling[i];
67 const MPVariableProto& mp_var = mp_model->variable(i);
68 const double old_lb = mp_var.lower_bound();
69 const double old_ub = mp_var.upper_bound();
70 const double old_obj = mp_var.objective_coefficient();
71 mp_model->mutable_variable(i)->set_lower_bound(old_lb * scaling);
72 mp_model->mutable_variable(i)->set_upper_bound(old_ub * scaling);
73 mp_model->mutable_variable(i)->set_objective_coefficient(old_obj / scaling);
75 for (MPConstraintProto& mp_constraint : *mp_model->mutable_constraint()) {
76 ScaleConstraint(var_scaling, &mp_constraint);
78 for (MPGeneralConstraintProto& general_constraint :
79 *mp_model->mutable_general_constraint()) {
80 switch (general_constraint.general_constraint_case()) {
81 case MPGeneralConstraintProto::kIndicatorConstraint:
82 ScaleConstraint(var_scaling,
83 general_constraint.mutable_indicator_constraint()
84 ->mutable_constraint());
86 case MPGeneralConstraintProto::kAndConstraint:
87 case MPGeneralConstraintProto::kOrConstraint:
92 LOG(
FATAL) <<
"Scaling unsupported for general constraint of type "
93 << general_constraint.general_constraint_case();
101 MPModelProto* mp_model) {
102 const int num_variables = mp_model->variable_size();
103 std::vector<double> var_scaling(num_variables, 1.0);
104 for (
int i = 0; i < num_variables; ++i) {
105 if (mp_model->variable(i).is_integer())
continue;
106 const double lb = mp_model->variable(i).lower_bound();
107 const double ub = mp_model->variable(i).upper_bound();
108 const double magnitude =
std::max(std::abs(lb), std::abs(ub));
109 if (magnitude == 0 || magnitude > max_bound)
continue;
110 var_scaling[i] =
std::min(scaling, max_bound / magnitude);
112 ApplyVarScaling(var_scaling, mp_model);
120 const double initial_x = x;
126 if (std::abs(q * initial_x - std::round(q * initial_x)) < q * tolerance) {
130 const int new_q = prev_q +
static_cast<int>(std::floor(x)) * q;
144 double GetIntegralityMultiplier(
const MPModelProto& mp_model,
145 const std::vector<double>& var_scaling,
int var,
146 int ct_index,
double tolerance) {
147 DCHECK(!mp_model.variable(
var).is_integer());
148 const MPConstraintProto&
ct = mp_model.constraint(ct_index);
149 double multiplier = 1.0;
150 double var_coeff = 0.0;
151 const double max_multiplier = 1e4;
152 for (
int i = 0; i <
ct.var_index().size(); ++i) {
153 if (
var ==
ct.var_index(i)) {
154 var_coeff =
ct.coefficient(i);
158 DCHECK(mp_model.variable(
ct.var_index(i)).is_integer());
162 multiplier *
ct.coefficient(i) / var_scaling[
ct.var_index(i)];
165 if (multiplier == 0 || multiplier > max_multiplier)
return 0.0;
170 for (
const double bound : {
ct.lower_bound(),
ct.upper_bound()}) {
171 if (!std::isfinite(
bound))
continue;
172 if (std::abs(std::round(
bound * multiplier) -
bound * multiplier) >
173 tolerance * multiplier) {
177 return std::abs(multiplier * var_coeff);
184 const int num_variables = mp_model->variable_size();
189 std::vector<double> max_bounds(num_variables);
190 for (
int i = 0; i < num_variables; ++i) {
191 double value = std::abs(mp_model->variable(i).lower_bound());
194 max_bounds[i] =
value;
202 int64_t num_removed = 0;
203 double largest_removed = 0.0;
204 const int num_constraints = mp_model->constraint_size();
205 for (
int c = 0; c < num_constraints; ++c) {
206 MPConstraintProto*
ct = mp_model->mutable_constraint(c);
208 const int size =
ct->var_index().size();
209 if (size == 0)
continue;
210 const double threshold =
211 params.mip_wanted_precision() /
static_cast<double>(size);
212 for (
int i = 0; i < size; ++i) {
213 const int var =
ct->var_index(i);
214 const double coeff =
ct->coefficient(i);
215 if (std::abs(coeff) * max_bounds[
var] < threshold) {
216 largest_removed =
std::max(largest_removed, std::abs(coeff));
219 ct->set_var_index(new_size,
var);
220 ct->set_coefficient(new_size, coeff);
223 num_removed += size - new_size;
224 ct->mutable_var_index()->Truncate(new_size);
225 ct->mutable_coefficient()->Truncate(new_size);
228 if (num_removed > 0) {
230 " near zero terms with largest magnitude of ", largest_removed,
237 const int num_variables = mp_model->variable_size();
238 std::vector<double> var_scaling(num_variables, 1.0);
240 int initial_num_integers = 0;
241 for (
int i = 0; i < num_variables; ++i) {
242 if (mp_model->variable(i).is_integer()) ++initial_num_integers;
244 VLOG(1) <<
"Initial num integers: " << initial_num_integers;
247 const double tolerance = 1e-6;
248 std::vector<int> constraint_queue;
250 const int num_constraints = mp_model->constraint_size();
251 std::vector<int> constraint_to_num_non_integer(num_constraints, 0);
252 std::vector<std::vector<int>> var_to_constraints(num_variables);
253 for (
int i = 0; i < num_constraints; ++i) {
254 const MPConstraintProto& mp_constraint = mp_model->constraint(i);
256 for (
const int var : mp_constraint.var_index()) {
257 if (!mp_model->variable(
var).is_integer()) {
258 var_to_constraints[
var].push_back(i);
259 constraint_to_num_non_integer[i]++;
262 if (constraint_to_num_non_integer[i] == 1) {
263 constraint_queue.push_back(i);
266 VLOG(1) <<
"Initial constraint queue: " << constraint_queue.size() <<
" / "
269 int num_detected = 0;
270 double max_scaling = 0.0;
271 auto scale_and_mark_as_integer = [&](
int var,
double scaling)
mutable {
273 CHECK(!mp_model->variable(
var).is_integer());
275 if (scaling != 1.0) {
276 VLOG(2) <<
"Scaled " <<
var <<
" by " << scaling;
280 max_scaling =
std::max(max_scaling, scaling);
284 var_scaling[
var] = scaling;
285 mp_model->mutable_variable(
var)->set_is_integer(
true);
288 for (
const int ct_index : var_to_constraints[
var]) {
289 constraint_to_num_non_integer[ct_index]--;
290 if (constraint_to_num_non_integer[ct_index] == 1) {
291 constraint_queue.push_back(ct_index);
296 int num_fail_due_to_rhs = 0;
297 int num_fail_due_to_large_multiplier = 0;
298 int num_processed_constraints = 0;
299 while (!constraint_queue.empty()) {
300 const int top_ct_index = constraint_queue.back();
301 constraint_queue.pop_back();
305 if (constraint_to_num_non_integer[top_ct_index] == 0)
continue;
308 const MPConstraintProto&
ct = mp_model->constraint(top_ct_index);
309 if (
ct.lower_bound() + tolerance <
ct.upper_bound())
continue;
311 ++num_processed_constraints;
323 double multiplier = 1.0;
324 const double max_multiplier = 1e4;
326 for (
int i = 0; i <
ct.var_index().size(); ++i) {
327 if (!mp_model->variable(
ct.var_index(i)).is_integer()) {
329 var =
ct.var_index(i);
330 var_coeff =
ct.coefficient(i);
335 multiplier *
ct.coefficient(i) / var_scaling[
ct.var_index(i)];
338 if (multiplier == 0 || multiplier > max_multiplier) {
344 if (multiplier == 0 || multiplier > max_multiplier) {
345 ++num_fail_due_to_large_multiplier;
350 const double rhs =
ct.lower_bound();
351 if (std::abs(std::round(rhs * multiplier) - rhs * multiplier) >
352 tolerance * multiplier) {
353 ++num_fail_due_to_rhs;
363 double best_scaling = std::abs(var_coeff * multiplier);
364 for (
const int ct_index : var_to_constraints[
var]) {
365 if (ct_index == top_ct_index)
continue;
366 if (constraint_to_num_non_integer[ct_index] != 1)
continue;
369 const MPConstraintProto&
ct = mp_model->constraint(top_ct_index);
370 if (
ct.lower_bound() + tolerance <
ct.upper_bound())
continue;
372 const double multiplier = GetIntegralityMultiplier(
373 *mp_model, var_scaling,
var, ct_index, tolerance);
374 if (multiplier != 0.0 && multiplier < best_scaling) {
375 best_scaling = multiplier;
379 scale_and_mark_as_integer(
var, best_scaling);
387 int num_in_inequalities = 0;
388 int num_to_be_handled = 0;
389 for (
int var = 0;
var < num_variables; ++
var) {
390 if (mp_model->variable(
var).is_integer())
continue;
393 if (var_to_constraints[
var].empty())
continue;
396 for (
const int ct_index : var_to_constraints[
var]) {
397 if (constraint_to_num_non_integer[ct_index] != 1) {
404 std::vector<double> scaled_coeffs;
405 for (
const int ct_index : var_to_constraints[
var]) {
406 const double multiplier = GetIntegralityMultiplier(
407 *mp_model, var_scaling,
var, ct_index, tolerance);
408 if (multiplier == 0.0) {
412 scaled_coeffs.push_back(multiplier);
421 double scaling = scaled_coeffs[0];
422 for (
const double c : scaled_coeffs) {
426 for (
const double c : scaled_coeffs) {
427 const double fraction = c / scaling;
428 if (std::abs(std::round(fraction) - fraction) > tolerance) {
441 mp_model->variable(
var).upper_bound()}) {
442 if (!std::isfinite(
bound))
continue;
443 if (std::abs(std::round(
bound * scaling) -
bound * scaling) >
444 tolerance * scaling) {
456 ++num_in_inequalities;
457 scale_and_mark_as_integer(
var, scaling);
459 VLOG(1) <<
"num_new_integer: " << num_detected
460 <<
" num_processed_constraints: " << num_processed_constraints
461 <<
" num_rhs_fail: " << num_fail_due_to_rhs
462 <<
" num_multiplier_fail: " << num_fail_due_to_large_multiplier;
464 if (num_to_be_handled > 0) {
465 SOLVER_LOG(logger,
"Missed ", num_to_be_handled,
466 " potential implied integer.");
469 const int num_integers = initial_num_integers + num_detected;
470 SOLVER_LOG(logger,
"Num integers: ", num_integers,
"/", num_variables,
471 " (implied: ", num_detected,
472 " in_inequalities: ", num_in_inequalities,
473 " max_scaling: ", max_scaling,
")",
474 (num_integers == num_variables ?
" [IP] " :
" [MIP] "));
476 ApplyVarScaling(var_scaling, mp_model);
483 struct ConstraintScaler {
485 ConstraintProto* AddConstraint(
const MPModelProto& mp_model,
486 const MPConstraintProto& mp_constraint,
487 CpModelProto* cp_model);
503 double FindFractionalScaling(
const std::vector<double>&
coefficients,
505 double multiplier = 1.0;
509 if (multiplier == 0.0)
break;
516 ConstraintProto* ConstraintScaler::AddConstraint(
517 const MPModelProto& mp_model,
const MPConstraintProto& mp_constraint,
518 CpModelProto* cp_model) {
519 if (mp_constraint.lower_bound() == -
kInfinity &&
520 mp_constraint.upper_bound() ==
kInfinity) {
524 auto* constraint = cp_model->add_constraints();
525 constraint->set_name(mp_constraint.name());
526 auto* arg = constraint->mutable_linear();
534 const int num_coeffs = mp_constraint.coefficient_size();
535 for (
int i = 0; i < num_coeffs; ++i) {
536 const auto& var_proto = cp_model->variables(mp_constraint.var_index(i));
537 const int64_t lb = var_proto.domain(0);
538 const int64_t ub = var_proto.domain(var_proto.domain_size() - 1);
539 if (lb == 0 && ub == 0)
continue;
541 const double coeff = mp_constraint.coefficient(i);
542 if (coeff == 0.0)
continue;
563 double x =
std::min(scaling_factor, 1.0);
564 double relative_coeff_error;
565 double scaled_sum_error;
566 for (; x <= scaling_factor; x *= 2) {
568 &relative_coeff_error, &scaled_sum_error);
578 const double integer_factor = FindFractionalScaling(
coefficients, 1e-8);
579 if (integer_factor != 0 && integer_factor < scaling_factor) {
581 &relative_coeff_error, &scaled_sum_error);
583 scaling_factor = integer_factor;
594 bool relax_bound = scaled_sum_error > 0;
597 const double scaled_value =
coefficients[i] * scaling_factor;
598 const int64_t
value =
static_cast<int64_t
>(std::round(scaled_value)) / gcd;
600 if (!mp_model.variable(
var_indices[i]).is_integer()) {
604 arg->add_coeffs(
value);
616 const Fractional scaled_lb = std::ceil(lb * scaling_factor);
620 arg->add_domain(
CeilRatio(IntegerValue(
static_cast<int64_t
>(scaled_lb)),
628 const Fractional scaled_ub = std::floor(ub * scaling_factor);
632 arg->add_domain(
FloorRatio(IntegerValue(
static_cast<int64_t
>(scaled_ub)),
643 const MPModelProto& mp_model,
644 CpModelProto* cp_model,
646 CHECK(cp_model !=
nullptr);
648 cp_model->set_name(mp_model.name());
662 const int64_t kMaxVariableBound =
663 static_cast<int64_t
>(params.mip_max_bound());
665 int num_truncated_bounds = 0;
666 int num_small_domains = 0;
667 const int64_t kSmallDomainSize = 1000;
668 const double kWantedPrecision = params.mip_wanted_precision();
671 const int num_variables = mp_model.variable_size();
672 for (
int i = 0; i < num_variables; ++i) {
673 const MPVariableProto& mp_var = mp_model.variable(i);
674 IntegerVariableProto* cp_var = cp_model->add_variables();
675 cp_var->set_name(mp_var.name());
682 if (mp_var.lower_bound() > kMaxVariableBound) {
684 ++num_truncated_bounds;
685 const int64_t
value =
686 static_cast<int64_t
>(std::round(mp_var.lower_bound()));
687 cp_var->add_domain(
value);
688 cp_var->add_domain(
value);
690 }
else if (mp_var.upper_bound() < -kMaxVariableBound) {
692 ++num_truncated_bounds;
693 const int64_t
value =
694 static_cast<int64_t
>(std::round(mp_var.upper_bound()));
695 cp_var->add_domain(
value);
696 cp_var->add_domain(
value);
701 for (
const bool lower : {
true,
false}) {
702 const double bound = lower ? mp_var.lower_bound() : mp_var.upper_bound();
703 if (std::abs(
bound) >= kMaxVariableBound) {
704 ++num_truncated_bounds;
705 cp_var->add_domain(
bound < 0 ? -kMaxVariableBound : kMaxVariableBound);
711 static_cast<int64_t
>(lower ? std::ceil(
bound - kWantedPrecision)
712 : std::floor(
bound + kWantedPrecision)));
715 if (cp_var->domain(0) > cp_var->domain(1)) {
716 LOG(
WARNING) <<
"Variable #" << i <<
" cannot take integer value. "
717 << mp_var.ShortDebugString();
723 if (!mp_var.is_integer() && cp_var->domain(0) != cp_var->domain(1) &&
724 cp_var->domain(1) - cp_var->domain(0) < kSmallDomainSize) {
730 << num_truncated_bounds <<
" bounds were truncated to "
731 << kMaxVariableBound <<
".";
733 << num_small_domains <<
" continuous variable domain with fewer than "
734 << kSmallDomainSize <<
" values.";
736 ConstraintScaler scaler;
737 const int64_t kScalingTarget = int64_t{1}
738 << params.mip_max_activity_exponent();
739 scaler.wanted_precision = kWantedPrecision;
740 scaler.scaling_target = kScalingTarget;
743 for (
const MPConstraintProto& mp_constraint : mp_model.constraint()) {
744 scaler.AddConstraint(mp_model, mp_constraint, cp_model);
746 for (
const MPGeneralConstraintProto& general_constraint :
747 mp_model.general_constraint()) {
748 switch (general_constraint.general_constraint_case()) {
749 case MPGeneralConstraintProto::kIndicatorConstraint: {
750 const auto& indicator_constraint =
751 general_constraint.indicator_constraint();
752 const MPConstraintProto& mp_constraint =
753 indicator_constraint.constraint();
754 ConstraintProto*
ct =
755 scaler.AddConstraint(mp_model, mp_constraint, cp_model);
756 if (
ct ==
nullptr)
continue;
759 const int var = indicator_constraint.var_index();
760 const int value = indicator_constraint.var_value();
764 case MPGeneralConstraintProto::kAndConstraint: {
765 const auto& and_constraint = general_constraint.and_constraint();
766 const std::string&
name = general_constraint.name();
768 ConstraintProto* ct_pos = cp_model->add_constraints();
769 ct_pos->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_pos"));
770 ct_pos->add_enforcement_literal(and_constraint.resultant_var_index());
771 *ct_pos->mutable_bool_and()->mutable_literals() =
772 and_constraint.var_index();
774 ConstraintProto* ct_neg = cp_model->add_constraints();
775 ct_neg->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_neg"));
776 ct_neg->add_enforcement_literal(
777 NegatedRef(and_constraint.resultant_var_index()));
778 for (
const int var_index : and_constraint.var_index()) {
779 ct_neg->mutable_bool_or()->add_literals(
NegatedRef(var_index));
783 case MPGeneralConstraintProto::kOrConstraint: {
784 const auto& or_constraint = general_constraint.or_constraint();
785 const std::string&
name = general_constraint.name();
787 ConstraintProto* ct_pos = cp_model->add_constraints();
788 ct_pos->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_pos"));
789 ct_pos->add_enforcement_literal(or_constraint.resultant_var_index());
790 *ct_pos->mutable_bool_or()->mutable_literals() =
791 or_constraint.var_index();
793 ConstraintProto* ct_neg = cp_model->add_constraints();
794 ct_neg->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_neg"));
795 ct_neg->add_enforcement_literal(
796 NegatedRef(or_constraint.resultant_var_index()));
797 for (
const int var_index : or_constraint.var_index()) {
798 ct_neg->mutable_bool_and()->add_literals(
NegatedRef(var_index));
803 LOG(
ERROR) <<
"Can't convert general constraints of type "
804 << general_constraint.general_constraint_case()
805 <<
" to CpModelProto.";
811 SOLVER_LOG(logger,
"Maximum constraint coefficient relative error: ",
812 scaler.max_relative_coeff_error);
813 SOLVER_LOG(logger,
"Maximum constraint worst-case activity relative error: ",
814 scaler.max_relative_rhs_error,
815 (scaler.max_relative_rhs_error > params.mip_check_precision()
816 ?
" [Potentially IMPRECISE]"
819 "Maximum constraint scaling factor: ", scaler.max_scaling_factor);
826 double min_magnitude = std::numeric_limits<double>::infinity();
827 double max_magnitude = 0.0;
828 double l1_norm = 0.0;
829 for (
int i = 0; i < num_variables; ++i) {
830 const MPVariableProto& mp_var = mp_model.variable(i);
831 if (mp_var.objective_coefficient() == 0.0)
continue;
833 const auto& var_proto = cp_model->variables(i);
834 const int64_t lb = var_proto.domain(0);
835 const int64_t ub = var_proto.domain(var_proto.domain_size() - 1);
836 if (lb == 0 && ub == 0)
continue;
847 const double average_magnitude =
849 SOLVER_LOG(logger,
"Objective magnitude in [", min_magnitude,
", ",
850 max_magnitude,
"] average = ", average_magnitude);
852 if (!
coefficients.empty() || mp_model.objective_offset() != 0.0) {
861 double x =
std::min(scaling_factor, 1.0);
862 double relative_coeff_error;
863 double scaled_sum_error;
864 for (; x <= scaling_factor; x *= 2) {
866 &relative_coeff_error, &scaled_sum_error);
867 if (scaled_sum_error < kWantedPrecision * x)
break;
873 const double integer_factor = FindFractionalScaling(
coefficients, 1e-8);
874 if (integer_factor != 0 && integer_factor < scaling_factor) {
876 &relative_coeff_error, &scaled_sum_error);
877 if (scaled_sum_error < kWantedPrecision * integer_factor) {
878 scaling_factor = integer_factor;
887 logger,
"Objective coefficient relative error: ", relative_coeff_error,
888 (relative_coeff_error > params.mip_check_precision() ?
" [IMPRECISE]"
890 SOLVER_LOG(logger,
"Objective worst-case absolute error: ",
891 scaled_sum_error / scaling_factor);
892 SOLVER_LOG(logger,
"Objective scaling factor: ", scaling_factor / gcd);
897 auto* objective = cp_model->mutable_objective();
898 const int mult = mp_model.maximize() ? -1 : 1;
899 objective->set_offset(mp_model.objective_offset() * scaling_factor / gcd *
901 objective->set_scaling_factor(1.0 / scaling_factor * gcd * mult);
903 const int64_t
value =
904 static_cast<int64_t
>(std::round(
coefficients[i] * scaling_factor)) /
908 objective->add_coeffs(
value * mult);
917 LinearBooleanProblem* problem) {
918 CHECK(problem !=
nullptr);
920 problem->set_name(mp_model.name());
921 const int num_variables = mp_model.variable_size();
922 problem->set_num_variables(num_variables);
926 for (
int var_id(0); var_id < num_variables; ++var_id) {
927 const MPVariableProto& mp_var = mp_model.variable(var_id);
928 problem->add_var_names(mp_var.name());
933 bool is_binary = mp_var.is_integer();
937 if (lb <= -1.0) is_binary =
false;
938 if (ub >= 2.0) is_binary =
false;
941 if (lb <= 0.0 && ub >= 1.0) {
943 }
else if (lb <= 1.0 && ub >= 1.0) {
945 LinearBooleanConstraint* constraint = problem->add_constraints();
946 constraint->set_lower_bound(1);
947 constraint->set_upper_bound(1);
948 constraint->add_literals(var_id + 1);
949 constraint->add_coefficients(1);
950 }
else if (lb <= 0.0 && ub >= 0.0) {
952 LinearBooleanConstraint* constraint = problem->add_constraints();
953 constraint->set_lower_bound(0);
954 constraint->set_upper_bound(0);
955 constraint->add_literals(var_id + 1);
956 constraint->add_coefficients(1);
965 LOG(
WARNING) <<
"The variable #" << var_id <<
" with name "
966 << mp_var.name() <<
" is not binary. "
967 <<
"lb: " << lb <<
" ub: " << ub;
974 double max_relative_error = 0.0;
975 double max_bound_error = 0.0;
977 double relative_error = 0.0;
978 double scaling_factor = 0.0;
982 for (
const MPConstraintProto& mp_constraint : mp_model.constraint()) {
983 LinearBooleanConstraint* constraint = problem->add_constraints();
984 constraint->set_name(mp_constraint.name());
988 const int num_coeffs = mp_constraint.coefficient_size();
989 for (
int i = 0; i < num_coeffs; ++i) {
996 max_relative_error =
std::max(relative_error, max_relative_error);
999 double bound_error = 0.0;
1000 for (
int i = 0; i < num_coeffs; ++i) {
1001 const double scaled_value = mp_constraint.coefficient(i) * scaling_factor;
1002 bound_error += std::abs(round(scaled_value) - scaled_value);
1003 const int64_t
value =
static_cast<int64_t
>(round(scaled_value)) / gcd;
1005 constraint->add_literals(mp_constraint.var_index(i) + 1);
1006 constraint->add_coefficients(
value);
1009 max_bound_error =
std::max(max_bound_error, bound_error);
1016 const Fractional lb = mp_constraint.lower_bound();
1018 if (lb * scaling_factor >
static_cast<double>(kInt64Max)) {
1019 LOG(
WARNING) <<
"A constraint is trivially unsatisfiable.";
1022 if (lb * scaling_factor > -
static_cast<double>(kInt64Max)) {
1024 constraint->set_lower_bound(
1025 static_cast<int64_t
>(round(lb * scaling_factor - bound_error)) /
1029 const Fractional ub = mp_constraint.upper_bound();
1031 if (ub * scaling_factor < -
static_cast<double>(kInt64Max)) {
1032 LOG(
WARNING) <<
"A constraint is trivially unsatisfiable.";
1035 if (ub * scaling_factor <
static_cast<double>(kInt64Max)) {
1037 constraint->set_upper_bound(
1038 static_cast<int64_t
>(round(ub * scaling_factor + bound_error)) /
1045 LOG(
INFO) <<
"Maximum constraint relative error: " << max_relative_error;
1046 LOG(
INFO) <<
"Maximum constraint bound error: " << max_bound_error;
1051 for (
int var_id = 0; var_id < num_variables; ++var_id) {
1052 const MPVariableProto& mp_var = mp_model.variable(var_id);
1053 coefficients.push_back(mp_var.objective_coefficient());
1058 max_relative_error =
std::max(relative_error, max_relative_error);
1061 LOG(
INFO) <<
"objective relative error: " << relative_error;
1062 LOG(
INFO) <<
"objective scaling factor: " << scaling_factor / gcd;
1064 LinearObjective* objective = problem->mutable_objective();
1065 objective->set_offset(mp_model.objective_offset() * scaling_factor / gcd);
1069 objective->set_scaling_factor(1.0 / scaling_factor * gcd);
1070 for (
int var_id = 0; var_id < num_variables; ++var_id) {
1071 const MPVariableProto& mp_var = mp_model.variable(var_id);
1072 const int64_t
value =
1073 static_cast<int64_t
>(
1074 round(mp_var.objective_coefficient() * scaling_factor)) /
1077 objective->add_literals(var_id + 1);
1078 objective->add_coefficients(
value);
1086 const double kRelativeTolerance = 1e-8;
1087 if (max_relative_error > kRelativeTolerance) {
1088 LOG(
WARNING) <<
"The relative error during double -> int64_t conversion "
1098 for (
int i = 0; i < problem.num_variables(); ++i) {
1105 if (problem.var_names_size() != 0) {
1106 CHECK_EQ(problem.var_names_size(), problem.num_variables());
1107 for (
int i = 0; i < problem.num_variables(); ++i) {
1112 for (
const LinearBooleanConstraint& constraint : problem.constraints()) {
1116 for (
int i = 0; i < constraint.literals_size(); ++i) {
1117 const int literal = constraint.literals(i);
1118 const double coeff = constraint.coefficients(i);
1119 const ColIndex variable_index = ColIndex(abs(
literal) - 1);
1129 constraint.has_lower_bound() ? constraint.lower_bound() - sum
1131 constraint.has_upper_bound() ? constraint.upper_bound() - sum
1138 const LinearObjective& objective = problem.objective();
1139 const double scaling_factor = objective.scaling_factor();
1140 for (
int i = 0; i < objective.literals_size(); ++i) {
1141 const int literal = objective.literals(i);
1142 const double coeff =
1143 static_cast<double>(objective.coefficients(i)) * scaling_factor;
1144 const ColIndex variable_index = ColIndex(abs(
literal) - 1);
1160 int num_fixed_variables = 0;
1162 for (
int i = 0; i < trail.
Index(); ++i) {
1163 const BooleanVariable
var = trail[i].Variable();
1164 const int value = trail[i].IsPositive() ? 1.0 : 0.0;
1166 ++num_fixed_variables;
1170 return num_fixed_variables;
1175 double max_time_in_seconds) {
1177 glop::GlopParameters glop_parameters;
1178 glop_parameters.set_max_time_in_seconds(max_time_in_seconds);
1196 LinearBooleanProblem* problem) {
1202 int num_variable_fixed = 0;
1206 if (
value > 1 - tolerance) {
1207 ++num_variable_fixed;
1208 LinearBooleanConstraint* constraint = problem->add_constraints();
1209 constraint->set_lower_bound(1);
1210 constraint->set_upper_bound(1);
1211 constraint->add_coefficients(1);
1212 constraint->add_literals(
col.value() + 1);
1213 }
else if (
value < tolerance) {
1214 ++num_variable_fixed;
1215 LinearBooleanConstraint* constraint = problem->add_constraints();
1216 constraint->set_lower_bound(0);
1217 constraint->set_upper_bound(0);
1218 constraint->add_coefficients(1);
1219 constraint->add_literals(
col.value() + 1);
1222 LOG(
INFO) <<
"LNS with " << num_variable_fixed <<
" fixed variables.";
#define LOG_IF(severity, condition)
#define DCHECK_NE(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GT(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
const DenseRow & variable_values() const
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
void SetParameters(const GlopParameters ¶meters)
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
void SetConstraintName(RowIndex row, absl::string_view name)
void SetObjectiveOffset(Fractional objective_offset)
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
void SetVariableName(ColIndex col, absl::string_view name)
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
ColIndex CreateNewVariable()
void SetVariableType(ColIndex col, VariableType type)
void SetObjectiveCoefficient(ColIndex col, Fractional value)
ColIndex num_variables() const
RowIndex CreateNewConstraint()
void SetMaximizationProblem(bool maximize)
const Trail & LiteralTrail() const
void SetAssignmentPreference(Literal literal, double weight)
const AssignmentInfo & Info(BooleanVariable var) const
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
bool SolveLpAndUseSolutionForSatAssignmentPreference(const glop::LinearProgram &lp, SatSolver *sat_solver, double max_time_in_seconds)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
void ConvertBooleanProblemToLinearProgram(const LinearBooleanProblem &problem, glop::LinearProgram *lp)
bool ConvertBinaryMPModelProtoToBooleanProblem(const MPModelProto &mp_model, LinearBooleanProblem *problem)
void RemoveNearZeroTerms(const SatParameters ¶ms, MPModelProto *mp_model, SolverLogger *logger)
bool ConvertMPModelProtoToCpModelProto(const SatParameters ¶ms, const MPModelProto &mp_model, CpModelProto *cp_model, SolverLogger *logger)
bool SolveLpAndUseIntegerVariableToStartLNS(const glop::LinearProgram &lp, LinearBooleanProblem *problem)
void ChangeOptimizationDirection(LinearBooleanProblem *problem)
int FixVariablesFromSat(const SatSolver &solver, glop::LinearProgram *lp)
std::vector< double > ScaleContinuousVariables(double scaling, double max_bound, MPModelProto *mp_model)
std::vector< double > DetectImpliedIntegers(MPModelProto *mp_model, SolverLogger *logger)
int FindRationalFactor(double x, int limit, double tolerance)
Collection of objects used to extend the Constraint Solver library.
void ComputeScalingErrors(const std::vector< double > &input, const std::vector< double > &lb, const std::vector< double > &ub, double scaling_factor, double *max_relative_coeff_error, double *max_scaled_sum_error)
int64_t ComputeGcdOfRoundedDoubles(const std::vector< double > &x, double scaling_factor)
double GetBestScalingOfDoublesToInt64(const std::vector< double > &input, const std::vector< double > &lb, const std::vector< double > &ub, int64_t max_absolute_sum)
double max_scaling_factor
double max_relative_coeff_error
std::vector< double > lower_bounds
std::vector< int > var_indices
std::vector< double > upper_bounds
std::vector< double > coefficients
double max_relative_rhs_error
#define SOLVER_LOG(logger,...)