Source code for hypergraphx.motifs.motifs

import logging

from hypergraphx import Hypergraph
from hypergraphx.generation.configuration_model import configuration_model
from hypergraphx.motifs.utils import (
    _motifs_ho_full,
    _motifs_ho_not_full,
    _motifs_standard,
    diff_sum,
    norm_vector,
)


[docs] def compute_motifs( hypergraph: Hypergraph, order=3, runs_config_model=10, *, seed: int | None = None, rng=None, ): """ Compute the number of motifs of a given order in a hypergraph. Parameters ---------- hypergraph : Hypergraph The hypergraph of interest order : int The order of the motifs to compute runs_config_model : int The number of runs of the configuration model Returns ------- dict keys: 'observed', 'config_model', 'norm_delta' 'observed' reports the number of occurrences of each motif in the observed hypergraph 'config_model' reports the number of occurrences of each motif in each sample of the configuration model 'norm_delta' reports the norm of the difference between the observed and the configuration model """ if rng is not None and seed is not None: raise ValueError("Provide only one of seed= or rng=.") import numpy as np rng = rng if rng is not None else np.random.default_rng(seed) def _motifs_order_3(edges): full, visited = _motifs_ho_full(edges, 3) standard = _motifs_standard(edges, 3, visited) res = [] for i in range(len(full)): res.append((full[i][0], max(full[i][1], standard[i][1]))) return res def _motifs_order_4(edges): full, visited = _motifs_ho_full(edges, 4) not_full, visited = _motifs_ho_not_full(edges, 4, visited) standard = _motifs_standard(edges, 4, visited) res = [] for i in range(len(full)): res.append((full[i][0], max([full[i][1], not_full[i][1], standard[i][1]]))) return res edges = hypergraph.get_edges(size=order, up_to=True) output = {} logger = logging.getLogger(__name__) logger.info("Computing observed motifs of order %s...", order) if order == 3: output["observed"] = _motifs_order_3(edges) elif order == 4: output["observed"] = _motifs_order_4(edges) else: raise ValueError("Exact computation of motifs of order > 4 is not available.") if runs_config_model == 0: return output STEPS = hypergraph.num_edges(size=order, up_to=True) * 10 ROUNDS = runs_config_model results = [] for i in range(ROUNDS): logger.info("Computing config model motifs of order %s. Step: %s", order, i + 1) sub_seed = int(rng.integers(0, 2**32 - 1, dtype=np.uint32)) e1 = configuration_model(hypergraph, label="edge", n_steps=STEPS, seed=sub_seed) if order == 3: m1 = _motifs_order_3(e1.get_edges()) elif order == 4: m1 = _motifs_order_4(e1.get_edges()) else: raise ValueError( "Exact computation of motifs of order > 4 is not available." ) results.append(m1) output["config_model"] = results delta = diff_sum(output["observed"], output["config_model"]) norm_delta = norm_vector(delta) output["norm_delta"] = [] for i in range(len(delta)): output["norm_delta"].append((output["observed"][i][0], norm_delta[i])) return output