rcbench 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. rcbench-0.1.0/LICENSE +21 -0
  2. rcbench-0.1.0/PKG-INFO +241 -0
  3. rcbench-0.1.0/README.md +198 -0
  4. rcbench-0.1.0/rcbench/__init__.py +13 -0
  5. rcbench-0.1.0/rcbench/classes/Measurement.py +84 -0
  6. rcbench-0.1.0/rcbench/classes/__init__.py +0 -0
  7. rcbench-0.1.0/rcbench/classes/sample.py +85 -0
  8. rcbench-0.1.0/rcbench/logger.py +48 -0
  9. rcbench-0.1.0/rcbench/measurements/__init__.py +0 -0
  10. rcbench-0.1.0/rcbench/measurements/dataset.py +219 -0
  11. rcbench-0.1.0/rcbench/measurements/loader.py +72 -0
  12. rcbench-0.1.0/rcbench/measurements/parser.py +227 -0
  13. rcbench-0.1.0/rcbench/tasks/__init__.py +1 -0
  14. rcbench-0.1.0/rcbench/tasks/baseevaluator.py +112 -0
  15. rcbench-0.1.0/rcbench/tasks/featureselector.py +209 -0
  16. rcbench-0.1.0/rcbench/tasks/generalizationrank.py +97 -0
  17. rcbench-0.1.0/rcbench/tasks/kernelrank.py +97 -0
  18. rcbench-0.1.0/rcbench/tasks/memorycapacity.py +350 -0
  19. rcbench-0.1.0/rcbench/tasks/narma.py +278 -0
  20. rcbench-0.1.0/rcbench/tasks/nlt.py +308 -0
  21. rcbench-0.1.0/rcbench/tasks/sinx.py +160 -0
  22. rcbench-0.1.0/rcbench/utils/__init__.py +0 -0
  23. rcbench-0.1.0/rcbench/utils/utils.py +117 -0
  24. rcbench-0.1.0/rcbench/visualization/__init__.py +0 -0
  25. rcbench-0.1.0/rcbench/visualization/base_plotter.py +421 -0
  26. rcbench-0.1.0/rcbench/visualization/mc_plotter.py +227 -0
  27. rcbench-0.1.0/rcbench/visualization/narma_plotter.py +169 -0
  28. rcbench-0.1.0/rcbench/visualization/nlt_plotter.py +389 -0
  29. rcbench-0.1.0/rcbench/visualization/plot_config.py +321 -0
  30. rcbench-0.1.0/rcbench/visualization/sinx_plotter.py +169 -0
  31. rcbench-0.1.0/rcbench.egg-info/PKG-INFO +241 -0
  32. rcbench-0.1.0/rcbench.egg-info/SOURCES.txt +37 -0
  33. rcbench-0.1.0/rcbench.egg-info/dependency_links.txt +1 -0
  34. rcbench-0.1.0/rcbench.egg-info/requires.txt +14 -0
  35. rcbench-0.1.0/rcbench.egg-info/top_level.txt +1 -0
  36. rcbench-0.1.0/setup.cfg +4 -0
  37. rcbench-0.1.0/setup.py +47 -0
  38. rcbench-0.1.0/tests/test_electrode_selection.py +689 -0
  39. rcbench-0.1.0/tests/test_reservoir_dataset_consistency.py +281 -0
