diff --git a/graph/ebert_graph.h b/graph/ebert_graph.h index be5302b243..4c511b2bfe 100644 --- a/graph/ebert_graph.h +++ b/graph/ebert_graph.h @@ -33,8 +33,11 @@ // Note that if arc (u, v) is defined, then the data structure also stores // (v, u). // Arc ~i thus denotes the arc reverse to arc i. -// This is what makes this representation useful for undirected graphs, -// and for implementing algorithms like two-directions shortest-path. +// This is what makes this representation useful for undirected graphs and for +// implementing algorithms like bi-directional shortest-path. +// Also note that the representation handles multi-graphs. If several arcs +// going from node u to node v are added to the graph, they will be handled as +// separate arcs. // // Now, for an integer u in [0..n-1] denoting the index of a node: // * first_incident_arc_[u] denotes the first arc in the adjacency list of u. @@ -218,6 +221,9 @@ template class EbertGraph { // Adds an arc to the graph and returns its index. // Returns kNilArc if the arc could not be added. + // Note that for a given pair (tail, head) AddArc does not overwrite an + // already-existing arc between tail and head: Another arc is created + // instead. This makes it possible to handle multi-graphs. ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head) { if (num_arcs_ >= max_num_arcs_ || !IsNodeValid(tail) || !IsNodeValid(head)) { @@ -924,5 +930,54 @@ typedef ZVector NodeIndexArray; typedef ZVector ArcIndexArray; typedef ZVector QuantityArray; typedef ZVector CostArray; + +// Builds a directed line graph for 'graph' (see "directed line graph" in +// http://en.wikipedia.org/wiki/Line_graph). Arcs of the original graph +// become nodes and the new graph contains only nodes created from arcs in the +// original graph (we use the notation (a->b) for these new nodes); the index +// of the node (a->b) in the new graph is exactly the same as the index of the +// arc a->b in the original graph. +// An arc from node (a->b) to node (c->d) in the new graph is added if and only +// if b == c in the original graph. +// This method expects that 'line_graph' is an empty graph (it has no nodes +// and no arcs). +template +void BuildLineGraph(const EbertGraph& graph, + EbertGraph* const line_graph) { + if (line_graph == NULL) { + LOG(DFATAL) << "line_graph must not be NULL"; + return; + } + typedef EbertGraph Graph; + typedef typename Graph::ArcIterator ArcIterator; + typedef typename Graph::OutgoingArcIterator OutgoingArcIterator; + // Sizing then filling. + const NodeIndexType num_nodes = graph.num_arcs(); + ArcIndexType num_arcs = 0; + for (ArcIterator arc_iterator(graph); + arc_iterator.Ok(); + arc_iterator.Next()) { + const ArcIndexType arc = arc_iterator.Index(); + const NodeIndexType head = graph.Head(arc); + for (OutgoingArcIterator iterator(graph, head); + iterator.Ok(); + iterator.Next()) { + ++num_arcs; + } + } + line_graph->Reserve(num_nodes, num_arcs); + for (ArcIterator arc_iterator(graph); + arc_iterator.Ok(); + arc_iterator.Next()) { + const ArcIndexType arc = arc_iterator.Index(); + const NodeIndexType head = graph.Head(arc); + for (OutgoingArcIterator iterator(graph, head); + iterator.Ok(); + iterator.Next()) { + line_graph->AddArc(arc, iterator.Index()); + } + } +} + } // namespace operations_research #endif // OR_TOOLS_GRAPH_EBERT_GRAPH_H_ diff --git a/graph/linear_assignment.cc b/graph/linear_assignment.cc index 914537f62c..37d74b6b57 100644 --- a/graph/linear_assignment.cc +++ b/graph/linear_assignment.cc @@ -317,8 +317,16 @@ LinearSumAssignment::BestArcAndGap(NodeIndex left_node) const { StarGraph::OutgoingArcIterator arc_it(graph_, left_node); ArcIndex best_arc = arc_it.Index(); CostValue min_partial_reduced_cost = PartialReducedCost(best_arc); + // We choose second_min_partial_reduced_cost so that in the case of + // the largest possible gap (which results from a left-side node + // with only a single incident residual arc), the corresponding + // right-side node will be relabeled by an amount that exactly + // matches price_reduction_bound_. The overall price_lower_bound_ is + // computed tightly enough that if we relabel by an amount even + // epsilon_ greater than that, we can incorrectly conclude + // infeasibility in DoublePush(). CostValue second_min_partial_reduced_cost = - min_partial_reduced_cost + price_reduction_bound_; + min_partial_reduced_cost + price_reduction_bound_ - epsilon_; for (arc_it.Next(); arc_it.Ok(); arc_it.Next()) { const ArcIndex arc = arc_it.Index(); const CostValue partial_reduced_cost = PartialReducedCost(arc); diff --git a/graph/linear_assignment.h b/graph/linear_assignment.h index 971d5b8c4b..4ba0d4c4e3 100644 --- a/graph/linear_assignment.h +++ b/graph/linear_assignment.h @@ -45,7 +45,7 @@ // // Retrieve the node-node correspondence of the optimum assignment and the // // cost of each node pairing. // for (::operations_research::LinearSumAssignment::BipartiteLeftNodeIterator -// node_it; +// node_it(a); // node_it.Ok(); // node_it.Next()) { // ::operations_research::NodeIndex left_node = node_it.Index();