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.
@@ -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