rcbench-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Davide Pilati
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.
rcbench-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,241 @@
1
+ Metadata-Version: 2.4
2
+ Name: rcbench
3
+ Version: 0.1.0
4
+ Summary: Reservoir computing benchmark toolkit
5
+ Home-page: https://github.com/nanotechdave/RCbench
6
+ Author: Davide Pilati
7
+ Author-email: davide.pilati@polito.it
8
+ License: MIT
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Operating System :: OS Independent
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: numpy
20
+ Requires-Dist: scipy
21
+ Requires-Dist: matplotlib
22
+ Requires-Dist: scikit-learn
23
+ Requires-Dist: pandas
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest; extra == "test"
26
+ Requires-Dist: pytest-cov; extra == "test"
27
+ Provides-Extra: dev
28
+ Requires-Dist: bump2version; extra == "dev"
29
+ Requires-Dist: twine; extra == "dev"
30
+ Requires-Dist: build; extra == "dev"
31
+ Dynamic: author
32
+ Dynamic: author-email
33
+ Dynamic: classifier
34
+ Dynamic: description
35
+ Dynamic: description-content-type
36
+ Dynamic: home-page
37
+ Dynamic: license
38
+ Dynamic: license-file
39
+ Dynamic: provides-extra
40
+ Dynamic: requires-dist
41
+ Dynamic: requires-python
42
+ Dynamic: summary
43
+
44
+ # RCbench - Reservoir Computing Benchmark Toolkit
45
+
46
+ ![Python](https://img.shields.io/badge/Python-3.9%2B-blue)
47
+ ![License](https://img.shields.io/badge/license-MIT-blue)
48
+
49
+
50
+ **RCbench (Reservoir Computing Benchmark Toolkit)** is a comprehensive Python package for evaluating and benchmarking reservoir computing systems. It provides standardized tasks, flexible visualization tools, and efficient evaluation methods for both physical and simulated reservoirs.
51
+
52
+ ## 🚀 Features
53
+
54
+ RCbench provides:
55
+
56
+ -**Multiple Benchmark Tasks:**
57
+ -**NLT (Nonlinear Transformation):** Evaluate reservoir performance on standard nonlinear transformations
58
+ -**NARMA:** Test with Nonlinear Auto-Regressive Moving Average models of different orders
59
+ -**Memory Capacity:** Measure the short and long-term memory capabilities
60
+ -**Sin(x):** Assess reservoir ability to transform a random signal into a nonlinear function that use the input as argument
61
+ -**KernelRank:** Evaluates the nonlinearityof the reservoir
62
+ -**GeneralizationRank:** Evaluates the generalization capabilities of the reservoir
63
+
64
+ -**Advanced Visualization:**
65
+ -Task-specific plotters with customizable configurations
66
+ -General reservoir properties visualization (input signals, output responses, nonlinearity)
67
+ -Frequency domain analysis of reservoir behavior
68
+ -Target vs. prediction comparison with proper time alignment
69
+
70
+ -**Efficient Data Handling:**
71
+ -Automatic measurement loading and parsing
72
+ -Support for various experimental data formats
73
+ -Feature selection and dimensionality reduction tools
74
+ ---
75
+
76
+ ## 📂 Project Structure
77
+
78
+ ```plaintext
79
+ RCbench/
80
+ ├── rcbench/
81
+ | |── examples/ # Example scripts
82
+ | | ├── example_nlt.py
83
+ | | ├── example_NARMA.py
84
+ | | ├── example_sinx.py
85
+ | | └── example_MC.py
86
+ │ ├── measurements/ # Data handling
87
+ │ │ ├── dataset.py # ReservoirDataset class
88
+ │ │ ├── loader.py # Data loading utilities
89
+ │ │ └── parser.py # Data parsing utilities
90
+ │ ├── tasks/ # Reservoir computing tasks
91
+ │ │ ├── baseevaluator.py # Base evaluation methods
92
+ │ │ ├── nlt.py # Nonlinear Transformation
93
+ │ │ ├── narma.py # NARMA tasks
94
+ │ │ ├── memorycapacity.py # Memory Capacity
95
+ │ │ ├── sinx.py # Sin(x) approximation
96
+ │ │ └── featureselector.py # Feature selection tools
97
+ │ ├── visualization/ # Plotting utilities
98
+ │ │ ├── base_plotter.py # Base plotting functionality
99
+ │ │ ├── plot_config.py # Plot configurations
100
+ │ │ ├── nlt_plotter.py # NLT visualization
101
+ │ │ ├── narma_plotter.py # NARMA visualization
102
+ │ │ └── sinx_plotter.py # Sin(x) visualization
103
+ │ └── logger.py # Logging utilities
104
+
105
+ ```
106
+ ---
107
+
108
+ ## 🔧 Installation
109
+
110
+ **Install directly from GitHub:**
111
+
112
+ ```bash
113
+ pip install rcbench
114
+ ```
115
+
116
+
117
+ Or, install locally (development mode):
118
+
119
+ ```bash
120
+ git clone https://github.com/nanotechdave/RCbench.git
121
+ cd RCbench
122
+ pip install -e .
123
+ ```
124
+
125
+
126
+ ## 🚦 Usage Example
127
+ Here's a quick example demonstrating how to perform an NLT evaluation:
128
+
129
+ ```python
130
+ import logging
131
+ from pathlib import Path
132
+ import numpy as np
133
+ import matplotlib.pyplot as plt
134
+
135
+ from rcbench import ReservoirDataset
136
+ from rcbench import NltEvaluator
137
+ from rcbench.visualization.plot_config import NLTPlotConfig
138
+ from rcbench.logger import get_logger
139
+
140
+ logger = get_logger(__name__)
141
+ logger.setLevel(logging.INFO)
142
+
143
+ BASE_DIR = "FILE_PATH"
144
+
145
+ filenameNLT = "YOUR_FILENAME"
146
+
147
+ measurement_file_NLT = BASE_DIR / filenameNLT
148
+
149
+ # Load the data directly using the ReservoirDataset class
150
+ dataset = ReservoirDataset(measurement_file_NLT)
151
+
152
+ # Get information about the electrodes
153
+ electrodes_info = dataset.summary()
154
+ logger.info(f"Parsed Electrodes: {electrodes_info}")
155
+
156
+ # Get input and node voltages directly from the dataset
157
+ input_elec = electrodes_info['input_electrodes'][0]
158
+ input_signal = dataset.get_input_voltages()[input_elec]
159
+ time = dataset.time
160
+
161
+ # Get node voltages (only node electrodes, not input)
162
+ nodes_output = dataset.get_node_voltages()
163
+ electrode_names = electrodes_info['node_electrodes']
164
+
165
+ # Create NLT plot configuration
166
+ plot_config = NLTPlotConfig(
167
+ save_dir=None, # Save plots to this directory
168
+
169
+ # General reservoir property plots
170
+ plot_input_signal=True, # Plot the input signal
171
+ plot_output_responses=True, # Plot node responses
172
+ plot_nonlinearity=True, # Plot nonlinearity of nodes
173
+ plot_frequency_analysis=True, # Plot frequency analysis
174
+
175
+ # Target-specific plots
176
+ plot_target_prediction=True, # Plot target vs prediction results
177
+
178
+ # Plot styling options
179
+ nonlinearity_plot_style='scatter',
180
+ frequency_range=(0, 20) # Limit frequency range to 0-20 Hz for clearer visualization
181
+ )
182
+
183
+ # Run NLT evaluation with plot config
184
+ evaluatorNLT = NltEvaluator(
185
+ input_signal=input_signal,
186
+ nodes_output=nodes_output,
187
+ time_array=time,
188
+ waveform_type='sine',
189
+ electrode_names=electrode_names,
190
+ plot_config=plot_config
191
+ )
192
+
193
+
194
+ resultsNLT = {}
195
+ for target_name in evaluatorNLT.targets:
196
+ try:
197
+ result = evaluatorNLT.run_evaluation(
198
+ target_name=target_name,
199
+ metric='NMSE',
200
+ feature_selection_method='pca',
201
+ num_features='all',
202
+ model="Ridge",
203
+ regression_alpha=0.01,
204
+ train_ratio=0.8,
205
+ plot=False, # Don't plot during evaluation
206
+ )
207
+ resultsNLT[target_name] = result
208
+ # Print results clearly
209
+ logger.output(f"NLT Analysis for Target: '{target_name}'")
210
+ logger.output(f" - Metric: {result['metric']}")
211
+ logger.output(f" - Accuracy: {result['accuracy']:.5f}")
212
+ logger.output(f" - Selected Features Indices: {[electrode_names[i] for i in result['selected_features']]}")
213
+ logger.output(f" - Model Weights: {result['model'].coef_}\n")
214
+ except Exception as e:
215
+ logger.error(f"Error evaluating {target_name}: {str(e)}")
216
+
217
+ evaluatorNLT.plot_results(existing_results=resultsNLT)
218
+ ```
219
+
220
+ ## 📈 Visualization Tools
221
+ RCbench features a unified visualization system with:
222
+ -**Task-Specific Plotters:** Dedicated plotters for each task (NLTPlotter, NarmaPlotter, SinxPlotter)
223
+ -**Customizable Configurations:** Control which plots to generate through configuration objects
224
+ -**Comprehensive Visualization:** For each task, view:
225
+ -General reservoir properties (input signals, node responses, nonlinearity)
226
+ -Frequency domain analysis
227
+ -Target vs. prediction comparisons
228
+
229
+
230
+
231
+ ## 📝 Contributions & Issues
232
+ Contributions are welcome! Please open a pull request or an issue on GitHub.
233
+
234
+ - Issue Tracker: https://github.com/nanotechdave/RCbench/issues
235
+
236
+ - Pull Requests: https://github.com/nanotechdave/RCbench/pulls
237
+
238
+ ## 📜 License
239
+
240
+ RCbench is licensed under the MIT License. See the LICENSE file for details.
241
+
@@ -0,0 +1,198 @@
1
+ # RCbench - Reservoir Computing Benchmark Toolkit
2
+
3
+ ![Python](https://img.shields.io/badge/Python-3.9%2B-blue)
4
+ ![License](https://img.shields.io/badge/license-MIT-blue)
5
+
6
+
7
+ **RCbench (Reservoir Computing Benchmark Toolkit)** is a comprehensive Python package for evaluating and benchmarking reservoir computing systems. It provides standardized tasks, flexible visualization tools, and efficient evaluation methods for both physical and simulated reservoirs.
8
+
9
+ ## 🚀 Features
10
+
11
+ RCbench provides:
12
+
13
+ -**Multiple Benchmark Tasks:**
14
+ -**NLT (Nonlinear Transformation):** Evaluate reservoir performance on standard nonlinear transformations
15
+ -**NARMA:** Test with Nonlinear Auto-Regressive Moving Average models of different orders
16
+ -**Memory Capacity:** Measure the short and long-term memory capabilities
17
+ -**Sin(x):** Assess reservoir ability to transform a random signal into a nonlinear function that use the input as argument
18
+ -**KernelRank:** Evaluates the nonlinearityof the reservoir
19
+ -**GeneralizationRank:** Evaluates the generalization capabilities of the reservoir
20
+
21
+ -**Advanced Visualization:**
22
+ -Task-specific plotters with customizable configurations
23
+ -General reservoir properties visualization (input signals, output responses, nonlinearity)
24
+ -Frequency domain analysis of reservoir behavior
25
+ -Target vs. prediction comparison with proper time alignment
26
+
27
+ -**Efficient Data Handling:**
28
+ -Automatic measurement loading and parsing
29
+ -Support for various experimental data formats
30
+ -Feature selection and dimensionality reduction tools
31
+ ---
32
+
33
+ ## 📂 Project Structure
34
+
35
+ ```plaintext
36
+ RCbench/
37
+ ├── rcbench/
38
+ | |── examples/ # Example scripts
39
+ | | ├── example_nlt.py
40
+ | | ├── example_NARMA.py
41
+ | | ├── example_sinx.py
42
+ | | └── example_MC.py
43
+ │ ├── measurements/ # Data handling
44
+ │ │ ├── dataset.py # ReservoirDataset class
45
+ │ │ ├── loader.py # Data loading utilities
46
+ │ │ └── parser.py # Data parsing utilities
47
+ │ ├── tasks/ # Reservoir computing tasks
48
+ │ │ ├── baseevaluator.py # Base evaluation methods
49
+ │ │ ├── nlt.py # Nonlinear Transformation
50
+ │ │ ├── narma.py # NARMA tasks
51
+ │ │ ├── memorycapacity.py # Memory Capacity
52
+ │ │ ├── sinx.py # Sin(x) approximation
53
+ │ │ └── featureselector.py # Feature selection tools
54
+ │ ├── visualization/ # Plotting utilities
55
+ │ │ ├── base_plotter.py # Base plotting functionality
56
+ │ │ ├── plot_config.py # Plot configurations
57
+ │ │ ├── nlt_plotter.py # NLT visualization
58
+ │ │ ├── narma_plotter.py # NARMA visualization
59
+ │ │ └── sinx_plotter.py # Sin(x) visualization
60
+ │ └── logger.py # Logging utilities
61
+
62
+ ```
63
+ ---
64
+
65
+ ## 🔧 Installation
66
+
67
+ **Install directly from GitHub:**
68
+
69
+ ```bash
70
+ pip install rcbench
71
+ ```
72
+
73
+
74
+ Or, install locally (development mode):
75
+
76
+ ```bash
77
+ git clone https://github.com/nanotechdave/RCbench.git
78
+ cd RCbench
79
+ pip install -e .
80
+ ```
81
+
82
+
83
+ ## 🚦 Usage Example
84
+ Here's a quick example demonstrating how to perform an NLT evaluation:
85
+
86
+ ```python
87
+ import logging
88
+ from pathlib import Path
89
+ import numpy as np
90
+ import matplotlib.pyplot as plt
91
+
92
+ from rcbench import ReservoirDataset
93
+ from rcbench import NltEvaluator
94
+ from rcbench.visualization.plot_config import NLTPlotConfig
95
+ from rcbench.logger import get_logger
96
+
97
+ logger = get_logger(__name__)
98
+ logger.setLevel(logging.INFO)
99
+
100
+ BASE_DIR = "FILE_PATH"
101
+
102
+ filenameNLT = "YOUR_FILENAME"
103
+
104
+ measurement_file_NLT = BASE_DIR / filenameNLT
105
+
106
+ # Load the data directly using the ReservoirDataset class
107
+ dataset = ReservoirDataset(measurement_file_NLT)
108
+
109
+ # Get information about the electrodes
110
+ electrodes_info = dataset.summary()
111
+ logger.info(f"Parsed Electrodes: {electrodes_info}")
112
+
113
+ # Get input and node voltages directly from the dataset
114
+ input_elec = electrodes_info['input_electrodes'][0]
115
+ input_signal = dataset.get_input_voltages()[input_elec]
116
+ time = dataset.time
117
+
118
+ # Get node voltages (only node electrodes, not input)
119
+ nodes_output = dataset.get_node_voltages()
120
+ electrode_names = electrodes_info['node_electrodes']
121
+
122
+ # Create NLT plot configuration
123
+ plot_config = NLTPlotConfig(
124
+ save_dir=None, # Save plots to this directory
125
+
126
+ # General reservoir property plots
127
+ plot_input_signal=True, # Plot the input signal
128
+ plot_output_responses=True, # Plot node responses
129
+ plot_nonlinearity=True, # Plot nonlinearity of nodes
130
+ plot_frequency_analysis=True, # Plot frequency analysis
131
+
132
+ # Target-specific plots
133
+ plot_target_prediction=True, # Plot target vs prediction results
134
+
135
+ # Plot styling options
136
+ nonlinearity_plot_style='scatter',
137
+ frequency_range=(0, 20) # Limit frequency range to 0-20 Hz for clearer visualization
138
+ )
139
+
140
+ # Run NLT evaluation with plot config
141
+ evaluatorNLT = NltEvaluator(
142
+ input_signal=input_signal,
143
+ nodes_output=nodes_output,
144
+ time_array=time,
145
+ waveform_type='sine',
146
+ electrode_names=electrode_names,
147
+ plot_config=plot_config
148
+ )
149
+
150
+
151
+ resultsNLT = {}
152
+ for target_name in evaluatorNLT.targets:
153
+ try:
154
+ result = evaluatorNLT.run_evaluation(
155
+ target_name=target_name,
156
+ metric='NMSE',
157
+ feature_selection_method='pca',
158
+ num_features='all',
159
+ model="Ridge",
160
+ regression_alpha=0.01,
161
+ train_ratio=0.8,
162
+ plot=False, # Don't plot during evaluation
163
+ )
164
+ resultsNLT[target_name] = result
165
+ # Print results clearly
166
+ logger.output(f"NLT Analysis for Target: '{target_name}'")
167
+ logger.output(f" - Metric: {result['metric']}")
168
+ logger.output(f" - Accuracy: {result['accuracy']:.5f}")
169
+ logger.output(f" - Selected Features Indices: {[electrode_names[i] for i in result['selected_features']]}")
170
+ logger.output(f" - Model Weights: {result['model'].coef_}\n")
171
+ except Exception as e:
172
+ logger.error(f"Error evaluating {target_name}: {str(e)}")
173
+
174
+ evaluatorNLT.plot_results(existing_results=resultsNLT)
175
+ ```
176
+
177
+ ## 📈 Visualization Tools
178
+ RCbench features a unified visualization system with:
179
+ -**Task-Specific Plotters:** Dedicated plotters for each task (NLTPlotter, NarmaPlotter, SinxPlotter)
180
+ -**Customizable Configurations:** Control which plots to generate through configuration objects
181
+ -**Comprehensive Visualization:** For each task, view:
182
+ -General reservoir properties (input signals, node responses, nonlinearity)
183
+ -Frequency domain analysis
184
+ -Target vs. prediction comparisons
185
+
186
+
187
+
188
+ ## 📝 Contributions & Issues
189
+ Contributions are welcome! Please open a pull request or an issue on GitHub.
190
+
191
+ - Issue Tracker: https://github.com/nanotechdave/RCbench/issues
192
+
193
+ - Pull Requests: https://github.com/nanotechdave/RCbench/pulls
194
+
195
+ ## 📜 License
196
+
197
+ RCbench is licensed under the MIT License. See the LICENSE file for details.
198
+
@@ -0,0 +1,13 @@
1
+ __version__ = "0.0.10.dev1"
2
+
3
+ from .utils import utils
4
+ from .tasks.nlt import NltEvaluator
5
+ from .tasks.memorycapacity import MemoryCapacityEvaluator
6
+ from .tasks.sinx import SinxEvaluator
7
+ from .tasks.kernelrank import KernelRankEvaluator
8
+ from .tasks.generalizationrank import GeneralizationRankEvaluator
9
+ from .tasks.narma import NarmaEvaluator
10
+ from .measurements.parser import MeasurementParser
11
+ from .measurements.loader import MeasurementLoader
12
+ from .measurements.dataset import ReservoirDataset
13
+ from .logger import get_logger
@@ -0,0 +1,84 @@
1
+ from enum import Enum
2
+ from typing import Optional
3
+ from rcbench.measurements.dataset import ReservoirDataset
4
+ from rcbench.measurements.parser import MeasurementParser
5
+ from rcbench.logger import get_logger
6
+
7
+ logger = get_logger(__name__)
8
+
9
+ class MeasurementType(Enum):
10
+ """Enumeration of possible measurement types."""
11
+ NLT = "nlt"
12
+ MEMORY_CAPACITY = "mc"
13
+ KERNEL_RANK = "kernel"
14
+ ACTIVATION = "activation"
15
+ UNKNOWN = "unknown"
16
+
17
+ class Measurement():
18
+ """Base class for all measurement types."""
19
+ def __init__(self, path: str):
20
+ """
21
+ Initialize a Measurement object.
22
+
23
+ Args:
24
+ path (str): Path to the measurement file
25
+ """
26
+ self.path = path
27
+ self.type = self._determine_measurement_type()
28
+ self.dataset: Optional[ReservoirDataset] = None
29
+ self.parser: Optional[MeasurementParser] = None
30
+ self._load_measurement()
31
+
32
+ def _determine_measurement_type(self) -> MeasurementType:
33
+ """Determine the type of measurement based on the filename."""
34
+ filename = self.path.lower()
35
+ if "nlt" in filename or "nonlinear" in filename:
36
+ return MeasurementType.NLT
37
+ elif "mc" in filename or "memory" in filename:
38
+ return MeasurementType.MEMORY_CAPACITY
39
+ elif "kernel" in filename:
40
+ return MeasurementType.KERNEL_RANK
41
+ elif "activation" in filename:
42
+ return MeasurementType.ACTIVATION
43
+ return MeasurementType.UNKNOWN
44
+
45
+ def _load_measurement(self):
46
+ """Load the measurement data using MeasurementLoader and MeasurementParser."""
47
+ try:
48
+ from rcbench.measurements.loader import MeasurementLoader
49
+ loader = MeasurementLoader(self.path)
50
+ self.dataset = loader.get_dataset()
51
+ self.parser = MeasurementParser(self.dataset)
52
+ logger.info(f"Successfully loaded measurement of type {self.type.value}")
53
+ except Exception as e:
54
+ logger.error(f"Error loading measurement {self.path}: {str(e)}")
55
+ raise
56
+
57
+ def get_input_voltages(self):
58
+ """Get input voltages from the measurement."""
59
+ if self.parser:
60
+ return self.parser.get_input_voltages()
61
+ return None
62
+
63
+ def get_node_voltages(self):
64
+ """Get node voltages from the measurement."""
65
+ if self.parser:
66
+ return self.parser.get_node_voltages()
67
+ return None
68
+
69
+ def get_time(self):
70
+ """Get time data from the measurement."""
71
+ if self.dataset:
72
+ return self.dataset.time
73
+ return None
74
+
75
+ def __str__(self):
76
+ return f"Measurement(type={self.type.value}, path={self.path})"
77
+
78
+ class MemoryCapacity(Measurement):
79
+ """Memory Capacity specific measurement class."""
80
+ def __init__(self, path: str):
81
+ super().__init__(path)
82
+ if self.type != MeasurementType.MEMORY_CAPACITY:
83
+ logger.warning(f"File {path} may not be a memory capacity measurement")
84
+
File without changes
@@ -0,0 +1,85 @@
1
+ from pathlib import Path
2
+ from typing import List, Dict
3
+ from rcbench.classes.Measurement import Measurement, MeasurementType
4
+ from rcbench.logger import get_logger
5
+
6
+ logger = get_logger(__name__)
7
+
8
+ class Sample():
9
+ """ Sample data class. Instance is an object containing all the measurements of a sample. """
10
+ def __init__(self, name: str, path: str):
11
+ """
12
+ Initialize a Sample object.
13
+
14
+ Args:
15
+ name (str): Name of the sample
16
+ path (str): Path to the folder containing measurement files
17
+ """
18
+ self.name = name
19
+ self.path = Path(path)
20
+ self.measurements: Dict[str, Measurement] = {}
21
+ self._scan_measurements()
22
+
23
+ def _scan_measurements(self):
24
+ """Scan the folder for measurement files and initialize measurement objects."""
25
+ if not self.path.exists():
26
+ raise FileNotFoundError(f"Folder not found: {self.path}")
27
+
28
+ # Find all .txt files that don't contain 'log' in their name
29
+ measurement_files = [f for f in self.path.glob("*.txt") if "log" not in f.name.lower()]
30
+
31
+ for file_path in measurement_files:
32
+ try:
33
+ # Create appropriate measurement object based on file type
34
+ measurement = Measurement(str(file_path))
35
+
36
+ # Store the measurement object with the filename as key
37
+ self.measurements[file_path.name] = measurement
38
+ logger.info(f"Loaded measurement: {file_path.name} (type: {measurement.type.value})")
39
+
40
+ except Exception as e:
41
+ logger.error(f"Error loading measurement {file_path.name}: {str(e)}")
42
+
43
+ def get_measurement(self, filename: str) -> Measurement:
44
+ """
45
+ Get a specific measurement by filename.
46
+
47
+ Args:
48
+ filename (str): Name of the measurement file
49
+
50
+ Returns:
51
+ Measurement: The measurement object
52
+ """
53
+ if filename not in self.measurements:
54
+ raise KeyError(f"Measurement {filename} not found")
55
+ return self.measurements[filename]
56
+
57
+ def get_measurements_by_type(self, measurement_type: MeasurementType) -> List[Measurement]:
58
+ """
59
+ Get all measurements of a specific type.
60
+
61
+ Args:
62
+ measurement_type (MeasurementType): Type of measurements to retrieve
63
+
64
+ Returns:
65
+ List[Measurement]: List of measurements of the specified type
66
+ """
67
+ return [m for m in self.measurements.values() if m.type == measurement_type]
68
+
69
+ def list_measurements(self) -> List[str]:
70
+ """
71
+ Get a list of all available measurement filenames.
72
+
73
+ Returns:
74
+ List[str]: List of measurement filenames
75
+ """
76
+ return list(self.measurements.keys())
77
+
78
+ def __str__(self):
79
+ measurement_types = {}
80
+ for m in self.measurements.values():
81
+ measurement_types[m.type.value] = measurement_types.get(m.type.value, 0) + 1
82
+
83
+ type_str = ", ".join(f"{t}: {c}" for t, c in measurement_types.items())
84
+ objstr = f"Sample NWN_Pad{self.name} with {len(self.measurements)} measurements ({type_str})"
85
+ return objstr
@@ -0,0 +1,48 @@
1
+ import logging
2
+ import sys
3
+
4
+ OUTPUT_LEVEL = 25
5
+ logging.addLevelName(OUTPUT_LEVEL, "OUTPUT")
6
+
7
+ # Define color ANSI codes
8
+ COLOR_RESET = "\033[0m"
9
+ COLORS = {
10
+ logging.DEBUG: "\033[36m", # Cyan
11
+ logging.INFO: "\033[34m", # Blue
12
+ OUTPUT_LEVEL: "\033[32m", # Green
13
+ logging.WARNING: "\033[33m", # Yellow
14
+ logging.ERROR: "\033[31m", # Red
15
+ logging.CRITICAL: "\033[41m", # Red Background
16
+ }
17
+
18
+ def output(self, message, *args, **kwargs):
19
+ if self.isEnabledFor(OUTPUT_LEVEL):
20
+ self._log(OUTPUT_LEVEL, message, args, **kwargs)
21
+
22
+ logging.Logger.output = output
23
+
24
+ class ColoredFormatter(logging.Formatter):
25
+ def format(self, record):
26
+ level_color = COLORS.get(record.levelno, COLOR_RESET)
27
+ levelname = f"{level_color}[{record.levelname}]{COLOR_RESET}"
28
+
29
+ formatter = logging.Formatter(
30
+ f"%(asctime)s {levelname} %(name)s — %(message)s",
31
+ datefmt="%H:%M:%S"
32
+ )
33
+
34
+ return formatter.format(record)
35
+
36
+ def get_logger(name: str = "rcda"):
37
+ logger = logging.getLogger(name)
38
+
39
+ if not logger.handlers:
40
+ handler = logging.StreamHandler(sys.stdout)
41
+ handler.setFormatter(ColoredFormatter())
42
+ logger.addHandler(handler)
43
+
44
+ logger.propagate = False
45
+ # Keep level unset here to control externally
46
+ # logger.setLevel(logging.INFO)
47
+
48
+ return logger