Skip to content

Commit b3ec1e4

Browse files
author
Laxman Dhulipala
committed
Change the stopping condition of the PageRank implementations (linhares)
1 parent 77265a8 commit b3ec1e4

File tree

5 files changed

+66
-25
lines changed

5 files changed

+66
-25
lines changed

benchmarks/PageRank/PageRank.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,9 @@ struct PR_F {
146146
//
147147
// The convergence threshold `eps` must be nonnegative. The algorithm stops when
148148
// the L1 distance between the PageRank values (seen as a vector with one entry
149-
// per node) in two consecutive iterations becomes smaller than `eps`, or when
150-
// `max_iters` iterations have been executed (whichever comes first).
149+
// per node) in two consecutive iterations becomes smaller than `eps * (number
150+
// of nodes in G)`, or when `max_iters` iterations have been executed (whichever
151+
// comes first).
151152
// `damping_factor` must be in the range [0, 1).
152153
//
153154
// If the source vector has non-zero length, the algorithm:
@@ -270,7 +271,7 @@ sequence<double> PageRank_edgeMap(const Graph& G, double eps = 0.000001,
270271

271272
// Swap p_curr and p_next. The final vector returned will be p_curr.
272273
std::swap(p_curr, p_next);
273-
if (L1_norm < eps) {
274+
if (L1_norm < eps * n) {
274275
break;
275276
}
276277

benchmarks/PageRank/PageRank_delta.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#ifndef THIRD_PARTY_GBBS_BENCHMARKS_PAGERANK_PAGERANK_DELTA_H_
2-
#define THIRD_PARTY_GBBS_BENCHMARKS_PAGERANK_PAGERANK_DELTA_H_
3-
41
// This code is part of the project "Theoretically Efficient Parallel Graph
52
// Algorithms Can Be Fast and Scalable", presented at Symposium on Parallelism
63
// in Algorithms and Architectures, 2018.
@@ -259,7 +256,7 @@ sequence<double> PageRankDelta(Graph& G, double eps = 0.000001,
259256
auto differences = parlay::delayed_seq<double>(
260257
n, [&](size_t i) { return fabs(Delta[i].delta); });
261258
double L1_norm = parlay::reduce(differences, parlay::plus<double>());
262-
if (L1_norm < eps) break;
259+
if (L1_norm < eps * n) break;
263260
gbbs_debug(std::cout << "L1_norm = " << L1_norm << std::endl;);
264261

265262
// Reset
@@ -277,5 +274,3 @@ sequence<double> PageRankDelta(Graph& G, double eps = 0.000001,
277274

278275
} // namespace delta
279276
} // namespace gbbs
280-
281-
#endif // THIRD_PARTY_GBBS_BENCHMARKS_PAGERANK_PAGERANK_DELTA_H_

benchmarks/PageRank/PageRank_edgeMapReduce.h

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#ifndef THIRD_PARTY_GBBS_BENCHMARKS_PAGERANK_PAGERANK_EDGEMAPREDUCE_H_
2-
#define THIRD_PARTY_GBBS_BENCHMARKS_PAGERANK_PAGERANK_EDGEMAPREDUCE_H_
3-
41
// This code is part of the project "Theoretically Efficient Parallel Graph
52
// Algorithms Can Be Fast and Scalable", presented at Symposium on Parallelism
63
// in Algorithms and Architectures, 2018.
@@ -25,7 +22,7 @@
2522
// SOFTWARE.
2623
//
2724
// This file provides an alternate implementation of computing PageRank. Please
28-
// see PageRank.h for comments that also apply to this file. The difference
25+
// see PageRank.h for comments that also apply to this file. The difference
2926
// between this implementation and the one in PageRank.h is some optimizations
3027
// used to speed up how the matrix-vector product works. We should carefully
3128
// benchmark the two implementations again, but from a few years ago (~2020),
@@ -70,10 +67,10 @@ inline void ValidatePageRankParameters(const double eps,
7067
const double damping_factor) {
7168
ASSERT(eps >= 0.0);
7269
ASSERT(0.0 <= damping_factor && damping_factor < 1.0);
73-
}
74-
7570
}
7671

72+
} // namespace pagerank_edgemapreduce_utils
73+
7774
// This version of PageRank uses edgeMapReduce_dense, an implementation
7875
// which reduces over the in-neighbors of every vertex and aggregates the
7976
// incoming contributions to each vertex in parallel.
@@ -203,7 +200,7 @@ sequence<double> PageRank_edgeMapReduce(Graph& G, double eps = 0.000001,
203200
std::swap(p_curr, p_next);
204201
// Reset p_curr and p_div.
205202
std::swap(p_div, p_div_next);
206-
if (L1_norm < eps) {
203+
if (L1_norm < eps * n) {
207204
break;
208205
}
209206
gbbs_debug(std::cout << "L1_norm = " << L1_norm << std::endl;);
@@ -216,8 +213,4 @@ sequence<double> PageRank_edgeMapReduce(Graph& G, double eps = 0.000001,
216213
return p_curr;
217214
}
218215

219-
220-
221-
}
222-
223-
#endif // THIRD_PARTY_GBBS_BENCHMARKS_PAGERANK_PAGERANK_EDGEMAPREDUCE_H_
216+
} // namespace gbbs

benchmarks/PageRank/PageRank_test.cc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "benchmarks/PageRank/PageRank.h"
44

5+
#include <cmath>
56
#include <cstddef>
67
#include <unordered_set>
78
#include <vector>
@@ -18,6 +19,7 @@
1819

1920
using ::testing::DoubleNear;
2021
using ::testing::ElementsAre;
22+
using ::testing::ElementsAreArray;
2123
using ::testing::IsEmpty;
2224
using ::testing::Pointwise;
2325

@@ -125,6 +127,59 @@ TYPED_TEST(PageRankFixture, Path) {
125127
}
126128
}
127129

