nnodely 1.3.1__tar.gz → 1.4.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 (85) hide show
  1. {nnodely-1.3.1/nnodely.egg-info → nnodely-1.4.0}/PKG-INFO +20 -8
  2. {nnodely-1.3.1 → nnodely-1.4.0}/README.md +13 -2
  3. nnodely-1.4.0/nnodely/__init__.py +47 -0
  4. nnodely-1.4.0/nnodely/basic/__init__.py +0 -0
  5. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/basic}/loss.py +13 -6
  6. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/basic}/model.py +5 -13
  7. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/basic}/modeldef.py +93 -90
  8. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/basic}/optimizer.py +1 -1
  9. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/basic}/relation.py +20 -20
  10. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/exporter/__init__.py +1 -1
  11. nnodely-1.3.1/nnodely/exporter/exporter.py → nnodely-1.4.0/nnodely/exporter/emptyexporter.py +1 -1
  12. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/exporter/export.py +7 -7
  13. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/exporter/reporter.py +10 -10
  14. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/exporter/standardexporter.py +8 -6
  15. nnodely-1.4.0/nnodely/layers/__init__.py +0 -0
  16. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/activation.py +3 -3
  17. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/arithmetic.py +17 -15
  18. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/equationlearner.py +12 -9
  19. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/fir.py +11 -8
  20. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/fuzzify.py +10 -4
  21. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/input.py +9 -5
  22. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/interpolation.py +8 -4
  23. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/linear.py +9 -6
  24. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/localmodel.py +6 -3
  25. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/output.py +2 -2
  26. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/parameter.py +12 -5
  27. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/parametricfunction.py +13 -8
  28. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/part.py +50 -13
  29. nnodely-1.4.0/nnodely/layers/timeoperation.py +75 -0
  30. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/layers}/trigonometric.py +4 -4
  31. nnodely-1.4.0/nnodely/nnodely.py +144 -0
  32. nnodely-1.4.0/nnodely/operators/__init__.py +0 -0
  33. nnodely-1.4.0/nnodely/operators/exporter.py +402 -0
  34. nnodely-1.4.0/nnodely/operators/loader.py +348 -0
  35. nnodely-1.4.0/nnodely/operators/memory.py +47 -0
  36. nnodely-1.4.0/nnodely/operators/network.py +412 -0
  37. nnodely-1.4.0/nnodely/operators/trainer.py +815 -0
  38. nnodely-1.4.0/nnodely/operators/validator.py +218 -0
  39. nnodely-1.4.0/nnodely/support/__init__.py +0 -0
  40. nnodely-1.4.0/nnodely/support/fixstepsolver.py +26 -0
  41. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/support}/utils.py +74 -5
  42. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/mplnotebookvisualizer.py +14 -12
  43. nnodely-1.4.0/nnodely/visualizer/mplvisualizer.py +215 -0
  44. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/textvisualizer.py +47 -47
  45. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/visualizer.py +3 -3
  46. {nnodely-1.3.1 → nnodely-1.4.0/nnodely.egg-info}/PKG-INFO +20 -8
  47. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely.egg-info/SOURCES.txt +36 -25
  48. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely.egg-info/requires.txt +3 -5
  49. {nnodely-1.3.1 → nnodely-1.4.0}/pyproject.toml +9 -5
  50. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_dataset.py +270 -169
  51. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_export.py +8 -4
  52. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_export_recurrent.py +16 -16
  53. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_input_dimensions.py +91 -91
  54. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_json.py +6 -6
  55. nnodely-1.4.0/tests/test_losses.py +189 -0
  56. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_model_predict.py +112 -4
  57. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_model_predict_recurrent.py +133 -48
  58. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_network_element.py +51 -16
  59. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_parameters_of_train.py +32 -22
  60. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_results.py +20 -20
  61. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_train.py +117 -76
  62. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_train_recurrent.py +483 -376
  63. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_utils.py +2 -2
  64. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_visualizer.py +64 -35
  65. nnodely-1.3.1/nnodely/__init__.py +0 -45
  66. nnodely-1.3.1/nnodely/nnodely.py +0 -1994
  67. nnodely-1.3.1/nnodely/timeoperation.py +0 -46
  68. nnodely-1.3.1/nnodely/visualizer/mplvisualizer.py +0 -215
  69. nnodely-1.3.1/tests/test_losses.py +0 -171
  70. {nnodely-1.3.1 → nnodely-1.4.0}/LICENSE +0 -0
  71. {nnodely-1.3.1 → nnodely-1.4.0}/mplplots/__init__.py +0 -0
  72. {nnodely-1.3.1 → nnodely-1.4.0}/mplplots/plots.py +0 -0
  73. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/support}/earlystopping.py +0 -0
  74. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/support}/initializer.py +0 -0
  75. {nnodely-1.3.1/nnodely → nnodely-1.4.0/nnodely/support}/logger.py +0 -0
  76. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/__init__.py +0 -0
  77. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/dynamicmpl/functionplot.py +0 -0
  78. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/dynamicmpl/fuzzyplot.py +0 -0
  79. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/dynamicmpl/resultsplot.py +0 -0
  80. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely/visualizer/dynamicmpl/trainingplot.py +0 -0
  81. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely.egg-info/dependency_links.txt +0 -0
  82. {nnodely-1.3.1 → nnodely-1.4.0}/nnodely.egg-info/top_level.txt +0 -0
  83. {nnodely-1.3.1 → nnodely-1.4.0}/setup.cfg +0 -0
  84. {nnodely-1.3.1 → nnodely-1.4.0}/setup.py +0 -0
  85. {nnodely-1.3.1 → nnodely-1.4.0}/tests/test_documentation.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: nnodely
