nnodely 1.5.2__tar.gz → 1.5.4__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 (87) hide show
  1. nnodely-1.5.4/PKG-INFO +318 -0
  2. nnodely-1.5.4/README.md +272 -0
  3. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/__init__.py +3 -1
  4. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/basic/relation.py +2 -2
  5. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/exporter/export.py +12 -2
  6. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/activation.py +10 -5
  7. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/arithmetic.py +12 -16
  8. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/equationlearner.py +1 -29
  9. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/fir.py +2 -18
  10. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/fuzzify.py +2 -19
  11. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/input.py +4 -21
  12. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/linear.py +2 -17
  13. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/localmodel.py +1 -29
  14. nnodely-1.5.4/nnodely/layers/neuralODE.py +104 -0
  15. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/parameter.py +4 -46
  16. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/parametricfunction.py +2 -13
  17. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/part.py +12 -37
  18. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/trigonometric.py +12 -6
  19. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/nnodely.py +0 -41
  20. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/operators/composer.py +12 -53
  21. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/operators/exporter.py +15 -83
  22. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/operators/loader.py +34 -55
  23. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/operators/network.py +9 -4
  24. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/operators/trainer.py +3 -41
  25. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/utils.py +2 -0
  26. nnodely-1.5.4/nnodely.egg-info/PKG-INFO +318 -0
  27. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely.egg-info/SOURCES.txt +1 -0
  28. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_documentation.py +2 -1
  29. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_train.py +30 -1
  30. nnodely-1.5.2/PKG-INFO +0 -406
  31. nnodely-1.5.2/README.md +0 -360
  32. nnodely-1.5.2/nnodely.egg-info/PKG-INFO +0 -406
  33. {nnodely-1.5.2 → nnodely-1.5.4}/LICENSE +0 -0
  34. {nnodely-1.5.2 → nnodely-1.5.4}/mplplots/__init__.py +0 -0
  35. {nnodely-1.5.2 → nnodely-1.5.4}/mplplots/plots.py +0 -0
  36. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/basic/__init__.py +0 -0
  37. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/basic/loss.py +0 -0
  38. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/basic/model.py +0 -0
  39. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/basic/modeldef.py +0 -0
  40. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/basic/optimizer.py +0 -0
  41. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/exporter/__init__.py +0 -0
  42. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/exporter/emptyexporter.py +0 -0
  43. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/exporter/reporter.py +0 -0
  44. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/exporter/standardexporter.py +0 -0
  45. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/__init__.py +0 -0
  46. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/interpolation.py +0 -0
  47. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/output.py +0 -0
  48. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/rungekutta.py +0 -0
  49. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/layers/timeoperation.py +0 -0
  50. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/operators/__init__.py +0 -0
  51. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/operators/validator.py +0 -0
  52. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/__init__.py +0 -0
  53. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/earlystopping.py +0 -0
  54. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/fixstepsolver.py +0 -0
  55. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/initializer.py +0 -0
  56. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/jsonutils.py +0 -0
  57. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/logger.py +0 -0
  58. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/support/mathutils.py +0 -0
  59. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/__init__.py +0 -0
  60. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/dynamicmpl/functionplot.py +0 -0
  61. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/dynamicmpl/fuzzyplot.py +0 -0
  62. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/dynamicmpl/resultsplot.py +0 -0
  63. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/dynamicmpl/trainingplot.py +0 -0
  64. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/emptyvisualizer.py +0 -0
  65. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/mplnotebookvisualizer.py +0 -0
  66. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/mplvisualizer.py +0 -0
  67. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely/visualizer/textvisualizer.py +0 -0
  68. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely.egg-info/dependency_links.txt +0 -0
  69. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely.egg-info/requires.txt +0 -0
  70. {nnodely-1.5.2 → nnodely-1.5.4}/nnodely.egg-info/top_level.txt +0 -0
  71. {nnodely-1.5.2 → nnodely-1.5.4}/pyproject.toml +0 -0
  72. {nnodely-1.5.2 → nnodely-1.5.4}/setup.cfg +0 -0
  73. {nnodely-1.5.2 → nnodely-1.5.4}/setup.py +0 -0
  74. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_dataset.py +0 -0
  75. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_export.py +0 -0
  76. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_export_recurrent.py +0 -0
  77. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_input_dimensions.py +0 -0
  78. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_json.py +0 -0
  79. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_losses.py +0 -0
  80. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_model_predict.py +0 -0
  81. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_model_predict_recurrent.py +0 -0
  82. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_network_element.py +0 -0
  83. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_parameters_of_train.py +0 -0
  84. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_results.py +0 -0
  85. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_train_recurrent.py +0 -0
  86. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_utils.py +0 -0
  87. {nnodely-1.5.2 → nnodely-1.5.4}/tests/test_visualizer.py +0 -0
