149 const WeightFunctionType&
weight) {
150 using ArcIndex =
typename GraphType::ArcIndex;
151 using NodeIndex =
typename GraphType::NodeIndex;
153 model.set_maximize(
false);
158 std::vector<int> variable_indices(
graph.num_arcs(), -1);
164 variable_indices[
arc] =
model.variable_size();
165 MPVariableProto*
const arc_var =
model.add_variable();
166 arc_var->set_lower_bound(0);
167 arc_var->set_upper_bound(1);
168 arc_var->set_is_integer(
true);
169 arc_var->set_objective_coefficient(
weight(
arc));
174 MPConstraintProto*
const one_of_ct =
model.add_constraint();
175 one_of_ct->set_lower_bound(1);
176 one_of_ct->set_upper_bound(1);
182 const int arc_var = variable_indices[
arc];
183 DCHECK_GE(arc_var, 0);
184 MPConstraintProto* one_of_ct =
model.mutable_constraint(node);
185 one_of_ct->add_var_index(arc_var);
186 one_of_ct->add_coefficient(1);
187 one_of_ct =
model.mutable_constraint(
head);
188 one_of_ct->add_var_index(arc_var);
189 one_of_ct->add_coefficient(1);
194 MPSolver mp_solver(
"MatchingWithSCIP",
196#elif defined(USE_CBC)
197 MPSolver mp_solver(
"MatchingWithCBC",
204 return absl::InvalidArgumentError(
"MIP-based matching failed");
206 MPSolutionResponse response;
208 std::vector<std::pair<NodeIndex, NodeIndex>> matching;
210 const int arc_var = variable_indices[
arc];
211 if (arc_var >= 0 && response.variable_value(arc_var) > .9) {
212 DCHECK_GE(response.variable_value(arc_var), 1.0 - 1e-4);
255 CostFunction>::Solve() {
256 const NodeIndex num_nodes = graph_.num_nodes();
259 if (num_nodes == 1) {
262 if (num_nodes <= 1) {
266 const std::vector<ArcIndex> mst =
268 return costs_(graph_.Tail(
arc), graph_.Head(
arc));
271 std::vector<NodeIndex>
degrees(num_nodes, 0);
276 std::vector<NodeIndex> odd_degree_nodes;
277 for (
int i = 0; i <
degrees.size(); ++i) {
279 odd_degree_nodes.push_back(i);
284 const NodeIndex reduced_size = odd_degree_nodes.size();
285 DCHECK_NE(0, reduced_size);
286 CompleteGraph<NodeIndex, ArcIndex> reduced_graph(reduced_size);
287 std::vector<std::pair<NodeIndex, NodeIndex>> closure_arcs;
289 case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING: {
291 reduced_graph, [
this, &reduced_graph,
292 &odd_degree_nodes](CompleteGraph<>::ArcIndex
arc) {
293 return costs_(odd_degree_nodes[reduced_graph.Tail(
arc)],
294 odd_degree_nodes[reduced_graph.Head(
arc)]);
299 result->swap(closure_arcs);
302#if defined(USE_CBC) || defined(USE_SCIP)
303 case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING_WITH_MIP: {
305 reduced_graph, [
this, &reduced_graph,
306 &odd_degree_nodes](CompleteGraph<>::ArcIndex
arc) {
307 return costs_(odd_degree_nodes[reduced_graph.Tail(
arc)],
308 odd_degree_nodes[reduced_graph.Head(
arc)]);
313 result->swap(closure_arcs);
317 case MatchingAlgorithm::MINIMAL_WEIGHT_MATCHING: {
320 std::vector<ArcIndex> ordered_arcs(reduced_graph.num_arcs());
321 std::vector<CostType> ordered_arc_costs(reduced_graph.num_arcs(), 0);
322 for (
const ArcIndex arc : reduced_graph.AllForwardArcs()) {
324 ordered_arc_costs[
arc] =
325 costs_(odd_degree_nodes[reduced_graph.Tail(
arc)],
326 odd_degree_nodes[reduced_graph.Head(
arc)]);
328 std::sort(ordered_arcs.begin(), ordered_arcs.end(),
330 return ordered_arc_costs[arc_a] < ordered_arc_costs[arc_b];
332 std::vector<bool> touched_nodes(reduced_size,
false);
333 for (
ArcIndex arc_index = 0; closure_arcs.size() * 2 < reduced_size;
339 touched_nodes[
tail] =
true;
340 touched_nodes[
head] =
true;
341 closure_arcs.emplace_back(
tail,
head);
351 num_nodes, closure_arcs.size() + mst.size());
355 for (
const auto arc : closure_arcs) {
356 egraph.
AddArc(odd_degree_nodes[
arc.first], odd_degree_nodes[
arc.second]);
358 std::vector<bool> touched(num_nodes,
false);
361 if (touched[node])
continue;
362 touched[node] =
true;
363 tsp_cost_ = SafeAdd(tsp_cost_,
364 tsp_path_.empty() ? 0 : costs_(tsp_path_.back(), node));
365 tsp_path_.push_back(node);
368 SafeAdd(tsp_cost_, tsp_path_.empty() ? 0 : costs_(tsp_path_.back(), 0));
369 tsp_path_.push_back(0);
absl::StatusOr< std::vector< std::pair< typename GraphType::NodeIndex, typename GraphType::NodeIndex > > > ComputeMinimumWeightMatching(const GraphType &graph, const WeightFunctionType &weight)
Computes a minimum weight perfect matching on an undirected graph.