3
- Version: 1.3.1
3
+ Version: 1.4.0
4
4
  Summary: Model-structured neural network framework for the modeling and control of physical systems
5
5
  Author-email: Gastone Pietro Rosati Papini <tonegas@gmail.com>
6
6
  License: MIT License
@@ -32,15 +32,16 @@ Classifier: Operating System :: OS Independent
32
32
  Requires-Python: <3.13,>=3.10
33
33
  Description-Content-Type: text/markdown
34
34
  License-File: LICENSE
35
- Requires-Dist: numpy==1.26.4; platform_machine == "x86_64"
36
- Requires-Dist: torch==2.2.2; platform_machine == "x86_64"
37
- Requires-Dist: numpy; platform_machine != "x86_64"
38
- Requires-Dist: torch; platform_machine != "x86_64"
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: numpy
38
+ Requires-Dist: torch
39
39
  Requires-Dist: onnx
40
40
  Requires-Dist: pandas
41
41
  Requires-Dist: reportlab
42
42
  Requires-Dist: matplotlib
43
43
  Requires-Dist: onnxruntime
44
+ Dynamic: license-file
44
45
 
45
46
  <p align="center">
46
47
  <img src="https://raw.githubusercontent.com/tonegas/nnodely/main/imgs/logo_white_info.png" alt="logo" >
@@ -308,7 +309,7 @@ This operation is presented in [[1]](#1).
308
309
  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).
309
310
  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).
310
311
  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).
311
- 6. __timeoperation.py__ contains the time operation functions. The time operation are used for extract a time window from a signal.
312
+ 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).
312
313
 
313
314
  <a name="testsfolder"></a>
314
315
  ### Tests Folder
@@ -359,6 +360,17 @@ and [[code extended]](https://github.com/tonegas/nnodely-applications/blob/main/
359
360
  <a id="6">[6]</a>
360
361
  Hector Perez-Villeda, Justus Piater, Matteo Saveriano. (2023).
361
362
  Learning and extrapolation of robotic skills using task-parameterized equation learner networks.
362
- Robotics and Autonomous Systems. https://doi.org/10.1016/j.robot.2022.104309
363
+ 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))
364
+
365
+ <a id="7">[7]</a>
366
+ M. Raissi. P. Perdikaris b, G.E. Karniadakis a. (2019).
367
+ Physics-informed neural networks: A deep learning framework for solving forward and inverse problems involving nonlinear partial differential equations
368
+ 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))
369
+
370
+ <a id="8">[8]</a>
371
+ Wojciech Marian Czarnecki, Simon Osindero, Max Jaderberg, Grzegorz Świrszcz, Razvan Pascanu. (2017).
372
+ Sobolev Training for Neural Networks.
373
+ arXiv. https://doi.org/10.48550/arXiv.1706.04859 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/sobolev/Sobolev_learning.ipynb))
374
+
363
375
 
364
376
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
@@ -264,7 +264,7 @@ This operation is presented in [[1]](#1).
264
264
  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).
265
265
  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).
266
266
  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).
267
- 6. __timeoperation.py__ contains the time operation functions. The time operation are used for extract a time window from a signal.
267
+ 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).
268
268
 
269
269
  <a name="testsfolder"></a>
