edmkit 0.0.13__tar.gz → 0.0.14__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 (30) hide show
  1. {edmkit-0.0.13 → edmkit-0.0.14}/PKG-INFO +1 -1
  2. {edmkit-0.0.13 → edmkit-0.0.14}/pyproject.toml +2 -1
  3. {edmkit-0.0.13 → edmkit-0.0.14}/pyproject.toml.orig +2 -1
  4. edmkit-0.0.14/src/edmkit/generate/__init__.py +10 -0
  5. edmkit-0.0.14/src/edmkit/generate/ctrnn.py +25 -0
  6. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/generate/double_pendulum.py +6 -30
  7. edmkit-0.0.14/src/edmkit/generate/duffing.py +31 -0
  8. edmkit-0.0.14/src/edmkit/generate/lorenz.py +27 -0
  9. edmkit-0.0.14/src/edmkit/generate/lorenz96.py +25 -0
  10. edmkit-0.0.14/src/edmkit/generate/rk45.py +85 -0
  11. edmkit-0.0.14/src/edmkit/generate/rossler.py +27 -0
  12. edmkit-0.0.13/src/edmkit/generate/__init__.py +0 -5
  13. edmkit-0.0.13/src/edmkit/generate/lorenz.py +0 -49
  14. {edmkit-0.0.13 → edmkit-0.0.14}/README.md +0 -0
  15. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/ccm.py +0 -0
  16. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/embedding.py +0 -0
  17. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/generate/mackey_glass.py +0 -0
  18. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/metrics/__init__.py +0 -0
  19. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/metrics/mae.py +0 -0
  20. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/metrics/pearson_correlation.py +0 -0
  21. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/metrics/rmse.py +0 -0
  22. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/simplex_projection/__init__.py +0 -0
  23. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/simplex_projection/knn.py +0 -0
  24. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/simplex_projection/simplex_projection.py +0 -0
  25. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/simplex_projection/soft.py +0 -0
  26. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/smap.py +0 -0
  27. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/splits.py +0 -0
  28. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/theiler_window.py +0 -0
  29. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/types.py +0 -0
  30. {edmkit-0.0.13 → edmkit-0.0.14}/src/edmkit/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: edmkit
3
- Version: 0.0.13
3
+ Version: 0.0.14
4
4
  Summary: Simple EDM (Empirical Dynamic Modeling) library
5
5
  Author: FUJISHIGE TEMMA
6
6
  Author-email: FUJISHIGE TEMMA <tenma.x0@gmail.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "edmkit"
3
- version = "0.0.13"
3
+ version = "0.0.14"
4
4
  description = "Simple EDM (Empirical Dynamic Modeling) library"
5
5
  readme = "README.md"
6
6
  requires-python = ">= 3.13"
