fix degeneracy data

This commit is contained in:
Laurent Perron
2019-05-05 18:02:49 +02:00
parent c1e61773b6
commit 0490fe5337
5 changed files with 76 additions and 80 deletions

View File

@@ -126,5 +126,6 @@
"editor.tabSize": 4,
},
"java.configuration.updateBuildConfiguration": "interactive",
"maven.view": "hierarchical",
}
}

View File

@@ -340,7 +340,7 @@ bool LinearProgrammingConstraint::SolveLp() {
simplex_.ClearStateForNextSolve();
return false;
}
UpdateDegeneracyData();
average_degeneracy_.AddData(CalculateDegeneracy());
if (average_degeneracy_.CurrentAverage() >= 1000.0) {
VLOG(1) << "High average degeneracy: "
<< average_degeneracy_.CurrentAverage();
@@ -1332,19 +1332,18 @@ void LinearProgrammingConstraint::FillReducedCostsReason() {
integer_trail_->RemoveLevelZeroBounds(&integer_reason_);
}
void LinearProgrammingConstraint::UpdateDegeneracyData() {
const int num_vars = integer_variables_.size();
int64 LinearProgrammingConstraint::CalculateDegeneracy() const {
const glop::ColIndex num_vars = simplex_.GetProblemNumCols();
int num_non_basic_with_zero_rc = 0;
for (int i = 0; i < num_vars; i++) {
const double rc = simplex_.GetReducedCost(glop::ColIndex(i));
for (glop::ColIndex i(0); i < num_vars; ++i) {
const double rc = simplex_.GetReducedCost(i);
if (rc != 0.0) continue;
if (simplex_.GetVariableStatus(glop::ColIndex(i)) ==
glop::VariableStatus::BASIC) {
if (simplex_.GetVariableStatus(i) == glop::VariableStatus::BASIC) {
continue;
}
num_non_basic_with_zero_rc++;
}
average_degeneracy_.AddData(num_non_basic_with_zero_rc);
return num_non_basic_with_zero_rc;
}
void LinearProgrammingConstraint::FillDualRayReason() {

View File

@@ -203,9 +203,8 @@ class LinearProgrammingConstraint : public PropagatorInterface,
// computations, true otherwise.
bool FillExactDualRayReason();
// Computes number of non basic variables with zero reduced costs and updates
// 'average_degeneracy_'.
void UpdateDegeneracyData();
// Returns number of non basic variables with zero reduced costs.
int64 CalculateDegeneracy() const;
// From a set of row multipliers (at LP scale), scale them back to the CP
// world and then make them integer (eventually multiplying them by a new

View File

@@ -286,78 +286,20 @@ void TryToLinearizeConstraint(const CpModelProto& model_proto,
relaxation->at_most_ones.push_back(at_most_one);
} else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMax) {
if (HasEnforcementLiteral(ct)) return;
// Case X = max(X_1, X_2, ..., X_N)
// Part 1: Encode X >= max(X_1, X_2, ..., X_N)
const int target = ct.int_max().target();
for (const int var : ct.int_max().vars()) {
// This deal with the corner case X = max(X, Y, Z, ..) !
// Note that this can be presolved into X >= Y, X >= Z, ...
if (target == var) continue;
LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
lc.AddTerm(mapping->Integer(var), IntegerValue(1));
lc.AddTerm(mapping->Integer(target), IntegerValue(-1));
relaxation->linear_constraints.push_back(lc.Build());
}
const IntegerVariable target = mapping->Integer(ct.int_max().target());
const std::vector<IntegerVariable> vars =
mapping->Integers(ct.int_max().vars());
AppendMaxRelaxation(target, vars, linearization_level, model, relaxation);
// TODO(user): Check the coefficient of target in the objective to avoid
// the second part.
// Part 2: Encode upper bound on X.
// NOTE(user) for size = 2, we can do this with 1 less variable.
if (ct.int_max().vars_size() == 2 || linearization_level >= 2) {
const int positive_target = PositiveRef(target);
// TODO(user): We can get tighter bound on max target value by going
// through all the constraint vars.
const int64 max_target_value =
RefIsPositive(target)
? model_proto.variables(positive_target)
.domain(
model_proto.variables(positive_target).domain_size() -
1)
: -model_proto.variables(positive_target).domain(0);
// For each X_i, we encode y_i => X <= X_i. And at least one of the y_i
// is true. Note that the correct y_i will be chosen because of the first
// part in linearlization (X >= X_i).
// TODO(user): Only lower bound is needed, experiment.
LinearConstraintBuilder lc_exactly_one(model, IntegerValue(1),
IntegerValue(1));
for (const int var : ct.int_max().vars()) {
if (target == var) continue;
// y => X <= X_i.
// <=> max_term_value * y + X - X_i <= max_term_value.
// where max_tern_value is X_ub - X_i_lb.
IntegerVariable y = model->Add(NewIntegerVariable(0, 1));
const int positive_var = PositiveRef(var);
const int64 min_var_value =
RefIsPositive(var)
? model_proto.variables(positive_var).domain(0)
: -model_proto.variables(positive_var)
.domain(
model_proto.variables(positive_var).domain_size() -
1);
int64 max_term_value = max_target_value - min_var_value;
LinearConstraintBuilder lc(model, kMinIntegerValue,
IntegerValue(max_term_value));
lc.AddTerm(mapping->Integer(target), IntegerValue(1));
lc.AddTerm(mapping->Integer(var), IntegerValue(-1));
lc.AddTerm(y, IntegerValue(max_term_value));
relaxation->linear_constraints.push_back(lc.Build());
lc_exactly_one.AddTerm(y, IntegerValue(1));
}
relaxation->linear_constraints.push_back(lc_exactly_one.Build());
}
} else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMin) {
if (HasEnforcementLiteral(ct)) return;
const int target = ct.int_min().target();
for (const int var : ct.int_min().vars()) {
if (target == var) continue;
LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
lc.AddTerm(mapping->Integer(target), IntegerValue(1));
lc.AddTerm(mapping->Integer(var), IntegerValue(-1));
relaxation->linear_constraints.push_back(lc.Build());
}
const IntegerVariable negative_target =
NegationOf(mapping->Integer(ct.int_min().target()));
const std::vector<IntegerVariable> negative_vars =
NegationOf(mapping->Integers(ct.int_min().vars()));
AppendMaxRelaxation(negative_target, negative_vars, linearization_level,
model, relaxation);
} else if (ct.constraint_case() ==
ConstraintProto::ConstraintCase::kIntProd) {
if (HasEnforcementLiteral(ct)) return;
@@ -441,6 +383,54 @@ void TryToLinearizeConstraint(const CpModelProto& model_proto,
}
}
void AppendMaxRelaxation(IntegerVariable target,
const std::vector<IntegerVariable>& vars,
int linearization_level, Model* model,
LinearRelaxation* relaxation) {
// Case X = max(X_1, X_2, ..., X_N)
// Part 1: Encode X >= max(X_1, X_2, ..., X_N)
for (const IntegerVariable var : vars) {
// This deal with the corner case X = max(X, Y, Z, ..) !
// Note that this can be presolved into X >= Y, X >= Z, ...
if (target == var) continue;
LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
lc.AddTerm(var, IntegerValue(1));
lc.AddTerm(target, IntegerValue(-1));
relaxation->linear_constraints.push_back(lc.Build());
}
// Part 2: Encode upper bound on X.
// NOTE(user) for size = 2, we can do this with 1 less variable.
if (vars.size() == 2 || linearization_level >= 2) {
IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
const IntegerValue max_target_value = integer_trail->UpperBound(target);
// For each X_i, we encode y_i => X <= X_i. And at least one of the y_i
// is true. Note that the correct y_i will be chosen because of the first
// part in linearlization (X >= X_i).
// TODO(user): Only lower bound is needed, experiment.
LinearConstraintBuilder lc_exactly_one(model, IntegerValue(1),
IntegerValue(1));
for (const IntegerVariable var : vars) {
if (target == var) continue;
// y => X <= X_i.
// <=> max_term_value * y + X - X_i <= max_term_value.
// where max_tern_value is X_ub - X_i_lb.
IntegerVariable y = model->Add(NewIntegerVariable(0, 1));
const IntegerValue min_var_value = integer_trail->LowerBound(var);
const IntegerValue max_term_value = max_target_value - min_var_value;
LinearConstraintBuilder lc(model, kMinIntegerValue, max_term_value);
lc.AddTerm(target, IntegerValue(1));
lc.AddTerm(var, IntegerValue(-1));
lc.AddTerm(y, max_term_value);
relaxation->linear_constraints.push_back(lc.Build());
lc_exactly_one.AddTerm(y, IntegerValue(1));
}
relaxation->linear_constraints.push_back(lc_exactly_one.Build());
}
}
void AppendLinearConstraintRelaxation(const ConstraintProto& constraint_proto,
const int linearization_level,
const Model& model,

View File

@@ -75,6 +75,13 @@ void TryToLinearizeConstraint(const CpModelProto& model_proto,
int linearization_level,
LinearRelaxation* relaxation);
// Adds linearization of int max constraints. This can also be used to linearize
// int min with negated variables.
void AppendMaxRelaxation(IntegerVariable target,
const std::vector<IntegerVariable>& vars,
int linearization_level, Model* model,
LinearRelaxation* relaxation);
// Appends linear constraints to the relaxation. This also handles the
// relaxation of linear constraints with enforcement literals.
// A linear constraint lb <= ax <= ub with enforcement literals {ei} is relaxed