270
270
  ### Tests Folder
@@ -315,6 +315,17 @@ and [[code extended]](https://github.com/tonegas/nnodely-applications/blob/main/
315
315
  <a id="6">[6]</a>
316
316
  Hector Perez-Villeda, Justus Piater, Matteo Saveriano. (2023).
317
317
  Learning and extrapolation of robotic skills using task-parameterized equation learner networks.
318
- Robotics and Autonomous Systems. https://doi.org/10.1016/j.robot.2022.104309
318
+ 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))
319
+
320
+ <a id="7">[7]</a>
321
+ M. Raissi. P. Perdikaris b, G.E. Karniadakis a. (2019).
322
+ Physics-informed neural networks: A deep learning framework for solving forward and inverse problems involving nonlinear partial differential equations
323
+ 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))
324
+
325
+ <a id="8">[8]</a>
326
+ Wojciech Marian Czarnecki, Simon Osindero, Max Jaderberg, Grzegorz Świrszcz, Razvan Pascanu. (2017).
327
+ Sobolev Training for Neural Networks.
328
+ arXiv. https://doi.org/10.48550/arXiv.1706.04859 (look the [[code]](https://github.com/tonegas/nnodely-applications/blob/main/sobolev/Sobolev_learning.ipynb))
329
+
319
330
 