nnodely-1.5.4/PKG-INFO ADDED
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: nnodely
3
+ Version: 1.5.4
4
+ Summary: Model-structured neural network framework for the modeling and control of physical systems
5
+ Author-email: Gastone Pietro Rosati Papini <tonegas@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Gastone Pietro Rosati Papini
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/tonegas/nnodely
29
+ Classifier: Programming Language :: Python :: 3
30
+ Classifier: License :: OSI Approved :: MIT License
31
+ Classifier: Operating System :: OS Independent
32
+ Requires-Python: <3.13,>=3.10
33
+ Description-Content-Type: text/markdown
34
+ License-File: LICENSE
35
+ Requires-Dist: numpy==1.26.4; platform_machine == "x86_64" and python_version == "3.10"
36
+ Requires-Dist: torch==2.2.2; platform_machine == "x86_64" and python_version == "3.10"
37
+ Requires-Dist: torch==2.6.0; platform_machine != "x86_64" or python_version != "3.10"
38
+ Requires-Dist: numpy
39
+ Requires-Dist: onnx
40
+ Requires-Dist: pandas
41
+ Requires-Dist: reportlab
42
+ Requires-Dist: matplotlib
43
+ Requires-Dist: onnxruntime
44
+ Requires-Dist: graphviz
45
+ Dynamic: license-file
46
+
47
+ <a name="readme-top"></a>
48
+ <p align="center">
49
+ <img src="https://raw.githubusercontent.com/tonegas/nnodely/main/imgs/logo_white_info.png" alt="logo" >
50
+ </p>
51
+
52
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
53
+ [![codecov](https://codecov.io/github/tonegas/nnodely/graph/badge.svg?token=8V6P2PSYT4)](https://codecov.io/github/tonegas/nnodely)
54
+ [![Documentation](https://readthedocs.org/projects/nnodely/badge/?version=main&style=default)](https://nnodely.readthedocs.io/)
55
+ [![PyPI](https://img.shields.io/pypi/v/nnodely?color=blue&label=PyPI%20Package)](https://pypi.org/project/nnodely/)
56
+
57
+ # Neural Network Framekwork for Modelling, Control, and Estimation of Physical Systems
58
+
59
+ Modeling, control, and estimation of physical systems are central to many engineering disciplines. While data-driven methods like neural networks offer powerful tools, they often struggle to **incorporate prior domain knowledge**, limiting their interpretability, generalizability, and safety.
60
+
61
+ To bridge this gap, we present ***nnodely*** (where "nn" can be read as "m," forming *Modely*) — a framework that facilitates the creation and deployment of **Model-Structured Neural Networks** (**MS-NNs**).
62
+ MS-NNs combine the learning capabilities of neural networks with structural **priors** grounded in **physics, control, and estimation theory**, enabling:
63
+
64
+ - **Reduced training data** requirements
65
+ - **Generalization** to unseen scenarios
66
+ - **Real-time** deployment in real-world applications
67
+
68
+ In short:
69
+
70
+ nnodely is not a replacement for a general purpose deep learning frameworks — it is a **structured layer on top of them**, purpose-built for physical systems.
71
+
72
+ <br>
73
+ <p align="center">
74
+ 📖 <a href="https://nnodely.readthedocs.io/"><b>Documentation</b></a> •
75
+ 🔬 <a href="./case-studies/"><b>Case Studies</b></a> •
76
+ 🚀 <a href="https://github.com/tonegas/nnodely-applications"><b>Other Applications</b></a>
77
+ </p>
78
+
79
+ <!-- > [!NOTE]
80
+ > **Full documentation** of the code is available at the following [link](https://nnodely.readthedocs.io/en/docs-update/)
81
+
82
+ > Some **examples of applications** of nnodely in different fields are collected in the following open-source repository: [nnodely-applications](https://github.com/tonegas/nnodely-applications) -->
83
+
84
+ <h2>Table of Contents</h2>
85
+ <ol>
86
+ <li><a href="#gettingstarted">Getting Started</a></li>
87
+ <ul>
88
+ <li><a href="#installation">Installation</a></li>
89
+ <li><a href="#helloworld">Hello, World!</a></li>
90
+ </ul>
91
+ <li><a href="#folderstructure">Structure of the Repository</a></li>
92
+ <li><a href="#contribute">How to contribute</a></li>
93
+ <li><a href="#license">License</a></li>
94
+ <li><a href="#references">References</a></li>
95
+ </ol>
96
+
97
+
98
+ <a name="gettingstarted"></a>
99
+ ## Getting Started
100
+
101
+ <a name="installation"></a>
102
+ ### Installation
103
+
104
+ You can install nnodely from PyPI via:
105
+
106
+ ```sh
107
+ pip install nnodely
108
+ ```
109
+
110
+ Alternatively, you can build it from source by first cloning the repository and installing the requirements and the nnodely library:
111
+
112
+ ```sh
113
+ git clone https://github.com/tonegas/nnodely.git
114
+ cd nnodely
115
+ pip install -r requirements.txt
116
+ pip install .
117
+ ```
118
+ <a name="helloworld"></a>
119
+ ### Hello, World!
120
+ To check if `nnodely` is installed correctly try running the following script.
121
+
122
+ ```python
123
+ from nnodely import Input, Output, nnodely, Parameter
124
+
125
+ x = Input("x")
126
+ l = x.last()
127
+ o = (Parameter('A')*l.sw([-2,-1])+Parameter('B')*l).closedLoop(x)
128
+ f = Output("fib",o)
129
+ model = nnodely()
130
+ model.addModel("Fibonacci",f)
131
+ model.addMinimize("target", l.sw([-2,-1])+l, f)
132
+ model.neuralizeModel(1)
133
+ model.loadData("data",{ "x" : list(range(100)) } )
134
+ model.trainModel(prediction_samples = 2, lr = 0.5, num_of_epochs = 500)
135
+ model.exportPythonModel(models = "Fibonacci")
136
+ print(model({ "x" : [1] },prediction_samples = 20,num_of_samples = 20))
137
+ ```
138
+ In the example, the neural network is trained to mimic the Fibonacci series.
139
+ Finally, a native pytorch network is exported in a file.
140
+
141
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
142
+
143
+ <a name="folderstructure"></a>
144
+ ## Structure of the Repository
145
+
146
+ ```bash
147
+ nnodely/ # root directory
148
+ ├── nnodely/ # source code
149
+ │ ├── basic/ # core low-level classes
150
+ │ ├── exporter/ # model export utilities
151
+ │ ├── layers/ # supported layers
152
+ │ ├── operators/ # core operators
153
+ │ ├── support/ # utility functions
154
+ │ └── visualizer/ # visualization tools
155
+ ├── case-studies/ # main case studies
156
+ ├── docs/ # documentation
157
+ ├── tests/ # unit and integration tests
158
+ ├── imgs/ # images used in the documentation
159
+ └── mplplots/ # utilities for MatPlotLib
160
+ ```
161
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
162
+
163
+ <details>
164
+ <summary>More info about repository structure</summary>
165
+ <a name="nnodelyfolder"></a>
166
+
167
+ ### nnodely Folder
168
+ This folder contains all the nnodely library files with relative references.
169
+
170
+ The `nnodely` main class defined in __nnodely.py__, it contains all the main properties of the nnodely object and it derives from five main operators, cointained in the folder `operators/`:
171
+ 1. __composer.py__ contains all the functions to build the networks: `addModel`, `neuralizeModel`, `addConnection`, `addClosedLoop` etc..
172
+ 2. __loader.py__ contains the function for managing the dataset, the main function is `dataLoad`.
173
+ 3. __trainer.py__ contains the function for training the network as the `trainModel`.
174
+ 4. __exporter.py__ contains all the function for import and export: `saveModel`, `loadModel`, `exportONNX` etc..
175
+ 5. __validator.py__ contains all the function for validate the model and the `resultsAnalysis`.
176
+ 6. All the operators derive from `Network` defined in __network.py__, that contains the shared support functions for all the operators.
177
+
178
+ The folder `basic/` contains the main classes for the low level functionalities:
179
+ 1. __model.py__ containts the pytorch template model for the structured network.
180
+ 2. __modeldef.py__ containts the operation for work with the json model definition.
181
+ 3. __loss.py__ contains the loss functions.
182
+ 4. __optimizer.py__ contains the optimizer calss.
183
+ 6. __relation.py__ contains all the main classes from which all the layers are derived.
184
+
185
+ The other folders are:
186
+ 1. `exporter/` that contains the classes for the export functions.
187
+ 2. `support/` for the support functions.
188
+ 3. `visualizer/` that contains all the classes related to the visualization.
189
+ 4. And finally the `layers/` folder.
190
+
191
+ The `layers/` folder contains all the layers that can be used in the MSNN.
192
+ In particular, the model structured NN is defined by `Inputs`, `Outputs` and `Parameters`:
193
+ 1. __input.py__ contains the Input class used for create an input for the network.
194
+ 2. __output.py__ contains the Output class used for create an output for the network.
195
+ 3. __parameter.py__ contains the logic for create a generic parameters and constants.
196
+
197
+ The main basic layers without parameters are:
198
+ 1. __activation.py__ this file contains all the activation functions. The activation are mainly based on the pytorch functions.
199
+ 2. __arithmetic.py__ this file contains the aritmetic functions as: +, -, /, *., **.
200
+ 3. __trigonometric.py__ this file contains all the trigonometric functions.
201
+ 4. __part.py__ are used for selecting part of the data.
202
+ 5. __fuzzify.py__ contains the operation for the fuzzification of a variable,
203
+ commonly used in the local model as activation function as in [[1]](#1) with rectangular activation functions or in [[3]](#3), [[4]](#4) and [[5]](#5) with triangular activation function activation functions.
204
+ Using fuzzification it is also possible create a channel coding as presented in [[2]](#2).
205
+
206
+ The main basic layers with parameters are:
207
+ 1. __fir.py__ this file contains the finite impulse response filter function. It is a linear operation on the time dimension (second dimension).
208
+ This filter was introduced in [[1]](#1).
209
+ 2. __linear.py__ this file contains the linear function. Typical Linear operation `W*x+b` operated on the space dimension (third dimension).
210
+ This operation is presented in [[1]](#1).
211
+ 3. __localmodel.py__ this file contains the logic for build a local model. This operation is presented in [[1]](#1), [[3]](#3), [[4]](#4) and [[5]](#5).
212
+ 4. __parametricfunction.py__ are the user custom function. The function can use the pytorch syntax. A parametric function is presented in [[3]](#3), [[4]](#4), [[5]](#5).
213
+ 5. __equationlearner.py__ contains the logic for the equation learner. The equation learner is used for learn a relation input outpur following a list of activation functions. The first implementation is presented in [[6]](#6).
214
+ 6. __timeoperation.py__ contains the time operation functions. The time operation are used for extract a time window from a signal. The derivative operation can be used to implement Physics-informed neural network [[7]](#7) Sobolev learning [[8]](#8).
215
+
216
+ <a name="casestudiesfolder"></a>
217
+ ### Case Studies Folder
218
+ In the case studies folder you can find the main case studies cited in the paper.
219
+ Each case study is a jupyter notebook that explains the main functionalities of the library.
220
+
221
+ <a name="docsfolder"></a>
222
+ ### Docs Folder
223
+ This folder contains all files used to automatically generate the documentation.
224
+
225
+ <a name="testsfolder"></a>
226
+ ### Tests Folder
227
+ This folder contains the unit tests of the library. Each file tests a specific functionality.
228
+
229
+ <a name="mplfolder"></a>
230
+ ### Matplotlib Folder
231
+ This folder contains the utilities for Matplotlib.
232
+
233
+ <a name="imgfolder"></a>
234
+ ### Images Folder
235
+ This folder contains the images used in the documentation.
236
+
237
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
238
+ </details>
239
+
240
+ <a name="contribute"></a>
241
+ ## How to Contribute
242
+
243
+ To contribute to the nnodely framework, you can:
244
+
245
+ - Open a pull request if you have a new feature or bug fix.
246
+ - Open an issue if you have a question or suggestion.
247
+
248
+ We welcome contributions and collaborations.
249
+
250
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
251
+
252
+ <a name="license"></a>
253
+ ## License
254
+ This project is released under the license [License: MIT](https://opensource.org/licenses/MIT).
255
+
256
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
257
+
258
+ <a name="references"></a>
259
+ ## References
260
+
261
+ <a id="1">[1]</a>
262
+ Mauro Da Lio, Daniele Bortoluzzi, Gastone Pietro Rosati Papini. (2019).
263
+ Modelling longitudinal vehicle dynamics with neural networks.
264
+ Vehicle System Dynamics. https://doi.org/10.1080/00423114.2019.1638947 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/model_longit_vehicle_dynamics/model_longit_vehicle_dynamics.py))
265
+
266
+ <a id="2">[2]</a>
267
+ Alice Plebe, Mauro Da Lio, Daniele Bortoluzzi. (2019).
268
+ On Reliable Neural Network Sensorimotor Control in Autonomous Vehicles.
269
+ IEEE Transaction on Intelligent Transportation System. https://doi.org/10.1109/TITS.2019.2896375
270
+
271
+ <a id="3">[3]</a>
272
+ Mauro Da Lio, Riccardo Donà, Gastone Pietro Rosati Papini, Francesco Biral, Henrik Svensson. (2020).
273
+ A Mental Simulation Approach for Learning Neural-Network Predictive Control (in Self-Driving Cars).
274
+ IEEE Access. https://doi.org/10.1109/ACCESS.2020.3032780 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/model_lateral_vehicle_dynamics/model_lateral_vehicle_dynamics.ipynb))
275
+
276
+ <a id="4">[4]</a>
277
+ Edoardo Pagot, Mattia Piccinini, Enrico Bertolazzi, Francesco Biral. (2023).
278
+ Fast Planning and Tracking of Complex Autonomous Parking Maneuvers With Optimal Control and Pseudo-Neural Networks.
279
+ IEEE Access. https://doi.org/10.1109/ACCESS.2023.3330431 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/control_steer_car_parking/control_steer_car_parking.ipynb))
280
+
281
+ <a id="5">[5]</a>
282
+ Mattia Piccinini, Sebastiano Taddei, Matteo Larcher, Mattia Piazza, Francesco Biral. (2023).
283
+ A Physics-Driven Artificial Agent for Online Time-Optimal Vehicle Motion Planning and Control.
284
+ IEEE Access. https://doi.org/10.1109/ACCESS.2023.3274836 (look [[code basic]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/control_steer_artificial_race_driver/control_steer_artificial_race_driver.ipynb)
285
+ and [[code extended]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/control_steer_artificial_race_driver_extended/control_steer_artificial_race_driver_extended.ipynb))
286
+
287
+ <a id="6">[6]</a>
288
+ Hector Perez-Villeda, Justus Piater, Matteo Saveriano. (2023).
289
+ Learning and extrapolation of robotic skills using task-parameterized equation learner networks.
290
+ Robotics and Autonomous Systems. https://doi.org/10.1016/j.robot.2022.104309 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/equation_learner/equation_learner.ipynb))
291
+
292
+ <a id="7">[7]</a>
293
+ M. Raissi. P. Perdikaris b, G.E. Karniadakis a. (2019).
294
+ Physics-informed neural networks: A deep learning framework for solving forward and inverse problems involving nonlinear partial differential equations
295
+ Journal of Computational Physics. https://doi.org/10.1016/j.jcp.2018.10.045 (look the [[example Burger's equation]](https://github.com/tonegas/nnodely-applications/blob/main/pinn/pinn_Burgers_equation.ipynb))
296
+
297
+ <a id="8">[8]</a>
298
+ Wojciech Marian Czarnecki, Simon Osindero, Max Jaderberg, Grzegorz Świrszcz, Razvan Pascanu. (2017).
299
+ Sobolev Training for Neural Networks.
300
+ arXiv. https://doi.org/10.48550/arXiv.1706.04859 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/sobolev/Sobolev_learning.ipynb))
301
+
302
+ <a id="9">[9]</a>
303
+ Mattia Piccinini, Matteo Zumerle, Johannes Betz, Gastone Pietro Rosati Papini. (2025).
304
+ A Road Friction-Aware Anti-Lock Braking System Based on Model-Structured Neural Networks.
305
+ IEEE Open Journal of Intelligent Transportation Systems. https://doi.org/10.1109/OJITS.2025.3563347 (look at the [[code]](https://github.com/tonegas/nnodely-applications/tree/main/vehicle/road_friction_aware_ABS))
306
+
307
+ <a id="10">[10]</a>
308
+ Mauro Da Lio, Mattia Piccinini, Francesco Biral. (2023).
309
+ Robust and Sample-Efficient Estimation of Vehicle Lateral Velocity Using Neural Networks With Explainable Structure Informed by Kinematic Principles.
310
+ IEEE Transactions on Intelligent Transportation Systems. https://doi.org/10.1109/TITS.2023.3303776
311
+
312
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
313
+ <!--
314
+ <a name="cite-us"></a>
315
+ ## Cite Us
316
+
317
+ > TODO: Possiamo aggiungere DOI di repo con zenodo e mettere la citazione di quello [guida](https://docs.github.com/en/repositories/archiving-a-github-repository/referencing-and-citing-content)
318
+ -->
@@ -0,0 +1,272 @@
1
+ <a name="readme-top"></a>
2
+ <p align="center">
3
+ <img src="https://raw.githubusercontent.com/tonegas/nnodely/main/imgs/logo_white_info.png" alt="logo" >
4
+ </p>
5
+
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![codecov](https://codecov.io/github/tonegas/nnodely/graph/badge.svg?token=8V6P2PSYT4)](https://codecov.io/github/tonegas/nnodely)
8
+ [![Documentation](https://readthedocs.org/projects/nnodely/badge/?version=main&style=default)](https://nnodely.readthedocs.io/)
9
+ [![PyPI](https://img.shields.io/pypi/v/nnodely?color=blue&label=PyPI%20Package)](https://pypi.org/project/nnodely/)
10
+
11
+ # Neural Network Framekwork for Modelling, Control, and Estimation of Physical Systems
12
+
13
+ Modeling, control, and estimation of physical systems are central to many engineering disciplines. While data-driven methods like neural networks offer powerful tools, they often struggle to **incorporate prior domain knowledge**, limiting their interpretability, generalizability, and safety.
14
+
15
+ To bridge this gap, we present ***nnodely*** (where "nn" can be read as "m," forming *Modely*) — a framework that facilitates the creation and deployment of **Model-Structured Neural Networks** (**MS-NNs**).
16
+ MS-NNs combine the learning capabilities of neural networks with structural **priors** grounded in **physics, control, and estimation theory**, enabling:
17
+
18
+ - **Reduced training data** requirements
19
+ - **Generalization** to unseen scenarios
20
+ - **Real-time** deployment in real-world applications
21
+
22
+ In short:
23
+
24
+ nnodely is not a replacement for a general purpose deep learning frameworks — it is a **structured layer on top of them**, purpose-built for physical systems.
25
+
26
+ <br>
27
+ <p align="center">
28
+ 📖 <a href="https://nnodely.readthedocs.io/"><b>Documentation</b></a> •
29
+ 🔬 <a href="./case-studies/"><b>Case Studies</b></a> •
30
+ 🚀 <a href="https://github.com/tonegas/nnodely-applications"><b>Other Applications</b></a>
31
+ </p>
32
+
33
+ <!-- > [!NOTE]
34
+ > **Full documentation** of the code is available at the following [link](https://nnodely.readthedocs.io/en/docs-update/)
35
+
36
+ > Some **examples of applications** of nnodely in different fields are collected in the following open-source repository: [nnodely-applications](https://github.com/tonegas/nnodely-applications) -->
37
+
38
+ <h2>Table of Contents</h2>
39
+ <ol>
40
+ <li><a href="#gettingstarted">Getting Started</a></li>
41
+ <ul>
42
+ <li><a href="#installation">Installation</a></li>
43
+ <li><a href="#helloworld">Hello, World!</a></li>
44
+ </ul>
45
+ <li><a href="#folderstructure">Structure of the Repository</a></li>
46
+ <li><a href="#contribute">How to contribute</a></li>
47
+ <li><a href="#license">License</a></li>
48
+ <li><a href="#references">References</a></li>
49
+ </ol>
50
+
51
+
52
+ <a name="gettingstarted"></a>
53
+ ## Getting Started
54
+
55
+ <a name="installation"></a>
56
+ ### Installation
57
+
58
+ You can install nnodely from PyPI via:
59
+
60
+ ```sh
61
+ pip install nnodely
62
+ ```
63
+
64
+ Alternatively, you can build it from source by first cloning the repository and installing the requirements and the nnodely library:
65
+
66
+ ```sh
67
+ git clone https://github.com/tonegas/nnodely.git
68
+ cd nnodely
69
+ pip install -r requirements.txt
70
+ pip install .
71
+ ```
72
+ <a name="helloworld"></a>
73
+ ### Hello, World!
74
+ To check if `nnodely` is installed correctly try running the following script.
75
+
76
+ ```python
77
+ from nnodely import Input, Output, nnodely, Parameter
78
+
79
+ x = Input("x")
80
+ l = x.last()
81
+ o = (Parameter('A')*l.sw([-2,-1])+Parameter('B')*l).closedLoop(x)
82
+ f = Output("fib",o)
83
+ model = nnodely()
84
+ model.addModel("Fibonacci",f)
85
+ model.addMinimize("target", l.sw([-2,-1])+l, f)
86
+ model.neuralizeModel(1)
87
+ model.loadData("data",{ "x" : list(range(100)) } )
88
+ model.trainModel(prediction_samples = 2, lr = 0.5, num_of_epochs = 500)
89
+ model.exportPythonModel(models = "Fibonacci")
90
+ print(model({ "x" : [1] },prediction_samples = 20,num_of_samples = 20))
91
+ ```
92
+ In the example, the neural network is trained to mimic the Fibonacci series.
93
+ Finally, a native pytorch network is exported in a file.
94
+
95
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
96
+
97
+ <a name="folderstructure"></a>
98
+ ## Structure of the Repository
99
+
100
+ ```bash
101
+ nnodely/ # root directory
102
+ ├── nnodely/ # source code
103
+ │ ├── basic/ # core low-level classes
104
+ │ ├── exporter/ # model export utilities
105
+ │ ├── layers/ # supported layers
106
+ │ ├── operators/ # core operators
107
+ │ ├── support/ # utility functions
108
+ │ └── visualizer/ # visualization tools
109
+ ├── case-studies/ # main case studies
110
+ ├── docs/ # documentation
111
+ ├── tests/ # unit and integration tests
112
+ ├── imgs/ # images used in the documentation
113
+ └── mplplots/ # utilities for MatPlotLib
114
+ ```
115
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
116
+
117
+ <details>
118
+ <summary>More info about repository structure</summary>
119
+ <a name="nnodelyfolder"></a>
120
+
121
+ ### nnodely Folder
122
+ This folder contains all the nnodely library files with relative references.
123
+
124
+ The `nnodely` main class defined in __nnodely.py__, it contains all the main properties of the nnodely object and it derives from five main operators, cointained in the folder `operators/`:
125
+ 1. __composer.py__ contains all the functions to build the networks: `addModel`, `neuralizeModel`, `addConnection`, `addClosedLoop` etc..
126
+ 2. __loader.py__ contains the function for managing the dataset, the main function is `dataLoad`.
127
+ 3. __trainer.py__ contains the function for training the network as the `trainModel`.
128
+ 4. __exporter.py__ contains all the function for import and export: `saveModel`, `loadModel`, `exportONNX` etc..
129
+ 5. __validator.py__ contains all the function for validate the model and the `resultsAnalysis`.
130
+ 6. All the operators derive from `Network` defined in __network.py__, that contains the shared support functions for all the operators.
131
+
132
+ The folder `basic/` contains the main classes for the low level functionalities:
133
+ 1. __model.py__ containts the pytorch template model for the structured network.
134
+ 2. __modeldef.py__ containts the operation for work with the json model definition.
135
+ 3. __loss.py__ contains the loss functions.
136
+ 4. __optimizer.py__ contains the optimizer calss.
137
+ 6. __relation.py__ contains all the main classes from which all the layers are derived.
138
+
139
+ The other folders are:
140
+ 1. `exporter/` that contains the classes for the export functions.
141
+ 2. `support/` for the support functions.
142
+ 3. `visualizer/` that contains all the classes related to the visualization.
143
+ 4. And finally the `layers/` folder.
144
+
145
+ The `layers/` folder contains all the layers that can be used in the MSNN.
146
+ In particular, the model structured NN is defined by `Inputs`, `Outputs` and `Parameters`:
147
+ 1. __input.py__ contains the Input class used for create an input for the network.
148
+ 2. __output.py__ contains the Output class used for create an output for the network.
149
+ 3. __parameter.py__ contains the logic for create a generic parameters and constants.
150
+
151
+ The main basic layers without parameters are:
152
+ 1. __activation.py__ this file contains all the activation functions. The activation are mainly based on the pytorch functions.
153
+ 2. __arithmetic.py__ this file contains the aritmetic functions as: +, -, /, *., **.
154
+ 3. __trigonometric.py__ this file contains all the trigonometric functions.
155
+ 4. __part.py__ are used for selecting part of the data.
156
+ 5. __fuzzify.py__ contains the operation for the fuzzification of a variable,
157
+ commonly used in the local model as activation function as in [[1]](#1) with rectangular activation functions or in [[3]](#3), [[4]](#4) and [[5]](#5) with triangular activation function activation functions.
158
+ Using fuzzification it is also possible create a channel coding as presented in [[2]](#2).
159
+
160
+ The main basic layers with parameters are:
161
+ 1. __fir.py__ this file contains the finite impulse response filter function. It is a linear operation on the time dimension (second dimension).
162
+ This filter was introduced in [[1]](#1).
163
+ 2. __linear.py__ this file contains the linear function. Typical Linear operation `W*x+b` operated on the space dimension (third dimension).
164
+ This operation is presented in [[1]](#1).
165
+ 3. __localmodel.py__ this file contains the logic for build a local model. This operation is presented in [[1]](#1), [[3]](#3), [[4]](#4) and [[5]](#5).
166
+ 4. __parametricfunction.py__ are the user custom function. The function can use the pytorch syntax. A parametric function is presented in [[3]](#3), [[4]](#4), [[5]](#5).
167
+ 5. __equationlearner.py__ contains the logic for the equation learner. The equation learner is used for learn a relation input outpur following a list of activation functions. The first implementation is presented in [[6]](#6).
168
+ 6. __timeoperation.py__ contains the time operation functions. The time operation are used for extract a time window from a signal. The derivative operation can be used to implement Physics-informed neural network [[7]](#7) Sobolev learning [[8]](#8).
169
+
170
+ <a name="casestudiesfolder"></a>
171
+ ### Case Studies Folder
172
+ In the case studies folder you can find the main case studies cited in the paper.
173
+ Each case study is a jupyter notebook that explains the main functionalities of the library.
174
+
175
+ <a name="docsfolder"></a>
176
+ ### Docs Folder
177
+ This folder contains all files used to automatically generate the documentation.
178
+
179
+ <a name="testsfolder"></a>
180
+ ### Tests Folder
181
+ This folder contains the unit tests of the library. Each file tests a specific functionality.
182
+
183
+ <a name="mplfolder"></a>
184
+ ### Matplotlib Folder
185
+ This folder contains the utilities for Matplotlib.
186
+
187
+ <a name="imgfolder"></a>
188
+ ### Images Folder
189
+ This folder contains the images used in the documentation.
190
+
191
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
192
+ </details>
193
+
194
+ <a name="contribute"></a>
195
+ ## How to Contribute
196
+
197
+ To contribute to the nnodely framework, you can:
198
+
199
+ - Open a pull request if you have a new feature or bug fix.
200
+ - Open an issue if you have a question or suggestion.
201
+
202
+ We welcome contributions and collaborations.
203
+
204
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
205
+
206
+ <a name="license"></a>
207
+ ## License
208
+ This project is released under the license [License: MIT](https://opensource.org/licenses/MIT).
209
+
210
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
211
+
212
+ <a name="references"></a>
213
+ ## References
214
+
215
+ <a id="1">[1]</a>
216
+ Mauro Da Lio, Daniele Bortoluzzi, Gastone Pietro Rosati Papini. (2019).
217
+ Modelling longitudinal vehicle dynamics with neural networks.
218
+ Vehicle System Dynamics. https://doi.org/10.1080/00423114.2019.1638947 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/model_longit_vehicle_dynamics/model_longit_vehicle_dynamics.py))
219
+
220
+ <a id="2">[2]</a>
221
+ Alice Plebe, Mauro Da Lio, Daniele Bortoluzzi. (2019).
222
+ On Reliable Neural Network Sensorimotor Control in Autonomous Vehicles.
223
+ IEEE Transaction on Intelligent Transportation System. https://doi.org/10.1109/TITS.2019.2896375
224
+
225
+ <a id="3">[3]</a>
226
+ Mauro Da Lio, Riccardo Donà, Gastone Pietro Rosati Papini, Francesco Biral, Henrik Svensson. (2020).
227
+ A Mental Simulation Approach for Learning Neural-Network Predictive Control (in Self-Driving Cars).
228
+ IEEE Access. https://doi.org/10.1109/ACCESS.2020.3032780 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/model_lateral_vehicle_dynamics/model_lateral_vehicle_dynamics.ipynb))
229
+
230
+ <a id="4">[4]</a>
231
+ Edoardo Pagot, Mattia Piccinini, Enrico Bertolazzi, Francesco Biral. (2023).
232
+ Fast Planning and Tracking of Complex Autonomous Parking Maneuvers With Optimal Control and Pseudo-Neural Networks.
233
+ IEEE Access. https://doi.org/10.1109/ACCESS.2023.3330431 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/control_steer_car_parking/control_steer_car_parking.ipynb))
234
+
235
+ <a id="5">[5]</a>
236
+ Mattia Piccinini, Sebastiano Taddei, Matteo Larcher, Mattia Piazza, Francesco Biral. (2023).
237
+ A Physics-Driven Artificial Agent for Online Time-Optimal Vehicle Motion Planning and Control.
238
+ IEEE Access. https://doi.org/10.1109/ACCESS.2023.3274836 (look [[code basic]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/control_steer_artificial_race_driver/control_steer_artificial_race_driver.ipynb)
239
+ and [[code extended]](https://github.com/tonegas/nnodely-applications/blob/main/vehicle/control_steer_artificial_race_driver_extended/control_steer_artificial_race_driver_extended.ipynb))
240
+
241
+ <a id="6">[6]</a>
242
+ Hector Perez-Villeda, Justus Piater, Matteo Saveriano. (2023).
243
+ Learning and extrapolation of robotic skills using task-parameterized equation learner networks.
244
+ Robotics and Autonomous Systems. https://doi.org/10.1016/j.robot.2022.104309 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/equation_learner/equation_learner.ipynb))
245
+
246
+ <a id="7">[7]</a>
247
+ M. Raissi. P. Perdikaris b, G.E. Karniadakis a. (2019).
248
+ Physics-informed neural networks: A deep learning framework for solving forward and inverse problems involving nonlinear partial differential equations
249
+ Journal of Computational Physics. https://doi.org/10.1016/j.jcp.2018.10.045 (look the [[example Burger's equation]](https://github.com/tonegas/nnodely-applications/blob/main/pinn/pinn_Burgers_equation.ipynb))
250
+
251
+ <a id="8">[8]</a>
252
+ Wojciech Marian Czarnecki, Simon Osindero, Max Jaderberg, Grzegorz Świrszcz, Razvan Pascanu. (2017).
253
+ Sobolev Training for Neural Networks.
254
+ arXiv. https://doi.org/10.48550/arXiv.1706.04859 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/sobolev/Sobolev_learning.ipynb))
255
+
256
+ <a id="9">[9]</a>
257
+ Mattia Piccinini, Matteo Zumerle, Johannes Betz, Gastone Pietro Rosati Papini. (2025).
258
+ A Road Friction-Aware Anti-Lock Braking System Based on Model-Structured Neural Networks.
259
+ IEEE Open Journal of Intelligent Transportation Systems. https://doi.org/10.1109/OJITS.2025.3563347 (look at the [[code]](https://github.com/tonegas/nnodely-applications/tree/main/vehicle/road_friction_aware_ABS))
260
+
261
+ <a id="10">[10]</a>
262
+ Mauro Da Lio, Mattia Piccinini, Francesco Biral. (2023).
263
+ Robust and Sample-Efficient Estimation of Vehicle Lateral Velocity Using Neural Networks With Explainable Structure Informed by Kinematic Principles.
264
+ IEEE Transactions on Intelligent Transportation Systems. https://doi.org/10.1109/TITS.2023.3303776
265
+
266
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
267
+ <!--
268
+ <a name="cite-us"></a>
269
+ ## Cite Us
270
+
271
+ > TODO: Possiamo aggiungere DOI di repo con zenodo e mettere la citazione di quello [guida](https://docs.github.com/en/repositories/archiving-a-github-repository/referencing-and-citing-content)
272
+ -->
@@ -20,6 +20,7 @@ from nnodely.layers.equationlearner import EquationLearner
20
20
  from nnodely.layers.timeoperation import Integrate, Differentiate
21
21
  from nnodely.layers.interpolation import Interpolation
22
22
  from nnodely.layers.rungekutta import ForwardEuler, RK2, RK4
23
+ from nnodely.layers.neuralODE import NeuralODE
23
24
 
24
25
  # Main nnodely classes
25
26
  from nnodely.nnodely import nnodely, Modely, clearNames
@@ -36,7 +37,7 @@ from nnodely.support import logger
36
37
  major, minor = sys.version_info.major, sys.version_info.minor
37
38
  logger.LOG_LEVEL = logging.INFO
38
39
 
39
- __version__ = '1.5.2'
40
+ __version__ = '1.5.4'
40
41
 
41
42
  if major < 3:
42
43
  sys.exit("Sorry, Python 2 is not supported. You need Python >= 3.10 for "+__package__+".")
@@ -56,6 +57,7 @@ __all__ = [
56
57
  'Relu', 'ELU', 'Softmax', 'Sigmoid', 'Identity',
57
58
  'Fir',
58
59
  'Linear',
60
+ 'NeuralODE',
59
61
  'Add', 'Sum', 'Sub', 'Mul', 'Div', 'Pow', 'Neg', 'Sign',
60
62
  'Sin', 'Cos', 'Tan', 'Cosh', 'Tanh', 'Sech',
61
63
  'ParamFun',
@@ -41,7 +41,7 @@ class NeuObj():
41
41
  names = []
42
42
  @classmethod
43
43
  @enforce_types
44
- def clearNames(self, names:str|list|None=None):
44
+ def clearNames(cls, names:str|list|None=None):
45
45
  if names is None:
46
46
  NeuObj.count = 0
47
47
  NeuObj.names = []
@@ -118,7 +118,7 @@ class Stream(Relation):
118
118
  """
119
119
  count = 0
120
120
  @classmethod
121
- def resetCount(self):
121
+ def resetCount(cls):
122
122
  Stream.count = 0
123
123
 
124
124
  def __init__(self, name, json, dim, count = 1):
@@ -107,6 +107,16 @@ def export_python_model(model_def, model, model_path):
107
107
  file.write("\n")
108
108
  saved_functions.append(function_name)
109
109
 
110
+ elif 'NeuralODE' in name:
111
+ function_name = model_def['Functions'][name]['name']
112
+ if function_name not in saved_functions:
113
+ code = model_def['Functions'][name]['code']
114
+ code = code.replace(f'def {function_name}', f'def {package_name}_layers_neuralODE_{function_name}')
115
+ file.write(code)
116
+ file.write("\n")
117
+ saved_functions.append(function_name)
118
+
119
+
110
120
  file.write("class TracerModel(torch.nn.Module):\n")
111
121
  file.write(" def __init__(self):\n")
112
122
  file.write(" super().__init__()\n")
@@ -184,8 +194,8 @@ def export_python_model(model_def, model, model_path):
184
194
  file.write(list_inputs)
185
195
  file.write(" self.states = dict()\n")
186
196
  file.write("\n")
187
- file.write(" def forward(self, kwargs):\n")
188
- file.write(" n_samples = min([kwargs[key].size(0) for key in self.inputs])\n")
197
+ file.write(" def forward(self, kwargs, n_samples = None):\n")
198
+ file.write(" n_samples = n_samples if n_samples else min([kwargs[key].size(0) for key in self.inputs])\n")
189
199
  for key in recurrent_inputs.keys():
190
200
  file.write(f" self.states['{key}'] = kwargs['{key}']\n")
191
201
  result_str = ""