robust fix to issue #4067

This commit is contained in:
Laurent Perron
2024-01-25 13:26:12 +01:00
parent fb20315080
commit 2fe123e0c9
5 changed files with 28 additions and 27 deletions

View File

@@ -120,7 +120,6 @@ cc_library(
"//ortools/graph:cliques",
"//ortools/util:logging",
"//ortools/util:saturated_arithmetic",
"//ortools/util:vector_map",
"@com_google_absl//absl/strings",
],
)

View File

@@ -989,19 +989,14 @@ bool CheckMinimumInt(const Constraint& ct,
}
bool CheckNetworkFlowConservation(
const Argument& arcs, const Argument& balance_input,
const Argument& arcs, const Argument& balance_input, int base_node,
const Argument& flow_vars,
const std::function<int64_t(Variable*)>& evaluator) {
std::vector<int64_t> balance(balance_input.values);
int min_node = std::numeric_limits<int>::max();
for (const int node : arcs.values) {
min_node = std::min(min_node, node);
}
const int num_arcs = Size(arcs) / 2;
for (int arc = 0; arc < num_arcs; arc++) {
const int tail = arcs.values[arc * 2] - min_node;
const int head = arcs.values[arc * 2 + 1] - min_node;
const int tail = arcs.values[arc * 2] - base_node;
const int head = arcs.values[arc * 2 + 1] - base_node;
const int64_t flow = EvalAt(flow_vars, arc, evaluator);
balance[tail] -= flow;
balance[head] += flow;
@@ -1017,13 +1012,15 @@ bool CheckNetworkFlowConservation(
bool CheckNetworkFlow(const Constraint& ct,
const std::function<int64_t(Variable*)>& evaluator) {
return CheckNetworkFlowConservation(ct.arguments[0], ct.arguments[1],
ct.arguments[2], evaluator);
ct.arguments[2].Value(), ct.arguments[3],
evaluator);
}
bool CheckNetworkFlowCost(const Constraint& ct,
const std::function<int64_t(Variable*)>& evaluator) {
if (!CheckNetworkFlowConservation(ct.arguments[0], ct.arguments[1],
ct.arguments[3], evaluator)) {
ct.arguments[2].Value(), ct.arguments[3],
evaluator)) {
return false;
}
@@ -1031,11 +1028,11 @@ bool CheckNetworkFlowCost(const Constraint& ct,
const int num_arcs = Size(ct.arguments[3]);
for (int arc = 0; arc < num_arcs; arc++) {
const int64_t flow = EvalAt(ct.arguments[3], arc, evaluator);
const int64_t cost = EvalAt(ct.arguments[2], arc, evaluator);
total_cost += flow * cost;
const int64_t unit_cost = ct.arguments[4].ValueAt(arc);
total_cost += flow * unit_cost;
}
return total_cost == Eval(ct.arguments[4], evaluator);
return total_cost == Eval(ct.arguments[5], evaluator);
}
bool CheckNvalue(const Constraint& ct,

View File

@@ -968,20 +968,18 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint& fz_ct,
// Note that we leave ct empty here (with just the name set).
// We simply do a linear encoding of this constraint.
const bool has_cost = fz_ct.type == "ortools_network_flow_cost";
const std::vector<int> flow = LookupVars(fz_ct.arguments[has_cost ? 3 : 2]);
const std::vector<int> flow = LookupVars(fz_ct.arguments[3]);
// Flow conservation constraints.
const int num_nodes = fz_ct.arguments[1].values.size();
const int base_node = fz_ct.arguments[2].Value();
std::vector<std::vector<int>> flows_per_node(num_nodes);
std::vector<std::vector<int>> coeffs_per_node(num_nodes);
int min_node = std::numeric_limits<int>::max();
for (const int node : fz_ct.arguments[0].values) {
min_node = std::min(min_node, node);
}
const int num_arcs = fz_ct.arguments[0].values.size() / 2;
for (int arc = 0; arc < num_arcs; arc++) {
const int tail = fz_ct.arguments[0].values[2 * arc] - min_node;
const int head = fz_ct.arguments[0].values[2 * arc + 1] - min_node;
const int tail = fz_ct.arguments[0].values[2 * arc] - base_node;
const int head = fz_ct.arguments[0].values[2 * arc + 1] - base_node;
if (tail == head) continue;
flows_per_node[tail].push_back(flow[arc]);
@@ -1004,19 +1002,19 @@ void CpModelProtoWithMapping::FillConstraint(const fz::Constraint& fz_ct,
arg->add_domain(0);
arg->add_domain(0);
for (int arc = 0; arc < num_arcs; arc++) {
const int64_t weight = fz_ct.arguments[2].values[arc];
const int64_t weight = fz_ct.arguments[4].values[arc];
if (weight != 0) {
arg->add_vars(flow[arc]);
arg->add_coeffs(weight);
}
}
arg->add_vars(LookupVar(fz_ct.arguments[4]));
arg->add_vars(LookupVar(fz_ct.arguments[5]));
arg->add_coeffs(-1);
}
} else {
LOG(FATAL) << " Not supported " << fz_ct.type;
}
}
} // NOLINT(readability/fn_size)
void CpModelProtoWithMapping::FillReifOrImpliedConstraint(
const fz::Constraint& fz_ct, ConstraintProto* ct) {

View File

@@ -1,8 +1,9 @@
predicate ortools_network_flow(array [int] of int: arc,
array [int] of int: balance,
int: base_node,
array [int] of var int: flow);
predicate fzn_network_flow(array [int,int] of int: arc,
array [int] of int: balance,
array [int] of var int: flow) =
ortools_network_flow(array1d(arc),balance,flow);
ortools_network_flow(array1d(arc), balance, min(index_set(balance)), flow);

View File

@@ -1,7 +1,8 @@
predicate ortools_network_flow_cost(array [int] of int: arc,
array [int] of int: balance,
array [int] of int: weight,
int: base_node,
array [int] of var int: flow,
array [int] of int: weight,
var int: cost);
predicate fzn_network_flow_cost(array [int,int] of int: arc,
@@ -9,4 +10,9 @@ predicate fzn_network_flow_cost(array [int,int] of int: arc,
array [int] of int: weight,
array [int] of var int: flow,
var int: cost) =
ortools_network_flow_cost(array1d(arc),balance,weight,flow,cost);
ortools_network_flow_cost(array1d(arc),
balance,
min(index_set(balance)),
flow,
weight,
cost);