Skip to main content

Vinnicombe nu-gap metric and a pipeline for comparing time-course data across two conditions

Project description

nugap

Detect condition-specific changes in dynamics using the Vinnicombe ν-gap metric.

![PyPI](https://pypi.org/project/nugap/) ![License: MIT](LICENSE) ![Open In Colab](https://colab.research.google.com/github/comparativechrono/nugap/blob/main/tutorial_nugap.ipynb)

nugap is a lightweight Python implementation of the Vinnicombe ν-gap — a bounded (0–1) distance between linear dynamical systems from robust control theory — together with the model identification and statistics needed to ask a practical question of two-condition time-course data:

**Which variables, or which relationships between them, change their *dynamical behaviour* between conditions?**

(for example wild type vs mutant, or untreated vs treated). Comparisons of expression level answer a different question and are blind to changes in timescale, gain or phase. The ν-gap is defined directly on dynamical models, so it is not: two systems close in ν-gap behave the same way under feedback, and a large ν-gap marks a genuine change in dynamics.

Installation

pip install nugap

For optional GPU acceleration of the pairwise-network sweep, also install a CUDA build of CuPy:

pip install nugap\[gpu]          # then a matching wheel, e.g. cupy-cuda12x

Requires Python ≥ 3.10. The core and pipelines depend only on NumPy, SciPy and pandas; the plotting helpers additionally use Matplotlib and NetworkX.

Tutorial

A guided, runnable tutorial covers the metric, model fitting, and the two-condition network comparison end to end:

Quick start

The ν-gap between two systems (coefficients in descending powers of s):

from nugap import tf, nu\_gap

P1 = tf(\[1], \[1, 1])     # 1/(s+1)
P2 = tf(\[1], \[1, 3])     # 1/(s+3)
nu\_gap(P1, P2)           # -> 0.447   (0 = identical, 1 = maximally different)

Comparing a whole interaction network between two conditions, with replicate-based significance:

from nugap import compare\_network

# data\_A, data\_B: dict {variable\_name: array of shape (replicates, timepoints)}
# t: the common time vector
edges = compare\_network(data\_A, data\_B, t, order=1, min\_r2=0.5)

edges.query("q\_global < 0.1")   # relationships rewired between conditions (FDR < 10%)

What it provides

  • nu\_gap — the Vinnicombe ν-gap for SISO systems in continuous or discrete time, with an optional frequency-band restriction (band=) and a switchable winding-number test (check\_winding=) for oscillatory data.
  • Model identificationfit\_first\_order, fit\_model, fit\_arx, fit\_prony, with simulation-based fit quality and an optional DC-gain floor (min\_dc\_gain=); plus the dc\_gain helper.
  • compare\_conditions — per-variable comparison of dynamics between two conditions, with a fit-quality reliability flag.
  • compare\_network — pairwise interaction-network comparison: a low-order model is fitted to every ordered pair of variables in each condition, the ν-gap is taken between conditions, and significance comes from a replicate-derived empirical null with Benjamini–Hochberg FDR control.
  • compare\_network\_batch — a vectorized, optionally GPU-accelerated drop-in for compare\_network (first-order models): same inputs, columns and statistics, but the per-edge fits and ν-gaps run in batches on NumPy (CPU) or CuPy (GPU), scaling to genome-size N\*(N-1) edge sweeps. Reproduces compare\_network to floating-point precision.
  • Plottingnugap.viz (volcano plot, hub network, hub bar plot).

Vectorized & GPU acceleration

For genome-scale sweeps (N\*(N-1) ordered edges), compare\_network\_batch is a drop-in, vectorized replacement for compare\_network. The per-edge first-order fits and ν-gaps are computed in batches with NumPy (CPU) or CuPy (GPU); it reproduces compare\_network's output to floating-point precision and scales to millions of edges.

from nugap import compare\_network\_batch

# identical call and columns to compare\_network; runs on CPU by default
edges = compare\_network\_batch(data\_A, data\_B, t, order=1, min\_r2=0.5)

# use a GPU if one is available (falls back to CPU otherwise)
edges = compare\_network\_batch(data\_A, data\_B, t, device="auto")
  • First-order only (order=1, n\_zeros=0/None); use compare\_network for higher orders.
  • Requires the same replicate count for every variable.
  • device ∈ {"cpu", "cuda", "auto"}; dtype ∈ {"float64" (exact, default), "float32" (lighter/faster on GPU, ~10⁻⁶)}; block sets the number of edges scored per batch (raise for throughput, lower to fit RAM/VRAM).
  • band= and check\_winding= are forwarded to the metric, so the frequency-local (DyDE-style) variant — band=(2\*pi/Pmax, 2\*pi/Pmin), check\_winding=False — is available here too.

Lower-level batched primitives are exposed for custom pipelines: fit\_first\_order\_batch, nu\_gap\_first\_order\_batch, sup\_chordal\_batch, full\_contour\_points, band\_contour\_points, plus the backend helpers get\_array\_module and gpu\_available.

How it works

For each variable or pairwise interaction, nugap fits a low-order linear input–output model under each condition, then measures the ν-gap between the fitted models. Because models are compared on mean-centred trajectories, the metric reflects changes in the relationship — timescale, gain or phase — rather than in absolute level. With biological replicates, the spread of within-condition ν-gaps provides an empirical null and a per-edge noise floor, against which between-condition changes are tested and FDR-controlled.

The models are single-input single-output, so an edge captures a pairwise input–output relationship, not proven causation.

Correctness

The ν-gap implementation is verified by several independent routes — exact closed-form values, an algebraic invariance of the chordal metric, an independent reference implementation, and the Vinnicombe robust-stability theorem — and is cross-checked against MATLAB's gapmetric (Robust Control Toolbox), which it reproduces to within ~10⁻⁶. The scripts are in validation/, with a fast subset run on every commit. The vectorized batch routines (compare\_network\_batch and the \*\_batch primitives) are validated against the scalar functions to floating-point precision (tests/test\_batch.py).

Citing

If you use nugap in your work, please cite the software:

Hearn, T. J. nugap: condition-specific changes in dynamical relationships via the
Vinnicombe ν-gap. Software archive: Zenodo, DOI: 10.5281/zenodo.20693443.

License

Released under the MIT License. Copyright © 2026 Tim Hearn. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nugap-0.6.0.tar.gz (51.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nugap-0.6.0-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file nugap-0.6.0.tar.gz.

File metadata

  • Download URL: nugap-0.6.0.tar.gz
  • Upload date:
  • Size: 51.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for nugap-0.6.0.tar.gz
Algorithm Hash digest
SHA256 3f248f6e18fbe47c67024e7beb1123c525e4bac1f747a82c3bb5cd50119c3c4c
MD5 0f1b209e7f37c4254612d0664516d143
BLAKE2b-256 a9b54b55c9399ed972a91e6f41f0d6851cd82f3d8a9f584660b05bb1b4fd2fff

See more details on using hashes here.

File details

Details for the file nugap-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: nugap-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for nugap-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 853b99c42f900244cfac46fb41e5fd582ad5c5c7f2b0f070d4c3347e659e3e0f
MD5 9ff9e0d0e0dacbd4fcc9530bb6bee237
BLAKE2b-256 c46f183dbd1fd5aa23588eb95aa5e2e90880490319733137f3f8e0221c446ce6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page