This folder contains the codes for analyzing the scalability of FUSE with respect to the fairly large datasets we used - ArXiV, MAG and Products for a single seed. For the datasets MAG and products, we have used the unsupervised version of FUSE tocompute the embeddings much faster. However one can also implement the label guided version, code of which can be found in the experimental procedure given in the folders for the benchmarks. For the supervised version of FUSE, the fuse_unsupervised function should be replaced by: 

def fuse_embedding(G, labels, label_mask, k=DEFAULT_EMB_DIM, eta=0.05, lambda_supervised=1.0,
                   lambda_semi=2.0, iterations=200, initialization='random',
                   num_walks=10, walk_length=5, walk_length_labelled=3, seed=None):
    """
    FUSE: your semi-supervised modularity-based embedding
    Returns S (n_nodes x k) numpy array
    """
    if seed is not None:
        np.random.seed(seed)
        random.seed(seed)

    A = csr_matrix(nx.to_scipy_sparse_array(G, format='csr'))
    degrees = np.array(A.sum(axis=1)).flatten()
    m = G.number_of_edges()
    n = A.shape[0]

    if initialization == 'random':
        S = np.random.randn(n, k)
    else:
        S = np.random.randn(n, k)
    # Orthonormalize columns
    S, _ = np.linalg.qr(S)

    labeled_walks = perform_labeled_random_walks(G, label_mask, labels, num_walks, walk_length, walk_length_labelled)
    attention_weights = compute_attention_weights(S, labeled_walks)

    for _ in tqdm(range(iterations)):
        neighbor_agg = A @ S
        global_correction = (degrees[:, None] / (2 * m)) * S.sum(axis=0)
        grad_modularity = (1 / (2 * m)) * (neighbor_agg - global_correction)

        grad_supervised = np.zeros_like(S)
        if np.any(label_mask):
            unique_labels = np.unique(labels[label_mask])
            for lab in unique_labels:
                mask = (labels == lab) & label_mask
                if mask.sum() == 0:
                    continue
                mean_embedding = np.mean(S[mask], axis=0, keepdims=True)
                grad_supervised[mask] = S[mask] - mean_embedding

        grad_semi_supervised = np.zeros_like(S)
        for i in range(n):
            if (not label_mask[i]) and (i in attention_weights):
                weighted_embedding = sum(w * S[j] for j, w in attention_weights[i].items())
                grad_semi_supervised[i] = S[i] - weighted_embedding

        grad_total = grad_modularity - lambda_supervised * grad_supervised - lambda_semi * grad_semi_supervised
        S += eta * grad_total
        S, _ = np.linalg.qr(S)

    return S

    