demathpy 0.1.1__py3-none-any.whl → 0.1.2__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/ode.py +53 -3
- demathpy/pde.py +53 -2
- demathpy/symbols.py +10 -2
- {demathpy-0.1.1.dist-info → demathpy-0.1.2.dist-info}/METADATA +1 -1
- demathpy-0.1.2.dist-info/RECORD +8 -0
- {demathpy-0.1.1.dist-info → demathpy-0.1.2.dist-info}/WHEEL +1 -1
- demathpy-0.1.1.dist-info/RECORD +0 -8
- {demathpy-0.1.1.dist-info → demathpy-0.1.2.dist-info}/licenses/LICENSE +0 -0
demathpy/ode.py
CHANGED
|
@@ -20,8 +20,6 @@ def _preprocess_expr(expr: str) -> str:
|
|
|
20
20
|
expr = (expr or "").strip()
|
|
21
21
|
expr = re.sub(r"\(\s*approx\s*\)", "", expr, flags=re.IGNORECASE)
|
|
22
22
|
expr = re.sub(r"\bapprox\b", "", expr, flags=re.IGNORECASE)
|
|
23
|
-
if "=" in expr:
|
|
24
|
-
expr = expr.split("=")[-1]
|
|
25
23
|
expr = normalize_symbols(expr)
|
|
26
24
|
return expr.strip()
|
|
27
25
|
|
|
@@ -185,6 +183,52 @@ class ODE:
|
|
|
185
183
|
def pos(u): return np.maximum(u, 0.0)
|
|
186
184
|
def sign(u): return np.sign(u)
|
|
187
185
|
def step_fn(u): return np.heaviside(u, 1.0)
|
|
186
|
+
def heaviside_fn(u, h0=1.0): return np.heaviside(u, h0)
|
|
187
|
+
def clamp(u, lower, upper): return np.clip(u, lower, upper)
|
|
188
|
+
|
|
189
|
+
def elementwise_min(*values):
|
|
190
|
+
if not values:
|
|
191
|
+
raise ValueError("min requires at least one value")
|
|
192
|
+
out = values[0]
|
|
193
|
+
for value in values[1:]:
|
|
194
|
+
out = np.minimum(out, value)
|
|
195
|
+
return out
|
|
196
|
+
|
|
197
|
+
def elementwise_max(*values):
|
|
198
|
+
if not values:
|
|
199
|
+
raise ValueError("max requires at least one value")
|
|
200
|
+
out = values[0]
|
|
201
|
+
for value in values[1:]:
|
|
202
|
+
out = np.maximum(out, value)
|
|
203
|
+
return out
|
|
204
|
+
|
|
205
|
+
def piecewise(*cases):
|
|
206
|
+
if not cases:
|
|
207
|
+
raise ValueError("Piecewise requires at least one case")
|
|
208
|
+
|
|
209
|
+
# Also support numpy-style piecewise(cond, if_true, if_false).
|
|
210
|
+
if len(cases) == 3 and not isinstance(cases[0], (tuple, list)):
|
|
211
|
+
cond, if_true, if_false = cases
|
|
212
|
+
return np.where(cond, if_true, if_false)
|
|
213
|
+
|
|
214
|
+
condlist = []
|
|
215
|
+
choicelist = []
|
|
216
|
+
default = 0.0
|
|
217
|
+
|
|
218
|
+
for case in cases:
|
|
219
|
+
if not isinstance(case, (tuple, list)) or len(case) != 2:
|
|
220
|
+
raise ValueError("Piecewise cases must be (expr, condition) pairs")
|
|
221
|
+
expr, cond = case
|
|
222
|
+
if isinstance(cond, (bool, np.bool_)):
|
|
223
|
+
if bool(cond):
|
|
224
|
+
default = expr
|
|
225
|
+
continue
|
|
226
|
+
condlist.append(cond)
|
|
227
|
+
choicelist.append(expr)
|
|
228
|
+
|
|
229
|
+
if not condlist:
|
|
230
|
+
return np.asarray(default)
|
|
231
|
+
return np.select(condlist, choicelist, default=default)
|
|
188
232
|
|
|
189
233
|
env = {
|
|
190
234
|
"np": np,
|
|
@@ -194,7 +238,13 @@ class ODE:
|
|
|
194
238
|
"log": np.log, "log10": np.log10, "log2": np.log2,
|
|
195
239
|
"exp": np.exp, "sqrt": np.sqrt, "abs": np.abs,
|
|
196
240
|
"pi": np.pi, "inf": np.inf,
|
|
197
|
-
"pos": pos, "sign": sign, "step": step_fn
|
|
241
|
+
"pos": pos, "sign": sign, "step": step_fn,
|
|
242
|
+
"heaviside": heaviside_fn, "Heaviside": heaviside_fn,
|
|
243
|
+
"clamp": clamp, "clip": np.clip,
|
|
244
|
+
"where": np.where,
|
|
245
|
+
"min": elementwise_min, "max": elementwise_max,
|
|
246
|
+
"minimum": np.minimum, "maximum": np.maximum,
|
|
247
|
+
"piecewise": piecewise, "Piecewise": piecewise,
|
|
198
248
|
}
|
|
199
249
|
|
|
200
250
|
env.update(self.external_variables)
|
demathpy/pde.py
CHANGED
|
@@ -20,8 +20,6 @@ def _preprocess_expr(expr: str) -> str:
|
|
|
20
20
|
expr = (expr or "").strip()
|
|
21
21
|
expr = re.sub(r"\(\s*approx\s*\)", "", expr, flags=re.IGNORECASE)
|
|
22
22
|
expr = re.sub(r"\bapprox\b", "", expr, flags=re.IGNORECASE)
|
|
23
|
-
if "=" in expr:
|
|
24
|
-
expr = expr.split("=")[-1]
|
|
25
23
|
expr = normalize_symbols(expr)
|
|
26
24
|
return expr.strip()
|
|
27
25
|
|
|
@@ -651,6 +649,53 @@ class PDE:
|
|
|
651
649
|
def pos(u): return np.maximum(u, 0.0)
|
|
652
650
|
def sech(u): return 1.0 / np.cosh(u)
|
|
653
651
|
def sign(u): return np.sign(u)
|
|
652
|
+
def step_fn(u): return np.heaviside(u, 1.0)
|
|
653
|
+
def heaviside_fn(u, h0=1.0): return np.heaviside(u, h0)
|
|
654
|
+
def clamp(u, lower, upper): return np.clip(u, lower, upper)
|
|
655
|
+
|
|
656
|
+
def elementwise_min(*values):
|
|
657
|
+
if not values:
|
|
658
|
+
raise ValueError("min requires at least one value")
|
|
659
|
+
out = values[0]
|
|
660
|
+
for value in values[1:]:
|
|
661
|
+
out = np.minimum(out, value)
|
|
662
|
+
return out
|
|
663
|
+
|
|
664
|
+
def elementwise_max(*values):
|
|
665
|
+
if not values:
|
|
666
|
+
raise ValueError("max requires at least one value")
|
|
667
|
+
out = values[0]
|
|
668
|
+
for value in values[1:]:
|
|
669
|
+
out = np.maximum(out, value)
|
|
670
|
+
return out
|
|
671
|
+
|
|
672
|
+
def piecewise(*cases):
|
|
673
|
+
if not cases:
|
|
674
|
+
raise ValueError("Piecewise requires at least one case")
|
|
675
|
+
|
|
676
|
+
# Also support numpy-style piecewise(cond, if_true, if_false).
|
|
677
|
+
if len(cases) == 3 and not isinstance(cases[0], (tuple, list)):
|
|
678
|
+
cond, if_true, if_false = cases
|
|
679
|
+
return np.where(cond, if_true, if_false)
|
|
680
|
+
|
|
681
|
+
condlist = []
|
|
682
|
+
choicelist = []
|
|
683
|
+
default = 0.0
|
|
684
|
+
|
|
685
|
+
for case in cases:
|
|
686
|
+
if not isinstance(case, (tuple, list)) or len(case) != 2:
|
|
687
|
+
raise ValueError("Piecewise cases must be (expr, condition) pairs")
|
|
688
|
+
expr, cond = case
|
|
689
|
+
if isinstance(cond, (bool, np.bool_)):
|
|
690
|
+
if bool(cond):
|
|
691
|
+
default = expr
|
|
692
|
+
continue
|
|
693
|
+
condlist.append(cond)
|
|
694
|
+
choicelist.append(expr)
|
|
695
|
+
|
|
696
|
+
if not condlist:
|
|
697
|
+
return np.asarray(default)
|
|
698
|
+
return np.select(condlist, choicelist, default=default)
|
|
654
699
|
|
|
655
700
|
env = {
|
|
656
701
|
"np": np,
|
|
@@ -666,6 +711,12 @@ class PDE:
|
|
|
666
711
|
"gradmag": gradmag, "gradl1": gradl1,
|
|
667
712
|
"grad": grad, "div": div, "advect": advect,
|
|
668
713
|
"pos": pos, "sech": sech, "sign": sign,
|
|
714
|
+
"step": step_fn, "heaviside": heaviside_fn, "Heaviside": heaviside_fn,
|
|
715
|
+
"clamp": clamp, "clip": np.clip,
|
|
716
|
+
"where": np.where,
|
|
717
|
+
"min": elementwise_min, "max": elementwise_max,
|
|
718
|
+
"minimum": np.minimum, "maximum": np.maximum,
|
|
719
|
+
"piecewise": piecewise, "Piecewise": piecewise,
|
|
669
720
|
}
|
|
670
721
|
|
|
671
722
|
env.update(self.external_variables)
|
demathpy/symbols.py
CHANGED
|
@@ -377,13 +377,17 @@ def normalize_symbols(expr: str) -> str:
|
|
|
377
377
|
expr = re.sub(r"(\))\s*([a-zA-Z_])", r"\1*\2", expr)
|
|
378
378
|
# Symbol followed by operator function: eta lap(u) -> eta*lap(u)
|
|
379
379
|
expr = re.sub(
|
|
380
|
-
r"([a-zA-Z_][a-zA-Z0-9_]*)\s*(lap|grad|div|dx|dz|dxx|dzz|pos|gradl1|gradmag)\s*\(",
|
|
380
|
+
r"([a-zA-Z_][a-zA-Z0-9_]*)\s*(lap|grad|div|dx|dz|dxx|dzz|pos|gradl1|gradmag|clamp|clip|piecewise|Piecewise|min|max|minimum|maximum|where)\s*\(",
|
|
381
381
|
r"\1*\2(",
|
|
382
382
|
expr,
|
|
383
383
|
)
|
|
384
384
|
|
|
385
385
|
# Fix accidental insertions like gradl1*(u) -> gradl1(u)
|
|
386
|
-
expr = re.sub(
|
|
386
|
+
expr = re.sub(
|
|
387
|
+
r"\b(gradl1|gradmag|lap|dx|dz|dxx|dzz|grad|div|pos|clamp|clip|piecewise|Piecewise|min|max|minimum|maximum|where)\s*\*\s*\(",
|
|
388
|
+
r"\1(",
|
|
389
|
+
expr,
|
|
390
|
+
)
|
|
387
391
|
# Avoid inserting * for known functions
|
|
388
392
|
def _fn_mul(match):
|
|
389
393
|
name = match.group(1)
|
|
@@ -395,6 +399,10 @@ def normalize_symbols(expr: str) -> str:
|
|
|
395
399
|
"log", "log10", "log2",
|
|
396
400
|
"abs", "sech", "sign", "step", "heaviside",
|
|
397
401
|
"lap", "dx", "dz", "dxx", "dzz", "grad", "div", "advect", "gradmag", "gradl1", "pos",
|
|
402
|
+
"clamp", "clip", "where",
|
|
403
|
+
"piecewise", "Piecewise",
|
|
404
|
+
"min", "max", "minimum", "maximum",
|
|
405
|
+
"Heaviside",
|
|
398
406
|
}:
|
|
399
407
|
return f"{name}("
|
|
400
408
|
return f"{name}*("
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
demathpy/__init__.py,sha256=gtvKvQKWns_OkAb9uyPmX8jIys0o62ccE_lMbi1_YQE,404
|
|
2
|
+
demathpy/ode.py,sha256=AKjNMWCQxKVCuT3f2Zl3x7ZfD0Aem-Rvw9TaNvwHq4Y,14875
|
|
3
|
+
demathpy/pde.py,sha256=pEVdtLXIMa14Vs89bCCg26k7CsJgXrWCJAM9L_i-Y-Q,33862
|
|
4
|
+
demathpy/symbols.py,sha256=XDCsyDg_fs1kgt5dRnme0UdWXH8e0_vL1t0Y0gY-rLc,14078
|
|
5
|
+
demathpy-0.1.2.dist-info/licenses/LICENSE,sha256=Vofo4OGPZaOEnCixsvF2MaZSGdpDI4uVMm9GNEjSGBM,1064
|
|
6
|
+
demathpy-0.1.2.dist-info/WHEEL,sha256=iHtWm8nRfs0VRdCYVXocAWFW8ppjHL-uTJkAdZJKOBM,80
|
|
7
|
+
demathpy-0.1.2.dist-info/METADATA,sha256=0gxgIbQjsd3mTT80W--tGyz9m5bbqt0jvw34KEdDdGY,6574
|
|
8
|
+
demathpy-0.1.2.dist-info/RECORD,,
|
demathpy-0.1.1.dist-info/RECORD
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
demathpy/__init__.py,sha256=gtvKvQKWns_OkAb9uyPmX8jIys0o62ccE_lMbi1_YQE,404
|
|
2
|
-
demathpy/ode.py,sha256=BTAqBdLP3otNi0zjOKA5eEGrJWlP0rK8n2uuYE8wGIk,12869
|
|
3
|
-
demathpy/pde.py,sha256=v8tMQGKyelmYaQI4mMJmge4WW8KK6NGTCmZlmZ8XI-I,31788
|
|
4
|
-
demathpy/symbols.py,sha256=ZJDL31vo8Ei3_MsffAO0efJsBaVMzgyGFv1Vva4iceg,13776
|
|
5
|
-
demathpy-0.1.1.dist-info/licenses/LICENSE,sha256=Vofo4OGPZaOEnCixsvF2MaZSGdpDI4uVMm9GNEjSGBM,1064
|
|
6
|
-
demathpy-0.1.1.dist-info/WHEEL,sha256=5DEXXimM34_d4Gx1AuF9ysMr1_maoEtGKjaILM3s4w4,80
|
|
7
|
-
demathpy-0.1.1.dist-info/METADATA,sha256=imE4ZojXX-L91VXpFdC-8AyPOXu01SLinC9ayHxD5dk,6574
|
|
8
|
-
demathpy-0.1.1.dist-info/RECORD,,
|
|
File without changes
|