Skip to content

Commit 2d9b003

Browse files
committed
graph: fix build
1 parent 8b78a63 commit 2d9b003

14 files changed

+4181
-14
lines changed

ortools/base/BUILD.bazel

+5
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,11 @@ cc_library(
309309
],
310310
)
311311

312+
cc_library(
313+
name = "top_n",
314+
hdrs = ["top_n.h"],
315+
)
316+
312317
cc_library(
313318
name = "types",
314319
hdrs = ["types.h"],

ortools/base/top_n.h

+302
Large diffs are not rendered by default.

ortools/graph/BUILD.bazel

+9
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ cc_library(
5151
],
5252
)
5353

54+
cc_library(
55+
name = "bfs",
56+
hdrs = ["bfs.h"],
57+
deps = [
58+
"@com_google_absl//absl/status",
59+
"@com_google_absl//absl/strings:str_format",
60+
],
61+
)
62+
5463
cc_library(
5564
name = "bounded_dijkstra",
5665
hdrs = ["bounded_dijkstra.h"],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// Copyright 2010-2024 Google LLC
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
#include "ortools/graph/bidirectional_dijkstra.h"
15+
16+
#include <cmath>
17+
#include <limits>
18+
#include <random>
19+
#include <string>
20+
#include <utility>
21+
#include <vector>
22+
23+
#include "absl/container/flat_hash_map.h"
24+
#include "absl/random/distributions.h"
25+
#include "absl/strings/str_cat.h"
26+
#include "gmock/gmock.h"
27+
#include "gtest/gtest.h"
28+
#include "ortools/base/map_util.h"
29+
#include "ortools/graph/bounded_dijkstra.h"
30+
#include "ortools/graph/graph.h"
31+
#include "util/tuple/dump_vars.h"
32+
33+
namespace operations_research {
34+
namespace {
35+
36+
using ::testing::AnyOf;
37+
using ::testing::ElementsAre;
38+
using ::testing::ElementsAreArray;
39+
using ::testing::IsEmpty;
40+
using ::util::ListGraph;
41+
using ::util::StaticGraph;
42+
43+
TEST(BidirectionalDijkstraTest, EmptyPathInspection) {
44+
ListGraph<> empty_graph;
45+
std::vector<double> empty_vector;
46+
BidirectionalDijkstra<ListGraph<>, double> dijkstra(
47+
&empty_graph, &empty_vector, &empty_graph, &empty_vector);
48+
const auto path = dijkstra.SetToSetShortestPath({}, {});
49+
ASSERT_EQ(path.meeting_point, -1);
50+
EXPECT_THAT(dijkstra.PathToNodePath(path), IsEmpty());
51+
EXPECT_EQ(dijkstra.PathDebugString(path), "<NO PATH>");
52+
}
53+
54+
TEST(BidirectionalDijkstraTest, SmallTest) {
55+
// Build a small "grid" graph. Arc indices and lengths of the forward graph
56+
// are in (); and the backward graph has the same, but reversed arcs.
57+
//
58+
// 0 --(#0:0.1)--> 1 --(#1:1.1)--> 2
59+
// | | |
60+
// (#2:0.1) (#3:0.19) (#4:0.3)
61+
// | | |
62+
// v v v
63+
// 3 --(#5:0.2)--> 4 --(#6:1.2)--> 5
64+
ListGraph<> forward_graph;
65+
std::vector<double> arc_lengths;
66+
forward_graph.AddArc(0, 1);
67+
arc_lengths.push_back(0.1);
68+
forward_graph.AddArc(1, 2);
69+
arc_lengths.push_back(1.1);
70+
forward_graph.AddArc(0, 3);
71+
arc_lengths.push_back(0.1);
72+
forward_graph.AddArc(1, 4);
73+
arc_lengths.push_back(0.19);
74+
forward_graph.AddArc(2, 5);
75+
arc_lengths.push_back(0.3);
76+
forward_graph.AddArc(3, 4);
77+
arc_lengths.push_back(0.2);
78+
forward_graph.AddArc(4, 5);
79+
arc_lengths.push_back(1.2);
80+
ListGraph<> backward_graph;
81+
for (int arc = 0; arc < forward_graph.num_arcs(); ++arc) {
82+
backward_graph.AddArc(forward_graph.Head(arc), forward_graph.Tail(arc));
83+
}
84+
BidirectionalDijkstra<ListGraph<>, double> dijkstra(
85+
&forward_graph, &arc_lengths, &backward_graph, &arc_lengths);
86+
// Since the meeting point may vary, depending on which search direction goes
87+
// faster, we run it many times to try and exercise more code paths.
88+
const int kNumPaths = 1000;
89+
for (int i = 0; i < kNumPaths; ++i) {
90+
SCOPED_TRACE(absl::StrCat("On attempt #", i));
91+
const auto path = dijkstra.OneToOneShortestPath(0, 5);
92+
EXPECT_THAT(dijkstra.PathToNodePath(path), ElementsAre(0, 1, 4, 5));
93+
ASSERT_THAT(dijkstra.PathDebugString(path),
94+
AnyOf("0 --(#0:0.1)--> 1 --(#3:0.19)--> 4 --(#6:1.2)--> [5]",
95+
"0 --(#0:0.1)--> 1 --(#3:0.19)--> [4] <--(#6:1.2)-- 5",
96+
"0 --(#0:0.1)--> [1] <--(#3:0.19)-- 4 <--(#6:1.2)-- 5",
97+
"[0] <--(#0:0.1)-- 1 <--(#3:0.19)-- 4 <--(#6:1.2)-- 5"));
98+
}
99+
}
100+
101+
TEST(BidirectionalDijkstraTest, RandomizedCorrectnessTest) {
102+
std::mt19937 random(12345);
103+
// Performance on forge as of 2016-10-05 with these numbers, over 1000 runs:
104+
// - fastbuild: max = 21.9s, avg = 10.7s.
105+
// - opt: max = 23.2s, avg = 10.4s.
106+
const int kNumGraphs = DEBUG_MODE ? 100 : 300;
107+
const int kNumQueriesPerGraph = DEBUG_MODE ? 10 : 30;
108+
const int kNumNodes = 1000;
109+
const int kNumArcs = 10000;
110+
for (int graph_iter = 0; graph_iter < kNumGraphs; ++graph_iter) {
111+
// Build the random graphs.
112+
StaticGraph<> forward_graph;
113+
StaticGraph<> backward_graph;
114+
std::vector<double> forward_lengths;
115+
std::vector<double> backward_lengths;
116+
std::vector<int> forward_arc_of_backward_arc;
117+
forward_graph.AddNode(kNumNodes - 1);
118+
backward_graph.AddNode(kNumNodes - 1);
119+
for (int i = 0; i < kNumArcs; ++i) {
120+
const int a = absl::Uniform(random, 0, kNumNodes);
121+
const int b = absl::Uniform(random, 0, kNumNodes);
122+
forward_graph.AddArc(a, b);
123+
backward_graph.AddArc(b, a);
124+
forward_arc_of_backward_arc.push_back(i);
125+
const double length = absl::Uniform<double>(random, 0.0, 1.0);
126+
forward_lengths.push_back(length);
127+
backward_lengths.push_back(length);
128+
}
129+
std::vector<int> forward_perm;
130+
forward_graph.Build(&forward_perm);
131+
util::Permute(forward_perm, &forward_lengths);
132+
for (int& a : forward_arc_of_backward_arc) {
133+
a = forward_perm[a];
134+
}
135+
std::vector<int> backward_perm;
136+
backward_graph.Build(&backward_perm);
137+
util::Permute(backward_perm, &backward_lengths);
138+
util::Permute(backward_perm, &forward_arc_of_backward_arc);
139+
140+
// Initialize the tested Dijkstra and the reference Dijkstra.
141+
typedef BidirectionalDijkstra<StaticGraph<>, double> Dijkstra;
142+
Dijkstra tested_dijkstra(&forward_graph, &forward_lengths, &backward_graph,
143+
&backward_lengths);
144+
BoundedDijkstraWrapper<StaticGraph<>, double> ref_dijkstra(
145+
&forward_graph, &forward_lengths);
146+
147+
// To print some debugging info in case the test fails.
148+
auto print_arc_path = [&](const std::vector<int>& arc_path) -> std::string {
149+
if (arc_path.empty()) return "<EMPTY>";
150+
std::string out = absl::StrCat(forward_graph.Tail(arc_path[0]));
151+
double total_length = 0.0;
152+
for (const int arc : arc_path) {
153+
absl::StrAppend(&out, "--(#", arc, ":", (forward_lengths[arc]), ")-->",
154+
forward_graph.Head(arc));
155+
total_length += forward_lengths[arc];
156+
}
157+
absl::StrAppend(&out, "; Total length=", (total_length));
158+
return out;
159+
};
160+
auto print_node_distances =
161+
[&](const std::vector<Dijkstra::NodeDistance>& nds) -> std::string {
162+
std::string out = "{";
163+
for (const Dijkstra::NodeDistance& nd : nds) {
164+
absl::StrAppend(&out, " #", nd.node, " dist=", (nd.distance), ",");
165+
}
166+
if (!nds.empty()) out.back() = ' '; // Replace the last ','.
167+
out += '}';
168+
return out;
169+
};
170+
171+
// Run random Dijkstra queries.
172+
for (int q = 0; q < kNumQueriesPerGraph; ++q) {
173+
const int num_src = ceil(absl::Exponential<double>(random));
174+
const int num_dst = ceil(absl::Exponential<double>(random));
175+
std::vector<std::pair<int, double>> ref_srcs;
176+
std::vector<std::pair<int, double>> ref_dsts;
177+
std::vector<Dijkstra::NodeDistance> srcs;
178+
std::vector<Dijkstra::NodeDistance> dsts;
179+
for (int i = 0; i < num_src; ++i) {
180+
const int src = absl::Uniform(random, 0, kNumNodes);
181+
// Try costs < 0.
182+
const double dist = absl::Uniform<double>(random, 1.0, 2.0);
183+
ref_srcs.push_back({src, dist});
184+
srcs.push_back({src, dist});
185+
}
186+
for (int i = 0; i < num_dst; ++i) {
187+
const int dst = absl::Uniform(random, 0, kNumNodes);
188+
const double dist = absl::Uniform<double>(random, 1.0, 2.0);
189+
ref_dsts.push_back({dst, dist});
190+
dsts.push_back({dst, dist});
191+
}
192+
const std::vector<int> ref_dests =
193+
ref_dijkstra
194+
.RunBoundedDijkstraFromMultipleSourcesToMultipleDestinations(
195+
ref_srcs, ref_dsts,
196+
/*num_destinations_to_reach=*/1,
197+
std::numeric_limits<double>::infinity());
198+
if (ref_dests.empty()) {
199+
// No path. Verify that.
200+
EXPECT_EQ(
201+
tested_dijkstra.SetToSetShortestPath(srcs, dsts).meeting_point, -1);
202+
continue;
203+
}
204+
const std::vector<int> ref_arc_path =
205+
ref_dijkstra.ArcPathToNode(ref_dests[0]);
206+
const auto path = tested_dijkstra.SetToSetShortestPath(srcs, dsts);
207+
std::vector<int> arc_path = path.forward_arc_path;
208+
for (const int arc : gtl::reversed_view(path.backward_arc_path)) {
209+
arc_path.push_back(forward_arc_of_backward_arc[arc]);
210+
}
211+
ASSERT_THAT(arc_path, ElementsAreArray(ref_arc_path))
212+
<< "On graph #" << graph_iter << ", query #" << q
213+
<< "\nSources : " << print_node_distances(srcs)
214+
<< "\nDestinations: " << print_node_distances(dsts)
215+
<< "\nReference path : " << print_arc_path(ref_arc_path)
216+
<< "\nObtained path : " << print_arc_path(arc_path);
217+
}
218+
}
219+
}
220+
221+
} // namespace
222+
} // namespace operations_research

ortools/graph/bounded_dijkstra.h

+3-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "absl/log/check.h"
2626
#include "absl/types/span.h"
2727
#include "ortools/base/iterator_adaptors.h"
28-
#include "ortools/base/threadlocal.h"
2928
#include "ortools/base/top_n.h"
3029
#include "ortools/graph/graph.h"
3130

@@ -256,11 +255,9 @@ class BoundedDijkstraWrapper {
256255
}
257256

258257
private:
259-
// We define a private copy constructor to be used by ThreadLocal<>,
260-
// exclusively. The default copy constructor is problematic in a
261-
// multi-threaded environment.
258+
// The default copy constructor is problematic in a multi-threaded
259+
// environment.
262260
BoundedDijkstraWrapper(const BoundedDijkstraWrapper& other);
263-
friend class ThreadLocal<BoundedDijkstraWrapper>;
264261

265262
// The Graph and length of each arc.
266263
const GraphType* const graph_;
@@ -425,7 +422,7 @@ BoundedDijkstraWrapper<GraphType, DistanceType, ArcLengthFunctor>::
425422
sources_with_distance_offsets, settled_node_callback, distance_limit);
426423

427424
// Clean up, sparsely, for the next call.
428-
for (const int node : gtl::key_view(destinations_with_distance_offsets)) {
425+
for (const auto& [node, _] : destinations_with_distance_offsets) {
429426
is_destination_[node] = false;
430427
}
431428

0 commit comments

Comments
 (0)