From a1905f98c5e046362321a93038400c764f50a7eb Mon Sep 17 00:00:00 2001 From: Iahn Cajigas Date: Sat, 14 Mar 2026 13:18:41 -0400 Subject: [PATCH 1/2] Document MATLAB/Simulink dependency for CIF simulation in README Add a new section explaining that CIF.simulateCIF() relies on Simulink models for exact point-process simulation, with a native Python Bernoulli fallback for approximate results. Documents the backend flag ('auto', 'matlab', 'python'), step-by-step MATLAB Engine setup instructions, and a call for contributions to implement a pure-Python thinning solver. Co-Authored-By: Claude Opus 4.6 --- README.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/README.md b/README.md index a83e2aa7..e282504a 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,82 @@ PMID: 22981419 The code repository for the Python port of nSTAT is hosted on GitHub at https://github.com/cajigaslab/nSTAT-python. +## MATLAB / Simulink Dependency for CIF Simulation + +The `CIF` class can simulate spike trains from a fitted conditional intensity +function. The original MATLAB implementation drives this simulation through +**Simulink models** (`PointProcessSimulation.slx`, +`PointProcessSimulationThinning.mdl`, and `SimulatedNetwork2.mdl`). These +models solve the point-process thinning algorithm as a continuous-time +block diagram and produce exact spike-train realisations. + +The Python port includes a **native discrete-time Bernoulli fallback** that +runs without MATLAB, but the results are approximate. For exact parity with +the MATLAB toolbox you need a working MATLAB + Simulink installation and the +MATLAB Engine API for Python. + +### The `backend` flag + +`CIF.simulateCIF()` accepts a `backend` parameter that controls which +simulation engine is used: + +| Flag | Behaviour | +|---|---| +| `backend='auto'` (default) | Uses MATLAB/Simulink when available; silently falls back to the native Python implementation with a `MatlabFallbackWarning` when it is not. | +| `backend='matlab'` | Forces the Simulink backend. Raises `RuntimeError` if MATLAB Engine or the MATLAB nSTAT repo cannot be found. | +| `backend='python'` | Forces the native Python implementation. No MATLAB is required and no warning is issued. | + +### Setting up the MATLAB backend + +1. **Install MATLAB** (R2020a or later recommended) with the **Simulink** + add-on. +2. **Install the MATLAB Engine API for Python** + ([MathWorks instructions](https://www.mathworks.com/help/matlab/matlab_external/install-the-matlab-engine-for-python.html)): + ```bash + cd "$(matlab -batch "disp(matlabroot)" | tail -1)/extern/engines/python" + python -m pip install . + ``` +3. **Point to the MATLAB nSTAT repo** so the engine can find the `.slx` / `.mdl` + models. Use either: + - The `NSTAT_MATLAB_PATH` environment variable: + ```bash + export NSTAT_MATLAB_PATH=/path/to/nSTAT + ``` + - Place the MATLAB repo as a sibling directory named `nSTAT/` next to this + Python repo (auto-detected). + - Or call `set_matlab_nstat_path()` at runtime: + ```python + from nstat.matlab_engine import set_matlab_nstat_path + set_matlab_nstat_path("/path/to/nSTAT") + ``` + +### Why this matters + +The native Python simulation uses a discrete-time Bernoulli draw at each time +step: at every bin the probability of a spike is `p = lambda * delta`, and a +uniform random draw decides whether a spike is emitted. The Simulink model, +by contrast, solves the point-process thinning integral in continuous time, +producing more accurate inter-spike-interval statistics — particularly at high +firing rates or with fast-varying stimuli. + +If your analysis depends on precise spike-timing statistics (e.g. KS +goodness-of-fit tests on simulated data, or decoding benchmarks), use the +MATLAB backend. + +### Call for contributions + +Replacing the Simulink dependency with a pure-Python continuous-time thinning +solver is an open goal for the project. A faithful implementation would need +to: + +- Implement Ogata's modified thinning algorithm (Lewis & Shedler 1979) for + the conditional intensity with history dependence. +- Match the Simulink model's interpolation and adaptive step-size behaviour. +- Pass parity tests against the MATLAB output for the existing paper examples. + +If you are interested in contributing this, please open an issue or pull +request — contributions are very welcome. + ## MATLAB Toolbox The original MATLAB nSTAT toolbox lives in a separate repository: From 40a43a0c752f902bf2b391f2d71da592addcd3b8 Mon Sep 17 00:00:00 2001 From: Iahn Cajigas Date: Sat, 14 Mar 2026 16:33:02 -0400 Subject: [PATCH 2/2] Fix 7 broken links in README - Remove non-existent pages.yml badge (workflow doesn't exist) - Fix 5 GitHub Pages URLs to match deployed site structure (help/*) - Fix parity report link: parity/parity_report.md -> parity/report.md Co-Authored-By: Claude Opus 4.6 --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e282504a..7fca3190 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ extensions to the toolbox based on your code contributions as well as for flaggi and tracking open issues. [![test-and-build](https://github.com/cajigaslab/nSTAT-python/actions/workflows/ci.yml/badge.svg)](https://github.com/cajigaslab/nSTAT-python/actions/workflows/ci.yml) -[![pages](https://github.com/cajigaslab/nSTAT-python/actions/workflows/pages.yml/badge.svg)](https://github.com/cajigaslab/nSTAT-python/actions/workflows/pages.yml) Lab websites: - Neuroscience Statistics Research Laboratory: https://www.neurostat.mit.edu @@ -149,11 +148,11 @@ These smaller demos remain useful as quick install and plotting checks. ## Documentation - Docs home: [cajigaslab.github.io/nSTAT-python](https://cajigaslab.github.io/nSTAT-python/) -- Help home: [cajigaslab.github.io/nSTAT-python/NeuralSpikeAnalysis_top.html](https://cajigaslab.github.io/nSTAT-python/NeuralSpikeAnalysis_top.html) -- Paper overview: [cajigaslab.github.io/nSTAT-python/PaperOverview.html](https://cajigaslab.github.io/nSTAT-python/PaperOverview.html) -- Example index: [cajigaslab.github.io/nSTAT-python/Examples.html](https://cajigaslab.github.io/nSTAT-python/Examples.html) -- Class definitions: [cajigaslab.github.io/nSTAT-python/ClassDefinitions.html](https://cajigaslab.github.io/nSTAT-python/ClassDefinitions.html) -- Documentation setup: [cajigaslab.github.io/nSTAT-python/DocumentationSetup.html](https://cajigaslab.github.io/nSTAT-python/DocumentationSetup.html) +- Help home: [cajigaslab.github.io/nSTAT-python/help](https://cajigaslab.github.io/nSTAT-python/help/index.html) +- Paper overview: [cajigaslab.github.io/nSTAT-python/help/paper_overview.html](https://cajigaslab.github.io/nSTAT-python/help/paper_overview.html) +- Example index: [cajigaslab.github.io/nSTAT-python/help/examples_index.html](https://cajigaslab.github.io/nSTAT-python/help/examples_index.html) +- Class definitions: [cajigaslab.github.io/nSTAT-python/help/class_definitions.html](https://cajigaslab.github.io/nSTAT-python/help/class_definitions.html) +- Documentation setup: [cajigaslab.github.io/nSTAT-python/help/examples/DocumentationSetup2025b.html](https://cajigaslab.github.io/nSTAT-python/help/examples/DocumentationSetup2025b.html) Source pages: - [docs/NeuralSpikeAnalysis_top.md](docs/NeuralSpikeAnalysis_top.md) @@ -241,7 +240,7 @@ parity verified. used `.^2` instead of `.^3` - `Analysis.m` — Granger causality mask zeroed all columns instead of column `i` -See [parity/parity_report.md](parity/parity_report.md) for the full audit. +See [parity/report.md](parity/report.md) for the full audit. ## License