def lazy_approximate_personalized_pagerank(s,
                                           r,
                                           w_i,
                                           a_i,
                                           out_degree,
                                           in_degree,
                                           seed_node,
                                           rho=0.2,
                                           epsilon=0.00001,
                                           laziness_factor=0.5):
    """
    Calculates the approximate personalized PageRank starting from a seed node with self-loops.

    Introduced in: Andersen, R., Chung, F., & Lang, K. (2006, October).
                   Local graph partitioning using pagerank vectors.
                   In Foundations of Computer Science, 2006. FOCS'06. 47th Annual IEEE Symposium on (pp. 475-486). IEEE.
    """
    # Initialize approximate PageRank and residual distributions
    # s = np.zeros(number_of_nodes, dtype=np.float64)
    # r = np.zeros(number_of_nodes, dtype=np.float64)
    r[seed_node] = 1.0

    # Initialize queue of nodes to be pushed
    pushable = deque()
    pushable.append(seed_node)

    # Do one push anyway
    push_node = pushable.popleft()

    pagerank_lazy_push(s,
                       r,
                       w_i[push_node],
                       a_i[push_node],
                       push_node,
                       rho,
                       laziness_factor)
    number_of_push_operations = 1

    i = np.where(np.divide(r[a_i[push_node]], in_degree[a_i[push_node]]) >= epsilon)[0]
    if i.size > 0:
        pushable.extend(a_i[push_node][i])

    while r[push_node]/in_degree[push_node] >= epsilon:
        pagerank_lazy_push(s,
                           r,
                           w_i[push_node],
                           a_i[push_node],
                           push_node,
                           rho,
                           laziness_factor)
        number_of_push_operations += 1

    # While there are nodes with large residual probabilities, push
    while len(pushable) > 0:
        push_node = pushable.popleft()

        if r[push_node]/in_degree[push_node] >= epsilon:
            pagerank_lazy_push(s,
                               r,
                               w_i[push_node],
                               a_i[push_node],
                               push_node,
                               rho,
                               laziness_factor)
            number_of_push_operations += 1

            i = np.where(np.divide(r[a_i[push_node]], in_degree[a_i[push_node]]) >= epsilon)[0]
            if i.size > 0:
                pushable.extend(a_i[push_node][i])

        while r[push_node]/in_degree[push_node] >= epsilon:
            pagerank_lazy_push(s,
                               r,
                               w_i[push_node],
                               a_i[push_node],
                               push_node,
                               rho,
                               laziness_factor)
            number_of_push_operations += 1

    return number_of_push_operations
Calculates the approximate personalized PageRank starting from a seed node with self-loops.

    Introduced in: Andersen, R., Chung, F., & Lang, K. (2006, October).
                   Local graph partitioning using pagerank vectors.
                   In Foundations of Computer Science, 2006. FOCS'06. 47th Annual IEEE Symposium on (pp. 475-486). IEEE.