pynamicalsys 1.0.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 +24 -0
- pynamicalsys/__version__.py +21 -0
- pynamicalsys/common/__init__.py +16 -0
- pynamicalsys/common/basin_analysis.py +170 -0
- pynamicalsys/common/recurrence_quantification_analysis.py +426 -0
- pynamicalsys/common/utils.py +344 -0
- pynamicalsys/continuous_time/__init__.py +16 -0
- pynamicalsys/core/__init__.py +16 -0
- pynamicalsys/core/basin_metrics.py +206 -0
- pynamicalsys/core/continuous_dynamical_systems.py +18 -0
- pynamicalsys/core/discrete_dynamical_systems.py +3391 -0
- pynamicalsys/core/plot_styler.py +155 -0
- pynamicalsys/core/time_series_metrics.py +139 -0
- pynamicalsys/discrete_time/__init__.py +16 -0
- pynamicalsys/discrete_time/dynamical_indicators.py +1226 -0
- pynamicalsys/discrete_time/models.py +435 -0
- pynamicalsys/discrete_time/trajectory_analysis.py +1459 -0
- pynamicalsys/discrete_time/transport.py +501 -0
- pynamicalsys/discrete_time/validators.py +313 -0
- pynamicalsys-1.0.0.dist-info/METADATA +791 -0
- pynamicalsys-1.0.0.dist-info/RECORD +23 -0
- pynamicalsys-1.0.0.dist-info/WHEEL +5 -0
- pynamicalsys-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,435 @@
|
|
1
|
+
# models.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/>.
|
17
|
+
|
18
|
+
import numpy as np
|
19
|
+
from numba import njit
|
20
|
+
from numpy.typing import NDArray
|
21
|
+
from typing import Union, Sequence, Any
|
22
|
+
|
23
|
+
# ! -------------------- !
|
24
|
+
# ! --- Standard map --- !
|
25
|
+
# ! -------------------- !
|
26
|
+
|
27
|
+
|
28
|
+
@njit
|
29
|
+
def standard_map(
|
30
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
31
|
+
) -> NDArray[np.float64]:
|
32
|
+
k = parameters[0]
|
33
|
+
x, y = u
|
34
|
+
y_new = y + k * np.sin(2 * np.pi * x) / (2 * np.pi)
|
35
|
+
x_new = x + y_new # + 0.5
|
36
|
+
|
37
|
+
x_new = x_new % 1
|
38
|
+
y_new = y_new % 1
|
39
|
+
|
40
|
+
return np.array([x_new, y_new])
|
41
|
+
|
42
|
+
|
43
|
+
@njit
|
44
|
+
def unbounded_standard_map(
|
45
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
46
|
+
) -> NDArray[np.float64]:
|
47
|
+
if len(parameters) == 1:
|
48
|
+
k = parameters[0]
|
49
|
+
gamma = 0
|
50
|
+
else:
|
51
|
+
k, gamma = parameters
|
52
|
+
|
53
|
+
x, y = u
|
54
|
+
y_new = (1 - gamma) * y + k * np.sin(2 * np.pi * x) / (2 * np.pi)
|
55
|
+
x_new = x + y_new
|
56
|
+
|
57
|
+
x_new = x_new % 1
|
58
|
+
|
59
|
+
return np.array([x_new, y_new])
|
60
|
+
|
61
|
+
|
62
|
+
@njit
|
63
|
+
def standard_map_backwards(
|
64
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
65
|
+
) -> NDArray[np.float64]:
|
66
|
+
k = parameters[0]
|
67
|
+
x, y = u
|
68
|
+
x_new = x - y
|
69
|
+
y_new = y - k * np.sin(2 * np.pi * x_new) / (2 * np.pi)
|
70
|
+
|
71
|
+
x_new = x_new % 1
|
72
|
+
y_new = y_new % 1
|
73
|
+
|
74
|
+
return np.array([x_new, y_new])
|
75
|
+
|
76
|
+
|
77
|
+
@njit
|
78
|
+
def standard_map_jacobian(
|
79
|
+
u: NDArray[np.float64],
|
80
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
81
|
+
*args: Any,
|
82
|
+
) -> NDArray[np.float64]:
|
83
|
+
k = parameters[0]
|
84
|
+
x, y = u
|
85
|
+
return np.array(
|
86
|
+
[[1 + k * np.cos(2 * np.pi * x), 1], [k * np.cos(2 * np.pi * x), 1]]
|
87
|
+
)
|
88
|
+
|
89
|
+
|
90
|
+
# ! ----------------------------- !
|
91
|
+
# ! --- Standard nontwist map --- !
|
92
|
+
# ! ----------------------------- !
|
93
|
+
|
94
|
+
|
95
|
+
@njit
|
96
|
+
def standard_nontwist_map(
|
97
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
98
|
+
) -> NDArray[np.float64]:
|
99
|
+
|
100
|
+
a, b = parameters
|
101
|
+
x, y = u
|
102
|
+
|
103
|
+
y_new = y - b * np.sin(2 * np.pi * x)
|
104
|
+
x_new = (x + a * (1 - y_new**2)) % 1.0
|
105
|
+
|
106
|
+
return np.array([x_new, y_new])
|
107
|
+
|
108
|
+
|
109
|
+
@njit
|
110
|
+
def standard_nontwist_map_backwards(
|
111
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
112
|
+
) -> NDArray[np.float64]:
|
113
|
+
|
114
|
+
a, b = parameters
|
115
|
+
|
116
|
+
x, y = u
|
117
|
+
|
118
|
+
x_new = (x - a * (1 - y**2)) % 1.0
|
119
|
+
y_new = y + b * np.sin(2 * np.pi * x_new)
|
120
|
+
|
121
|
+
return np.array([x_new, y_new])
|
122
|
+
|
123
|
+
|
124
|
+
@njit
|
125
|
+
def standard_nontwist_map_jacobian(
|
126
|
+
u: NDArray[np.float64],
|
127
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
128
|
+
*args: Any,
|
129
|
+
) -> NDArray[np.float64]:
|
130
|
+
|
131
|
+
a, b = parameters
|
132
|
+
x, _ = u
|
133
|
+
_, y_new = standard_nontwist_map(u, parameters)
|
134
|
+
dy_newdx = -2 * np.pi * b * np.cos(2 * np.pi * x)
|
135
|
+
dy_newdy = 1
|
136
|
+
|
137
|
+
J = np.zeros((2, 2))
|
138
|
+
J[0, 0] = 1 - 2 * a * y_new * dy_newdx
|
139
|
+
J[0, 1] = -2 * a * y_new * dy_newdy
|
140
|
+
J[1, 0] = dy_newdx
|
141
|
+
J[1, 1] = dy_newdy
|
142
|
+
|
143
|
+
return J
|
144
|
+
|
145
|
+
|
146
|
+
# ! -------------------------------------- !
|
147
|
+
# ! --- Extended standard nontwist map --- !
|
148
|
+
# ! -------------------------------------- !
|
149
|
+
|
150
|
+
|
151
|
+
@njit
|
152
|
+
def extended_standard_nontwist_map(
|
153
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
154
|
+
) -> NDArray[np.float64]:
|
155
|
+
|
156
|
+
a, b, c, m = parameters
|
157
|
+
|
158
|
+
x, y = u
|
159
|
+
|
160
|
+
y_new = y - b * np.sin(2 * np.pi * x) - c * np.sin(2 * np.pi * m * x)
|
161
|
+
x_new = (x + a * (1 - y_new**2)) % 1.0
|
162
|
+
|
163
|
+
return np.array([x_new, y_new])
|
164
|
+
|
165
|
+
|
166
|
+
@njit
|
167
|
+
def extended_standard_nontwist_map_backwards(
|
168
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
169
|
+
) -> NDArray[np.float64]:
|
170
|
+
a, b, c, m = parameters
|
171
|
+
x, y = u
|
172
|
+
|
173
|
+
x_new = (x - a * (1 - y**2)) % 1.0
|
174
|
+
y_new = y + b * np.sin(2 * np.pi * x_new) + c * np.sin(2 * np.pi * m * x_new)
|
175
|
+
|
176
|
+
return np.array([x_new, y_new])
|
177
|
+
|
178
|
+
|
179
|
+
@njit
|
180
|
+
def extended_standard_nontwist_map_jacobian(
|
181
|
+
u: NDArray[np.float64],
|
182
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
183
|
+
*args: Any,
|
184
|
+
) -> NDArray[np.float64]:
|
185
|
+
a, b, c, m = parameters
|
186
|
+
x, _ = u
|
187
|
+
_, y_new = extended_standard_nontwist_map(u, parameters)
|
188
|
+
dy_newdx = -2 * np.pi * b * np.cos(2 * np.pi * x) - 2 * np.pi * c * m * np.cos(
|
189
|
+
2 * np.pi * m * x
|
190
|
+
)
|
191
|
+
dy_newdy = 1
|
192
|
+
|
193
|
+
J = np.zeros((2, 2))
|
194
|
+
J[0, 0] = 1 - 2 * a * y_new * dy_newdx
|
195
|
+
J[0, 1] = -2 * a * y_new * dy_newdy
|
196
|
+
J[1, 0] = dy_newdx
|
197
|
+
J[1, 1] = dy_newdy
|
198
|
+
|
199
|
+
return J
|
200
|
+
|
201
|
+
|
202
|
+
# ! ------------------ !
|
203
|
+
# ! --- Leonel map --- !
|
204
|
+
# ! ------------------ !
|
205
|
+
|
206
|
+
|
207
|
+
@njit
|
208
|
+
def leonel_map(
|
209
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
210
|
+
) -> NDArray[np.float64]:
|
211
|
+
eps, gamma = parameters
|
212
|
+
|
213
|
+
x, y = u
|
214
|
+
y_new = y + eps * np.sin(x)
|
215
|
+
x_new = (x + 1 / abs(y_new) ** gamma) % (2 * np.pi)
|
216
|
+
|
217
|
+
return np.array([x_new, y_new])
|
218
|
+
|
219
|
+
|
220
|
+
@njit
|
221
|
+
def leonel_map_backwards(
|
222
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
223
|
+
) -> NDArray[np.float64]:
|
224
|
+
eps, gamma = parameters
|
225
|
+
|
226
|
+
x, y = u
|
227
|
+
|
228
|
+
x_new = (x - 1 / abs(y) ** gamma) % (2 * np.pi)
|
229
|
+
y_new = y - eps * np.sin(x_new)
|
230
|
+
|
231
|
+
return np.array([x_new, y_new])
|
232
|
+
|
233
|
+
|
234
|
+
@njit
|
235
|
+
def leonel_map_jacobian(
|
236
|
+
u: NDArray[np.float64],
|
237
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
238
|
+
*args: Any,
|
239
|
+
) -> NDArray[np.float64]:
|
240
|
+
eps, gamma = parameters
|
241
|
+
|
242
|
+
x, y = u
|
243
|
+
_, y_new = leonel_map(u, parameters)
|
244
|
+
dy_newdx = eps * np.cos(x)
|
245
|
+
dy_newdy = 1
|
246
|
+
|
247
|
+
J = np.zeros((2, 2))
|
248
|
+
J[0, 0] = 1 - (gamma / (y_new * abs(y_new) ** gamma)) * dy_newdx
|
249
|
+
J[0, 1] = -(gamma / (y_new * abs(y_new) ** gamma)) * dy_newdy
|
250
|
+
J[1, 0] = dy_newdx
|
251
|
+
J[1, 1] = dy_newdy
|
252
|
+
|
253
|
+
return J
|
254
|
+
|
255
|
+
|
256
|
+
# ! ------------------------- !
|
257
|
+
# ! --- 4D symplectic map --- !
|
258
|
+
# ! ------------------------- !
|
259
|
+
|
260
|
+
|
261
|
+
@njit
|
262
|
+
def symplectic_map_4D(
|
263
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
264
|
+
) -> NDArray[np.float64]:
|
265
|
+
eps1, eps2, xi = parameters
|
266
|
+
x1, x2, x3, x4 = u
|
267
|
+
|
268
|
+
x1_new = x1 + x2
|
269
|
+
x2_new = x2 - eps1 * np.sin(x1 + x2) - xi * (1 - np.cos(x1 + x2 + x3 + x4))
|
270
|
+
x3_new = x3 + x4
|
271
|
+
x4_new = x4 - eps2 * np.sin(x3 + x4) - xi * (1 - np.cos(x1 + x2 + x3 + x4))
|
272
|
+
|
273
|
+
x1_new = x1_new % (2 * np.pi)
|
274
|
+
x2_new = x2_new % (2 * np.pi)
|
275
|
+
x3_new = x3_new % (2 * np.pi)
|
276
|
+
x4_new = x4_new % (2 * np.pi)
|
277
|
+
|
278
|
+
return np.array([x1_new, x2_new, x3_new, x4_new])
|
279
|
+
|
280
|
+
|
281
|
+
@njit
|
282
|
+
def symplectic_map_4D_backwards(
|
283
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
284
|
+
) -> NDArray[np.float64]:
|
285
|
+
eps1, eps2, xi = parameters
|
286
|
+
x1, x2, x3, x4 = u
|
287
|
+
|
288
|
+
x1_new = x1 - x2
|
289
|
+
x2_new = x2 + eps1 * np.sin(x1 - x2) + xi * (1 - np.cos(x1 - x2 + x3 + x4))
|
290
|
+
x3_new = x3 - x4
|
291
|
+
x4_new = x4 + eps2 * np.sin(x3 - x4) + xi * (1 - np.cos(x1 - x2 + x3 + x4))
|
292
|
+
|
293
|
+
x1_new = x1_new % (2 * np.pi)
|
294
|
+
x2_new = x2_new % (2 * np.pi)
|
295
|
+
x3_new = x3_new % (2 * np.pi)
|
296
|
+
x4_new = x4_new % (2 * np.pi)
|
297
|
+
|
298
|
+
return np.array([x1_new, x2_new, x3_new, x4_new])
|
299
|
+
|
300
|
+
|
301
|
+
@njit
|
302
|
+
def symplectic_map_4D_jacobian(
|
303
|
+
u: NDArray[np.float64],
|
304
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
305
|
+
*args: Any,
|
306
|
+
) -> NDArray[np.float64]:
|
307
|
+
eps1, eps2, xi = parameters
|
308
|
+
|
309
|
+
J = np.zeros((4, 4))
|
310
|
+
J[0, 0] = 1
|
311
|
+
J[0, 1] = 1
|
312
|
+
J[1, 0] = -eps1 * np.cos(u[0] + u[1]) - xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
313
|
+
J[1, 1] = 1 - eps1 * np.cos(u[0] + u[1]) - xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
314
|
+
J[1, 2] = -xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
315
|
+
J[1, 3] = -xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
316
|
+
J[2, 2] = 1
|
317
|
+
J[2, 3] = 1
|
318
|
+
J[3, 0] = -xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
319
|
+
J[3, 1] = -xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
320
|
+
J[3, 2] = -eps2 * np.cos(u[2] + u[3]) - xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
321
|
+
J[3, 3] = 1 - eps2 * np.cos(u[2] + u[3]) - xi * np.sin(u[0] + u[1] + u[2] + u[3])
|
322
|
+
|
323
|
+
return J
|
324
|
+
|
325
|
+
|
326
|
+
# ! ----------------- !
|
327
|
+
# ! --- Henon map --- !
|
328
|
+
# ! ----------------- !
|
329
|
+
|
330
|
+
|
331
|
+
@njit
|
332
|
+
def henon_map(
|
333
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
334
|
+
) -> NDArray[np.float64]:
|
335
|
+
a, b = parameters
|
336
|
+
x, y = u
|
337
|
+
x_new = 1 - a * x**2 + y
|
338
|
+
y_new = b * x
|
339
|
+
return np.array([x_new, y_new])
|
340
|
+
|
341
|
+
|
342
|
+
@njit
|
343
|
+
def henon_map_jacobian(
|
344
|
+
u: NDArray[np.float64],
|
345
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
346
|
+
*args: Any,
|
347
|
+
) -> NDArray[np.float64]:
|
348
|
+
a, b = parameters
|
349
|
+
x, y = u
|
350
|
+
return np.array([[-2 * a * x, 1], [b, 0]])
|
351
|
+
|
352
|
+
|
353
|
+
# ! ----------------- !
|
354
|
+
# ! --- Lozi map --- !
|
355
|
+
# ! ----------------- !
|
356
|
+
|
357
|
+
|
358
|
+
@njit
|
359
|
+
def lozi_map(
|
360
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
361
|
+
) -> NDArray[np.float64]:
|
362
|
+
a, b = parameters
|
363
|
+
x, y = u
|
364
|
+
x_new = 1 - a * abs(x) + y
|
365
|
+
y_new = b * x
|
366
|
+
return np.array([x_new, y_new])
|
367
|
+
|
368
|
+
|
369
|
+
@njit
|
370
|
+
def lozi_map_jacobian(
|
371
|
+
u: NDArray[np.float64],
|
372
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
373
|
+
*args: Any,
|
374
|
+
) -> NDArray[np.float64]:
|
375
|
+
a, b = parameters
|
376
|
+
x, y = u
|
377
|
+
return np.array([[a * np.sign(x), 1], [b, 0]])
|
378
|
+
|
379
|
+
|
380
|
+
# ! -------------------- !
|
381
|
+
# ! --- Logistic map --- !
|
382
|
+
# ! -------------------- !
|
383
|
+
|
384
|
+
|
385
|
+
@njit
|
386
|
+
def logistic_map(
|
387
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
388
|
+
) -> NDArray[np.float64]:
|
389
|
+
r = parameters[0]
|
390
|
+
x = u[0]
|
391
|
+
x_new = r * x * (1 - x)
|
392
|
+
return np.array([x_new])
|
393
|
+
|
394
|
+
|
395
|
+
@njit
|
396
|
+
def logistic_map_jacobian(
|
397
|
+
u: NDArray[np.float64],
|
398
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
399
|
+
*args: Any,
|
400
|
+
) -> NDArray[np.float64]:
|
401
|
+
r = parameters[0]
|
402
|
+
x = u[0]
|
403
|
+
return np.array([[r * (1 - 2 * x)]])
|
404
|
+
|
405
|
+
|
406
|
+
# ! ------------------ !
|
407
|
+
# ! --- Rulkov map --- !
|
408
|
+
# ! ------------------ !
|
409
|
+
|
410
|
+
|
411
|
+
@njit(cache=True)
|
412
|
+
def rulkov_map(
|
413
|
+
u: NDArray[np.float64], parameters: Union[NDArray[np.float64], Sequence[float]]
|
414
|
+
) -> NDArray[np.float64]:
|
415
|
+
alpha, sigma, mu = parameters
|
416
|
+
x, y = u
|
417
|
+
x_new = alpha / (1 + x**2) + y
|
418
|
+
y_new = y - mu * (x - sigma)
|
419
|
+
return np.array([x_new, y_new])
|
420
|
+
|
421
|
+
|
422
|
+
@njit(cache=True)
|
423
|
+
def rulkov_map_jacobian(
|
424
|
+
u: NDArray[np.float64],
|
425
|
+
parameters: Union[NDArray[np.float64], Sequence[float]],
|
426
|
+
*args: Any,
|
427
|
+
) -> NDArray[np.float64]:
|
428
|
+
alpha, sigma, mu = parameters
|
429
|
+
x, y = u
|
430
|
+
J = np.zeros((2, 2))
|
431
|
+
J[0, 0] = -2 * alpha * x / (1 + x**2) ** 2
|
432
|
+
J[0, 1] = 1
|
433
|
+
J[1, 0] = -mu
|
434
|
+
J[1, 1] = 1
|
435
|
+
return J
|