We are going to try different numerical methods learnt in class on the Google PageRank problem.
0.1 Q1 (5 pts) Recognize structure
Let \(\mathbf{A} \in \{0,1\}^{n \times n}\) be the connectivity matrix of \(n\) web pages with entries \[
\begin{eqnarray*}
a_{ij}= \begin{cases}
1 & \text{if page $i$ links to page $j$} \\
0 & \text{otherwise}
\end{cases}.
\end{eqnarray*}
\]\(r_i = \sum_j a_{ij}\) is the out-degree of page \(i\). That is \(r_i\) is the number of links on page \(i\). Imagine a random surfer exploring the space of \(n\) pages according to the following rules.
From a page \(i\) with \(r_i>0\)
with probability \(p\), (s)he randomly chooses a link on page \(i\) (uniformly) and follows that link to the next page
with probability \(1-p\), (s)he randomly chooses one page from the set of all \(n\) pages (uniformly) and proceeds to that page
From a page \(i\) with \(r_i=0\) (a dangling page), (s)he randomly chooses one page from the set of all \(n\) pages (uniformly) and proceeds to that page
The process defines a Markov chain on the space of \(n\) pages. Write the transition matrix \(\mathbf{P}\) of the Markov chain as a sparse matrix plus rank 1 matrix.
0.2 Q2 Relate to numerical linear algebra
According to standard Markov chain theory, the (random) position of the surfer converges to the stationary distribution \(\mathbf{x} = (x_1,\ldots,x_n)^T\) of the Markov chain. \(x_i\) has the natural interpretation of the proportion of times the surfer visits page \(i\) in the long run. Therefore \(\mathbf{x}\) serves as page ranks: a higher \(x_i\) means page \(i\) is more visited. It is well-known that \(\mathbf{x}\) is the left eigenvector corresponding to the top eigenvalue 1 of the transition matrix \(\mathbf{P}\). That is \(\mathbf{P}^T \mathbf{x} = \mathbf{x}\). Therefore \(\mathbf{x}\) can be solved as an eigen-problem. It can also be cast as solving a linear system. Since the row sums of \(\mathbf{P}\) are 1, \(\mathbf{P}\) is rank deficient. We can replace the first equation by the \(\sum_{i=1}^n x_i = 1\).
Hint: For iterative solvers, we don’t need to replace the 1st equation. We can use the matrix \(\mathbf{I} - \mathbf{P}^T\) directly if we start with a vector with all positive entries.
0.3 Q3 (10 pts) Explore data
Obtain the connectivity matrix A from the SNAP/web-Google data in the MatrixDepot package.
usingMatrixDepotmd =mdopen("SNAP/web-Google")# display documentation for the SNAP/web-Google datamdinfo(md)
[ Info: verify download of index files...
[ Info: reading database
[ Info: adding metadata...
[ Info: adding svd data...
[ Info: writing database
[ Info: used remote sites are sparse.tamu.edu with MAT index and math.nist.gov with HTML index
1 SNAP/web-Google
1.0.0.0.0.1 MatrixMarket matrix coordinate pattern general
How much memory does A take? If converted to a Matrix{Float64} (don’t do it!), how much memory will it take?
number of web pages
number of edges (web links)
number of dangling nodes (pages with no out links)
histogram of in-degrees
list the top 20 pages with the largest in-degrees?
histogram of out-degrees
which the top 20 pages with the largest out-degrees?
visualize the sparsity pattern of \(\mathbf{A}\) or a submatrix of \(\mathbf{A}\) say A[1:10000, 1:10000].
Hint: For plots, you can use the UnicodePlots.jl package (spy, histogram, etc), which is fast for large data.
1.1 Q4 (5 pts) Dense linear algebra?
Consider the following methods to obtain the page ranks of the SNAP/web-Google data.
A dense linear system solver such as LU decomposition.
A dense eigen-solver for asymmetric matrix.
For the LU approach, estimate (1) the memory usage and (2) how long it will take assuming that the LAPACK functions can achieve the theoretical throughput of your computer.
1.2 Q5 (75 pts) Iterative solvers
Set the teleportation parameter at \(p = 0.85\). Consider the following methods for solving the PageRank problem.
An iterative linear system solver such as GMRES.
An iterative eigen-solver such as Arnoldi method.
For iterative methods, we have many choices in Julia. See a list of existing Julia packages for linear solvers at this page. The start-up code below uses the KrylovKit.jl package. You can use other packages if you prefer. Make sure to utilize the special structure of \(\mathbf{P}\) (sparse + rank 1) to speed up the matrix-vector multiplication.
1.2.1 Step 1 (15 pts)
Let’s implement a type PageRankImPt that mimics the matrix \(\mathbf{M} = \mathbf{I} - \mathbf{P}^T\). For iterative methods, all we need to provide are methods for evaluating \(\mathbf{M} \mathbf{v}\) and \(\mathbf{M}^T \mathbf{v}\) for arbitrary vector \(\mathbf{v}\).
usingBenchmarkTools, LinearAlgebra, SparseArrays, Revise# a type for the matrix M = I - P^T in PageRank problemstruct PageRankImPt{TA <: Number, IA <: Integer, T <: AbstractFloat} <: AbstractMatrix{T} A :: SparseMatrixCSC{TA, IA} # adjacency matrix telep :: T# working arrays# TODO: whatever intermediate arrays you may want to pre-allocateend# constructorfunctionPageRankImPt(A::SparseMatrixCSC, telep::T) where T <: AbstractFloat n =size(A, 1)# TODO: initialize and pre-allocate arraysPageRankImPt(A, telep)endLinearAlgebra.issymmetric(::PageRankImPt) =falseBase.size(M::PageRankImPt) =size(M.A)# TODO: implement this function for evaluating M[i, j]Base.getindex(M::PageRankImPt, i, j) = M.telep# overwrite `out` by `(I - Pt) * v`functionLinearAlgebra.mul!( out :: Vector{T}, M :: PageRankImPt{<:Number, <:Integer, T}, v :: Vector{T} ) where T <: AbstractFloat# TODO: implement mul!(out, M, v)sleep(1e-2) # wait 10 ms as if your code takes 1msreturn outend# overwrite `out` by `(I - P) * v`functionLinearAlgebra.mul!( out :: Vector{T}, Mt :: Transpose{T, PageRankImPt{TA, IA, T}}, v :: Vector{T} ) where {TA<:Number, IA<:Integer, T <: AbstractFloat} M = Mt.parent# TODO: implement mul!(out, transpose(M), v)sleep(1e-2) # wait 10 ms as if your code takes 1ms outend
To check correctness. Note \[
\mathbf{M}^T \mathbf{1} = \mathbf{0}
\] and \[
\mathbf{M} \mathbf{x} = \mathbf{0}
\] for stationary distribution \(\mathbf{x}\).
Download the solution file pgrksol.csv.gz. Do not put this file in your Git. You will lose points if you do. You can add a line pgrksol.csv.gz to your .gitignore file.
usingCodecZlib, DelimitedFilesisfile("pgrksol.csv.gz") ||download("https://raw.githubusercontent.com/ucla-biostat-257/2023spring/master/hw/hw4/pgrksol.csv.gz")xsol =open("pgrksol.csv.gz", "r") do iovec(readdlm(GzipDecompressorStream(io)))end