@@ -20,6 +20,7 @@ email = "tenma.x0@gmail.com"
20
20
  dev = [
21
21
  "griffe2md>=1.5.0",
22
22
  "hypothesis>=6.151.9",
23
+ "matplotlib>=3.11.2",
23
24
  "pytest>=9.1.1",
24
25
  "ruff>=0.15.20",
25
26
  "ty>=0.0.56",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "edmkit"
3
- version = "0.0.13"
3
+ version = "0.0.14"
4
4
  description = "Simple EDM (Empirical Dynamic Modeling) library"
5
5
  authors = [{ name = "FUJISHIGE TEMMA", email = "tenma.x0@gmail.com" }]
6
6
  readme = "README.md"
@@ -17,6 +17,7 @@ dependencies = [
17
17
  dev = [
18
18
  "griffe2md>=1.5.0",
19
19
  "hypothesis>=6.151.9",
20
+ "matplotlib>=3.11.2",
20
21
  "pytest>=9.1.1",
21
22
  "ruff>=0.15.20",
22
23
  "ty>=0.0.56",
@@ -0,0 +1,10 @@
1
+ from .ctrnn import ctrnn
2
+ from .double_pendulum import double_pendulum, to_xy
3
+ from .duffing import duffing
4
+ from .lorenz import lorenz
5
+ from .lorenz96 import lorenz96
6
+ from .mackey_glass import mackey_glass
7
+ from .rk45 import rk45
8
+ from .rossler import rossler
9
+
10
+ __all__ = ["ctrnn", "double_pendulum", "duffing", "lorenz", "lorenz96", "mackey_glass", "rk45", "rossler", "to_xy"]
@@ -0,0 +1,25 @@
1
+ import numpy as np
2
+
3
+ __all__ = ["ctrnn"]
4
+
5
+
6
+ def ctrnn(g: float, J: np.ndarray):
7
+ """Vector field of a continuous-time recurrent neural network ``dx/dt = -x + g J tanh(x)``.
8
+
9
+ Parameters
10
+ ----------
11
+ g : float
12
+ Gain (chaos for ``g > 1`` when ``J`` is large and random with variance ``1 / N``).
13
+ J : np.ndarray
14
+ Connectivity of shape ``(N, N)``; ``J[i, j]`` is the weight with which unit ``j`` drives unit ``i``.
15
+
16
+ Returns
17
+ -------
18
+ f : Callable[[float, np.ndarray], np.ndarray]
19
+ Right-hand side ``f(t, x)`` for a state of shape ``(N,)``.
20
+ """
21
+
22
+ def f(t: float, x: np.ndarray):
23
+ return -x + g * J @ np.tanh(x)
24
+
25
+ return f
@@ -3,17 +3,8 @@ import numpy as np
3
3
  __all__ = ["double_pendulum", "to_xy"]
4
4
 
5
5
 
6
- def double_pendulum(
7
- m1: float,
8
- m2: float,
9
- L1: float,
10
- L2: float,
11
- g: float,
12
- X0: np.ndarray,
13
- dt: float,
14
- t_max: int,
15
- ):
16
- """Generate double pendulum dynamics via forward Euler integration.
6
+ def double_pendulum(m1: float, m2: float, L1: float, L2: float, g: float):
7
+ """Vector field of the double pendulum.
17
8
 
18
9
  Parameters
19
10
  ----------
@@ -27,22 +18,14 @@ def double_pendulum(
27
18
  Length of second pendulum.
28
19
  g : float
29
20
  Gravitational acceleration.
30
- X0 : np.ndarray
31
- Initial state ``(theta1, theta2, omega1, omega2)`` of shape ``(4,)``.
32
- dt : float
33
- Integration time step.
34
- t_max : int
35
- Maximum time.
36
21
 
37
22
  Returns
38
23
  -------
39
- t : np.ndarray
40
- Time array.
41
- X : np.ndarray
42
- State trajectory of shape ``(N, 4)``.
24
+ f : Callable[[float, np.ndarray], np.ndarray]
25
+ Right-hand side ``f(t, x)`` for a state ``(theta1, theta2, omega1, omega2)`` of shape ``(4,)``.
43
26
  """
44
27
 
45
- def f(x: np.ndarray):
28
+ def f(t: float, x: np.ndarray):
46
29
  theta1, theta2, omega1, omega2 = x
47
30
  delta = theta1 - theta2
48
31
 
@@ -63,14 +46,7 @@ def double_pendulum(
63
46
 
64
47
  return np.array([dtheta1_dt, dtheta2_dt, domega1_dt, domega2_dt])
65
48
 
66
- t = np.arange(0, t_max, dt)
67
- X = np.zeros((len(t), 4))
68
- X[0] = X0
69
-
70
- for i in range(1, len(t)):
71
- X[i] = X[i - 1] + dt * f(X[i - 1])
72
-
73
- return t, X
49
+ return f
74
50
 
75
51
 
76
52
  def to_xy(L1: float, L2: float, theta1: np.ndarray, theta2: np.ndarray):
@@ -0,0 +1,31 @@
1
+ import numpy as np
2
+
3
+ __all__ = ["duffing"]
4
+
5
+
6
+ def duffing(alpha: float, beta: float, delta: float, gamma: float, omega: float):
7
+ """Vector field of the forced Duffing oscillator.
8
+
9
+ Parameters
10
+ ----------
11
+ alpha : float
12
+ Linear stiffness (typical: -1).
13
+ beta : float
14
+ Cubic stiffness (typical: 1).
15
+ delta : float
16
+ Damping coefficient (typical: 0.3).
17
+ gamma : float
18
+ Forcing amplitude (typical: 0.5 for chaos).
19
+ omega : float
20
+ Forcing angular frequency (typical: 1.2).
21
+
22
+ Returns
23
+ -------
24
+ f : Callable[[float, np.ndarray], np.ndarray]
25
+ Right-hand side ``f(t, x)`` for a state ``(x, v)`` of shape ``(2,)``.
26
+ """
27
+
28
+ def f(t: float, x: np.ndarray):
29
+ return np.array([[0, 1], [-alpha - beta * x[0] ** 2, -delta]]) @ x + np.array([0, gamma * np.cos(omega * t)])
30
+
31
+ return f
@@ -0,0 +1,27 @@
1
+ import numpy as np
2
+
3
+ __all__ = ["lorenz"]
4
+
5
+
6
+ def lorenz(sigma: float, rho: float, beta: float):
7
+ """Vector field of the Lorenz system.
8
+
9
+ Parameters
10
+ ----------
11
+ sigma : float
12
+ Prandtl number (typical: 10).
13
+ rho : float
14
+ Rayleigh number (typical: 28).
15
+ beta : float
16
+ Geometric factor (typical: 8/3).
17
+
18
+ Returns
19
+ -------
20
+ f : Callable[[float, np.ndarray], np.ndarray]
21
+ Right-hand side ``f(t, x)`` for a state ``(x, y, z)`` of shape ``(3,)``.
22
+ """
23
+
24
+ def f(t: float, x: np.ndarray):
25
+ return np.array([[-sigma, sigma, 0], [rho, -1, -x[0]], [0, x[0], -beta]]) @ x
26
+
27
+ return f
@@ -0,0 +1,25 @@
1
+ import numpy as np
2
+
3
+ __all__ = ["lorenz96"]
4
+
5
+
6
+ def lorenz96(F: float):
7
+ """Vector field of the Lorenz 96 system.
8
+
9
+ Parameters
10
+ ----------
11
+ F : float
12
+ Forcing constant (typical: 8 for chaos).
13
+
14
+ Returns
15
+ -------
16
+ f : Callable[[float, np.ndarray], np.ndarray]
17
+ Right-hand side ``f(t, x)`` for a state of shape ``(D,)`` with ``D >= 4``.
18
+ """
19
+
20
+ def f(t: float, x: np.ndarray):
21
+ # p[i + 2] is x[i] on the ring, so this is (x[i + 1] - x[i - 2]) * x[i - 1] - x[i] + F
22
+ p = np.concatenate([x[-2:], x, x[:1]])
23
+ return (p[3:] - p[:-3]) * p[1:-2] - x + F
24
+
25
+ return f
@@ -0,0 +1,85 @@
1
+ from collections.abc import Callable
2
+
3
+ import numpy as np
4
+
5
+ __all__ = ["rk45"]
6
+
7
+ # Dormand-Prince 5(4)
8
+ A = np.array(
9
+ [
10
+ [0, 0, 0, 0, 0, 0],
11
+ [1 / 5, 0, 0, 0, 0, 0],
12
+ [3 / 40, 9 / 40, 0, 0, 0, 0],
13
+ [44 / 45, -56 / 15, 32 / 9, 0, 0, 0],
14
+ [19372 / 6561, -25360 / 2187, 64448 / 6561, -212 / 729, 0, 0],
15
+ [9017 / 3168, -355 / 33, 46732 / 5247, 49 / 176, -5103 / 18656, 0],
16
+ [35 / 384, 0, 500 / 1113, 125 / 192, -2187 / 6784, 11 / 84],
17
+ ]
18
+ )
19
+ C = A.sum(axis=1)
20
+ E = np.array([71 / 57600, 0, -71 / 16695, 71 / 1920, -17253 / 339200, 22 / 525, -1 / 40])
21
+
22
+
23
+ def rk45(
24
+ f: Callable[[float, np.ndarray], np.ndarray],
25
+ X0: np.ndarray,
26
+ dt: float,
27
+ t_max: int,
28
+ rtol: float = 1e-6,
29
+ atol: float = 1e-9,
30
+ ):
31
+ """Integrate ``dx/dt = f(t, x)`` via the adaptive Dormand-Prince RK45 method.
32
+
33
+ The step size adapts between samples, while the output stays on the uniform grid of spacing ``dt``.
34
+
35
+ Parameters
36
+ ----------
37
+ f : Callable[[float, np.ndarray], np.ndarray]
38
+ Right-hand side of the system.
39
+ X0 : np.ndarray
40
+ Initial condition of shape ``(D,)``.
41
+ dt : float
42
+ Sampling time step.
43
+ t_max : int
44
+ Maximum time.
45
+ rtol : float
46
+ Relative tolerance of the local error.
47
+ atol : float
48
+ Absolute tolerance of the local error.
49
+
50
+ Returns
51
+ -------
52
+ t : np.ndarray
53
+ Time array.
54
+ X : np.ndarray
55
+ Trajectory of shape ``(N, D)``.
56
+ """
57
+ t = np.arange(0, t_max, dt)
58
+ X = np.zeros((len(t), len(X0)))
59
+ X[0] = X0
60
+
61
+ K = np.zeros((7, len(X0)))
62
+ h = dt
63
+
64
+ for i in range(1, len(t)):
65
+ s, x = t[i - 1], X[i - 1]
66
+
67
+ while s < t[i]:
68
+ last = h >= t[i] - s
69
+ step = t[i] - s if last else h
70
+
71
+ for j in range(7):
72
+ K[j] = f(s + C[j] * step, x + step * (A[j, :j] @ K[:j]))
73
+
74
+ x_new = x + step * (A[6] @ K[:6])
75
+ error = np.max(np.abs(step * (E @ K)) / (atol + rtol * np.maximum(np.abs(x), np.abs(x_new))))
76
+ accepted = error <= 1
77
+
78
+ if accepted:
79
+ s, x = t[i] if last else s + step, x_new
80
+ if not (accepted and last):
81
+ h = step * min(10, max(0.2, 0.9 * error**-0.2)) if error > 0 else step * 10
82
+
83
+ X[i] = x
84
+
85
+ return t, X
@@ -0,0 +1,27 @@
1
+ import numpy as np
2
+
3
+ __all__ = ["rossler"]
4
+
5
+
6
+ def rossler(a: float, b: float, c: float):
7
+ """Vector field of the Rössler system.
8
+
9
+ Parameters
10
+ ----------
11
+ a : float
12
+ Spiral growth rate (typical: 0.2).
13
+ b : float
14
+ Constant injection into z (typical: 0.2).
15
+ c : float
16
+ Folding threshold (typical: 5.7).
17
+
18
+ Returns
19
+ -------
20
+ f : Callable[[float, np.ndarray], np.ndarray]
21
+ Right-hand side ``f(t, x)`` for a state ``(x, y, z)`` of shape ``(3,)``.
22
+ """
23
+
24
+ def f(t: float, x: np.ndarray):
25
+ return np.array([[0, -1, -1], [1, a, 0], [0, 0, x[0] - c]]) @ x + np.array([0, 0, b])
26
+
27
+ return f
@@ -1,5 +0,0 @@
1
- from .double_pendulum import double_pendulum, to_xy
2
- from .lorenz import lorenz
3
- from .mackey_glass import mackey_glass
4
-
5
- __all__ = ["double_pendulum", "lorenz", "mackey_glass", "to_xy"]
@@ -1,49 +0,0 @@
1
- import numpy as np
2
-
3
- __all__ = ["lorenz"]
4
-
5
-
6
- def lorenz(
7
- sigma: float,
8
- rho: float,
9
- beta: float,
10
- X0: np.ndarray,
11
- dt: float,
12
- t_max: int,
13
- ):
14
- """Generate a Lorenz system trajectory via forward Euler integration.
15
-
16
- Parameters
17
- ----------
18
- sigma : float
19
- Prandtl number (typical: 10).
20
- rho : float
21
- Rayleigh number (typical: 28).
22
- beta : float
23
- Geometric factor (typical: 8/3).
24
- X0 : np.ndarray
25
- Initial condition of shape ``(3,)``.
26
- dt : float
27
- Integration time step.
28
- t_max : int
29
- Maximum time.
30
-
31
- Returns
32
- -------
33
- t : np.ndarray
34
- Time array.
35
- X : np.ndarray
36
- Trajectory of shape ``(N, 3)`` for ``(x, y, z)``.
37
- """
38
-
39
- def f(x: np.ndarray):
40
- return np.array([[-sigma, sigma, 0], [rho, -1, -x[0]], [0, x[0], -beta]]) @ x
41
-
42
- t = np.arange(0, t_max, dt)
43
- X = np.zeros((len(t), 3))
44
- X[0] = X0
45
-
46
- for i in range(1, len(t)):
47
- X[i] = X[i - 1] + dt * f(X[i - 1])
48
-
49
- return t, X
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes