Source code for paragon.algorithms.pagerank

"""
Parallel PageRank Algorithms

This module provides Python interfaces for high-performance
C++ implementations of PageRank in PARAGON.
"""

from typing import List
from ..core import Graph
from .._paragon import (
    parallel_pagerank as _parallel_pagerank,
    parallel_pagerank_bfs as _parallel_pagerank_bfs,
)


[docs] def parallel_pagerank( graph: Graph, iterations: int = 20, damping: float = 0.85, threads: int = -1, ) -> List[float]: """ Compute PageRank scores using a parallel pull-based approach. This method updates each node’s rank by aggregating contributions from incoming neighbors (reverse adjacency). Parameters ---------- graph : Graph Input graph (typically directed). iterations : int, optional (default = 20) Number of PageRank iterations. damping : float, optional (default = 0.85) Damping factor (probability of following links). threads : int, optional (default = -1) Number of threads to use. -1 means automatically use hardware concurrency. Returns ------- List[float] PageRank score for each node. Notes ----- - Pull-based computation using incoming edges. - Stable and widely used formulation. - Parallelized across nodes. Time Complexity --------------- O(iterations × (V + E)) Example ------- >>> from paragon import Graph >>> from paragon.algorithms import pagerank >>> g = Graph(4, directed=True) >>> g.add_edges([(0,1), (1,2), (2,0), (2,3)]) >>> parallel_pagerank(g) [0.25, 0.25, 0.25, 0.25] """ # Graph validation if not isinstance(graph, Graph): raise TypeError("graph must be an instance of Graph") # Iterations validation if not isinstance(iterations, int): raise TypeError("iterations must be an integer") if iterations <= 0: raise ValueError("iterations must be a positive integer") # Damping validation if not isinstance(damping, (int, float)): raise TypeError("damping must be a numeric value") if not (0.0 < damping < 1.0): raise ValueError("damping must be between 0 and 1 (exclusive)") # Threads validation if not isinstance(threads, int): raise TypeError("threads must be an integer") if threads == 0: raise ValueError("threads must be >= 1 or -1") if threads < -1: raise ValueError("threads must be -1 (auto) or a positive integer") return _parallel_pagerank(graph, iterations, damping, threads)
[docs] def parallel_pagerank_bfs( graph: Graph, iterations: int = 20, damping: float = 0.85, threads: int = -1, ) -> List[float]: """ Compute PageRank using a push-based (BFS-style) parallel approach. Each node distributes its rank to its outgoing neighbors, similar to a frontier expansion strategy. Parameters ---------- graph : Graph Input graph (typically directed). iterations : int, optional (default = 20) Number of PageRank iterations. damping : float, optional (default = 0.85) Damping factor. threads : int, optional (default = -1) Number of threads to use. Returns ------- List[float] PageRank score for each node. Notes ----- - Push-based computation (each node distributes rank). - Uses per-thread local buffers to avoid contention. - Efficient for sparse graphs. Time Complexity --------------- O(iterations × (V + E)) Example ------- >>> from paragon.algorithms import parallel_pagerank_bfs >>> parallel_pagerank_bfs(g) [0.25, 0.25, 0.25, 0.25] """ # Graph validation if not isinstance(graph, Graph): raise TypeError("graph must be an instance of Graph") # Iterations validation if not isinstance(iterations, int): raise TypeError("iterations must be an integer") if iterations <= 0: raise ValueError("iterations must be a positive integer") # Damping validation if not isinstance(damping, (int, float)): raise TypeError("damping must be a numeric value") if not (0.0 < damping < 1.0): raise ValueError("damping must be between 0 and 1 (exclusive)") # Threads validation if not isinstance(threads, int): raise TypeError("threads must be an integer") if threads == 0: raise ValueError("threads must be >= 1 or -1") if threads < -1: raise ValueError("threads must be -1 (auto) or a positive integer") return _parallel_pagerank_bfs(graph, iterations, damping, threads)