From 2fe123e0c9592096a81ca6e2f9f206389d7ff191 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Thu, 25 Jan 2024 13:26:12 +0100 Subject: [PATCH] robust fix to issue #4067 --- ortools/flatzinc/BUILD.bazel | 1 - ortools/flatzinc/checker.cc | 23 ++++++++----------- ortools/flatzinc/cp_model_fz_solver.cc | 18 +++++++-------- ortools/flatzinc/mznlib/fzn_network_flow.mzn | 3 ++- .../flatzinc/mznlib/fzn_network_flow_cost.mzn | 10 ++++++-- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/ortools/flatzinc/BUILD.bazel b/ortools/flatzinc/BUILD.bazel index 130f8ba20e..d3e8b22116 100644 --- a/ortools/flatzinc/BUILD.bazel +++ b/ortools/flatzinc/BUILD.bazel @@ -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", ], ) diff --git a/ortools/flatzinc/checker.cc b/ortools/flatzinc/checker.cc index c20abab617..e21375ffe2 100644 --- a/ortools/flatzinc/checker.cc +++ b/ortools/flatzinc/checker.cc @@ -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& evaluator) { std::vector balance(balance_input.values); - int min_node = std::numeric_limits::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& 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& 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, diff --git a/ortools/flatzinc/cp_model_fz_solver.cc b/ortools/flatzinc/cp_model_fz_solver.cc index c5094ce7ec..66ca749e08 100644 --- a/ortools/flatzinc/cp_model_fz_solver.cc +++ b/ortools/flatzinc/cp_model_fz_solver.cc @@ -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 flow = LookupVars(fz_ct.arguments[has_cost ? 3 : 2]); + const std::vector 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> flows_per_node(num_nodes); std::vector> coeffs_per_node(num_nodes); - int min_node = std::numeric_limits::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) { diff --git a/ortools/flatzinc/mznlib/fzn_network_flow.mzn b/ortools/flatzinc/mznlib/fzn_network_flow.mzn index 5fda68a8d2..8e7a15aec7 100644 --- a/ortools/flatzinc/mznlib/fzn_network_flow.mzn +++ b/ortools/flatzinc/mznlib/fzn_network_flow.mzn @@ -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); diff --git a/ortools/flatzinc/mznlib/fzn_network_flow_cost.mzn b/ortools/flatzinc/mznlib/fzn_network_flow_cost.mzn index 5b085f8ede..23b572e2d8 100644 --- a/ortools/flatzinc/mznlib/fzn_network_flow_cost.mzn +++ b/ortools/flatzinc/mznlib/fzn_network_flow_cost.mzn @@ -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);