esnfed 1.0.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.
@@ -0,0 +1,56 @@
1
+ # LaTeX build artifacts
2
+ *.aux
3
+ *.bbl
4
+ *.bcf
5
+ *.blg
6
+ *.fdb_latexmk
7
+ *.fls
8
+ *.log
9
+ *.out
10
+ *.run.xml
11
+ *.synctex.gz
12
+ *.toc
13
+ *.lof
14
+ *.lot
15
+ *.nav
16
+ *.snm
17
+ *.vrb
18
+ memoria/memoria.pdf
19
+
20
+ # Python
21
+ __pycache__/
22
+ *.py[cod]
23
+ *.pyo
24
+ .venv/
25
+ venv/
26
+ env/
27
+ *.egg-info/
28
+ dist/
29
+ build/
30
+ .ipynb_checkpoints/
31
+ *.pyc
32
+ .pytest_cache/
33
+
34
+ # Data (may be large/licensed)
35
+ datos/crudos/
36
+ datos/procesados/
37
+ !datos/crudos/.gitkeep
38
+ !datos/procesados/.gitkeep
39
+
40
+ # Generated outputs
41
+ salidas/
42
+ !salidas/.gitkeep
43
+
44
+ # OS
45
+ .DS_Store
46
+ Thumbs.db
47
+ desktop.ini
48
+
49
+ # Editors
50
+ .vscode/
51
+ .idea/
52
+ *.swp
53
+ *.swo
54
+
55
+ # Claude Code
56
+ .claude/
esnfed-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dairon Andres Benites Aldaz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
esnfed-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: esnfed
3
+ Version: 1.0.0
4
+ Summary: Echo State Networks for Federated Learning: reservoirs, topologies and federated strategies
5
+ Project-URL: Homepage, https://github.com/daibeal/tfg-inf
6
+ Project-URL: Repository, https://github.com/daibeal/tfg-inf
7
+ Project-URL: Issues, https://github.com/daibeal/tfg-inf/issues
8
+ Author-email: Dairon Andres Benites Aldaz <dairon.aldaz@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: echo state networks,ensemble learning,federated learning,machine learning,recurrent neural networks,reservoir computing,time series
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: networkx>=3.0
26
+ Requires-Dist: numpy>=1.21
27
+ Provides-Extra: dev
28
+ Requires-Dist: build>=1.0; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0; extra == 'dev'
30
+ Requires-Dist: twine>=4.0; extra == 'dev'
31
+ Provides-Extra: experiments
32
+ Requires-Dist: matplotlib>=3.5; extra == 'experiments'
33
+ Requires-Dist: pandas>=1.3; extra == 'experiments'
34
+ Requires-Dist: scikit-learn>=1.0; extra == 'experiments'
35
+ Requires-Dist: scipy>=1.7; extra == 'experiments'
36
+ Provides-Extra: flower
37
+ Requires-Dist: flwr>=1.7; extra == 'flower'
38
+ Provides-Extra: reservoirpy
39
+ Requires-Dist: reservoirpy>=0.3; extra == 'reservoirpy'
40
+ Description-Content-Type: text/markdown
41
+
42
+ # esnfed — a federated reservoir computing toolkit
43
+
44
+ `esnfed` is a small, dependency-light Python library for training **Echo State
45
+ Networks** (reservoir computing) in a **federated** setting — where several
46
+ parties jointly train a model without sharing their raw data. It accompanies the
47
+ Final Degree Project *Ensemble of Recurrent Networks for Federated Learning*
48
+ (ETSINF, Universitat Politècnica de València).
49
+
50
+ The core library depends only on **NumPy** and **NetworkX**.
51
+
52
+ > **Why this and not ReservoirPy?** [ReservoirPy](https://reservoirpy.readthedocs.io)
53
+ > is the mature, full-featured library for *building and tuning* reservoir
54
+ > computing models, and `esnfed` does **not** try to replace it. `esnfed`
55
+ > focuses on the part ReservoirPy does not cover: **federating** reservoir
56
+ > models across parties. You can design a reservoir in ReservoirPy and federate
57
+ > it here in one line (see *Interoperability* below).
58
+
59
+ ## Features
60
+
61
+ - **Echo State Network** with leaky-integrator neurons and a closed-form ridge
62
+ readout (`EchoStateNetwork`).
63
+ - **Federated strategies**:
64
+ - `federated_ridge` — *exact* federated training for a shared reservoir
65
+ (clients exchange only ridge sufficient statistics; provably equal to pooled
66
+ training, in one communication round);
67
+ - `fedavg` — iterative FedAvg on the readout;
68
+ - `ensemble_predict` — prediction ensemble for *heterogeneous* reservoirs;
69
+ - `structural_alignment` — interpolate reservoirs toward a shared structure.
70
+ - **Reservoir topologies**: Erdős–Rényi, small-world, scale-free, ring.
71
+ - **Data**: synthetic benchmarks (NARMA-10, Mackey-Glass, Lorenz) **and** real
72
+ data — a bundled counterparty-risk series (the TED spread) plus generic
73
+ loaders (`from_array`, `load_csv`, `load_fred`).
74
+ - **Interoperability**: adapters for [ReservoirPy](https://reservoirpy.readthedocs.io)
75
+ reservoirs and an example integration with the
76
+ [Flower](https://flower.ai) federated-learning framework.
77
+
78
+ ## Installation
79
+
80
+ ```bash
81
+ pip install esnfed # core (numpy + networkx)
82
+ pip install "esnfed[experiments]" # + matplotlib/pandas/scipy/scikit-learn
83
+ pip install "esnfed[reservoirpy]" # + ReservoirPy interop
84
+ pip install "esnfed[flower]" # + Flower integration
85
+ ```
86
+
87
+ ## Quick start
88
+
89
+ ### Federated counterparty-risk forecasting (real data)
90
+
91
+ Several institutions jointly forecast the **TED spread** (a classic gauge of
92
+ interbank/counterparty credit risk) without sharing their data. Exact federated
93
+ ridge equals pooled training in a single round:
94
+
95
+ ```python
96
+ from esnfed import datasets, federated, topologies, metrics
97
+
98
+ u, y = datasets.load_ted_spread() # bundled real series (FRED)
99
+ u_tr, y_tr, u_te, y_te = datasets.split(u, y, 0.7)
100
+ parts = datasets.partition_iid(u_tr, y_tr, n_clients=8) # 8 "institutions"
101
+
102
+ W = topologies.random_reservoir(200, density=0.1, rng=0)
103
+ esn_kw = dict(spectral_radius=0.9, leaking_rate=0.5, washout=100, ridge=1e-6)
104
+ clients, ref = federated.make_shared_clients(W, parts, input_seed=0, esn_kwargs=esn_kw)
105
+
106
+ W_out = federated.federated_ridge(clients, ref) # one round, exact, private
107
+ Z_test = ref.harvest(u_te)[ref.washout:]
108
+ print("federated NRMSE:", metrics.nrmse(y_te[ref.washout:], Z_test @ W_out))
109
+ ```
110
+
111
+ Need another series? `datasets.load_fred("BAMLH0A0HYM2")` pulls a high-yield
112
+ credit spread from FRED; `datasets.from_array(my_series)` or
113
+ `datasets.load_csv("my.csv")` turn any series into a forecasting task.
114
+
115
+ ### Train a single ESN
116
+
117
+ ```python
118
+ import numpy as np
119
+ from esnfed import EchoStateNetwork, datasets, topologies, metrics
120
+
121
+ u, y = datasets.narma10(3000, rng=0)
122
+ u_tr, y_tr, u_te, y_te = datasets.split(u, y)
123
+ W = topologies.random_reservoir(200, density=0.1, rng=0)
124
+ esn = EchoStateNetwork(1, 1, W, spectral_radius=0.9, washout=100).fit(u_tr, y_tr)
125
+ print("NRMSE:", metrics.nrmse(y_te[100:], esn.predict(u_te)[100:]))
126
+ ```
127
+
128
+ ## Interoperability
129
+
130
+ ### ReservoirPy — design there, federate here
131
+
132
+ ```python
133
+ from reservoirpy.nodes import Reservoir
134
+ from esnfed import interop, datasets, federated
135
+
136
+ res = Reservoir(200, sr=0.9, lr=0.5, input_dim=1) # design/tune in ReservoirPy
137
+ esn = interop.to_esn(res, n_inputs=1) # -> esnfed EchoStateNetwork
138
+ W = interop.reservoir_matrix(res) # ... then federate it
139
+ ```
140
+
141
+ ### Flower — a real FL framework
142
+
143
+ `examples/flower_federated_ridge.py` shows the exact federated-ridge scheme as a
144
+ Flower `NumPyClient` + custom `Strategy`: each client's `fit` returns its ridge
145
+ sufficient statistics and the server sums them and solves once. The Flower-routed
146
+ result is identical to `federated_ridge` to numerical precision.
147
+
148
+ ## Modules
149
+
150
+ | Module | Contents |
151
+ |--------|----------|
152
+ | `esnfed.esn` | `EchoStateNetwork`, ridge helpers |
153
+ | `esnfed.topologies` | reservoir generators + `graph_metrics` |
154
+ | `esnfed.datasets` | NARMA-10, Mackey-Glass, Lorenz; `from_array`, `load_csv`, `load_ted_spread`, `load_fred` |
155
+ | `esnfed.metrics` | `nrmse`, `rmse`, `mse`, `r2_score` |
156
+ | `esnfed.federated` | `Client`, `federated_ridge`, `fedavg`, `ensemble_predict`, `structural_alignment` |
157
+ | `esnfed.interop` | ReservoirPy adapters (`to_esn`, `reservoir_matrix`) |
158
+
159
+ ## Reproducing the research experiments
160
+
161
+ ```bash
162
+ pip install -e ".[experiments,reservoirpy,flower]"
163
+ python -m pytest # 37 tests
164
+ python experiments/run_all.py # synthetic-benchmark figures and tables
165
+ python experiments/exp6_finance.py # federated counterparty-risk (TED spread)
166
+ ```
167
+
168
+ ## Data attribution
169
+
170
+ The bundled TED spread is sourced from the Federal Reserve Bank of St. Louis
171
+ (FRED, series `TEDRATE`) and is used for demonstration under FRED's terms.
172
+
173
+ ## Citation
174
+
175
+ ```bibtex
176
+ @thesis{benites2026esnfed,
177
+ author = {Benites Aldaz, Dairon Andres},
178
+ title = {Ensemble of Recurrent Networks for Federated Learning},
179
+ school = {Universitat Politecnica de Valencia (ETSINF)},
180
+ year = {2026},
181
+ type = {Bachelor's thesis},
182
+ }
183
+ ```
184
+
185
+ ## License
186
+
187
+ MIT — see [LICENSE](LICENSE).
esnfed-1.0.0/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # esnfed — a federated reservoir computing toolkit
2
+
3
+ `esnfed` is a small, dependency-light Python library for training **Echo State
4
+ Networks** (reservoir computing) in a **federated** setting — where several
5
+ parties jointly train a model without sharing their raw data. It accompanies the
6
+ Final Degree Project *Ensemble of Recurrent Networks for Federated Learning*
7
+ (ETSINF, Universitat Politècnica de València).
8
+
9
+ The core library depends only on **NumPy** and **NetworkX**.
10
+
11
+ > **Why this and not ReservoirPy?** [ReservoirPy](https://reservoirpy.readthedocs.io)
12
+ > is the mature, full-featured library for *building and tuning* reservoir
13
+ > computing models, and `esnfed` does **not** try to replace it. `esnfed`
14
+ > focuses on the part ReservoirPy does not cover: **federating** reservoir
15
+ > models across parties. You can design a reservoir in ReservoirPy and federate
16
+ > it here in one line (see *Interoperability* below).
17
+
18
+ ## Features
19
+
20
+ - **Echo State Network** with leaky-integrator neurons and a closed-form ridge
21
+ readout (`EchoStateNetwork`).
22
+ - **Federated strategies**:
23
+ - `federated_ridge` — *exact* federated training for a shared reservoir
24
+ (clients exchange only ridge sufficient statistics; provably equal to pooled
25
+ training, in one communication round);
26
+ - `fedavg` — iterative FedAvg on the readout;
27
+ - `ensemble_predict` — prediction ensemble for *heterogeneous* reservoirs;
28
+ - `structural_alignment` — interpolate reservoirs toward a shared structure.
29
+ - **Reservoir topologies**: Erdős–Rényi, small-world, scale-free, ring.
30
+ - **Data**: synthetic benchmarks (NARMA-10, Mackey-Glass, Lorenz) **and** real
31
+ data — a bundled counterparty-risk series (the TED spread) plus generic
32
+ loaders (`from_array`, `load_csv`, `load_fred`).
33
+ - **Interoperability**: adapters for [ReservoirPy](https://reservoirpy.readthedocs.io)
34
+ reservoirs and an example integration with the
35
+ [Flower](https://flower.ai) federated-learning framework.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install esnfed # core (numpy + networkx)
41
+ pip install "esnfed[experiments]" # + matplotlib/pandas/scipy/scikit-learn
42
+ pip install "esnfed[reservoirpy]" # + ReservoirPy interop
43
+ pip install "esnfed[flower]" # + Flower integration
44
+ ```
45
+
46
+ ## Quick start
47
+
48
+ ### Federated counterparty-risk forecasting (real data)
49
+
50
+ Several institutions jointly forecast the **TED spread** (a classic gauge of
51
+ interbank/counterparty credit risk) without sharing their data. Exact federated
52
+ ridge equals pooled training in a single round:
53
+
54
+ ```python
55
+ from esnfed import datasets, federated, topologies, metrics
56
+
57
+ u, y = datasets.load_ted_spread() # bundled real series (FRED)
58
+ u_tr, y_tr, u_te, y_te = datasets.split(u, y, 0.7)
59
+ parts = datasets.partition_iid(u_tr, y_tr, n_clients=8) # 8 "institutions"
60
+
61
+ W = topologies.random_reservoir(200, density=0.1, rng=0)
62
+ esn_kw = dict(spectral_radius=0.9, leaking_rate=0.5, washout=100, ridge=1e-6)
63
+ clients, ref = federated.make_shared_clients(W, parts, input_seed=0, esn_kwargs=esn_kw)
64
+
65
+ W_out = federated.federated_ridge(clients, ref) # one round, exact, private
66
+ Z_test = ref.harvest(u_te)[ref.washout:]
67
+ print("federated NRMSE:", metrics.nrmse(y_te[ref.washout:], Z_test @ W_out))
68
+ ```
69
+
70
+ Need another series? `datasets.load_fred("BAMLH0A0HYM2")` pulls a high-yield
71
+ credit spread from FRED; `datasets.from_array(my_series)` or
72
+ `datasets.load_csv("my.csv")` turn any series into a forecasting task.
73
+
74
+ ### Train a single ESN
75
+
76
+ ```python
77
+ import numpy as np
78
+ from esnfed import EchoStateNetwork, datasets, topologies, metrics
79
+
80
+ u, y = datasets.narma10(3000, rng=0)
81
+ u_tr, y_tr, u_te, y_te = datasets.split(u, y)
82
+ W = topologies.random_reservoir(200, density=0.1, rng=0)
83
+ esn = EchoStateNetwork(1, 1, W, spectral_radius=0.9, washout=100).fit(u_tr, y_tr)
84
+ print("NRMSE:", metrics.nrmse(y_te[100:], esn.predict(u_te)[100:]))
85
+ ```
86
+
87
+ ## Interoperability
88
+
89
+ ### ReservoirPy — design there, federate here
90
+
91
+ ```python
92
+ from reservoirpy.nodes import Reservoir
93
+ from esnfed import interop, datasets, federated
94
+
95
+ res = Reservoir(200, sr=0.9, lr=0.5, input_dim=1) # design/tune in ReservoirPy
96
+ esn = interop.to_esn(res, n_inputs=1) # -> esnfed EchoStateNetwork
97
+ W = interop.reservoir_matrix(res) # ... then federate it
98
+ ```
99
+
100
+ ### Flower — a real FL framework
101
+
102
+ `examples/flower_federated_ridge.py` shows the exact federated-ridge scheme as a
103
+ Flower `NumPyClient` + custom `Strategy`: each client's `fit` returns its ridge
104
+ sufficient statistics and the server sums them and solves once. The Flower-routed
105
+ result is identical to `federated_ridge` to numerical precision.
106
+
107
+ ## Modules
108
+
109
+ | Module | Contents |
110
+ |--------|----------|
111
+ | `esnfed.esn` | `EchoStateNetwork`, ridge helpers |
112
+ | `esnfed.topologies` | reservoir generators + `graph_metrics` |
113
+ | `esnfed.datasets` | NARMA-10, Mackey-Glass, Lorenz; `from_array`, `load_csv`, `load_ted_spread`, `load_fred` |
114
+ | `esnfed.metrics` | `nrmse`, `rmse`, `mse`, `r2_score` |
115
+ | `esnfed.federated` | `Client`, `federated_ridge`, `fedavg`, `ensemble_predict`, `structural_alignment` |
116
+ | `esnfed.interop` | ReservoirPy adapters (`to_esn`, `reservoir_matrix`) |
117
+
118
+ ## Reproducing the research experiments
119
+
120
+ ```bash
121
+ pip install -e ".[experiments,reservoirpy,flower]"
122
+ python -m pytest # 37 tests
123
+ python experiments/run_all.py # synthetic-benchmark figures and tables
124
+ python experiments/exp6_finance.py # federated counterparty-risk (TED spread)
125
+ ```
126
+
127
+ ## Data attribution
128
+
129
+ The bundled TED spread is sourced from the Federal Reserve Bank of St. Louis
130
+ (FRED, series `TEDRATE`) and is used for demonstration under FRED's terms.
131
+
132
+ ## Citation
133
+
134
+ ```bibtex
135
+ @thesis{benites2026esnfed,
136
+ author = {Benites Aldaz, Dairon Andres},
137
+ title = {Ensemble of Recurrent Networks for Federated Learning},
138
+ school = {Universitat Politecnica de Valencia (ETSINF)},
139
+ year = {2026},
140
+ type = {Bachelor's thesis},
141
+ }
142
+ ```
143
+
144
+ ## License
145
+
146
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,31 @@
1
+ """esnfed - Echo State Networks for Federated Learning.
2
+
3
+ A small, dependency-light research library accompanying the Final Degree Project
4
+ *Ensemble of Recurrent Networks for Federated Learning* (ETSINF, UPV).
5
+
6
+ Modules
7
+ -------
8
+ esn Echo State Network (reservoir + ridge readout).
9
+ topologies Reservoir topology generators (random, small-world, scale-free, ring).
10
+ datasets Benchmark sequential tasks (NARMA-10, Mackey-Glass, Lorenz, sine).
11
+ metrics Error metrics (NRMSE, MSE, memory capacity).
12
+ federated Federated strategies (FedAvg, exact federated ridge, ensemble, alignment).
13
+ """
14
+
15
+ from .esn import EchoStateNetwork
16
+ from .metrics import nrmse, mse, rmse
17
+ from . import topologies, datasets, federated, metrics, interop
18
+
19
+ __all__ = [
20
+ "EchoStateNetwork",
21
+ "nrmse",
22
+ "mse",
23
+ "rmse",
24
+ "topologies",
25
+ "datasets",
26
+ "federated",
27
+ "metrics",
28
+ "interop",
29
+ ]
30
+
31
+ __version__ = "1.0.0"