Skip to content

Commit 2b73424

Browse files
committed
more graph cleaning
1 parent 10b5ec6 commit 2b73424

File tree

5 files changed

+186
-135
lines changed

5 files changed

+186
-135
lines changed

ortools/graph/BUILD.bazel

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,8 @@ cc_test(
366366
srcs = ["ebert_graph_test.cc"],
367367
deps = [
368368
":ebert_graph",
369-
"//ortools/base",
370369
"//ortools/base:gmock_main",
371370
"//ortools/util:permutation",
372-
"@com_google_absl//absl/base:core_headers",
373371
"@com_google_absl//absl/random:distributions",
374372
"@com_google_absl//absl/strings",
375373
"@com_google_benchmark//:benchmark",
@@ -617,6 +615,17 @@ cc_test(
617615
],
618616
)
619617

618+
cc_test(
619+
name = "line_graph_test",
620+
srcs = ["line_graph_test.cc"],
621+
deps = [
622+
":graph",
623+
":line_graph",
624+
"//ortools/base:gmock_main",
625+
"@com_google_absl//absl/base:core_headers",
626+
],
627+
)
628+
620629
# Linear Assignment with full-featured interface and efficient
621630
# implementation.
622631
cc_library(
@@ -717,6 +726,12 @@ cc_library(
717726
],
718727
)
719728

729+
cc_library(
730+
name = "line_graph",
731+
hdrs = ["line_graph.h"],
732+
deps = ["@com_google_absl//absl/log"],
733+
)
734+
720735
cc_test(
721736
name = "rooted_tree_test",
722737
srcs = ["rooted_tree_test.cc"],

ortools/graph/ebert_graph.h

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,53 +1718,6 @@ class AnnotatedGraphBuildManager
17181718
num_nodes, num_arcs, sort_arcs) {}
17191719
};
17201720

1721-
// Builds a directed line graph for 'graph' (see "directed line graph" in
1722-
// http://en.wikipedia.org/wiki/Line_graph). Arcs of the original graph
1723-
// become nodes and the new graph contains only nodes created from arcs in the
1724-
// original graph (we use the notation (a->b) for these new nodes); the index
1725-
// of the node (a->b) in the new graph is exactly the same as the index of the
1726-
// arc a->b in the original graph.
1727-
// An arc from node (a->b) to node (c->d) in the new graph is added if and only
1728-
// if b == c in the original graph.
1729-
// This method expects that 'line_graph' is an empty graph (it has no nodes
1730-
// and no arcs).
1731-
// Returns false on an error.
1732-
template <typename GraphType>
1733-
bool BuildLineGraph(const GraphType& graph, GraphType* const line_graph) {
1734-
if (line_graph == nullptr) {
1735-
LOG(DFATAL) << "line_graph must not be NULL";
1736-
return false;
1737-
}
1738-
if (line_graph->num_nodes() != 0) {
1739-
LOG(DFATAL) << "line_graph must be empty";
1740-
return false;
1741-
}
1742-
typedef typename GraphType::ArcIterator ArcIterator;
1743-
typedef typename GraphType::OutgoingArcIterator OutgoingArcIterator;
1744-
// Sizing then filling.
1745-
typename GraphType::ArcIndex num_arcs = 0;
1746-
for (ArcIterator arc_iterator(graph); arc_iterator.Ok();
1747-
arc_iterator.Next()) {
1748-
const typename GraphType::ArcIndex arc = arc_iterator.Index();
1749-
const typename GraphType::NodeIndex head = graph.Head(arc);
1750-
for (OutgoingArcIterator iterator(graph, head); iterator.Ok();
1751-
iterator.Next()) {
1752-
++num_arcs;
1753-
}
1754-
}
1755-
line_graph->Reserve(graph.num_arcs(), num_arcs);
1756-
for (ArcIterator arc_iterator(graph); arc_iterator.Ok();
1757-
arc_iterator.Next()) {
1758-
const typename GraphType::ArcIndex arc = arc_iterator.Index();
1759-
const typename GraphType::NodeIndex head = graph.Head(arc);
1760-
for (OutgoingArcIterator iterator(graph, head); iterator.Ok();
1761-
iterator.Next()) {
1762-
line_graph->AddArc(arc, iterator.Index());
1763-
}
1764-
}
1765-
return true;
1766-
}
1767-
17681721
#undef DEFINE_STL_ITERATOR_FUNCTIONS
17691722

