Skip to contents

Records how the PageRank stationary vector was obtained: which solver ran, how many iterations it used (when that is observable), and how well the returned vector satisfies the PageRank fixed-point equation. It is attached to the result of [compute_pagerank()] / [pagerank()] as the `"convergence"` attribute and is the companion to the [transition_audit][transition_audit] provenance record.

Details

## Why the solver matters

`igraph::page_rank()` offers two back-ends:

`"prpack"`

(default) A direct/sparse solver (the PRPACK library). It is fast and exact to machine precision, but it is **not** iterative in any way it exposes: there is no iteration count and no tolerance knob, so `iters` is reported as `NA` and `eps` / `niter` have no effect.

`"arpack"`

An iterative eigensolver. It honors a tolerance and a maximum iteration count and reports the iterations it actually used and whether it converged. This is the only back-end on which `eps` and `niter` take effect; supplying either to [compute_pagerank()] / [pagerank()] therefore transparently selects it.

The old `igraph` `eps` / `niter` arguments to `page_rank()` were removed in modern `igraph` (2.x); this package re-introduces them as friendly aliases that map onto the ARPACK `options$tol` / `options$maxiter` controls.

## The residual is solver-independent

Regardless of back-end, `residual` is computed here directly from the returned vector as the L1 norm of one PageRank operator application, \(\|G x - x\|_1\), where \(G\) is the Google operator implied by the scored graph, the damping factor, and the teleport vector (uniform, or the supplied TIPR prior). This is the standard Kamvar, Haveliwala & Golub (2004) stopping criterion, evaluated *post hoc* so it is a genuine, comparable quality check across both solvers (a converged solution sits near machine precision). `tol_met` reports whether `residual` is at or below `tol` (the supplied `eps`, or the conventional default of `1e-3` when `eps` is `NULL`), additionally requiring `info == 0` for the ARPACK back-end.

## Iteration-count rule of thumb

Power-iteration PageRank needs about \(\log_{10}(\tau) / \log_{10}(\alpha)\) iterations to reach residual \(\tau\) at damping \(\alpha\) (Langville & Meyer, 2004). At \(\tau = 10^{-8}\): \(\alpha = 0.85\) needs ~114, \(\alpha = 0.95\) ~362, and \(\alpha = 0.99\) ~1,833 iterations — so a high damping factor degrades convergence sharply. ARPACK is not plain power iteration, so its reported `iters` is typically far lower, but the same qualitative warning applies: raise `niter` if you raise the damping factor toward 1.

See also

[compute_pagerank()], [pagerank()], [transition_audit]

Examples

edges <- data.frame(
  from = c("A", "B", "C", "A"),
  to = c("B", "C", "A", "C")
)

# The default PRPACK back-end is direct, so it reports no iteration count.
# The residual is still computed post hoc, so it stays comparable.
conv <- attr(compute_pagerank(edges), "convergence")
conv
#> === PageRank Convergence ===
#> 
#>   Solver:     prpack (direct; no iteration count) 
#>   Iterations: NA (not exposed by this solver) 
#>   Residual:   5.551e-17 (L1 |Gx - x|)
#>   Tolerance:  1.000e-03 (default) 
#>   Converged:  yes 
conv$algo
#> [1] "prpack"
conv$iters # NA: PRPACK does not expose iterations
#> [1] NA
conv$tol_met
#> [1] TRUE

# Supplying eps / niter transparently selects the iterative ARPACK
# back-end (with a message), which honors the tolerance and reports the
# iterations it used. Pass algo = "arpack" explicitly to silence it.
conv_arpack <- attr(
  compute_pagerank(edges, eps = 1e-10, niter = 1000), "convergence"
)
#> `eps`/`niter` are only honoured by the ARPACK solver; switching `algo` to "arpack". Pass `algo = "arpack"` explicitly to silence this message.
conv_arpack$algo
#> [1] "arpack"
conv_arpack$iters
#> [1] 1
conv_arpack$tol
#> [1] 1e-10