24 #include "absl/strings/str_cat.h"
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);
183 const int num_variables = mp_model->variable_size();
188 std::vector<double> max_bounds(num_variables);
189 for (
int i = 0; i < num_variables; ++i) {
190 double value = std::abs(mp_model->variable(i).lower_bound());
193 max_bounds[i] =
value;
201 int64 num_removed = 0;
202 double largest_removed = 0.0;
203 const int num_constraints = mp_model->constraint_size();
204 for (
int c = 0; c < num_constraints; ++c) {
205 MPConstraintProto*
ct = mp_model->mutable_constraint(c);
207 const int size =
ct->var_index().size();
208 if (size == 0)
continue;
209 const double threshold =
210 params.mip_wanted_precision() /
static_cast<double>(size);
211 for (
int i = 0; i < size; ++i) {
212 const int var =
ct->var_index(i);
213 const double coeff =
ct->coefficient(i);
214 if (std::abs(coeff) * max_bounds[
var] < threshold) {
215 largest_removed =
std::max(largest_removed, std::abs(coeff));
218 ct->set_var_index(new_size,
var);
219 ct->set_coefficient(new_size, coeff);
222 num_removed += size - new_size;
223 ct->mutable_var_index()->Truncate(new_size);
224 ct->mutable_coefficient()->Truncate(new_size);
227 const bool log_info =
VLOG_IS_ON(1) || params.log_search_progress();
228 if (log_info && num_removed > 0) {
229 LOG(
INFO) <<
"Removed " << num_removed
230 <<
" near zero terms with largest magnitude of "
231 << largest_removed <<
".";
236 MPModelProto* mp_model) {
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) {
440 for (
const double bound : {mp_model->variable(
var).lower_bound(),
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 (log_info && num_to_be_handled > 0) {
465 LOG(
INFO) <<
"Missed " << num_to_be_handled
466 <<
" potential implied integer.";
469 const int num_integers = initial_num_integers + num_detected;
470 LOG_IF(
INFO, log_info) <<
"Num integers: " << num_integers <<
"/"
471 << num_variables <<
" (implied: " << num_detected
472 <<
" in_inequalities: " << num_in_inequalities
473 <<
" max_scaling: " << max_scaling <<
")"
474 << (num_integers == num_variables ?
" [IP] "
477 ApplyVarScaling(var_scaling, mp_model);
484 struct ConstraintScaler {
486 ConstraintProto* AddConstraint(
const MPModelProto& mp_model,
487 const MPConstraintProto& mp_constraint,
488 CpModelProto* cp_model);
504 double FindFractionalScaling(
const std::vector<double>&
coefficients,
506 double multiplier = 1.0;
510 if (multiplier == 0.0)
break;
517 ConstraintProto* ConstraintScaler::AddConstraint(
518 const MPModelProto& mp_model,
const MPConstraintProto& mp_constraint,
519 CpModelProto* cp_model) {
520 if (mp_constraint.lower_bound() == -
kInfinity &&
521 mp_constraint.upper_bound() ==
kInfinity) {
525 auto* constraint = cp_model->add_constraints();
526 constraint->set_name(mp_constraint.name());
527 auto* arg = constraint->mutable_linear();
535 const int num_coeffs = mp_constraint.coefficient_size();
536 for (
int i = 0; i < num_coeffs; ++i) {
537 const auto& var_proto = cp_model->variables(mp_constraint.var_index(i));
538 const int64 lb = var_proto.domain(0);
539 const int64 ub = var_proto.domain(var_proto.domain_size() - 1);
540 if (lb == 0 && ub == 0)
continue;
542 const double coeff = mp_constraint.coefficient(i);
543 if (coeff == 0.0)
continue;
564 double x =
std::min(scaling_factor, 1.0);
565 double relative_coeff_error;
566 double scaled_sum_error;
567 for (; x <= scaling_factor; x *= 2) {
569 &relative_coeff_error, &scaled_sum_error);
579 const double integer_factor = FindFractionalScaling(
coefficients, 1e-8);
580 if (integer_factor != 0 && integer_factor < scaling_factor) {
582 &relative_coeff_error, &scaled_sum_error);
584 scaling_factor = integer_factor;
595 bool relax_bound = scaled_sum_error > 0;
598 const double scaled_value =
coefficients[i] * scaling_factor;
599 const int64 value =
static_cast<int64>(std::round(scaled_value)) / gcd;
601 if (!mp_model.variable(
var_indices[i]).is_integer()) {
605 arg->add_coeffs(
value);
617 const Fractional scaled_lb = std::ceil(lb * scaling_factor);
621 arg->add_domain(
CeilRatio(IntegerValue(
static_cast<int64>(scaled_lb)),
629 const Fractional scaled_ub = std::floor(ub * scaling_factor);
633 arg->add_domain(
FloorRatio(IntegerValue(
static_cast<int64>(scaled_ub)),
644 const MPModelProto& mp_model,
645 CpModelProto* cp_model) {
646 CHECK(cp_model !=
nullptr);
648 cp_model->set_name(mp_model.name());
662 const int64 kMaxVariableBound =
static_cast<int64>(params.mip_max_bound());
664 int num_truncated_bounds = 0;
665 int num_small_domains = 0;
666 const int64 kSmallDomainSize = 1000;
667 const double kWantedPrecision = params.mip_wanted_precision();
670 const int num_variables = mp_model.variable_size();
671 for (
int i = 0; i < num_variables; ++i) {
672 const MPVariableProto& mp_var = mp_model.variable(i);
673 IntegerVariableProto* cp_var = cp_model->add_variables();
674 cp_var->set_name(mp_var.name());
681 if (mp_var.lower_bound() > kMaxVariableBound) {
683 ++num_truncated_bounds;
684 const int64 value =
static_cast<int64>(std::round(mp_var.lower_bound()));
685 cp_var->add_domain(
value);
686 cp_var->add_domain(
value);
688 }
else if (mp_var.upper_bound() < -kMaxVariableBound) {
690 ++num_truncated_bounds;
691 const int64 value =
static_cast<int64>(std::round(mp_var.upper_bound()));
692 cp_var->add_domain(
value);
693 cp_var->add_domain(
value);
698 for (
const bool lower : {
true,
false}) {
699 const double bound = lower ? mp_var.lower_bound() : mp_var.upper_bound();
700 if (std::abs(
bound) >= kMaxVariableBound) {
701 ++num_truncated_bounds;
702 cp_var->add_domain(
bound < 0 ? -kMaxVariableBound : kMaxVariableBound);
708 static_cast<int64>(lower ? std::ceil(
bound - kWantedPrecision)
709 : std::floor(
bound + kWantedPrecision)));
712 if (cp_var->domain(0) > cp_var->domain(1)) {
713 LOG(
WARNING) <<
"Variable #" << i <<
" cannot take integer value. "
714 << mp_var.ShortDebugString();
720 if (!mp_var.is_integer() && cp_var->domain(0) != cp_var->domain(1) &&
721 cp_var->domain(1) - cp_var->domain(0) < kSmallDomainSize) {
727 << num_truncated_bounds <<
" bounds were truncated to "
728 << kMaxVariableBound <<
".";
730 << num_small_domains <<
" continuous variable domain with fewer than "
731 << kSmallDomainSize <<
" values.";
733 ConstraintScaler scaler;
734 const int64 kScalingTarget =
int64{1} << params.mip_max_activity_exponent();
735 scaler.wanted_precision = kWantedPrecision;
736 scaler.scaling_target = kScalingTarget;
739 for (
const MPConstraintProto& mp_constraint : mp_model.constraint()) {
740 scaler.AddConstraint(mp_model, mp_constraint, cp_model);
742 for (
const MPGeneralConstraintProto& general_constraint :
743 mp_model.general_constraint()) {
744 switch (general_constraint.general_constraint_case()) {
745 case MPGeneralConstraintProto::kIndicatorConstraint: {
746 const auto& indicator_constraint =
747 general_constraint.indicator_constraint();
748 const MPConstraintProto& mp_constraint =
749 indicator_constraint.constraint();
750 ConstraintProto*
ct =
751 scaler.AddConstraint(mp_model, mp_constraint, cp_model);
752 if (
ct ==
nullptr)
continue;
755 const int var = indicator_constraint.var_index();
756 const int value = indicator_constraint.var_value();
760 case MPGeneralConstraintProto::kAndConstraint: {
761 const auto& and_constraint = general_constraint.and_constraint();
762 const std::string&
name = general_constraint.name();
764 ConstraintProto* ct_pos = cp_model->add_constraints();
765 ct_pos->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_pos"));
766 ct_pos->add_enforcement_literal(and_constraint.resultant_var_index());
767 *ct_pos->mutable_bool_and()->mutable_literals() =
768 and_constraint.var_index();
770 ConstraintProto* ct_neg = cp_model->add_constraints();
771 ct_neg->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_neg"));
772 ct_neg->add_enforcement_literal(
773 NegatedRef(and_constraint.resultant_var_index()));
774 for (
const int var_index : and_constraint.var_index()) {
775 ct_neg->mutable_bool_or()->add_literals(
NegatedRef(var_index));
779 case MPGeneralConstraintProto::kOrConstraint: {
780 const auto& or_constraint = general_constraint.or_constraint();
781 const std::string&
name = general_constraint.name();
783 ConstraintProto* ct_pos = cp_model->add_constraints();
784 ct_pos->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_pos"));
785 ct_pos->add_enforcement_literal(or_constraint.resultant_var_index());
786 *ct_pos->mutable_bool_or()->mutable_literals() =
787 or_constraint.var_index();
789 ConstraintProto* ct_neg = cp_model->add_constraints();
790 ct_neg->set_name(
name.empty() ?
"" : absl::StrCat(
name,
"_neg"));
791 ct_neg->add_enforcement_literal(
792 NegatedRef(or_constraint.resultant_var_index()));
793 for (
const int var_index : or_constraint.var_index()) {
794 ct_neg->mutable_bool_and()->add_literals(
NegatedRef(var_index));
799 LOG(
ERROR) <<
"Can't convert general constraints of type "
800 << general_constraint.general_constraint_case()
801 <<
" to CpModelProto.";
807 const bool log_info =
VLOG_IS_ON(1) || params.log_search_progress();
808 LOG_IF(
INFO, log_info) <<
"Maximum constraint coefficient relative error: "
809 << scaler.max_relative_coeff_error;
811 <<
"Maximum constraint worst-case activity relative error: "
812 << scaler.max_relative_rhs_error
813 << (scaler.max_relative_rhs_error > params.mip_check_precision()
814 ?
" [Potentially IMPRECISE]"
816 LOG_IF(
INFO, log_info) <<
"Maximum constraint scaling factor: "
817 << scaler.max_scaling_factor;
824 double min_magnitude = std::numeric_limits<double>::infinity();
825 double max_magnitude = 0.0;
826 double l1_norm = 0.0;
827 for (
int i = 0; i < num_variables; ++i) {
828 const MPVariableProto& mp_var = mp_model.variable(i);
829 if (mp_var.objective_coefficient() == 0.0)
continue;
831 const auto& var_proto = cp_model->variables(i);
832 const int64 lb = var_proto.domain(0);
833 const int64 ub = var_proto.domain(var_proto.domain_size() - 1);
834 if (lb == 0 && ub == 0)
continue;
845 const double average_magnitude =
847 LOG_IF(
INFO, log_info) <<
"Objective magnitude in [" << min_magnitude
848 <<
", " << max_magnitude
849 <<
"] average = " << average_magnitude;
851 if (!
coefficients.empty() || mp_model.objective_offset() != 0.0) {
860 double x =
std::min(scaling_factor, 1.0);
861 double relative_coeff_error;
862 double scaled_sum_error;
863 for (; x <= scaling_factor; x *= 2) {
865 &relative_coeff_error, &scaled_sum_error);
866 if (scaled_sum_error < kWantedPrecision * x)
break;
872 const double integer_factor = FindFractionalScaling(
coefficients, 1e-8);
873 if (integer_factor != 0 && integer_factor < scaling_factor) {
875 &relative_coeff_error, &scaled_sum_error);
876 if (scaled_sum_error < kWantedPrecision * integer_factor) {
877 scaling_factor = integer_factor;
885 <<
"Objective coefficient relative error: " << relative_coeff_error
886 << (relative_coeff_error > params.mip_check_precision() ?
" [IMPRECISE]"
888 LOG_IF(
INFO, log_info) <<
"Objective worst-case absolute error: "
889 << scaled_sum_error / scaling_factor;
890 LOG_IF(
INFO, log_info) <<
"Objective scaling factor: "
891 << scaling_factor / gcd;
896 auto* objective = cp_model->mutable_objective();
897 const int mult = mp_model.maximize() ? -1 : 1;
898 objective->set_offset(mp_model.objective_offset() * scaling_factor / gcd *
900 objective->set_scaling_factor(1.0 / scaling_factor * gcd * mult);
907 objective->add_coeffs(
value * mult);
916 LinearBooleanProblem* problem) {
917 CHECK(problem !=
nullptr);
919 problem->set_name(mp_model.name());
920 const int num_variables = mp_model.variable_size();
921 problem->set_num_variables(num_variables);
925 for (
int var_id(0); var_id < num_variables; ++var_id) {
926 const MPVariableProto& mp_var = mp_model.variable(var_id);
927 problem->add_var_names(mp_var.name());
932 bool is_binary = mp_var.is_integer();
936 if (lb <= -1.0) is_binary =
false;
937 if (ub >= 2.0) is_binary =
false;
940 if (lb <= 0.0 && ub >= 1.0) {
942 }
else if (lb <= 1.0 && ub >= 1.0) {
944 LinearBooleanConstraint* constraint = problem->add_constraints();
945 constraint->set_lower_bound(1);
946 constraint->set_upper_bound(1);
947 constraint->add_literals(var_id + 1);
948 constraint->add_coefficients(1);
949 }
else if (lb <= 0.0 && ub >= 0.0) {
951 LinearBooleanConstraint* constraint = problem->add_constraints();
952 constraint->set_lower_bound(0);
953 constraint->set_upper_bound(0);
954 constraint->add_literals(var_id + 1);
955 constraint->add_coefficients(1);
964 LOG(
WARNING) <<
"The variable #" << var_id <<
" with name "
965 << mp_var.name() <<
" is not binary. "
966 <<
"lb: " << lb <<
" ub: " << ub;
973 double max_relative_error = 0.0;
974 double max_bound_error = 0.0;
976 double relative_error = 0.0;
977 double scaling_factor = 0.0;
981 for (
const MPConstraintProto& mp_constraint : mp_model.constraint()) {
982 LinearBooleanConstraint* constraint = problem->add_constraints();
983 constraint->set_name(mp_constraint.name());
987 const int num_coeffs = mp_constraint.coefficient_size();
988 for (
int i = 0; i < num_coeffs; ++i) {
994 max_relative_error =
std::max(relative_error, max_relative_error);
997 double bound_error = 0.0;
998 for (
int i = 0; i < num_coeffs; ++i) {
999 const double scaled_value = mp_constraint.coefficient(i) * scaling_factor;
1000 bound_error += std::abs(round(scaled_value) - scaled_value);
1003 constraint->add_literals(mp_constraint.var_index(i) + 1);
1004 constraint->add_coefficients(
value);
1007 max_bound_error =
std::max(max_bound_error, bound_error);
1014 const Fractional lb = mp_constraint.lower_bound();
1016 if (lb * scaling_factor >
static_cast<double>(kInt64Max)) {
1017 LOG(
WARNING) <<
"A constraint is trivially unsatisfiable.";
1020 if (lb * scaling_factor > -
static_cast<double>(kInt64Max)) {
1022 constraint->set_lower_bound(
1023 static_cast<int64>(round(lb * scaling_factor - bound_error)) / gcd);
1026 const Fractional ub = mp_constraint.upper_bound();
1028 if (ub * scaling_factor < -
static_cast<double>(kInt64Max)) {
1029 LOG(
WARNING) <<
"A constraint is trivially unsatisfiable.";
1032 if (ub * scaling_factor <
static_cast<double>(kInt64Max)) {
1034 constraint->set_upper_bound(
1035 static_cast<int64>(round(ub * scaling_factor + bound_error)) / gcd);
1041 LOG(
INFO) <<
"Maximum constraint relative error: " << max_relative_error;
1042 LOG(
INFO) <<
"Maximum constraint bound error: " << max_bound_error;
1047 for (
int var_id = 0; var_id < num_variables; ++var_id) {
1048 const MPVariableProto& mp_var = mp_model.variable(var_id);
1049 coefficients.push_back(mp_var.objective_coefficient());
1054 max_relative_error =
std::max(relative_error, max_relative_error);
1057 LOG(
INFO) <<
"objective relative error: " << relative_error;
1058 LOG(
INFO) <<
"objective scaling factor: " << scaling_factor / gcd;
1060 LinearObjective* objective = problem->mutable_objective();
1061 objective->set_offset(mp_model.objective_offset() * scaling_factor / gcd);
1065 objective->set_scaling_factor(1.0 / scaling_factor * gcd);
1066 for (
int var_id = 0; var_id < num_variables; ++var_id) {
1067 const MPVariableProto& mp_var = mp_model.variable(var_id);
1069 mp_var.objective_coefficient() * scaling_factor)) /
1072 objective->add_literals(var_id + 1);
1073 objective->add_coefficients(
value);
1081 const double kRelativeTolerance = 1e-8;
1082 if (max_relative_error > kRelativeTolerance) {
1083 LOG(
WARNING) <<
"The relative error during double -> int64 conversion "
1093 for (
int i = 0; i < problem.num_variables(); ++i) {
1100 if (problem.var_names_size() != 0) {
1101 CHECK_EQ(problem.var_names_size(), problem.num_variables());
1102 for (
int i = 0; i < problem.num_variables(); ++i) {
1107 for (
const LinearBooleanConstraint& constraint : problem.constraints()) {
1111 for (
int i = 0; i < constraint.literals_size(); ++i) {
1112 const int literal = constraint.literals(i);
1113 const double coeff = constraint.coefficients(i);
1114 const ColIndex variable_index = ColIndex(abs(
literal) - 1);
1124 constraint.has_lower_bound() ? constraint.lower_bound() - sum
1126 constraint.has_upper_bound() ? constraint.upper_bound() - sum
1133 const LinearObjective& objective = problem.objective();
1134 const double scaling_factor = objective.scaling_factor();
1135 for (
int i = 0; i < objective.literals_size(); ++i) {
1136 const int literal = objective.literals(i);
1137 const double coeff =
1138 static_cast<double>(objective.coefficients(i)) * scaling_factor;
1139 const ColIndex variable_index = ColIndex(abs(
literal) - 1);
1155 int num_fixed_variables = 0;
1157 for (
int i = 0; i < trail.
Index(); ++i) {
1158 const BooleanVariable
var = trail[i].Variable();
1159 const int value = trail[i].IsPositive() ? 1.0 : 0.0;
1161 ++num_fixed_variables;
1165 return num_fixed_variables;
1170 double max_time_in_seconds) {
1172 glop::GlopParameters glop_parameters;
1173 glop_parameters.set_max_time_in_seconds(max_time_in_seconds);
1178 status != glop::ProblemStatus::PRIMAL_FEASIBLE) {
1191 LinearBooleanProblem* problem) {
1195 status != glop::ProblemStatus::PRIMAL_FEASIBLE)
1197 int num_variable_fixed = 0;
1201 if (
value > 1 - tolerance) {
1202 ++num_variable_fixed;
1203 LinearBooleanConstraint* constraint = problem->add_constraints();
1204 constraint->set_lower_bound(1);
1205 constraint->set_upper_bound(1);
1206 constraint->add_coefficients(1);
1207 constraint->add_literals(
col.value() + 1);
1208 }
else if (
value < tolerance) {
1209 ++num_variable_fixed;
1210 LinearBooleanConstraint* constraint = problem->add_constraints();
1211 constraint->set_lower_bound(0);
1212 constraint->set_upper_bound(0);
1213 constraint->add_coefficients(1);
1214 constraint->add_literals(
col.value() + 1);
1217 LOG(
INFO) <<
"LNS with " << num_variable_fixed <<
" fixed variables.";