dimensionality 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. dimensionality-0.1.0/CLAUDE.md +142 -0
  2. dimensionality-0.1.0/PKG-INFO +21 -0
  3. dimensionality-0.1.0/README.md +237 -0
  4. dimensionality-0.1.0/examples/demo.ipynb +568 -0
  5. dimensionality-0.1.0/examples/synthetic.py +147 -0
  6. dimensionality-0.1.0/legacy/biology/.ipynb_checkpoints/on_Stringer-checkpoint.ipynb +565 -0
  7. dimensionality-0.1.0/legacy/biology/.ipynb_checkpoints/on_TVSD-checkpoint.ipynb +1112 -0
  8. dimensionality-0.1.0/legacy/biology/.ipynb_checkpoints/tvsd_all_cat_dim-checkpoint.pdf +0 -0
  9. dimensionality-0.1.0/legacy/biology/BrainScore/.ipynb_checkpoints/Compare_all_DiCarlo-checkpoint.ipynb +1380 -0
  10. dimensionality-0.1.0/legacy/biology/BrainScore/.ipynb_checkpoints/Get_DiCarlo_Data_and_Save-checkpoint.ipynb +932 -0
  11. dimensionality-0.1.0/legacy/biology/BrainScore/.ipynb_checkpoints/on_Majaj-checkpoint.ipynb +2049 -0
  12. dimensionality-0.1.0/legacy/biology/BrainScore/Compare_all_DiCarlo.ipynb +1380 -0
  13. dimensionality-0.1.0/legacy/biology/BrainScore/Get_DiCarlo_Data_and_Save.ipynb +975 -0
  14. dimensionality-0.1.0/legacy/biology/BrainScore/IT_Chabo.npz +0 -0
  15. dimensionality-0.1.0/legacy/biology/BrainScore/IT_Tito.npz +0 -0
  16. dimensionality-0.1.0/legacy/biology/BrainScore/V4_Chabo.npz +0 -0
  17. dimensionality-0.1.0/legacy/biology/BrainScore/V4_Tito.npz +0 -0
  18. dimensionality-0.1.0/legacy/biology/BrainScore/dicarlo_data.npz +0 -0
  19. dimensionality-0.1.0/legacy/biology/BrainScore/dicarlo_data2.npz +0 -0
  20. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Ps_Chabo_IT.pdf +0 -0
  21. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Ps_Chabo_V4.pdf +0 -0
  22. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Ps_Tito_IT.pdf +0 -0
  23. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Ps_Tito_V4.pdf +0 -0
  24. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Qs_Chabo_IT.pdf +0 -0
  25. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Qs_Chabo_V4.pdf +0 -0
  26. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Qs_Tito_IT.pdf +0 -0
  27. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_Qs_Tito_V4.pdf +0 -0
  28. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Ps_Chabo_IT.pdf +0 -0
  29. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Ps_Chabo_V4.pdf +0 -0
  30. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Ps_Tito_IT.pdf +0 -0
  31. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Ps_Tito_V4.pdf +0 -0
  32. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Qs_Chabo_IT.pdf +0 -0
  33. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Qs_Chabo_V4.pdf +0 -0
  34. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Qs_Tito_IT.pdf +0 -0
  35. dimensionality-0.1.0/legacy/biology/BrainScore/majaj_dim_mse_Qs_Tito_V4.pdf +0 -0
  36. dimensionality-0.1.0/legacy/biology/BrainScore/on_Majaj.ipynb +2069 -0
  37. dimensionality-0.1.0/legacy/biology/on_Stringer.ipynb +572 -0
  38. dimensionality-0.1.0/legacy/biology/on_TVSD.ipynb +1256 -0
  39. dimensionality-0.1.0/legacy/biology/stinger_dim_Ps.pdf +0 -0
  40. dimensionality-0.1.0/legacy/biology/stringer_dim_Ps.pdf +0 -0
  41. dimensionality-0.1.0/legacy/biology/stringer_dim_Qs.pdf +0 -0
  42. dimensionality-0.1.0/legacy/biology/stringer_dim_mse_Ps.pdf +0 -0
  43. dimensionality-0.1.0/legacy/biology/stringer_dim_mse_Qs.pdf +0 -0
  44. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim.pdf +0 -0
  45. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_diff_mid0.pdf +0 -0
  46. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_diff_mid1.pdf +0 -0
  47. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_diff_mid2.pdf +0 -0
  48. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi0.pdf +0 -0
  49. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi0_mid0.pdf +0 -0
  50. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi0_mid1.pdf +0 -0
  51. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi1.pdf +0 -0
  52. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi1_mid0.pdf +0 -0
  53. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi1_mid1.pdf +0 -0
  54. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi2.pdf +0 -0
  55. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi2_mid0.pdf +0 -0
  56. dimensionality-0.1.0/legacy/biology/tvsd_all_cat_dim_roi2_mid1.pdf +0 -0
  57. dimensionality-0.1.0/legacy/biology/tvsd_cat_dim.pdf +0 -0
  58. dimensionality-0.1.0/legacy/biology/tvsd_dim.pdf +0 -0
  59. dimensionality-0.1.0/legacy/biology/tvsd_dim_mse.pdf +0 -0
  60. dimensionality-0.1.0/legacy/intrinsic/.ipynb_checkpoints/Final_dim-checkpoint.ipynb +116 -0
  61. dimensionality-0.1.0/legacy/intrinsic/.ipynb_checkpoints/nonlin_manifold-checkpoint.ipynb +830 -0
  62. dimensionality-0.1.0/legacy/intrinsic/Final_dim.ipynb +176 -0
  63. dimensionality-0.1.0/legacy/intrinsic/nonlin_manifold.ipynb +943 -0
  64. dimensionality-0.1.0/legacy/synthetic/.ipynb_checkpoints/Linear_example-checkpoint.ipynb +146 -0
  65. dimensionality-0.1.0/legacy/synthetic/.ipynb_checkpoints/linear_dim-checkpoint.pdf +0 -0
  66. dimensionality-0.1.0/legacy/synthetic/Linear_example.ipynb +303 -0
  67. dimensionality-0.1.0/legacy/synthetic/linear_dim.pdf +0 -0
  68. dimensionality-0.1.0/legacy/synthetic/linear_dim.png +0 -0
  69. dimensionality-0.1.0/legacy/synthetic/linear_dim_mse.pdf +0 -0
  70. dimensionality-0.1.0/pyproject.toml +51 -0
  71. dimensionality-0.1.0/src/dimensionality/__init__.py +56 -0
  72. dimensionality-0.1.0/src/dimensionality/_core.py +44 -0
  73. dimensionality-0.1.0/src/dimensionality/estimators.py +206 -0
  74. dimensionality-0.1.0/src/dimensionality/finite.py +224 -0
  75. dimensionality-0.1.0/src/dimensionality/plot.py +95 -0
  76. dimensionality-0.1.0/src/dimensionality/sweep.py +200 -0
  77. dimensionality-0.1.0/tests/__init__.py +0 -0
  78. dimensionality-0.1.0/tests/test_estimators.py +268 -0