130+
TYPED_TEST(PageRankFixture, RespectsEps) {
131+
// Graph diagram:
132+
// 0 - 1 - 2
133+
//
134+
constexpr uintE kNumVertices{3};
135+
const std::unordered_set<UndirectedEdge> kEdges{
136+
{0, 1},
137+
{1, 2},
138+
};
139+
auto graph{graph_test::MakeUnweightedSymmetricGraph(kNumVertices, kEdges)};
140+
using Impl = typename TestFixture::Impl;
141+
142+
{
143+
// Between iterations 4 and 5 and between iterations 5 and 6, the L1
144+
// distance between the PageRank values are approximately 0.295804 and
145+
// 0.251433 respectively. The next lines verify that assumption.
146+
const sequence<double> result_with_4_iterations =
147+
Impl::compute_pagerank(graph, /*eps=*/1e-6, /*sources=*/{},
148+
/*damping_factor=*/0.85, /*max_iters=*/4);
149+
const sequence<double> result_with_5_iterations =
150+
Impl::compute_pagerank(graph, /*eps=*/1e-6, /*sources=*/{},
151+
/*damping_factor=*/0.85, /*max_iters=*/5);
152+
const sequence<double> result_with_6_iterations =
153+
Impl::compute_pagerank(graph, /*eps=*/1e-6, /*sources=*/{},
154+
/*damping_factor=*/0.85, /*max_iters=*/6);
155+
156+
double l1_distance_iteration_4_to_5 = 0.0;
157+
for (int i = 0; i < 3; ++i) {
158+
l1_distance_iteration_4_to_5 +=
159+
fabs(result_with_4_iterations[i] - result_with_5_iterations[i]);
160+
}
161+
ASSERT_GT(l1_distance_iteration_4_to_5, 0.28);
162+
ASSERT_LT(l1_distance_iteration_4_to_5, 0.3);
163+
164+
double l1_distance_iteration_5_to_6 = 0.0;
165+
for (int i = 0; i < 3; ++i) {
166+
l1_distance_iteration_5_to_6 +=
167+
fabs(result_with_5_iterations[i] - result_with_6_iterations[i]);
168+
}
169+
ASSERT_GT(l1_distance_iteration_5_to_6, 0.24);
170+
ASSERT_LT(l1_distance_iteration_5_to_6, 0.26);
171+
172+
// Run the algorithm with `eps` small enough to reach iteration 5, but not
173+
// iteration 6.
174+
EXPECT_THAT(Impl::compute_pagerank(graph, /*eps=*/0.31 / 3),
175+
ElementsAreArray(result_with_5_iterations));
176+
// Run the algorithm with `eps` small enough to reach iteration 6, but not
177+
// iteration 7.
178+
EXPECT_THAT(Impl::compute_pagerank(graph, /*eps=*/0.27 / 3),
179+
ElementsAreArray(result_with_6_iterations));
180+
}
181+
}
182+
128183
TYPED_TEST(PageRankFixture, BasicUndirected) {
129184
// Graph diagram:
130185
// 0 - 1 2 - 3 - 4

gbbs/helpers/parallel_for_with_status.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
#ifndef THIRD_PARTY_GBBS_GBBS_HELPERS_PARALLEL_FOR_WITH_STATUS_H_
2-
#define THIRD_PARTY_GBBS_GBBS_HELPERS_PARALLEL_FOR_WITH_STATUS_H_
1+
#pragma once
32

43
#include <cstddef>
54

@@ -41,5 +40,3 @@ absl::Status parallel_for_with_status(
4140
}
4241

4342
} // namespace gbbs
44-
45-
#endif // THIRD_PARTY_GBBS_GBBS_HELPERS_PARALLEL_FOR_WITH_STATUS_H_

0 commit comments

Comments
 (0)