20 #ifndef OR_TOOLS_GRAPH_CHRISTOFIDES_H_
21 #define OR_TOOLS_GRAPH_CHRISTOFIDES_H_
35 using ::util::CompleteGraph;
44 #if defined(USE_CBC) || defined(USE_SCIP)
46 #endif // defined(USE_CBC) || defined(USE_SCIP)
85 CompleteGraph<NodeIndex, ArcIndex> graph_;
88 const CostFunction costs_;
94 std::vector<NodeIndex> tsp_path_;
101 template <
typename WeightFunctionType,
typename GraphType>
103 std::pair<typename GraphType::NodeIndex, typename GraphType::NodeIndex>>
105 const WeightFunctionType&
weight) {
120 std::vector<std::pair<NodeIndex, NodeIndex>> match;
130 #if defined(USE_CBC) || defined(USE_SCIP)
135 template <
typename WeightFunctionType,
typename GraphType>
137 std::pair<typename GraphType::NodeIndex, typename GraphType::NodeIndex>>
139 const WeightFunctionType&
weight) {
143 model.set_maximize(
false);
148 std::vector<int> variable_indices(graph.num_arcs(), -1);
149 for (
NodeIndex node : graph.AllNodes()) {
151 for (
const ArcIndex arc : graph.OutgoingArcs(node)) {
154 variable_indices[arc] =
model.variable_size();
155 MPVariableProto*
const arc_var =
model.add_variable();
156 arc_var->set_lower_bound(0);
157 arc_var->set_upper_bound(1);
158 arc_var->set_is_integer(
true);
159 arc_var->set_objective_coefficient(
weight(arc));
164 MPConstraintProto*
const one_of_ct =
model.add_constraint();
165 one_of_ct->set_lower_bound(1);
166 one_of_ct->set_upper_bound(1);
168 for (
NodeIndex node : graph.AllNodes()) {
169 for (
const ArcIndex arc : graph.OutgoingArcs(node)) {
172 const int arc_var = variable_indices[arc];
174 MPConstraintProto* one_of_ct =
model.mutable_constraint(node);
175 one_of_ct->add_var_index(arc_var);
176 one_of_ct->add_coefficient(1);
177 one_of_ct =
model.mutable_constraint(
head);
178 one_of_ct->add_var_index(arc_var);
179 one_of_ct->add_coefficient(1);
183 #if defined(USE_SCIP)
184 MPSolver mp_solver(
"MatchingWithSCIP",
186 #elif defined(USE_CBC)
187 MPSolver mp_solver(
"MatchingWithCBC",
196 std::vector<std::pair<NodeIndex, NodeIndex>> matching;
197 for (
ArcIndex arc = 0; arc < variable_indices.size(); ++arc) {
198 const int arc_var = variable_indices[arc];
199 if (arc_var >= 0 &&
response.variable_value(arc_var) > .9) {
201 matching.emplace_back(graph.Tail(arc), graph.Head(arc));
206 #endif // defined(USE_CBC) || defined(USE_SCIP)
209 typename CostFunction>
214 costs_(std::move(costs)),
219 typename CostFunction>
221 CostFunction>::TravelingSalesmanCost() {
229 typename CostFunction>
239 typename CostFunction>
242 const NodeIndex num_nodes = graph_.num_nodes();
245 if (num_nodes == 1) {
248 if (num_nodes <= 1) {
252 const std::vector<ArcIndex> mst =
254 return costs_(graph_.Tail(arc), graph_.Head(arc));
257 std::vector<NodeIndex> degrees(num_nodes, 0);
259 degrees[graph_.Tail(arc)]++;
260 degrees[graph_.Head(arc)]++;
262 std::vector<NodeIndex> odd_degree_nodes;
263 for (
int i = 0; i < degrees.size(); ++i) {
264 if (degrees[i] % 2 != 0) {
265 odd_degree_nodes.push_back(i);
270 const NodeIndex reduced_size = odd_degree_nodes.size();
272 CompleteGraph<NodeIndex, ArcIndex> reduced_graph(reduced_size);
273 std::vector<std::pair<NodeIndex, NodeIndex>> closure_arcs;
275 case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING: {
277 reduced_graph, [
this, &reduced_graph,
279 return costs_(odd_degree_nodes[reduced_graph.Tail(arc)],
280 odd_degree_nodes[reduced_graph.Head(arc)]);
284 #if defined(USE_CBC) || defined(USE_SCIP)
285 case MatchingAlgorithm::MINIMUM_WEIGHT_MATCHING_WITH_MIP: {
287 reduced_graph, [
this, &reduced_graph,
289 return costs_(odd_degree_nodes[reduced_graph.Tail(arc)],
290 odd_degree_nodes[reduced_graph.Head(arc)]);
294 #endif // defined(USE_CBC) || defined(USE_SCIP)
295 case MatchingAlgorithm::MINIMAL_WEIGHT_MATCHING: {
298 std::vector<ArcIndex> ordered_arcs(reduced_graph.num_arcs());
299 std::vector<CostType> ordered_arc_costs(reduced_graph.num_arcs(), 0);
300 for (
const ArcIndex arc : reduced_graph.AllForwardArcs()) {
301 ordered_arcs[arc] = arc;
302 ordered_arc_costs[arc] =
303 costs_(odd_degree_nodes[reduced_graph.Tail(arc)],
304 odd_degree_nodes[reduced_graph.Head(arc)]);
306 std::sort(ordered_arcs.begin(), ordered_arcs.end(),
308 return ordered_arc_costs[arc_a] < ordered_arc_costs[arc_b];
310 std::vector<bool> touched_nodes(reduced_size,
false);
311 for (
ArcIndex arc_index = 0; closure_arcs.size() * 2 < reduced_size;
313 const ArcIndex arc = ordered_arcs[arc_index];
317 touched_nodes[
tail] =
true;
318 touched_nodes[
head] =
true;
319 closure_arcs.emplace_back(
tail,
head);
329 num_nodes, closure_arcs.size() + mst.size());
331 egraph.AddArc(graph_.Tail(arc), graph_.Head(arc));
333 for (
const auto arc : closure_arcs) {
334 egraph.AddArc(odd_degree_nodes[arc.first], odd_degree_nodes[arc.second]);
336 std::vector<bool> touched(num_nodes,
false);
339 if (touched[node])
continue;
340 touched[node] =
true;
341 tsp_cost_ = SafeAdd(tsp_cost_,
342 tsp_path_.empty() ? 0 : costs_(tsp_path_.back(), node));
343 tsp_path_.push_back(node);
346 SafeAdd(tsp_cost_, tsp_path_.empty() ? 0 : costs_(tsp_path_.back(), 0));
347 tsp_path_.push_back(0);
352 #endif // OR_TOOLS_GRAPH_CHRISTOFIDES_H_