@@ -0,0 +1,142 @@
1
+ # Dimensionality Estimator
2
+
3
+ Python research repository implementing a bias-corrected participation ratio (PR) estimator for measuring global (and local) dimensionality of neural representation manifolds. Based on the ICLR 2026 paper:
4
+
5
+ > **Estimating Dimensionality of Neural Representations from Finite Samples**
6
+ > Chanwoo Chun\*, Abdulkadir Canatar\*, SueYeon Chung, Daniel Lee
7
+
8
+ ---
9
+
10
+ ## Background
11
+
12
+ The **participation ratio (PR)** γ is a soft count of nonzero eigenvalues of a covariance matrix K = (1/Q) ΦΦᵀ, where Φ ∈ ℝ^{P×Q} is the neural activation matrix (P stimuli × Q neurons):
13
+
14
+ ```
15
+ γ = (Σᵢ λᵢ)² / Σᵢ λᵢ² = A / B
16
+ ```
17
+
18
+ The naive estimator γ_naive is heavily biased when P or Q is small. The key insight: bias arises from **overlapping indices** in the sums for A and B. The fix is to average over **disjoint/unequal indices** only.
19
+
20
+ ### Estimators
21
+
22
+ | Estimator | Corrects | Use when |
23
+ |--------------|------------------|-----------------------------------------------|
24
+ | `γ_naive` | nothing | baseline comparison |
25
+ | `γ_row` | row (stimulus) sampling bias | full neuron access, sampled stimuli |
26
+ | `γ_col` | column (neuron) sampling bias | full stimulus access, sampled neurons |
27
+ | `γ_both` | both row and column bias | general case (recommended) |
28
+
29
+ ### Extensions
30
+
31
+ - **Noise correction**: pass two trial matrices Φ⁽¹⁾, Φ⁽²⁾; redefine v^{αβ}_{ijkl} ← Φ⁽¹⁾_{iα} Φ⁽²⁾_{jα} Φ⁽¹⁾_{kβ} Φ⁽²⁾_{lβ}. Eliminates additive/multiplicative noise bias.
32
+ - **Importance sampling**: weight samples by r(x) = ρ_X(x)/ρ_X^obs(x) and c(w) = ρ_W(w)/ρ_W^obs(w) to correct for biased sampling distributions.
33
+ - **Sparse matrices**: skip summands that include any missing entry.
34
+ - **Finite underlying matrix**: when sampling P rows/cols from a finite R×C matrix (without replacement), use the corrected estimators that require knowledge of R and C.
35
+ - **Local dimensionality**: weight samples by proximity (Mahalanobis distance with local metric), take average over all center points. Noise-resistant unlike TwoNN.
36
+
37
+ ### Scaling law of γ_naive
38
+
39
+ Under uniform row/column norms:
40
+ ```
41
+ E[1/γ_naive] ≈ 1/P + 1/Q + 1/γ
42
+ ```
43
+ γ_naive is approximately a harmonic mean of P, Q, and γ — like parallel resistance.
44
+
45
+ ---
46
+
47
+ ## Implementation Notes
48
+
49
+ - Core computation uses `opt_einsum` (no JAX). Disjoint-index sums are re-expressed as linear combinations of regular sums to enable vectorization. See Sec. A.3 of the paper for the full expansions.
50
+ - **Centering is algebraic**: the three-term formula structure encodes centering (e.g. A = ⟨v_iijj⟩ − 2⟨v_iijl⟩ + ⟨v_ijlr⟩). Do **not** pre-subtract column means before calling the estimators — doing so introduces statistical dependencies that break the bias correction.
51
+ - Task dimensionality (default): pass Φ directly (rows = stimuli, columns = neurons).
52
+ - Neuron dimensionality: pass Φ.T instead.
53
+ - The ratio A/B introduces a small, unavoidable O((1/P + 1/Q)²) bias even when A and B are individually unbiased — this is negligible in practice.
54
+
55
+ ---
56
+
57
+ ## Package API
58
+
59
+ ```python
60
+ from dimensionality import participation_ratio, participation_ratio_finite
61
+
62
+ # Single-trial, default output (γ_both, bias-corrected for both axes)
63
+ gamma = participation_ratio(Phi) # float
64
+
65
+ # Two-trial noise correction
66
+ gamma = participation_ratio(Phi1, Phi2) # float
67
+
68
+ # Return all four estimators
69
+ result = participation_ratio(Phi, return_all=True)
70
+ # result['naive'], result['row'], result['col'], result['both']
71
+
72
+ # Return numerator A and denominator B
73
+ result = participation_ratio(Phi, return_parts=True)
74
+ # result['both'], result['A'], result['B']
75
+
76
+ # Both options at once — adds A_naive/B_naive, A_row/B_row, etc.
77
+ result = participation_ratio(Phi, return_all=True, return_parts=True)
78
+
79
+ # Finite underlying matrix (R×C), submatrix Φ is P×Q
80
+ gamma = participation_ratio_finite(Phi, R=5000, C=2000) # float
81
+ gamma = participation_ratio_finite(Phi1, R=5000, C=2000, Phi2=Phi2) # two-trial
82
+ result = participation_ratio_finite(Phi, R=5000, C=2000, return_parts=True)
83
+ # result['gamma'], result['A'], result['B']
84
+ ```
85
+
86
+ Minimum sizes: `participation_ratio` requires P ≥ 4, Q ≥ 2. `participation_ratio_finite` requires the same plus R ≥ P, C ≥ Q.
87
+
88
+ ---
89
+
90
+ ## Repository Structure
91
+
92
+ ```
93
+ src/
94
+ dimensionality/
95
+ __init__.py # exports participation_ratio, participation_ratio_finite
96
+ _core.py # _gett_all(pattern, A, B) — quartic einsum helper
97
+ estimators.py # participation_ratio (infinite underlying matrix)
98
+ finite.py # participation_ratio_finite (finite R×C underlying matrix)
99
+ tests/
100
+ test_estimators.py # API tests, bias ordering, noise correction, finite estimator
101
+ examples/
102
+ synthetic.py # Figure 1 reproduction (vary P or Q, all four estimators)
103
+ legacy/ # Old exploratory notebooks — ignore unless explicitly referenced
104
+ biology/ # Brain data experiments (Stringer, MajajHong, TVSD)
105
+ intrinsic/ # Local dimensionality experiments
106
+ synthetic/ # Synthetic data experiments
107
+ ```
108
+
109
+ The `legacy/` folder contains the original research notebooks used to produce figures in the paper. **Do not modify or base new code on legacy/ unless explicitly asked.**
110
+
111
+ To run examples:
112
+ ```bash
113
+ python examples/synthetic.py # saves examples/figure1.png
114
+ python examples/synthetic.py --show # also opens interactive window
115
+ ```
116
+
117
+ To run tests:
118
+ ```bash
119
+ pytest tests/
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Key Symbols
125
+
126
+ | Symbol | Meaning |
127
+ |--------|---------|
128
+ | Φ ∈ ℝ^{P×Q} | Sample activation matrix (P stimuli, Q neurons) |
129
+ | Φ^{(∞)} | True infinite underlying matrix |
130
+ | K = (1/Q)ΦΦᵀ | Sample covariance matrix |
131
+ | γ | True participation ratio (dimensionality) |
132
+ | γ_naive | Naive estimator (biased) |
133
+ | γ_both | Bias-corrected estimator (both row and column) |
134
+ | A, B | Numerator and denominator of γ (centered) |
135
+ | v^{αβ}_{ijlr} = Φ_{iα}Φ_{jα}Φ_{lβ}Φ_{rβ} | Elementary quartic tensor |
136
+ | r_{ijlr} | Column-marginalized tensor (sum over α≠β) |
137
+ | t¹–t⁵ | Five unique terms in A and B |
138
+
139
+
140
+ ## Environment
141
+ - Conda environment: `dimensionality`
142
+ - Activate before running any Python: `conda activate dimensionality`
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: dimensionality
3
+ Version: 0.1.0
4
+ Summary: Bias-corrected participation ratio estimator for measuring dimensionality of neural representations
5
+ Project-URL: Homepage, https://github.com/badooki/dimensionality
6
+ Project-URL: Paper, https://arxiv.org/abs/2509.26560
7
+ Author: Chanwoo Chun, Abdulkadir Canatar, SueYeon Chung, Daniel Lee
8
+ License: MIT
9
+ Keywords: dimensionality,neural manifold,neuroscience,participation ratio,representation geometry
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
14
+ Requires-Python: >=3.9
15
+ Requires-Dist: numpy>=1.24
16
+ Requires-Dist: opt-einsum>=3.3
17
+ Provides-Extra: dev
18
+ Requires-Dist: jupyter; extra == 'dev'
19
+ Requires-Dist: matplotlib>=3.6; extra == 'dev'
20
+ Requires-Dist: pytest>=7; extra == 'dev'
21
+ Requires-Dist: scipy>=1.10; extra == 'dev'
@@ -0,0 +1,237 @@
1
+ # Sample-size invariant measure of dimensionality
2
+
3
+ Bias-corrected **participation ratio (PR)** estimators for measuring the dimensionality of neural representation manifolds, as introduced in:
4
+
5
+ > **Estimating Dimensionality of Neural Representations from Finite Samples**
6
+ > Chanwoo Chun\*, Abdulkadir Canatar\*, SueYeon Chung, Daniel Lee
7
+ > *ICLR 2026*
8
+
9
+ ---
10
+
11
+ ## 📐 Background
12
+
13
+ Given a neural activation matrix $\Phi \in \mathbb{R}^{P\times Q}$ (P stimuli × Q neurons), the participation ratio
14
+
15
+
16
+ $$ \gamma =\frac{\left(\sum_i \lambda_i \right)^2}{\sum_i \lambda_i^2} $$
17
+
18
+
19
+ is a soft count of the number of nonzero eigenvalues of the stimulus covariance $K=\frac{1}{Q}\Phi\Phi^\top$. The naive estimator is severely biased downward when P or Q is small — it behaves approximately as a harmonic mean of P, Q, and the true $\gamma$:
20
+
21
+ $$ \mathbb{E}\left[ \frac{1}{\gamma_{\text{naive}}}\right] \approx \frac{1}{P}+ \frac{1}{Q} +\frac{1}{\gamma} $$
22
+
23
+ This package provides unbiased estimators that correct for finite P and/or Q by averaging over disjoint index sets.
24
+
25
+ | Estimator | Corrects | Use when |
26
+ |-----------|----------|----------|
27
+ | `γ_naive` | nothing | baseline reference |
28
+ | `γ_row` | row (stimulus) sampling bias | full neuron access, subsampled stimuli |
29
+ | `γ_col` | column (neuron) sampling bias | full stimulus access, subsampled neurons |
30
+ | `γ_both` | both row and column bias | subsampled neurons, subsampled stimuli|
31
+
32
+ An additional `participation_ratio_finite` estimator handles the case where Φ is a submatrix sampled without replacement from a large-but-finite R×C matrix (Appendix A.6 of the paper).
33
+
34
+ ---
35
+
36
+ ## 📦 Installation
37
+
38
+ ```bash
39
+ pip install git+https://github.com/badooki/dimensionality.git
40
+ ```
41
+
42
+ Or, for development:
43
+
44
+ ```bash
45
+ git clone https://github.com/badooki/dimensionality.git
46
+ cd dimensionality
47
+ pip install -e ".[dev]"
48
+ ```
49
+
50
+ **Dependencies:** `numpy >= 1.24`, `opt_einsum >= 3.3`. Python ≥ 3.9.
51
+
52
+ ---
53
+
54
+ ## 🚀 Quick start
55
+
56
+ ```python
57
+ import numpy as np
58
+ from dimensionality import participation_ratio
59
+
60
+ # Phi: P stimuli × Q neurons (do NOT pre-center)
61
+ Phi = np.random.randn(200, 100)
62
+
63
+ # Default: γ_both (bias-corrected for both row and column subsampling)
64
+ gamma = participation_ratio(Phi)
65
+ print(gamma)
66
+ ```
67
+
68
+ ### All four estimators
69
+
70
+ ```python
71
+ result = participation_ratio(Phi, return_all=True)
72
+ # result['naive'], result['row'], result['col'], result['both']
73
+ ```
74
+
75
+ ### Two-trial noise correction
76
+
77
+ When two independent repeat trials are available for the same stimuli and neurons, the cross-trial construction removes additive and multiplicative noise bias:
78
+
79
+ ```python
80
+ gamma = participation_ratio(Phi1, Phi2)
81
+ ```
82
+
83
+ ### Return numerator and denominator separately
84
+
85
+ ```python
86
+ result = participation_ratio(Phi, return_parts=True)
87
+ # result['both'], result['A'], result['B']
88
+
89
+ # Combined with return_all:
90
+ result = participation_ratio(Phi, return_all=True, return_parts=True)
91
+ # result['naive'], result['A_naive'], result['B_naive'], ...
92
+ ```
93
+
94
+ ### Neuron dimensionality
95
+
96
+ To estimate dimensionality along the neuron axis (centering across stimuli), transpose the matrix:
97
+
98
+ ```python
99
+ gamma_neuron = participation_ratio(Phi.T)
100
+ ```
101
+
102
+ ---
103
+
104
+ ## 🔢 Finite underlying matrix
105
+
106
+ When Φ is a P×Q submatrix sampled without replacement from a finite R×C population matrix, use `participation_ratio_finite`:
107
+
108
+ ```python
109
+ from dimensionality import participation_ratio_finite
110
+
111
+ gamma = participation_ratio_finite(Phi, R=5000, C=2000)
112
+
113
+ # With noise correction:
114
+ gamma = participation_ratio_finite(Phi1, R=5000, C=2000, Phi2=Phi2)
115
+
116
+ # Also return the naive estimate:
117
+ result = participation_ratio_finite(Phi, R=5000, C=2000, return_naive=True)
118
+ # result['gamma'], result['naive']
119
+ ```
120
+
121
+ ---
122
+
123
+ ## 📊 Subsampling sweep
124
+
125
+ To assess how the estimate converges with sample size, sweep over P or Q:
126
+
127
+ ```python
128
+ from dimensionality import sweep_dimensionality, plot_sweep
129
+
130
+ # Sweep over number of stimuli; keep all neurons
131
+ result = sweep_dimensionality(Phi, axis='P', n_trials=20)
132
+
133
+ # result['values'] — array of P values used
134
+ # result['naive'], result['row'], result['col'], result['both'] — mean estimates
135
+ # result['both_sem'] — standard error of the mean
136
+
137
+ fig, ax = plot_sweep(result, true_d=50)
138
+ ```
139
+
140
+ To sweep over number of neurons instead:
141
+
142
+ ```python
143
+ result = sweep_dimensionality(Phi, axis='Q')
144
+ ```
145
+
146
+ For the finite estimator:
147
+
148
+ ```python
149
+ result = sweep_dimensionality(Phi, axis='P', estimator='finite', R=5000, C=2000)
150
+ # result['naive'], result['gamma']
151
+ ```
152
+
153
+ ---
154
+
155
+ ## ⚠️ Important: do not pre-center
156
+
157
+ The bias corrections rely on an algebraic three-term centering structure built into the estimator formulas. Subtracting column means from Φ before passing it to the estimator introduces statistical dependencies between rows that break the bias correction. **Pass the raw activation matrix directly.**
158
+
159
+ ---
160
+
161
+ ## 🔧 API reference
162
+
163
+ ### `participation_ratio(Phi, Phi2=None, *, return_all=False, return_parts=False)`
164
+
165
+ Estimate the task dimensionality (PR of the centered covariance) of Φ.
166
+
167
+ - **Phi** — raw activation matrix, shape (P, Q); P ≥ 4, Q ≥ 2.
168
+ - **Phi2** — optional second trial for noise correction.
169
+ - **return_all** — if `True`, return dict with all four estimator variants.
170
+ - **return_parts** — if `True`, include numerator A and denominator B.
171
+
172
+ Returns a scalar (`γ_both`) by default, or a dict when either flag is set.
173
+
174
+ ---
175
+
176
+ ### `participation_ratio_finite(Phi, R, C, Phi2=None, *, return_naive=False, return_parts=False)`
177
+
178
+ Estimate the PR of the full R×C matrix from the observed P×Q submatrix.
179
+
180
+ - **R, C** — number of rows/columns in the full underlying matrix; R ≥ P, C ≥ Q.
181
+ - **return_naive** — if `True`, also return the (uncorrected) naive estimate.
182
+ - **return_parts** — if `True`, include numerator A and denominator B.
183
+
184
+ Returns a scalar by default, or a dict when either flag is set.
185
+
186
+ ---
187
+
188
+ ### `sweep_dimensionality(Phi, axis='P', values=None, n_trials=20, Phi2=None, estimator='infinite', R=None, C=None, ...)`
189
+
190
+ Run a subsampling sweep. Returns a dict with mean estimates and SEMs at each value. See docstring for full parameter list.
191
+
192
+ ---
193
+
194
+ ### `plot_sweep(result, ax=None, true_d=None, title=None, figsize=(5, 4))`
195
+
196
+ Plot the output of `sweep_dimensionality`. Returns `(fig, ax)`.
197
+
198
+ ---
199
+
200
+ ## 🗂️ Repository structure
201
+
202
+ ```
203
+ src/
204
+ dimensionality/
205
+ __init__.py # public API
206
+ _core.py # quartic einsum helper
207
+ estimators.py # participation_ratio
208
+ finite.py # participation_ratio_finite
209
+ sweep.py # sweep_dimensionality
210
+ plot.py # plot_sweep
211
+ tests/
212
+ test_estimators.py
213
+ examples/
214
+ demo.ipynb # interactive walkthrough on synthetic data
215
+ synthetic.py # Figure 1 reproduction
216
+ ```
217
+
218
+ ---
219
+
220
+ ## 📄 Citation
221
+
222
+ If you use this package, please cite:
223
+
224
+ ```bibtex
225
+ @inproceedings{chun2026estimating,
226
+ title = {Estimating Dimensionality of Neural Representations from Finite Samples},
227
+ author = {Chun, Chanwoo and Canatar, Abdulkadir and Chung, SueYeon and Lee, Daniel},
228
+ booktitle = {International Conference on Learning Representations},
229
+ year = {2026},
230
+ }
231
+ ```
232
+
233
+ ---
234
+
235
+ ## License
236
+
237
+ MIT