17701723
} // namespace operations_research

ortools/graph/ebert_graph_test.cc

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717
#include <random>
1818
#include <string>
1919

20-
#include "absl/base/macros.h"
2120
#include "absl/random/distributions.h"
2221
#include "absl/strings/str_cat.h"
2322
#include "absl/strings/string_view.h"
2423
#include "benchmark/benchmark.h"
2524
#include "gtest/gtest.h"
26-
#include "ortools/base/macros.h"
2725
#include "ortools/util/permutation.h"
2826

2927
namespace operations_research {
@@ -1092,90 +1090,6 @@ TEST(ForwardEbertGraphTest, ImpossibleBuildTailArray) {
10921090
EXPECT_FALSE(g.BuildTailArray());
10931091
}
10941092

1095-
// Testing line graph creation.
1096-
1097-
// Empty fixture templates to collect the types of graphs on which we want to
1098-
// base the shortest paths template instances that we test.
1099-
template <typename GraphType>
1100-
class LineGraphDeathTest : public testing::Test {};
1101-
template <typename GraphType>
1102-
class LineGraphTest : public testing::Test {};
1103-
1104-
typedef testing::Types<StarGraph, ForwardStarGraph>
1105-
GraphTypesForLineGraphTesting;
1106-
1107-
TYPED_TEST_SUITE(LineGraphDeathTest, GraphTypesForLineGraphTesting);
1108-
TYPED_TEST_SUITE(LineGraphTest, GraphTypesForLineGraphTesting);
1109-
1110-
TYPED_TEST(LineGraphDeathTest, NullLineGraph) {
1111-
TypeParam graph;
1112-
#ifndef NDEBUG
1113-
EXPECT_DEATH(BuildLineGraph<TypeParam>(graph, nullptr),
1114-
"line_graph must not be NULL");
1115-
#else
1116-
EXPECT_FALSE(BuildLineGraph<TypeParam>(graph, nullptr));
1117-
#endif
1118-
}
1119-
1120-
TYPED_TEST(LineGraphDeathTest, NonEmptyLineGraph) {
1121-
TypeParam graph;
1122-
TypeParam line_graph(1, 1);
1123-
line_graph.AddArc(0, 0);
1124-
#ifndef NDEBUG
1125-
EXPECT_DEATH(BuildLineGraph<TypeParam>(graph, &line_graph),
1126-
"line_graph must be empty");
1127-
#else
1128-
EXPECT_FALSE(BuildLineGraph<TypeParam>(graph, &line_graph));
1129-
#endif
1130-
}
1131-
1132-
TYPED_TEST(LineGraphDeathTest, LineGraphOfEmptyGraph) {
1133-
TypeParam graph;
1134-
TypeParam line_graph;
1135-
EXPECT_TRUE(BuildLineGraph<TypeParam>(graph, &line_graph));
1136-
EXPECT_EQ(0, line_graph.num_nodes());
1137-
EXPECT_EQ(0, line_graph.num_arcs());
1138-
}
1139-
1140-
TYPED_TEST(LineGraphTest, LineGraphOfSingleton) {
1141-
TypeParam graph(1, 1);
1142-
graph.AddArc(0, 0);
1143-
TypeParam line_graph;
1144-
EXPECT_TRUE(BuildLineGraph<TypeParam>(graph, &line_graph));
1145-
EXPECT_EQ(1, line_graph.num_nodes());
1146-
EXPECT_EQ(1, line_graph.num_arcs());
1147-
}
1148-
1149-
TYPED_TEST(LineGraphTest, LineGraph) {
1150-
const NodeIndex kNodes = 4;
1151-
const ArcIndex kArcs[][2] = {{0, 1}, {0, 2}, {1, 2}, {2, 0}, {2, 3}};
1152-
const ArcIndex kExpectedLineArcs[][2] = {{0, 2}, {2, 3}, {3, 0}, {3, 1},
1153-
{2, 4}, {1, 4}, {1, 3}};
1154-
TypeParam graph(kNodes, ABSL_ARRAYSIZE(kArcs));
1155-
for (int i = 0; i < ABSL_ARRAYSIZE(kArcs); ++i) {
1156-
graph.AddArc(kArcs[i][0], kArcs[i][1]);
1157-
}
1158-
TypeParam line_graph;
1159-
EXPECT_TRUE(BuildLineGraph<TypeParam>(graph, &line_graph));
1160-
EXPECT_EQ(ABSL_ARRAYSIZE(kArcs), line_graph.num_nodes());
1161-
EXPECT_EQ(ABSL_ARRAYSIZE(kExpectedLineArcs), line_graph.num_arcs());
1162-
for (int i = 0; i < ABSL_ARRAYSIZE(kExpectedLineArcs); ++i) {
1163-
const NodeIndex expected_tail = kExpectedLineArcs[i][0];
1164-
const NodeIndex expected_head = kExpectedLineArcs[i][1];
1165-
bool found = false;
1166-
for (typename TypeParam::OutgoingArcIterator out_iterator(line_graph,
1167-
expected_tail);
1168-
out_iterator.Ok(); out_iterator.Next()) {
1169-
const ArcIndex arc = out_iterator.Index();
1170-
if (line_graph.Head(arc) == expected_head) {
1171-
found = true;
1172-
break;
1173-
}
1174-
}
1175-
EXPECT_TRUE(found) << expected_tail << " " << expected_head;
1176-
}
1177-
}
1178-
11791093
template <typename GraphType, bool sort_arcs>
11801094
static void BM_RandomArcs(benchmark::State& state) {
11811095
const int kRandomSeed = 0;

ortools/graph/line_graph.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
#ifndef OR_TOOLS_GRAPH_LINE_GRAPH_H_
15+
#define OR_TOOLS_GRAPH_LINE_GRAPH_H_
16+
17+
#include "ortools/base/logging.h"
18+
19+
namespace operations_research {
20+
21+
// Builds a directed line graph for `graph` (see "directed line graph" in
22+
// http://en.wikipedia.org/wiki/Line_graph). Arcs of the original graph
23+
// become nodes and the new graph contains only nodes created from arcs in the
24+
// original graph (we use the notation (a->b) for these new nodes); the index
25+
// of the node (a->b) in the new graph is exactly the same as the index of the
26+
// arc a->b in the original graph.
27+
// An arc from node (a->b) to node (c->d) in the new graph is added if and only
28+
// if b == c in the original graph.
29+
// This method expects that `line_graph` is an empty graph (it has no nodes
30+
// and no arcs).
31+
// Returns false on an error.
32+
template <typename GraphType>
33+
bool BuildLineGraph(const GraphType& graph, GraphType* const line_graph) {
34+
if (line_graph == nullptr) {
35+
LOG(DFATAL) << "line_graph must not be NULL";
36+
return false;
37+
}
38+
if (line_graph->num_nodes() != 0) {
39+
LOG(DFATAL) << "line_graph must be empty";
40+
return false;
41+
}
42+
// Sizing then filling.
43+
using NodeIndex = typename GraphType::NodeIndex;
44+
using ArcIndex = typename GraphType::ArcIndex;
45+
ArcIndex num_arcs = 0;
46+
for (const ArcIndex arc : graph.AllForwardArcs()) {
47+
const NodeIndex head = graph.Head(arc);
48+
num_arcs += graph.OutDegree(head);
49+
}
50+
line_graph->Reserve(graph.num_arcs(), num_arcs);
51+
for (const ArcIndex arc : graph.AllForwardArcs()) {
52+
const NodeIndex head = graph.Head(arc);
53+
for (const ArcIndex outgoing_arc : graph.OutgoingArcs(head)) {
54+
line_graph->AddArc(arc, outgoing_arc);
55+
}
56+
}
57+
return true;
58+
}
59+
60+
} // namespace operations_research
61+
62+
#endif // OR_TOOLS_GRAPH_LINE_GRAPH_H_

ortools/graph/line_graph_test.cc

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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/line_graph.h"
15+
16+
#include "absl/base/macros.h"
17+
#include "gtest/gtest.h"
18+
#include "ortools/graph/graph.h"
19+
20+
namespace operations_research {
21+
namespace {
22+
23+
// Empty fixture templates to collect the types of graphs on which we want to
24+
// base the shortest paths template instances that we test.
25+
template <typename GraphType>
26+
class LineGraphDeathTest : public testing::Test {};
27+
template <typename GraphType>
28+
class LineGraphTest : public testing::Test {};
29+
30+
typedef testing::Types<::util::ListGraph<>, ::util::ReverseArcListGraph<>>
31+
GraphTypesForLineGraphTesting;
32+
33+
TYPED_TEST_SUITE(LineGraphDeathTest, GraphTypesForLineGraphTesting);
34+
TYPED_TEST_SUITE(LineGraphTest, GraphTypesForLineGraphTesting);
35+
36+
TYPED_TEST(LineGraphDeathTest, NullLineGraph) {
37+
TypeParam graph;
38+
#ifndef NDEBUG
39+
EXPECT_DEATH(BuildLineGraph<TypeParam>(graph, nullptr),
40+
"line_graph must not be NULL");
41+
#else
42+
EXPECT_FALSE(BuildLineGraph<TypeParam>(graph, nullptr));
43+
#endif
44+
}
45+
46+
TYPED_TEST(LineGraphDeathTest, NonEmptyLineGraph) {
47+
TypeParam graph;
48+
TypeParam line_graph(1, 1);
49+
line_graph.AddArc(0, 0);
50+
#ifndef NDEBUG
51+
EXPECT_DEATH(BuildLineGraph<TypeParam>(graph, &line_graph),
52+
"line_graph must be empty");
53+
#else
54+
EXPECT_FALSE(BuildLineGraph<TypeParam>(graph, &line_graph));
55+
#endif
56+
}
57+
58+
TYPED_TEST(LineGraphDeathTest, LineGraphOfEmptyGraph) {
59+
TypeParam graph;
60+
TypeParam line_graph;
61+
EXPECT_TRUE(BuildLineGraph<TypeParam>(graph, &line_graph));
62+
EXPECT_EQ(0, line_graph.num_nodes());
63+
EXPECT_EQ(0, line_graph.num_arcs());
64+
}
65+
66+
TYPED_TEST(LineGraphTest, LineGraphOfSingleton) {
67+
TypeParam graph(1, 1);
68+
graph.AddArc(0, 0);
69+
TypeParam line_graph;
70+
EXPECT_TRUE(BuildLineGraph<TypeParam>(graph, &line_graph));
71+
EXPECT_EQ(1, line_graph.num_nodes());
72+
EXPECT_EQ(1, line_graph.num_arcs());
73+
}
74+
75+
TYPED_TEST(LineGraphTest, LineGraph) {
76+
const typename TypeParam::NodeIndex kNodes = 4;
77+
const typename TypeParam::ArcIndex kArcs[][2] = {
78+
{0, 1}, {0, 2}, {1, 2}, {2, 0}, {2, 3}};
79+
const typename TypeParam::ArcIndex kExpectedLineArcs[][2] = {
80+
{0, 2}, {2, 3}, {3, 0}, {3, 1}, {2, 4}, {1, 4}, {1, 3}};
81+
TypeParam graph(kNodes, ABSL_ARRAYSIZE(kArcs));
82+
for (int i = 0; i < ABSL_ARRAYSIZE(kArcs); ++i) {
83+
graph.AddArc(kArcs[i][0], kArcs[i][1]);
84+
}
85+
TypeParam line_graph;
86+
EXPECT_TRUE(BuildLineGraph<TypeParam>(graph, &line_graph));
87+
EXPECT_EQ(ABSL_ARRAYSIZE(kArcs), line_graph.num_nodes());
88+
EXPECT_EQ(ABSL_ARRAYSIZE(kExpectedLineArcs), line_graph.num_arcs());
89+
for (int i = 0; i < ABSL_ARRAYSIZE(kExpectedLineArcs); ++i) {
90+
const typename TypeParam::NodeIndex expected_tail = kExpectedLineArcs[i][0];
91+
const typename TypeParam::NodeIndex expected_head = kExpectedLineArcs[i][1];
92+
bool found = false;
93+
for (typename TypeParam::OutgoingArcIterator out_iterator(line_graph,
94+
expected_tail);
95+
out_iterator.Ok(); out_iterator.Next()) {
96+
const typename TypeParam::ArcIndex arc = out_iterator.Index();
97+
if (line_graph.Head(arc) == expected_head) {
98+
found = true;
99+
break;
100+
}
101+
}
102+
EXPECT_TRUE(found) << expected_tail << " " << expected_head;
103+
}
104+
}
105+
106+
} // namespace
107+
} // namespace operations_research

0 commit comments

Comments
 (0)