<jupyter_start><jupyter_text>Basic syntaxLet's examine some basic graphblas syntax<jupyter_code>A = Matrix.from_values(
    [0, 0, 1, 2, 2, 3, 4],
    [1, 2, 3, 3, 4, 4, 0],
    [1.1, 9.8, 4.2, 7.1, 0.2, 6.9, 2.2],
)
A
gio.draw(A)
v = Vector(dtypes.FP64, 5)
v
v << A.reduce_columnwise(monoid.max)
v
A.mxv(v, semiring.min_plus).new(name="μ_0")<jupyter_output><empty_output><jupyter_text>Compare with CLet's compare syntax from with the GraphBLAS C API.This is an example from `LAGraph_pagerank3f````c++GrB_Info LAGraph_pagerank3f // PageRank definition(    GrB_Vector *result,     // output: array of LAGraph_PageRank structs    GrB_Matrix A,           // binary input graph, not modified    GrB_Vector d_out,       // outbound degree of all nodes (not modified)    float damping,          // damping factor (typically 0.85)    int itermax,            // maximum number of iterations    int *iters              // output: number of iterations taken){    //--------------------------------------------------------------------------    // initializations    //--------------------------------------------------------------------------    GrB_Info info ;    GrB_Index n ;    GrB_Vector r = NULL, d = NULL, t = NULL, w = NULL ;    (*result) = NULL ;    LAGr_Matrix_nrows (&n, A) ;    GrB_Descriptor desc_t0 = GrB_DESC_T0 ;    const float teleport = (1 - damping) / n ;    const float tol = 1e-4 ;    float rdiff = 1 ;       // first iteration is always done    // r = 1 / n    LAGr_Vector_new (&t, GrB_FP32, n) ;    LAGr_Vector_new (&r, GrB_FP32, n) ;    LAGr_Vector_new (&w, GrB_FP32, n) ;    LAGr_assign (r, NULL, NULL, 1.0 / n, GrB_ALL, n, NULL) ;    // prescale with damping factor, so it isn't done each iteration    // d = d_out / damping ;    LAGr_Vector_dup (&d, d_out) ;    LAGr_assign (d, NULL, GrB_DIV_FP32, damping, GrB_ALL, n, NULL) ;    //--------------------------------------------------------------------------    // pagerank iterations    //--------------------------------------------------------------------------    for ((*iters) = 0 ; (*iters)  tol ; (*iters)++)    {        // swap t and r ; now t is the old score        GrB_Vector temp = t ; t = r ; r = temp ;        // w = t ./ d        LAGr_eWiseMult (w, NULL, NULL, GrB_DIV_FP32, t, d, NULL) ;        // r = teleport        LAGr_assign (r, NULL, NULL, teleport, GrB_ALL, n, NULL) ;        // r += A'*w        LAGr_mxv (r, NULL, GrB_PLUS_FP32, GxB_PLUS_SECOND_FP32, A, w, desc_t0) ;        // t -= r        LAGr_assign (t, NULL, GrB_MINUS_FP32, r, GrB_ALL, n, NULL) ;        // t = abs (t)        LAGr_apply (t, NULL, NULL, GxB_ABS_FP32, t, NULL) ;        // rdiff = sum (t)        LAGr_reduce (&rdiff, NULL, GxB_PLUS_FP32_MONOID, t, NULL) ;    }```<jupyter_code>def pagerank_3f(A, d_out, damping=0.85, itermax=100, tol=1e-4):
    """
    Returns (result as Vector, iters as int)
    """
    n = A.nrows
    teleport = (1 - damping) / n
    rdiff = 1  # first iteration is always done

    # r = 1 / n
    t = Vector(dtypes.FP32, n)
    r = Vector(dtypes.FP32, n)
    w = Vector(dtypes.FP32, n)
    r[:] << 1.0 / n

    # prescale with damping factor, so it isn't done each iteration
    # d = d_out / damping
    d = d_out.dup(dtype="FP32")
    d(accum=binary.truediv)[:] << damping

    # --------------------------------------------------------------------------
    # pagerank iterations
    # --------------------------------------------------------------------------
    for i in range(itermax):
        if rdiff <= tol:
            break

        # swap t and r ; now t is the old score
        r, t = t, r

        # w = t ./ d
        w << t.ewise_mult(d, binary.truediv)

        # r = teleport
        r[:] << teleport

        # r += A'*w
        r(binary.plus) << A.T.mxv(w, semiring.plus_second)

        # t -= r
        t(binary.minus)[:] << r

        # t = abs (t)
        t << t.apply(unary.abs)

        # rdiff = sum (t)
        rdiff = t.reduce(monoid.plus).value

    return r, i
A
# Pagerank requires binary input graph
A << A.apply(unary.one)
A
# Compute outbound degree of nodes
d_out = A.reduce_rowwise(monoid.plus).new()
d_out
result, iters = pagerank_3f(A, d_out)
result
iters<jupyter_output><empty_output><jupyter_text>Compare with networkx for accuracy<jupyter_code>import networkx as nx

g = gio.to_networkx(A)
g.edges()
nx.pagerank(g, tol=1e-4)<jupyter_output><empty_output><jupyter_text>Compare with networkx for speedNeed a larger graph for this test<jupyter_code>big = nx.erdos_renyi_graph(1000, 0.04, directed=True)
%%timeit
pr = nx.pagerank(big, tol=1e-6)
B = gio.from_networkx(big, dtype="UINT8")
B
%%timeit
bd_out = B.reduce_rowwise(monoid.plus).new()
results, iter = pagerank_3f(B, bd_out, tol=1e-6)
# timeit doesn't save variables, so recompute
pr = nx.pagerank(big, tol=1e-6)
bd_out = B.reduce_rowwise(monoid.plus).new()
results, iter = pagerank_3f(B, bd_out, tol=1e-6)
iter
results
# Only look at first 10 results from networkx
{k: v for k, v in pr.items() if k < 10}
# Verify all results match
all(abs(results[i].value - pr[i]) < 1e-5 for i in range(1000))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.2115987460815047, 'fraction_numerical': 0.023706896551724137, 'mean_word_length': 1.9645760743321719, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '75217', 'license': 'Apache-2.0', 'n_tokens_mistral': 1920, 'n_tokens_neox': 1825, 'n_words': 498, 'path': 'notebooks/Pagerank Demo.ipynb', 'repo_name': 'ParticularMiner/grblas', 'size': '5104'}