SIBERIA provides maximum-entropy null models and validation methods for signed networks derived from time series.
Starting from an N × T matrix of standardized time series, it builds signed co-fluctuation signatures, fits maximum-entropy models, and produces validated signed graphs that can be analyzed via community detection.
The library implements advanced null models (bSRGM and bSCM, plus the naive projection) to distinguish meaningful mesoscale structure from noise, supporting reproducible and interpretable time-series network analysis.
Here is a minimal end-to-end example that generates synthetic data, fits a null model, validates signatures, builds a graph, and detects communities:
import numpy as np
from siberia import TSeries
# 1. Generate synthetic standardized time series (N nodes, T time steps)
N, Tlen = 50, 500
rng = np.random.default_rng(42)
data = rng.normal(size=(N, Tlen)).astype(float)
# 2. Initialize TSeries
T = TSeries(data=data, n_jobs=4)
# 3. Compute signature
T.compute_signature()
# 4. Fit a null model (bSCM with fixed-point solver)
T.fit(
model="bSCM",
maxiter=1000,
max_nfev=1000,
tol=1e-8,
eps=1e-8,
solver_type="fixed_point"
)
# 5. Predict event probabilities under the null model
T.predict()
# 6. Check signature distributions (ensemble vs analytical, KS score)
ks_score = T.check_distribution_signature(
n_ensemble=500,
ks_score=True,
alpha=0.05
)
print("KS score:", ks_score)
# 7. Build a validated signed graph with FDR correction
graph = T.build_graph(
fdr_correction_flag=True,
alpha=0.05
)
# 8. Detect communities via signed SBM BIC minimization
communities = T.community_detection(
trials=200,
n_jobs=4,
method="bic",
show=False,
random_state=42,
starter="mixture"
)
print("Detected communities:", np.unique(communities))
# 9. Plot adjacency and community structure
T.plot_graph(export_path="results/adjacency", show=True)
T.plot_communities(export_path="results/communities", show=True)
T.plot_block_matrix(export_path="results/block_matrix", show=True)If you use SIBERIA in your research, please cite the following paper:
@misc{divece2025assessingimbalancesignedbrain,
title={Assessing (im)balance in signed brain networks},
author={Marzio Di Vece and Emanuele Agrimi and Samuele Tatullo and Tommaso Gili and Miguel Ibáñez-Berganza and Tiziano Squartini},
year={2025},
eprint={2508.00542},
archivePrefix={arXiv},
primaryClass={physics.soc-ph},
url={https://arxiv.org/abs/2508.00542},
}SIBERIA can be installed via pip. Run:
pip install siberiaTo upgrade to the latest version:
pip install siberia --upgradeSIBERIA requires the following libraries:
- numpy for numerical operations
- scipy for optimization and statistical functions
- pandas for structured data handling
- fast-poibin for Poisson–Binomial distributions
- joblib for parallel computation
- statsmodels for multiple testing corrections (FDR)
- matplotlib and seaborn for visualization
- tqdm for progress bars
- numba for accelerating heavy computations
Install them via:
pip install numpy scipy pandas fast-poibin joblib statsmodels matplotlib seaborn tqdm numbaThe main entry point of SIBERIA is the TSeries class, initialized with an N × T float matrix representing N time series of length T.
If the rows are not standardized (mean ≈ 0, std ≈ 1), they are standardized internally.
from siberia import TSeries
import numpy as np
# Tij is a 2D numpy array of shape (N, T) with float values
Tij = np.asarray(Tij, dtype=float)
T = TSeries(data=Tij, n_jobs=4)After initialization, you can explore marginal statistics of the binarized series:
T.ai_plus, T.ai_minus # row-wise positive / negative counts
T.kt_plus, T.kt_minus # column-wise positive / negative counts
T.a_plus, T.a_minus # total positive / negative countsThe signature captures concordant and discordant co-fluctuation motifs:
binary_signature = T.compute_signature()Internally:
- Concordant motifs = positive–positive + negative–negative
- Discordant motifs = positive–negative + negative–positive
- Binary signature = concordant − discordant
The result is stored in:
T.binary_signatureYou can list the available models:
T.implemented_models
# ['naive', 'bSRGM', 'bSCM']Choose and fit a maximum-entropy model:
T.fit(
model="bSCM", # 'bSRGM' or 'bSCM' or 'naive'
maxiter=1000,
max_nfev=1000,
tol=1e-8,
eps=1e-8,
solver_type="fixed_point" # 'fixed_point' or 'lsq' for bSCM
)After fitting, the following attributes become available:
T.params # fitted parameters
T.ll # log-likelihood
T.jac # Jacobian of the constraints
T.norm # infinite norm of the Jacobian
T.norm_rel_error # relative norm of the constraint error
T.aic # Akaike Information CriterionCompute the expected probability of observing positive and negative events in each i, t entry:
pit_plus, pit_minus = T.predict()These matrices are stored in:
T.pit_plus
T.pit_minusand represent the null-model probabilities for positive and negative events for each time series and time step.
You can compare the empirical signature with the null-model signature distributions using ensemble sampling and analytical calculations, summarized by a Kolmogorov–Smirnov score:
ks_score = T.check_distribution_signature(
n_ensemble=1000,
ks_score=True,
alpha=0.05
)This method:
- Generates an ensemble of signatures from the fitted model via Monte Carlo sampling.
- Computes analytical signature distributions (binomial / Poisson–Binomial) under the null model.
- Performs KS tests pairwise and returns a normalized KS score in
[0, 1], stored as:
T.ks_score
T.ensemble_signature # N × N × n_ensemble
T.analytical_signature # N × N × n_ensemble (or equivalent)
T.analytical_signature_dist # N × N × (T+1) PMFs for bSCM; analogous for bSRGMA higher ks_score indicates better agreement between ensemble and analytical signatures at the chosen alpha threshold.
From the empirical signature and the fitted model, you can construct a signed adjacency matrix using analytical p-values and (optionally) FDR correction:
graph = T.build_graph(
fdr_correction_flag=True,
alpha=0.05
)- For
model='naive', the graph is simply the sign of the empirical binary signature. - For
model='bSRGM'andmodel='bSCM', SIBERIA:- Computes analytical p-values for concordant motifs under the fitted model.
- Optionally applies Benjamini–Hochberg FDR correction on the upper triangle (
fdr_correction_flag=True). - Builds a signed adjacency matrix where only significant links are kept, with sign indicating concordant excess or deficit.
The validated projection is stored as:
T.graph # N × N signed adjacency matrix with entries in {-1, 0, 1}SIBERIA provides community detection based on greedy minimization of:
- BIC of a signed stochastic block model (
method="bic") - Frustration of the signed network (
method="frustration")
communities = T.community_detection(
trials=500,
n_jobs=4,
method="bic", # or "frustration"
show=False,
random_state=42,
starter="uniform" # or "mixture"
)This:
- Runs multiple randomized greedy trials in parallel.
- Minimizes the chosen objective for each trial.
- Returns the best partition and stores it as:
T.communities # length-N array of community labels (0, 1, 2, …)Plot the projected signed adjacency matrix:
T.plot_graph(
export_path="results/adjacency", # saves results/adjacency_adjacency.pdf
show=True
)This displays a heatmap with discrete values in {-1, 0, 1}.
Visualize the adjacency matrix reordered by detected communities, with blocks highlighted:
T.plot_communities(
export_path="results/communities", # saves results/communities_communities.pdf
show=True
)This produces:
- A reordered adjacency heatmap.
- Lines separating communities, based on
T.communities.
You can also inspect a coarse-grained block matrix summarizing dominant link signs between communities:
M = T.plot_block_matrix(
export_path="results/block_matrix", # saves results/block_matrix_block_matrix.pdf
show=True
)M is a K × K matrix (where K is the number of communities) with entries in {-1, 0, 1}, indicating whether positive or negative links dominate each intra- and inter-community block.
You can find the complete documentation of the SIBERIA library at:
https://siberia.readthedocs.io/en/latest/
Authors:
- Marzio Di Vece (a.k.a. MarsMDK)
- Emanuele Agrimi (a.k.a. Emaagr)
- Samuele Tatullo
Acknowledgments:
The module was developed under the supervision of
Tiziano Squartini,
Miguel Ibáñez Berganza, and
Tommaso Gili.
It was developed at the IMT School for Advanced Studies Lucca and Scuola Normale Superiore of Pisa.
This work is supported by the PNRR-M4C2-Investimento 1.3, Partenariato Esteso PE00000013 “FAIR–Future Artificial Intelligence Research” – Spoke 1 “Human-centered AI”, funded by the European Commission under the NextGeneration EU programme. MDV also acknowledges support by the European Community programme under the funding scheme ERC-2018-ADG G.A. 834756 “XAI: Science and technology for the eXplanation of AI decision making”.