pynamicalsys 1.3.1__py3-none-any.whl → 1.4.0__py3-none-any.whl
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.
- pynamicalsys/__init__.py +2 -0
- pynamicalsys/__version__.py +2 -2
- pynamicalsys/common/time_series_metrics.py +85 -0
- pynamicalsys/continuous_time/chaotic_indicators.py +305 -7
- pynamicalsys/continuous_time/models.py +25 -0
- pynamicalsys/continuous_time/trajectory_analysis.py +457 -10
- pynamicalsys/core/continuous_dynamical_systems.py +933 -35
- pynamicalsys/core/discrete_dynamical_systems.py +20 -9
- pynamicalsys/core/hamiltonian_systems.py +1193 -0
- pynamicalsys/core/time_series_metrics.py +65 -0
- pynamicalsys/discrete_time/dynamical_indicators.py +5 -94
- pynamicalsys/hamiltonian_systems/__init__.py +16 -0
- pynamicalsys/hamiltonian_systems/chaotic_indicators.py +638 -0
- pynamicalsys/hamiltonian_systems/models.py +68 -0
- pynamicalsys/hamiltonian_systems/numerical_integrators.py +248 -0
- pynamicalsys/hamiltonian_systems/trajectory_analysis.py +293 -0
- pynamicalsys/hamiltonian_systems/validators.py +114 -0
- {pynamicalsys-1.3.1.dist-info → pynamicalsys-1.4.0.dist-info}/METADATA +37 -8
- pynamicalsys-1.4.0.dist-info/RECORD +36 -0
- pynamicalsys-1.3.1.dist-info/RECORD +0 -28
- {pynamicalsys-1.3.1.dist-info → pynamicalsys-1.4.0.dist-info}/WHEEL +0 -0
- {pynamicalsys-1.3.1.dist-info → pynamicalsys-1.4.0.dist-info}/top_level.txt +0 -0
@@ -18,12 +18,18 @@
|
|
18
18
|
import numpy as np
|
19
19
|
from numpy.typing import NDArray
|
20
20
|
|
21
|
+
from numbers import Integral, Real
|
22
|
+
|
21
23
|
from pynamicalsys.common.recurrence_quantification_analysis import (
|
22
24
|
recurrence_matrix,
|
23
25
|
RTEConfig,
|
24
26
|
white_vertline_distr,
|
25
27
|
)
|
26
28
|
|
29
|
+
from pynamicalsys.discrete_time.validators import validate_positive
|
30
|
+
|
31
|
+
from pynamicalsys.common.time_series_metrics import hurst_exponent
|
32
|
+
|
27
33
|
|
28
34
|
class TimeSeriesMetrics:
|
29
35
|
def __init__(self, time_series: NDArray[np.float64]) -> None:
|
@@ -137,3 +143,62 @@ class TimeSeriesMetrics:
|
|
137
143
|
result.append(P)
|
138
144
|
|
139
145
|
return result[0] if len(result) == 1 else tuple(result)
|
146
|
+
|
147
|
+
def hurst_exponent(self, wmin: int = 2):
|
148
|
+
"""
|
149
|
+
Estimate the Hurst exponent for a system trajectory using the rescaled range (R/S) method.
|
150
|
+
|
151
|
+
Parameters
|
152
|
+
----------
|
153
|
+
u : NDArray[np.float64]
|
154
|
+
Initial condition vector of shape (n,).
|
155
|
+
parameters : NDArray[np.float64]
|
156
|
+
Parameters passed to the mapping function.
|
157
|
+
total_time : int
|
158
|
+
Total number of iterations used to generate the trajectory.
|
159
|
+
mapping : Callable[[NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]]
|
160
|
+
A function that defines the system dynamics, i.e., how `u` evolves over time given `parameters`.
|
161
|
+
wmin : int, optional
|
162
|
+
Minimum window size for the rescaled range calculation. Default is 2.
|
163
|
+
transient_time : Optional[int], optional
|
164
|
+
Number of initial iterations to discard as transient. If `None`, no transient is removed. Default is `None`.
|
165
|
+
|
166
|
+
Returns
|
167
|
+
-------
|
168
|
+
NDArray[np.float64]
|
169
|
+
Estimated Hurst exponents for each dimension of the input vector `u`, of shape (n,).
|
170
|
+
|
171
|
+
Notes
|
172
|
+
-----
|
173
|
+
The Hurst exponent is a measure of the long-term memory of a time series:
|
174
|
+
|
175
|
+
- H = 0.5 indicates a random walk (no memory).
|
176
|
+
- H > 0.5 indicates persistent behavior (positive autocorrelation).
|
177
|
+
- H < 0.5 indicates anti-persistent behavior (negative autocorrelation).
|
178
|
+
|
179
|
+
This implementation computes the rescaled range (R/S) for various window sizes and
|
180
|
+
performs a linear regression in log-log space to estimate the exponent.
|
181
|
+
|
182
|
+
The function supports multivariate time series, estimating one Hurst exponent per dimension.
|
183
|
+
"""
|
184
|
+
|
185
|
+
sample_size = self.time_series.shape[0]
|
186
|
+
|
187
|
+
validate_positive(wmin, "wmin", Integral)
|
188
|
+
|
189
|
+
if wmin < 2 or wmin >= sample_size // 2:
|
190
|
+
raise ValueError(
|
191
|
+
f"`wmin` must be an integer >= 2 and <= len(time_series) / 2. Got {wmin}."
|
192
|
+
)
|
193
|
+
|
194
|
+
if self.time_series.ndim == 1:
|
195
|
+
time_series = self.time_series.reshape(sample_size, 1)
|
196
|
+
else:
|
197
|
+
time_series = self.time_series
|
198
|
+
|
199
|
+
result = hurst_exponent(time_series, wmin=wmin)
|
200
|
+
|
201
|
+
if self.time_series.ndim == 1:
|
202
|
+
return result[0]
|
203
|
+
else:
|
204
|
+
return result
|
@@ -18,7 +18,7 @@
|
|
18
18
|
from typing import Optional, Tuple, Union, Callable
|
19
19
|
from numpy.typing import NDArray
|
20
20
|
import numpy as np
|
21
|
-
from numba import njit
|
21
|
+
from numba import njit, prange
|
22
22
|
|
23
23
|
from pynamicalsys.common.recurrence_quantification_analysis import (
|
24
24
|
RTEConfig,
|
@@ -31,6 +31,8 @@ from pynamicalsys.discrete_time.trajectory_analysis import (
|
|
31
31
|
)
|
32
32
|
from pynamicalsys.common.utils import qr, householder_qr, fit_poly, wedge_norm
|
33
33
|
|
34
|
+
from pynamicalsys.common.time_series_metrics import hurst_exponent
|
35
|
+
|
34
36
|
|
35
37
|
@njit
|
36
38
|
def lyapunov_1D(
|
@@ -1047,8 +1049,7 @@ def GALI_k(
|
|
1047
1049
|
return np.array([gali])
|
1048
1050
|
|
1049
1051
|
|
1050
|
-
|
1051
|
-
def hurst_exponent(
|
1052
|
+
def hurst_exponent_wrapped(
|
1052
1053
|
u: NDArray[np.float64],
|
1053
1054
|
parameters: NDArray[np.float64],
|
1054
1055
|
total_time: int,
|
@@ -1057,105 +1058,15 @@ def hurst_exponent(
|
|
1057
1058
|
transient_time: Optional[int] = None,
|
1058
1059
|
return_last: bool = False,
|
1059
1060
|
) -> NDArray[np.float64]:
|
1060
|
-
"""
|
1061
|
-
Estimate the Hurst exponent for a system trajectory using the rescaled range (R/S) method.
|
1062
|
-
|
1063
|
-
Parameters
|
1064
|
-
----------
|
1065
|
-
u : NDArray[np.float64]
|
1066
|
-
Initial condition vector of shape (n,).
|
1067
|
-
parameters : NDArray[np.float64]
|
1068
|
-
Parameters passed to the mapping function.
|
1069
|
-
total_time : int
|
1070
|
-
Total number of iterations used to generate the trajectory.
|
1071
|
-
mapping : Callable[[NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]]
|
1072
|
-
A function that defines the system dynamics, i.e., how `u` evolves over time given `parameters`.
|
1073
|
-
wmin : int, optional
|
1074
|
-
Minimum window size for the rescaled range calculation. Default is 2.
|
1075
|
-
transient_time : Optional[int], optional
|
1076
|
-
Number of initial iterations to discard as transient. If `None`, no transient is removed. Default is `None`.
|
1077
|
-
|
1078
|
-
Returns
|
1079
|
-
-------
|
1080
|
-
NDArray[np.float64]
|
1081
|
-
Estimated Hurst exponents for each dimension of the input vector `u`, of shape (n,).
|
1082
|
-
|
1083
|
-
Notes
|
1084
|
-
-----
|
1085
|
-
The Hurst exponent is a measure of the long-term memory of a time series:
|
1086
|
-
|
1087
|
-
- H = 0.5 indicates a random walk (no memory).
|
1088
|
-
- H > 0.5 indicates persistent behavior (positive autocorrelation).
|
1089
|
-
- H < 0.5 indicates anti-persistent behavior (negative autocorrelation).
|
1090
|
-
|
1091
|
-
This implementation computes the rescaled range (R/S) for various window sizes and
|
1092
|
-
performs a linear regression in log-log space to estimate the exponent.
|
1093
|
-
|
1094
|
-
The function supports multivariate time series, estimating one Hurst exponent per dimension.
|
1095
|
-
"""
|
1096
|
-
|
1097
1061
|
u = u.copy()
|
1098
1062
|
neq = len(u)
|
1099
1063
|
H = np.zeros(neq)
|
1100
1064
|
|
1101
|
-
# Handle transient time
|
1102
|
-
if transient_time is not None:
|
1103
|
-
sample_size = total_time - transient_time
|
1104
|
-
for i in range(transient_time):
|
1105
|
-
u = mapping(u, parameters)
|
1106
|
-
else:
|
1107
|
-
sample_size = total_time
|
1108
|
-
|
1109
1065
|
time_series = generate_trajectory(
|
1110
1066
|
u, parameters, total_time, mapping, transient_time=transient_time
|
1111
1067
|
)
|
1112
1068
|
|
1113
|
-
|
1114
|
-
RS = np.empty((ells.shape[0], neq))
|
1115
|
-
for j in range(neq):
|
1116
|
-
|
1117
|
-
for i, ell in enumerate(ells):
|
1118
|
-
num_blocks = sample_size // ell
|
1119
|
-
R_over_S = np.empty(num_blocks)
|
1120
|
-
|
1121
|
-
for block in range(num_blocks):
|
1122
|
-
start = block * ell
|
1123
|
-
end = start + ell
|
1124
|
-
block_series = time_series[start:end, j]
|
1125
|
-
|
1126
|
-
# Mean adjustment
|
1127
|
-
mean_adjusted_series = block_series - np.mean(block_series)
|
1128
|
-
|
1129
|
-
# Cumulative sum
|
1130
|
-
Z = np.cumsum(mean_adjusted_series)
|
1131
|
-
|
1132
|
-
# Range (R)
|
1133
|
-
R = np.max(Z) - np.min(Z)
|
1134
|
-
|
1135
|
-
# Standard deviation (S)
|
1136
|
-
S = np.std(block_series)
|
1137
|
-
|
1138
|
-
# Avoid division by zero
|
1139
|
-
if S > 0:
|
1140
|
-
R_over_S[block] = R / S
|
1141
|
-
else:
|
1142
|
-
R_over_S[block] = 0
|
1143
|
-
|
1144
|
-
if np.all(R_over_S == 0):
|
1145
|
-
RS[i, j] == 0
|
1146
|
-
else:
|
1147
|
-
RS[i, j] = np.mean(R_over_S[R_over_S > 0])
|
1148
|
-
|
1149
|
-
if np.all(RS[:, j] == 0):
|
1150
|
-
H[j] = 0
|
1151
|
-
else:
|
1152
|
-
# Log-log plot and linear regression to estimate the Hurst exponent
|
1153
|
-
inds = np.where(RS[:, j] > 0)[0]
|
1154
|
-
x_fit = np.log(ells[inds])
|
1155
|
-
y_fit = np.log(RS[inds, j])
|
1156
|
-
fitting = fit_poly(x_fit, y_fit, 1)
|
1157
|
-
|
1158
|
-
H[j] = fitting[0]
|
1069
|
+
H = hurst_exponent(time_series, wmin=wmin)
|
1159
1070
|
|
1160
1071
|
if return_last:
|
1161
1072
|
result = np.zeros(2 * neq)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# # __init__.py
|
2
|
+
|
3
|
+
# # Copyright (C) 2025 Matheus Rolim Sales
|
4
|
+
# #
|
5
|
+
# # This program is free software: you can redistribute it and/or modify
|
6
|
+
# # it under the terms of the GNU General Public License as published by
|
7
|
+
# # the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# # (at your option) any later version.
|
9
|
+
# #
|
10
|
+
# # This program is distributed in the hope that it will be useful,
|
11
|
+
# # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# # GNU General Public License for more details.
|
14
|
+
# #
|
15
|
+
# # You should have received a copy of the GNU General Public License
|
16
|
+
# # along with this program. If not, see <https://www.gnu.org/licenses/>.
|