import math


def iterate_pagerank(corpus, damping_factor):
    """
    Return PageRank values for each page by iteratively updating
    PageRank values until convergence.

    Return a dictionary where keys are page names, and values are
    their estimated PageRank value (a value between 0 and 1). All
    PageRank values should sum to 1.
    """
    # initialize a dictionary for storing pagerank
    pagerank = {}

    # abbreviation
    n = len(corpus)
    d = damping_factor

    # assign same pagerank to each page
    for pages in corpus:
        pagerank[pages] = 1 / n

    # initialize an update pagerank dictionary
    update_pagerank = {}

    # while the different between rank is not close enough
    diff_not_close = True
    while diff_not_close:

        # pick an page(p) from pagerank dictionary
        for page_p in pagerank:

            # initialize a score contributed by the previous page
            rank_by_prev_page = 0

            # pick an page(i) from corpus of webpages
            for page_i in corpus:

                # if page(i) link to page(p)
                if page_p in corpus[page_i]:
                    rank_by_prev_page += pagerank[page_i]/len(corpus[page_i])

                # if page(i) do not link to any pages, assume it links to all pages with same probability
                if not corpus[page_i]:
                    rank_by_prev_page += pagerank[page_i]/n

            # Iterative Algorithm
            update_pagerank[page_p] = (1-d)/n + d*rank_by_prev_page

        for page in pagerank:

            # compute if the previous pagerank and update pagerank are close enough to each other
            if not math.isclose(update_pagerank[page], pagerank[page], abs_tol=0.001):
                diff_not_close = True
            else:
                diff_not_close = False

            # go to the next page
            pagerank[page] = update_pagerank[page]

    return pagerank