demathpy 0.0.1__py3-none-any.whl → 0.1.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.
demathpy/symbols.py CHANGED
@@ -168,6 +168,24 @@ REGEX_RULES = [
168
168
  # divergence shorthand: ∇ * u or ∇ * (u)
169
169
  (r"∇\s*\*\s*\(([^\)]*)\)", r"div(\1)"),
170
170
  (r"∇\s*\*\s*([a-zA-Z_][a-zA-Z0-9_]*)", r"div(\1)"),
171
+ # advection operator: (u · ∇) v -> advect(u, v)
172
+ # Match (u · ∇) or (u * ∇) followed by v or (v)
173
+ # Handle both · (before replacement) and * (after replacement if regex runs late)?
174
+ # actually SYMBOL_MAP runs later or earlier?
175
+ # In normalize_symbols, SYMBOL_MAP runs BEFORE regex rules.
176
+ # So · becomes *.
177
+ # But wait, in code:
178
+ # 1. replace greek
179
+ # 2. replace ∇·, ∇(
180
+ # 3. balanced paren calls
181
+ # 4. SYMBOL_MAP replacement (· -> *)
182
+ # 5. REGEX_RULES
183
+ # So we only need to match * for dot product.
184
+
185
+ # (u * ∇) v -> advect(u, v)
186
+ (r"\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\*\s*∇\s*\)\s*([a-zA-Z_][a-zA-Z0-9_]*)", r"advect(\1, \2)"),
187
+ (r"\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\*\s*∇\s*\)\s*\(([^\)]*)\)", r"advect(\1, \2)"),
188
+
171
189
  # gradient: ∇(u)
172
190
  (r"∇\s*\(([^\)]*)\)", r"grad(\1)"),
173
191
  # gradient magnitude |∇u|^2
@@ -287,25 +305,40 @@ def normalize_symbols(expr: str) -> str:
287
305
  "omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega"
288
306
  )
289
307
  fn_words = "sin|cos|tan|sinh|cosh|tanh|exp|log|log10|log2|sqrt|abs|sech|sign"
308
+ # Use word boundary \b to avoid matching inside words
290
309
  expr = re.sub(rf"\b({greek_words})(?=({fn_words})\b)", r"\1*", expr)
291
- # Greek word directly followed by a single-letter variable (e.g., beta u)
292
- # Greek word directly followed by a single-letter variable (e.g., beta u) or concatenated (betau).
310
+ # Greek word directly followed by a single-letter variable (e.g., beta u) or concatenated (betau).
293
311
  # BUT do not split axis-suffixed coefficients like alphax/alphaz (common in anisotropic diffusion terms).
294
312
  _axis_coeffs = {
295
313
  "alphax", "alphaz", "betax", "betaz", "gammax", "gammaz", "deltax", "deltaz",
296
314
  "sigmax", "sigmaz", "thetax", "thetaz", "kappax", "kappaz", "lambdax", "lambdaz",
297
315
  "rhox", "rhoz", "mux", "muz", "nux", "nuz",
316
+ # Also protect eps/epsilon from being split
317
+ "epsilon", "eps",
298
318
  }
299
319
 
300
320
  def _split_greek_letter_var(m: re.Match) -> str:
301
321
  greek = m.group(1)
302
322
  letter = m.group(2)
303
323
  combined = f"{greek}{letter}"
324
+ # Don't split if this creates a known coefficient (e.g., alphax, sigmaz)
304
325
  if combined in _axis_coeffs:
305
326
  return combined
327
+ # Don't split if combined is the start of a greek word (to avoid "epsi*lon" from "epsilon")
328
+ # Check if any greek word starts with the combined string
329
+ all_greek_words = {"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta",
330
+ "iota", "kappa", "lam", "mu", "nu", "xi", "omicron", "pi", "rho",
331
+ "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega"}
332
+ for gw in all_greek_words:
333
+ if gw.startswith(combined) and len(gw) > len(combined):
334
+ # combined is a prefix of a longer greek word, so don't split
335
+ return combined
336
+ # Otherwise, insert multiplication: betau -> beta*u
306
337
  return f"{greek}*{letter}"
307
338
 
308
- expr = re.sub(rf"({greek_words})([A-Za-z])", _split_greek_letter_var, expr)
339
+ # Only match at word boundaries to avoid splitting within words like 'epsilon'
340
+ # Use lookahead to detect when a greek word is followed by a single letter that starts a new token
341
+ expr = re.sub(rf"\b({greek_words})([A-Za-z])(?=([^a-zA-Z]|$))", _split_greek_letter_var, expr)
309
342
 
310
343
  # Absolute value for variables/parentheses
311
344
  expr = re.sub(r"\|\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\|", r"abs(\1)", expr)
@@ -361,7 +394,7 @@ def normalize_symbols(expr: str) -> str:
361
394
  "exp", "sqrt",