320
331
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
@@ -0,0 +1,47 @@
1
+
2
+ __version__ = '1.4.0'
3
+
4
+ import sys
5
+ major, minor = sys.version_info.major, sys.version_info.minor
6
+
7
+ import logging
8
+ LOG_LEVEL = logging.INFO
9
+
10
+ if major < 3:
11
+ sys.exit("Sorry, Python 2 is not supported. You need Python >= 3.10 for "+__package__+".")
12
+ elif minor < 9:
13
+ sys.exit("Sorry, You need Python >= 3.10 for "+__package__+".")
14
+ else:
15
+ print(f'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'+
16
+ f' {__package__}_v{__version__} '.center(20, '-')+
17
+ f'<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
18
+
19
+ # Network input, outputs and parameters
20
+ from nnodely.layers.input import Input, State, Connect, ClosedLoop
21
+ from nnodely.layers.parameter import Parameter, Constant, SampleTime
22
+ from nnodely.layers.output import Output
23
+
24
+ # Network elements
25
+ from nnodely.layers.activation import Relu, ELU, Softmax, Sigmoid, Identity
26
+ from nnodely.layers.fir import Fir
27
+ from nnodely.layers.linear import Linear
28
+ from nnodely.layers.arithmetic import Add, Sum, Sub, Mul, Div, Pow, Neg
29
+ from nnodely.layers.trigonometric import Sin, Cos, Tan, Cosh, Tanh, Sech
30
+ from nnodely.layers.parametricfunction import ParamFun
31
+ from nnodely.layers.fuzzify import Fuzzify
32
+ from nnodely.layers.part import Part, Select, Concatenate, SamplePart, SampleSelect, TimePart, TimeConcatenate
33
+ from nnodely.layers.localmodel import LocalModel
34
+ from nnodely.layers.equationlearner import EquationLearner
35
+ from nnodely.layers.timeoperation import Integrate, Derivate
36
+ from nnodely.layers.interpolation import Interpolation
37
+
38
+ # Main nnodely classes
39
+ from nnodely.nnodely import nnodely, Modely, clearNames
40
+ from nnodely.visualizer import Visualizer, TextVisualizer, MPLVisualizer, MPLNotebookVisualizer
41
+ from nnodely.exporter import StandardExporter
42
+
43
+ # Basic nnodely
44
+ from nnodely.basic.optimizer import Optimizer, SGD, Adam
45
+
46
+ # Support functions
47
+ from nnodely.support.initializer import init_negexp, init_lin, init_constant, init_exp
File without changes
@@ -1,8 +1,8 @@
1
1
  import torch.nn as nn
2
2
  import torch
3
- from nnodely.utils import check
3
+ from nnodely.support.utils import check
4
4
 
5
- available_losses = ['mse', 'rmse', 'mae']
5
+ available_losses = ['mse', 'rmse', 'mae', 'cross_entropy']
6
6
 
7
7
  # class CustomRMSE(nn.Module):
8
8
  # def __init__(self):
@@ -15,15 +15,22 @@ available_losses = ['mse', 'rmse', 'mae']
15
15
  # return self.mse(inA, inB)
16
16
 
17
17
  class CustomLoss(nn.Module):
18
- def __init__(self, loss_type='mse'):
18
+ def __init__(self, loss_type='mse', **kwargs):
19
19
  super(CustomLoss, self).__init__()
20
20
  check(loss_type in available_losses, TypeError, f'The \"{loss_type}\" loss is not available. Possible losses are: {available_losses}.')
21
21
  self.loss_type = loss_type
22
- self.loss = nn.MSELoss()
23
- if self.loss_type == 'mae':
24
- self.loss = nn.L1Loss()
22
+ self.loss = nn.MSELoss(**kwargs)
23
+ if callable(loss_type):
24
+ self.loss = loss_type
25
+ elif self.loss_type == 'mae':
26
+ self.loss = nn.L1Loss(**kwargs)
27
+ elif self.loss_type == 'cross_entropy':
28
+ self.loss = nn.CrossEntropyLoss(**kwargs)
25
29
 
26
30
  def forward(self, inA, inB):
31
+ if self.loss_type == 'cross_entropy':
32
+ inB = inB.squeeze().float() if inA.shape == inB.shape else inB.squeeze().long()
33
+ inA = inA.squeeze()
27
34
  res = self.loss(inA,inB)
28
35
  if self.loss_type == 'rmse':
29
36
  res = torch.sqrt(res)
@@ -1,6 +1,6 @@
1
1
  from itertools import product
2
- from nnodely.utils import TORCH_DTYPE
3
- from nnodely import initializer
2
+ from nnodely.support.utils import TORCH_DTYPE
3
+ from nnodely.support import initializer
4
4
  import numpy as np
5
5
 
6
6
  import torch.nn as nn
@@ -34,14 +34,6 @@ class Model(nn.Module):
34
34
  self.input_n_samples = {key:value['ntot'] for key, value in (model_def['Inputs']|model_def['States']).items()}
35
35
  self.minimizers_keys = [self.minimizers[key]['A'] for key in self.minimizers] + [self.minimizers[key]['B'] for key in self.minimizers]
36
36
 
37
- #print('inputs: ',self.inputs)
38
- #print('outputs: ',self.outputs)
39
- #print('relations: ',self.relations)
40
- #print('params: ',self.params)
41
- #print('constants: ',self.constants)
42
- #print('sample_time: ',self.sample_time)
43
- #print('states: ',self.states)
44
-
45
37
  ## Build the network
46
38
  self.all_parameters = {}
47
39
  self.all_constants = {}
@@ -149,7 +141,7 @@ class Model(nn.Module):
149
141
  self.network_output_predictions = set(self.outputs.values())
150
142
 
151
143
  ## list of network minimization outputs
152
- self.network_output_minimizers = []
144
+ self.network_output_minimizers = []
153
145
  for _,value in self.minimizers.items():
154
146
  self.network_output_minimizers.append(self.outputs[value['A']]) if value['A'] in self.outputs.keys() else self.network_output_minimizers.append(value['A'])
155
147
  self.network_output_minimizers.append(self.outputs[value['B']]) if value['B'] in self.outputs.keys() else self.network_output_minimizers.append(value['B'])
@@ -178,7 +170,7 @@ class Model(nn.Module):
178
170
  layer_inputs.append(self.all_constants[key])
179
171
  elif key in available_states: ## relation that takes a state
180
172
  layer_inputs.append(kwargs[key])
181
- elif key in available_inputs: ## relation that takes inputs
173
+ elif key in available_inputs: ## relation that takes inputs
182
174
  layer_inputs.append(kwargs[key])
183
175
  elif key in self.all_parameters.keys(): ## relation that takes parameters
184
176
  layer_inputs.append(self.all_parameters[key])
@@ -205,7 +197,7 @@ class Model(nn.Module):
205
197
  minimize_dict = {}
206
198
  for key in self.minimizers_keys:
207
199
  minimize_dict[key] = result_dict[self.outputs[key]] if key in self.outputs.keys() else result_dict[key]
208
-
200
+
209
201
  return output_dict, minimize_dict, closed_loop_update_dict, connect_update_dict
210
202
 
211
203
 
@@ -2,90 +2,100 @@ import copy
2
2
 
3
3
  import numpy as np
4
4
 
5
- from nnodely.input import closedloop_name, connect_name
6
- from nnodely.utils import check, merge
7
- from nnodely.relation import MAIN_JSON, Stream
8
- from nnodely.output import Output
5
+ from nnodely.support.utils import check, merge
6
+ from nnodely.basic.relation import MAIN_JSON, Stream
7
+ from nnodely.layers.output import Output
9
8
 
10
- from nnodely.logger import logging, nnLogger
9
+ from nnodely.support.logger import logging, nnLogger
11
10
  log = nnLogger(__name__, logging.INFO)
12
11
 
13
12
  class ModelDef():
14
13
  def __init__(self, model_def = MAIN_JSON):
15
14
  # Models definition
16
- self.json_base = copy.deepcopy(model_def)
15
+ self.__json_base = copy.deepcopy(model_def)
17
16
 
18
17
  # Inizialize the model definition
19
- self.json = copy.deepcopy(self.json_base)
20
- if "SampleTime" in self.json['Info']:
21
- self.sample_time = self.json['Info']["SampleTime"]
18
+ self.__json = copy.deepcopy(self.__json_base)
19
+ if "SampleTime" in self.__json['Info']:
20
+ self.__sample_time = self.__json['Info']["SampleTime"]
22
21
  else:
23
- self.sample_time = None
24
- self.model_dict = {}
25
- self.minimize_dict = {}
26
- self.update_state_dict = {}
22
+ self.__sample_time = None
23
+ self.__model_dict = {}
24
+ self.__minimize_dict = {}
25
+ self.__update_state_dict = {}
27
26
 
28
27
  def __contains__(self, key):
29
- return key in self.json
28
+ return key in self.__json
30
29
 
31
30
  def __getitem__(self, key):
32
- return self.json[key]
31
+ return self.__json[key]
33
32
 
34
33
  def __setitem__(self, key, value):
35
- self.json[key] = value
34
+ self.__json[key] = value
35
+
36
+ #TODO to remove when getJson takes a model list as argment
37
+ def getModelDict(self):
38
+ return copy.deepcopy(self.__model_dict)
39
+
40
+ def getJson(self):
41
+ return copy.deepcopy(self.__json)
42
+
43
+ def getSampleTime(self):
44
+ check(self.__sample_time is not None, AttributeError, "Sample time is not defined the model is not neuralized!")
45
+ return self.__sample_time
36
46
 
37
47
  def isDefined(self):
38
- return self.json is not None
48
+ return self.__json is not None
39
49
 
40
50
  def update(self, model_def = None, model_dict = None, minimize_dict = None, update_state_dict = None):
41
- self.json = copy.deepcopy(model_def) if model_def is not None else copy.deepcopy(self.json_base)
42
- model_dict = copy.deepcopy(model_dict) if model_dict is not None else self.model_dict
43
- minimize_dict = copy.deepcopy(minimize_dict) if minimize_dict is not None else self.minimize_dict
44
- update_state_dict = copy.deepcopy(update_state_dict) if update_state_dict is not None else self.update_state_dict
51
+ self.__json = copy.deepcopy(model_def) if model_def is not None else copy.deepcopy(self.__json_base)
52
+ model_dict = copy.deepcopy(model_dict) if model_dict is not None else self.__model_dict
53
+ minimize_dict = copy.deepcopy(minimize_dict) if minimize_dict is not None else self.__minimize_dict
54
+ update_state_dict = copy.deepcopy(update_state_dict) if update_state_dict is not None else self.__update_state_dict
45
55
 
46
56
  # Add models to the model_def
47
57
  for key, stream_list in model_dict.items():
48
58
  for stream in stream_list:
49
- self.json = merge(self.json, stream.json)
59
+ self.__json = merge(self.__json, stream.json)
50
60
  if len(model_dict) > 1:
51
- if 'Models' not in self.json:
52
- self.json['Models'] = {}
61
+ if 'Models' not in self.__json:
62
+ self.__json['Models'] = {}
53
63
  for model_name, model_params in model_dict.items():
54
- self.json['Models'][model_name] = {'Inputs': [], 'States': [], 'Outputs': [], 'Parameters': [],
64
+ self.__json['Models'][model_name] = {'Inputs': [], 'States': [], 'Outputs': [], 'Parameters': [],
55
65
  'Constants': []}
56
66
  parameters, constants, inputs, states = set(), set(), set(), set()
57
67
  for param in model_params:
58
- self.json['Models'][model_name]['Outputs'].append(param.name)
68
+ self.__json['Models'][model_name]['Outputs'].append(param.name)
59
69
  parameters |= set(param.json['Parameters'].keys())
60
70
  constants |= set(param.json['Constants'].keys())
61
71
  inputs |= set(param.json['Inputs'].keys())
62
72
  states |= set(param.json['States'].keys())
63
- self.json['Models'][model_name]['Parameters'] = list(parameters)
64
- self.json['Models'][model_name]['Constants'] = list(constants)
65
- self.json['Models'][model_name]['Inputs'] = list(inputs)
66
- self.json['Models'][model_name]['States'] = list(states)
73
+ self.__json['Models'][model_name]['Parameters'] = list(parameters)
74
+ self.__json['Models'][model_name]['Constants'] = list(constants)
75
+ self.__json['Models'][model_name]['Inputs'] = list(inputs)
76
+ self.__json['Models'][model_name]['States'] = list(states)
67
77
  elif len(model_dict) == 1:
68
- self.json['Models'] = list(model_dict.keys())[0]
78
+ self.__json['Models'] = list(model_dict.keys())[0]
69
79
 
70
- if 'Minimizers' not in self.json:
71
- self.json['Minimizers'] = {}
80
+ if 'Minimizers' not in self.__json:
81
+ self.__json['Minimizers'] = {}
72
82
  for key, minimize in minimize_dict.items():
73
- self.json = merge(self.json, minimize['A'].json)
74
- self.json = merge(self.json, minimize['B'].json)
75
- self.json['Minimizers'][key] = {}
76
- self.json['Minimizers'][key]['A'] = minimize['A'].name
77
- self.json['Minimizers'][key]['B'] = minimize['B'].name
78
- self.json['Minimizers'][key]['loss'] = minimize['loss']
83
+ self.__json = merge(self.__json, minimize['A'].json)
84
+ self.__json = merge(self.__json, minimize['B'].json)
85
+ self.__json['Minimizers'][key] = {}
86
+ self.__json['Minimizers'][key]['A'] = minimize['A'].name
87
+ self.__json['Minimizers'][key]['B'] = minimize['B'].name
88
+ self.__json['Minimizers'][key]['loss'] = minimize['loss']
79
89
 
80
90
  for key, update_state in update_state_dict.items():
81
- self.json = merge(self.json, update_state.json)
91
+ self.__json = merge(self.__json, update_state.json)
82
92
 
83
- if "SampleTime" in self.json['Info']:
84
- self.sample_time = self.json['Info']["SampleTime"]
93
+ if "SampleTime" in self.__json['Info']:
94
+ self.__sample_time = self.__json['Info']["SampleTime"]
85
95
 
86
96
 
87
97
  def __update_state(self, stream_out, state_list_in, UpdateState):
88
- from nnodely.input import State
98
+ from nnodely.layers.input import State
89
99
  if type(state_list_in) is not list:
90
100
  state_list_in = [state_list_in]
91
101
  for state_in in state_list_in:
@@ -96,17 +106,17 @@ class ModelDef():
96
106
  check(stream_out.dim['dim'] == state_in.dim['dim'], ValueError,
97
107
  f"The dimension of {stream_out.name} is not equal to the dimension of {state_in.name} ({stream_out.dim['dim']}!={state_in.dim['dim']}).")
98
108
  if type(stream_out) is Output:
99
- stream_name = self.json['Outputs'][stream_out.name]
109
+ stream_name = self.__json['Outputs'][stream_out.name]
100
110
  stream_out = Stream(stream_name,stream_out.json,stream_out.dim, 0)
101
- self.update_state_dict[state_in.name] = UpdateState(stream_out, state_in)
111
+ self.__update_state_dict[state_in.name] = UpdateState(stream_out, state_in)
102
112
 
103
113
  def addConnect(self, stream_out, state_list_in):
104
- from nnodely.input import Connect
114
+ from nnodely.layers.input import Connect
105
115
  self.__update_state(stream_out, state_list_in, Connect)
106
116
  self.update()
107
117
 
108
118
  def addClosedLoop(self, stream_out, state_list_in):
109
- from nnodely.input import ClosedLoop
119
+ from nnodely.layers.input import ClosedLoop
110
120
  self.__update_state(stream_out, state_list_in, ClosedLoop)
111
121
  self.update()
112
122
 
@@ -114,8 +124,8 @@ class ModelDef():
114
124
  if isinstance(stream_list, (Output,Stream)):
115
125
  stream_list = [stream_list]
116
126
  if type(stream_list) is list:
117
- check(name not in self.model_dict.keys(),ValueError,f"The name '{name}' of the model is already used")
118
- self.model_dict[name] = copy.deepcopy(stream_list)
127
+ check(name not in self.__model_dict.keys(), ValueError, f"The name '{name}' of the model is already used")
128
+ self.__model_dict[name] = copy.deepcopy(stream_list)
119
129
  else:
120
130
  raise TypeError(f'stream_list is type {type(stream_list)} but must be an Output or Stream or a list of them')
121
131
  self.update()
@@ -125,15 +135,15 @@ class ModelDef():
125
135
  name_list = [name_list]
126
136
  if type(name_list) is list:
127
137
  for name in name_list:
128
- check(name in self.model_dict, IndexError, f"The name {name} is not part of the available models")
129
- del self.model_dict[name]
138
+ check(name in self.__model_dict, IndexError, f"The name {name} is not part of the available models")
139
+ del self.__model_dict[name]
130
140
  self.update()
131
141
 
132
142
  def addMinimize(self, name, streamA, streamB, loss_function='mse'):
133
143
  check(isinstance(streamA, (Output, Stream)), TypeError, 'streamA must be an instance of Output or Stream')
134
144
  check(isinstance(streamB, (Output, Stream)), TypeError, 'streamA must be an instance of Output or Stream')
135
- check(streamA.dim == streamB.dim, ValueError, f'Dimension of streamA={streamA.dim} and streamB={streamB.dim} are not equal.')
136
- self.minimize_dict[name]={'A':copy.deepcopy(streamA), 'B': copy.deepcopy(streamB), 'loss':loss_function}
145
+ #check(streamA.dim == streamB.dim, ValueError, f'Dimension of streamA={streamA.dim} and streamB={streamB.dim} are not equal.')
146
+ self.__minimize_dict[name]={'A':copy.deepcopy(streamA), 'B': copy.deepcopy(streamB), 'loss':loss_function}
137
147
  self.update()
138
148
 
139
149
  def removeMinimize(self, name_list):
@@ -141,23 +151,23 @@ class ModelDef():
141
151
  name_list = [name_list]
142
152
  if type(name_list) is list:
143
153
  for name in name_list:
144
- check(name in self.minimize_dict, IndexError, f"The name {name} is not part of the available minimuzes")
145
- del self.minimize_dict[name]
154
+ check(name in self.__minimize_dict, IndexError, f"The name {name} is not part of the available minimuzes")
155
+ del self.__minimize_dict[name]
146
156
  self.update()
147
157
 
148
158
  def setBuildWindow(self, sample_time = None):
149
- check(self.json is not None, RuntimeError, "No model is defined!")
159
+ check(self.__json is not None, RuntimeError, "No model is defined!")
150
160
  if sample_time is not None:
151
161
  check(sample_time > 0, RuntimeError, 'Sample time must be strictly positive!')
152
- self.sample_time = sample_time
162
+ self.__sample_time = sample_time
153
163
  else:
154
- if self.sample_time is None:
155
- self.sample_time = 1
164
+ if self.__sample_time is None:
165
+ self.__sample_time = 1
156
166
 
157
- self.json['Info'] = {"SampleTime": self.sample_time}
167
+ self.__json['Info'] = {"SampleTime": self.__sample_time}
158
168
 
159
- check(self.json['Inputs'] | self.json['States'] != {}, RuntimeError, "No model is defined!")
160
- json_inputs = self.json['Inputs'] | self.json['States']
169
+ check(self.__json['Inputs'] | self.__json['States'] != {}, RuntimeError, "No model is defined!")
170
+ json_inputs = self.__json['Inputs'] | self.__json['States']
161
171
 
162
172
  # for key,value in self.json['States'].items():
163
173
  # check(closedloop_name in self.json['States'][key].keys() or connect_name in self.json['States'][key].keys(),
@@ -167,16 +177,16 @@ class ModelDef():
167
177
  for key, value in json_inputs.items():
168
178
  if value['sw'] == [0,0] and value['tw'] == [0,0]:
169
179
  assert(False), f"Input '{key}' has no time window or sample window"
170
- if value['sw'] == [0, 0] and self.sample_time is not None:
180
+ if value['sw'] == [0, 0] and self.__sample_time is not None:
171
181
  ## check if value['tw'] is a multiple of sample_time
172
182
  absolute_tw = abs(value['tw'][0]) + abs(value['tw'][1])
173
- check(round(absolute_tw % self.sample_time) == 0, ValueError,
183
+ check(round(absolute_tw % self.__sample_time) == 0, ValueError,
174
184
  f"Time window of input '{key}' is not a multiple of sample time. This network cannot be neuralized")
175
- input_ns_backward[key] = round(-value['tw'][0] / self.sample_time)
176
- input_ns_forward[key] = round(value['tw'][1] / self.sample_time)
177
- elif self.sample_time is not None:
178
- input_ns_backward[key] = max(round(-value['tw'][0] / self.sample_time),-value['sw'][0])
179
- input_ns_forward[key] = max(round(value['tw'][1] / self.sample_time),value['sw'][1])
185
+ input_ns_backward[key] = round(-value['tw'][0] / self.__sample_time)
186
+ input_ns_forward[key] = round(value['tw'][1] / self.__sample_time)
187
+ elif self.__sample_time is not None:
188
+ input_ns_backward[key] = max(round(-value['tw'][0] / self.__sample_time), -value['sw'][0])
189
+ input_ns_forward[key] = max(round(value['tw'][1] / self.__sample_time), value['sw'][1])
180
190
  else:
181
191
  check(value['tw'] == [0,0], RuntimeError, f"Sample time is not defined for input '{key}'")
182
192
  input_ns_backward[key] = -value['sw'][0]
@@ -184,35 +194,28 @@ class ModelDef():
184
194
  value['ns'] = [input_ns_backward[key], input_ns_forward[key]]
185
195
  value['ntot'] = sum(value['ns'])
186
196
 
187
- self.json['Info']['ns'] = [max(input_ns_backward.values()), max(input_ns_forward.values())]
188
- self.json['Info']['ntot'] = sum(self.json['Info']['ns'])
189
- if self.json['Info']['ns'][0] < 0:
197
+ self.__json['Info']['ns'] = [max(input_ns_backward.values()), max(input_ns_forward.values())]
198
+ self.__json['Info']['ntot'] = sum(self.__json['Info']['ns'])
199
+ if self.__json['Info']['ns'][0] < 0:
190
200
  log.warning(
191
- f"The input is only in the far past the max_samples_backward is: {self.json['Info']['ns'][0]}")
192
- if self.json['Info']['ns'][1] < 0:
201
+ f"The input is only in the far past the max_samples_backward is: {self.__json['Info']['ns'][0]}")
202
+ if self.__json['Info']['ns'][1] < 0:
193
203
  log.warning(
194
- f"The input is only in the far future the max_sample_forward is: {self.json['Info']['ns'][1]}")
204
+ f"The input is only in the far future the max_sample_forward is: {self.__json['Info']['ns'][1]}")
195
205
 
196
- for k, v in (self.json['Parameters']|self.json['Constants']).items():
206
+ for k, v in (self.__json['Parameters'] | self.__json['Constants']).items():
197
207
  if 'values' in v:
198
208
  window = 'tw' if 'tw' in v.keys() else ('sw' if 'sw' in v.keys() else None)
199
209
  if window == 'tw':
200
- check(np.array(v['values']).shape[0] == v['tw']/self.sample_time, ValueError,
210
+ check(np.array(v['values']).shape[0] == v['tw'] / self.__sample_time, ValueError,
201
211
  f"{k} has a different number of values for this sample time.")
202
212
  if v['values'] == "SampleTime":
203
- v['values'] = self.sample_time
204
-
213
+ v['values'] = self.__sample_time
205
214
 
206
- def updateParameters(self, model, recurrent=True):
215
+ def updateParameters(self, model):
207
216
  if model is not None:
208
- for key in self.json['Parameters'].keys():
209
- # if recurrent:
210
- # if key in model.Cell.all_parameters:
211
- # self.json['Parameters'][key]['values'] = model.Cell.all_parameters[key].tolist()
212
- # if 'init_fun' in self.json['Parameters'][key]:
213
- # del self.json['Parameters'][key]['init_fun']
214
- # else:
217
+ for key in self.__json['Parameters'].keys():
215
218
  if key in model.all_parameters:
216
- self.json['Parameters'][key]['values'] = model.all_parameters[key].tolist()
217
- if 'init_fun' in self.json['Parameters'][key]:
218
- del self.json['Parameters'][key]['init_fun']
219
+ self.__json['Parameters'][key]['values'] = model.all_parameters[key].tolist()
220
+ if 'init_fun' in self.__json['Parameters'][key]:
221
+ del self.__json['Parameters'][key]['init_fun']
@@ -1,7 +1,7 @@
1
1
  import copy
2
2
  import torch
3
3
 
4
- from nnodely.utils import check
4
+ from nnodely.support.utils import check
5
5
 
6
6
  class Optimizer:
7
7
  """