allow minimal solve on flatzinc

This commit is contained in:
Laurent Perron
2019-11-06 16:52:40 +01:00
parent 248210b21c
commit d1e4dc52c0
4 changed files with 86 additions and 4 deletions

View File

@@ -139,6 +139,9 @@ std::vector<int> CpModelProtoWithMapping::LookupVars(
for (int64 value : argument.values) {
result.push_back(LookupConstant(value));
}
} else if (argument.type == fz::Argument::INT_VALUE) {
result.push_back(LookupConstant(argument.Value()));
} else {
CHECK_EQ(argument.type, fz::Argument::INT_VAR_REF_ARRAY);
for (fz::IntegerVariable* var : argument.variables) {
@@ -256,9 +259,32 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint& fz_ct,
arg->add_literals(FalseLiteral(var));
}
} else if (fz_ct.type == "bool_xor") {
auto* arg = ct->mutable_bool_xor();
arg->add_literals(TrueLiteral(LookupVar(fz_ct.arguments[0])));
arg->add_literals(TrueLiteral(LookupVar(fz_ct.arguments[1])));
// This is not the same semantics as the array_bool_xor as this constraint
// is actually a fully reified xor(a, b) <==> x.
const int a = LookupVar(fz_ct.arguments[0]);
const int b = LookupVar(fz_ct.arguments[1]);
const int x = LookupVar(fz_ct.arguments[2]);
// not(x) => a == b
ct->add_enforcement_literal(NegatedRef(x));
auto* const refute = ct->mutable_linear();
refute->add_vars(a);
refute->add_coeffs(1);
refute->add_vars(b);
refute->add_coeffs(-1);
refute->add_domain(0);
refute->add_domain(0);
// x => a + b == 1
auto* ct2 = proto.add_constraints();
ct2->add_enforcement_literal(x);
auto* const enforce = ct2->mutable_linear();
enforce->add_vars(a);
enforce->add_coeffs(1);
enforce->add_vars(b);
enforce->add_coeffs(1);
enforce->add_domain(1);
enforce->add_domain(1);
} else if (fz_ct.type == "array_bool_or") {
auto* arg = ct->mutable_bool_or();
for (const int var : LookupVars(fz_ct.arguments[0])) {
@@ -428,7 +454,8 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint& fz_ct,
fz_ct.type == "array_var_int_element" ||
fz_ct.type == "array_var_bool_element" ||
fz_ct.type == "array_int_element_nonshifted") {
if (fz_ct.arguments[0].type == fz::Argument::INT_VAR_REF) {
if (fz_ct.arguments[0].type == fz::Argument::INT_VAR_REF ||
fz_ct.arguments[0].type == fz::Argument::INT_VALUE) {
auto* arg = ct->mutable_element();
arg->set_index(LookupVar(fz_ct.arguments[0]));
arg->set_target(LookupVar(fz_ct.arguments[2]));

View File

@@ -150,6 +150,12 @@ Model ParseFlatzincModel(const std::string& input, bool input_is_filename) {
timer.Start();
presolve.Run(&model);
FZLOG << " - done in " << timer.GetInMs() << " ms" << FZENDL;
} else {
FZLOG << "Presolve model using minimal rules" << FZENDL;
timer.Reset();
timer.Start();
presolve.RunMinimal(&model);
FZLOG << " - done in " << timer.GetInMs() << " ms" << FZENDL;
}
// Print statistics.

View File

@@ -3644,6 +3644,50 @@ bool Presolver::RegroupDifferent(Model* model) {
return killed > 0;
}
bool Presolver::RunMinimal(Model* model) {
auto constraint = [model](int index) { return model->constraints()[index]; };
// Rebuild var_constraint map if empty.
if (var_to_constraint_indices_.empty()) {
for (int i = 0; i < model->constraints().size(); ++i) {
AddConstraintToMapping(i, constraint(i));
}
}
bool changed = false;
// Let's presolve the bool2int predicates first.
for (int index = 0; index < model->constraints().size(); ++index) {
Constraint* const ct = constraint(index);
if (ct->active && ct->type == "bool2int") {
std::string log;
ApplyRule(index, ct, "PresolveBool2Int",
[this](Constraint* ct, std::string* log) {
return PresolveBool2Int(ct, log);
});
changed = true;
}
}
if (!var_representative_map_.empty()) {
// Some new substitutions were introduced. Let's process them.
SubstituteEverywhere(model);
var_representative_map_.clear();
var_representative_vector_.clear();
}
// Report presolve rules statistics.
if (!successful_rules_.empty()) {
for (const auto& rule : successful_rules_) {
if (rule.second == 1) {
FZLOG << " - rule " << rule.first << " was applied 1 time" << FZENDL;
} else {
FZLOG << " - rule " << rule.first << " was applied " << rule.second
<< " times" << FZENDL;
}
}
}
return changed;
}
bool Presolver::Run(Model* model) {
// Check the validity of variable domains.
for (const IntegerVariable* var : model->variables()) {

View File

@@ -48,6 +48,11 @@ class Presolver {
// TODO(user): Returns the number of rules applied instead.
bool Run(Model* model);
// Minimal version of the presolve.
// TODO(user): Currently, without this, the solver fails on a series of
// problems like hrc_exp1-1-945_sat.fzn. To investigate.
bool RunMinimal(Model* model);
// Cleans the model for the CP solver.
// In particular, it knows if we use a sat solver inside the CP
// solver. In that case, for Boolean constraints, it remove the link