362
395
  "log", "log10", "log2",
363
396
  "abs", "sech", "sign",
364
- "lap", "dx", "dz", "dxx", "dzz", "grad", "div", "gradmag", "gradl1", "pos",
397
+ "lap", "dx", "dz", "dxx", "dzz", "grad", "div", "advect", "gradmag", "gradl1", "pos",
365
398
  }:
366
399
  return f"{name}("
367
400
  return f"{name}*("
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.4
2
+ Name: demathpy
3
+ Version: 0.1.0
4
+ Summary: PDE/ODE math backend
5
+ Author: Misekai
6
+ Author-email: Misekai <mcore-us@misekai.net>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Requires-Dist: numpy>=1.24.0
10
+ Requires-Dist: sympy>=1.12.0
11
+ Requires-Dist: typing>=3.10.0.0
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Demathpy
16
+
17
+ A Python library for parsing and safely evaluating symbolic Ordinary and Partial Differential Equations (ODEs/PDEs) on numerical grids.
18
+
19
+ This repository provides:
20
+ - A class-based `PDE` solver (`from demathpy import PDE`) for running simulations.
21
+ - A lightweight **symbol normalizer** that converts human-readable mathematical notation into valid Python expressions.
22
+ - Equation-based Boundary Conditions and Initial Conditions.
23
+ - Built-in support for common differential operators and vector calculus notation using Finite Differences.
24
+
25
+ ### Key Features
26
+
27
+ #### 1. The PDE Class
28
+
29
+ The core of the library is the `PDE` class. It manages the grid state, parsing, and time-stepping.
30
+
31
+ ```python
32
+ from demathpy import PDE
33
+ import numpy as np
34
+
35
+ # Define a Heat Equation: du/dt = Laplacian(u)
36
+ p = PDE("du/dt = lap(u)", space_axis=["x", "y"])
37
+
38
+ # Configure the grid
39
+ p.init_grid(width=100, height=100, dx=0.5)
40
+
41
+ # Set Initial Conditions using equations
42
+ p.initial = ["u = exp(-(x-25)**2 - (y-25)**2)"]
43
+ p.set_initial_state()
44
+
45
+ # Set Boundary Conditions using equations
46
+ # Format: "axis(coord) = value" or "axis=coord = value"
47
+ p.boundry = [
48
+ "x=0 = 1.0", # Left boundary (x=0) is fixed at 1.0
49
+ "x=100 = 0.0", # Right boundary (x=100) is fixed at 0.0
50
+ "y=0 = 0.0", # Bottom boundary is 0.0
51
+ "periodic" # Other unset boundaries (y=100) default to periodic or 0
52
+ ]
53
+
54
+ # Run simulation
55
+ for _ in range(100):
56
+ p.step(dt=0.01)
57
+
58
+ print(p.u.mean())
59
+ ```
60
+
61
+ #### 2. Equation-Based Configuration
62
+
63
+ You can configure boundaries and initial states using string equations instead of manual array manipulation.
64
+
65
+ **Boundary Conditions (`p.boundry` list):**
66
+ - **Dirichlet:** `x=0 = 1.0` (Fixes value at boundary)
67
+ - **Neumann:** `dx(u) = 0` (Not fully exposed yet, currently defaults to Dirichlet logic if value provided).
68
+ - **Periodic:** Use `periodic` keyword or leave empty for default periodic behavior (if implemented).
69
+
70
+ **Initial Conditions (`p.initial` list):**
71
+ - **Scalar:** `u = sin(x) * cos(y)`
72
+ - **Vector Components:** `ux = 1.0`, `uy = 0.0` (if `p.u_shape = ["ux", "uy"]`)
73
+
74
+ #### 3. Vector Fields
75
+
76
+ The solver supports vector-valued PDEs (e.g., Navier-Stokes, Reaction-Diffusion systems).
77
+
78
+ ```python
79
+ # 2D Advection: du/dt = - (u · ∇) u
80
+ p = PDE("du/dt = -advect(u, u)", space_axis=["x", "y"])
81
+ p.u_shape = ["ux", "uy"] # Define component names
82
+ p.init_grid(width=50, height=50, dx=1.0)
83
+
84
+ # Initialize Vortex
85
+ p.initial = [
86
+ "ux = -sin(y)",
87
+ "uy = sin(x)"
88
+ ]
89
+ p.set_initial_state()
90
+ ```
91
+
92
+ ### Supported Operators
93
+
94
+ The parser recognizes and maps these to NumPy finite difference functions:
95
+
96
+ - **Derivatives:** `du/dt`, `dx(u)`, `dy(u)`, `dz(u)`
97
+ - **Second Derivatives:** `dxx(u)`, `dzz(u)`
98
+ - **Laplacian:** `lap(u)` or `∇²u`
99
+ - **Gradient:** `grad(u)` or `∇u` (Returns vector)
100
+ - **Divergence:** `div(u)` or `∇·u` (Expects vector input)
101
+ - **Advection:** `advect(velocity, field)` -> `(velocity · ∇) field`
102
+ - **Math Functions:** `sin, cos, exp, log, abs, sqrt, tanh` ...
103
+
104
+ ### Symbol Normalization
105
+
106
+ The parser supports Unicode and mathematical shorthand:
107
+ - `α, β, γ` → `alpha, beta, gamma`
108
+ - `u²` → `u**2`
109
+ - `|u|` → `abs(u)`
110
+
111
+ ### Workflow & Visualization
112
+
113
+ To integrate `Demathpy` into visualization software or interactive notebooks, you can use the `get_grid()` method to probe the field dynamics without advancing the simulation time.
114
+
115
+ #### Visualization Step-by-Step
116
+
117
+ 1. **Initialize**:
118
+ ```python
119
+ p = PDE("du/dt = lap(u) - u**3 + u", space_axis=["x", "y"])
120
+ p.init_grid(width=20, height=20, dx=0.5)
121
+ p.initial = ["u = 0.1 * sin(x)"]
122
+ p.boundry = ["periodic"]
123
+ p.set_initial_state()
124
+ ```
125
+
126
+ 2. **Probe the Vector Field (du/dt)**:
127
+ Use `get_grid(dt=0)` to get the instantaneous rate of change. This is useful for visualizing flow fields or phase plots.
128
+ ```python
129
+ # Get Rate of Change (RHS of PDE)
130
+ du_dt = p.get_grid(dt=0)
131
+
132
+ # Or calculate the hypothetical next step delta
133
+ delta_u = p.get_grid(dt=0.01)
134
+ ```
135
+
136
+ 3. **Predict on Arbitrary States**:
137
+ You can evaluate the PDE on a hypothetical state `u_test` without updating the solver's internal state. This is useful for drawing vector fields in phase space.
138
+ ```python
139
+ # Create a test state
140
+ test_u = np.sin(p.u)
141
+
142
+ # Calculate how the PDE would evolve this state
143
+ # Returns the rate of change for the test state
144
+ response = p.get_grid(u_state=test_u, dt=0)
145
+ ```
146
+
147
+ 4. **Run Simulation Loops**:
148
+ ```python
149
+ import matplotlib.pyplot as plt
150
+
151
+ for i in range(100):
152
+ p.step(dt=0.01)
153
+ if i % 10 == 0:
154
+ plt.imshow(p.u) # Visualization logic
155
+ # plt.show()
156
+ ```
157
+
158
+ ### License
159
+
160
+ MIT
@@ -0,0 +1,8 @@
1
+ demathpy/__init__.py,sha256=O2m_YqVOiPaPVC7b9jJdObU9mFmPVZuvIvHf5JY2bKQ,448
2
+ demathpy/ode.py,sha256=3SgeiYbHUov9NtrKCOhCo2I4DFLLdh5iIqkhPxwt254,4188
3
+ demathpy/pde.py,sha256=v8tMQGKyelmYaQI4mMJmge4WW8KK6NGTCmZlmZ8XI-I,31788
4
+ demathpy/symbols.py,sha256=kdONgSB_-9jL6DEGx9GyJMorYY1wTOZ6C-GV18_rMd0,13755
5
+ demathpy-0.1.0.dist-info/licenses/LICENSE,sha256=Vofo4OGPZaOEnCixsvF2MaZSGdpDI4uVMm9GNEjSGBM,1064
6
+ demathpy-0.1.0.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
7
+ demathpy-0.1.0.dist-info/METADATA,sha256=AUpR7HK1cHuDJMWQNYubUs6VN-bnMCHcB60HprMWdLc,5018
8
+ demathpy-0.1.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.27
2
+ Generator: uv 0.9.28
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,106 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: demathpy
3
- Version: 0.0.1
4
- Summary: PDE/ODE math backend
5
- Author: Misekai
6
- Author-email: Misekai <mcore-us@misekai.net>
7
- License-Expression: MIT
8
- License-File: LICENSE
9
- Requires-Dist: numpy>=1.24.0
10
- Requires-Dist: sympy>=1.12.0
11
- Requires-Dist: typing>=3.10.0.0
12
- Requires-Python: >=3.10
13
- Description-Content-Type: text/markdown
14
-
15
- # Demathpy
16
-
17
- A Python library for parsing and safely evaluating symbolic Ordinary and Partial Differential Equations (ODEs/PDEs) on numerical grids.
18
-
19
- This repository provides:
20
-
21
- - A lightweight **symbol normalizer** that converts human-readable mathematical notation into valid Python expressions.
22
- - A **secure evaluation engine** that evaluates PDE/ODE right-hand sides on NumPy grids without using raw `eval` on untrusted input.
23
- - Built-in support for common differential operators and vector calculus notation.
24
-
25
- ### Key Features
26
-
27
- #### 1. Symbol Normalization
28
-
29
- The parser supports Unicode and mathematical shorthand, including:
30
-
31
- - Greek letters: `α, β, γ, λ, ε, φ, θ` → `alpha, beta, gamma, lam, epsilon, phi, theta`
32
- - Powers: `u², v³` → `u**2, v**3`
33
- - Implicit multiplication:
34
- - `αu` → `alpha*u`
35
- - `2u` → `2*u`
36
- - `(u+1)(v+1)` → `(u+1)*(v+1)`
37
- - Absolute values: `|u|` → `abs(u)`
38
- - Common functions:
39
- `sin, cos, tan, exp, log, tanh, sech, sign, sqrt`
40
-
41
- #### 2. Differential Operator Support
42
-
43
- The parser recognizes and evaluates:
44
-
45
- - First derivatives:
46
- - `du/dt`, `u_t`
47
- - Second derivatives:
48
- - `dxx(u)`, `dzz(u)`
49
- - Laplacian:
50
- - `∇²u`, `lap(u)`
51
- - Gradient:
52
- - `∇u`, `grad(u)`
53
- - Divergence:
54
- - `∇·(A)`, `div(A)`
55
-
56
- These are mapped to finite-difference operators implemented in NumPy.
57
-
58
- #### 3. PDE / ODE Parsing
59
-
60
- The library provides:
61
-
62
- - `parse_pde(equation: str)`
63
- Parses a PDE string and returns `(lhs_variable, rhs_expression)`.
64
-
65
- - `evaluate_rhs(rhs: str, grids: dict, constants: dict, grid_dx: float)`
66
- Safely evaluates the right-hand side on NumPy arrays representing fields and parameters.
67
-
68
- Supports equations such as:
69
-
70
- ```text
71
- ∂T/∂t = α ∇²T - σ T
72
- u_t = D dxx(u) + f(u)
73
- ∂φ/∂t = ∇·((1 + T²) ∇φ)
74
- ```
75
- #### 4. Secure Evaluation Environment
76
- Only a restricted set of functions and operators are exposed.
77
- No access to Python builtins, file I/O, or unsafe functions.
78
- All variables must come from:
79
- grids: NumPy arrays for fields (u, T, phi, etc.)
80
- constants: scalar parameters (alpha, beta, lambda, etc.)
81
- #### 5. Coordinate-Aware PDEs
82
- The evaluator automatically provides spatial coordinate grids:
83
- x, z as NumPy arrays derived from grid shape and spacing.
84
- This enables anisotropic and spatially varying coefficients such as:
85
- ``` α x dxx(T) + α z dzz(T)```
86
- Typical Use:
87
-
88
- ```text
89
- from pde import parse_pde, evaluate_rhs
90
-
91
- lhs, rhs = parse_pde("∂T/∂t = α ∇²T - σ T")
92
-
93
- result = evaluate_rhs(
94
- rhs,
95
- grids={"T": T_grid},
96
- constants={"alpha": 0.1, "sigma": 0.01},
97
- grid_dx=0.01
98
- )
99
- ```
100
-
101
- #### 6. Purpose
102
- This project is intended as a safe mathematical expression parser for:
103
- Scientific computing
104
- PDE/ODE solvers
105
- Physics and engineering simulations
106
- Educational or sandboxed equation evaluation
@@ -1,8 +0,0 @@
1
- demathpy/__init__.py,sha256=M9USmv1V8FoXhHVFtOlwO8zyEA1cafpubvBEDLQ4eXw,722
2
- demathpy/ode.py,sha256=3SgeiYbHUov9NtrKCOhCo2I4DFLLdh5iIqkhPxwt254,4188
3
- demathpy/pde.py,sha256=TjX9ICiJOO54_CPRZljRdOgMCuHwXFs-eaXDdM4O1hQ,13645
4
- demathpy/symbols.py,sha256=LwwqdmvDX_-G2T9t885sPdI4G7bSzMY6d07-uwuzyl4,11904
5
- demathpy-0.0.1.dist-info/licenses/LICENSE,sha256=Vofo4OGPZaOEnCixsvF2MaZSGdpDI4uVMm9GNEjSGBM,1064
6
- demathpy-0.0.1.dist-info/WHEEL,sha256=e_m4S054HL0hyR3CpOk-b7Q7fDX6BuFkgL5OjAExXas,80
7
- demathpy-0.0.1.dist-info/METADATA,sha256=wK14apREWoyXvKuekx-jcOahaG8gOk4IhmIdXj4P7P0,3118
8
- demathpy-0.0.1.dist-info/RECORD,,