mathjson-solver 1.13.0__tar.gz → 1.15.0__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.
- mathjson_solver-1.15.0/PKG-INFO +166 -0
- mathjson_solver-1.15.0/README.md +141 -0
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/setup.cfg +1 -1
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/setup.py +1 -1
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/src/mathjson_solver/__main__.py +211 -11
- mathjson_solver-1.15.0/src/mathjson_solver.egg-info/PKG-INFO +166 -0
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/tests/test_with_pytest.py +232 -9
- mathjson_solver-1.13.0/PKG-INFO +0 -83
- mathjson_solver-1.13.0/README.md +0 -59
- mathjson_solver-1.13.0/src/mathjson_solver.egg-info/PKG-INFO +0 -83
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/LICENSE +0 -0
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/pyproject.toml +0 -0
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/src/mathjson_solver/__init__.py +0 -0
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/src/mathjson_solver.egg-info/SOURCES.txt +0 -0
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/src/mathjson_solver.egg-info/dependency_links.txt +0 -0
- {mathjson_solver-1.13.0 → mathjson_solver-1.15.0}/src/mathjson_solver.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mathjson-solver
|
|
3
|
+
Version: 1.15.0
|
|
4
|
+
Summary: Utilities for MathJSON evaluation
|
|
5
|
+
Home-page: https://github.com/LongenesisLtd/mathjson-solver
|
|
6
|
+
Author: Martins Mednis
|
|
7
|
+
Author-email: mrt@mednis.info
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.6
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
Dynamic: project-url
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
Dynamic: summary
|
|
25
|
+
|
|
26
|
+
# MathJSON Solver
|
|
27
|
+
|
|
28
|
+
[](https://pypi.org/project/mathjson-solver/)
|
|
29
|
+
[](https://pepy.tech/projects/mathjson-solver)
|
|
30
|
+
[](https://www.python.org/downloads/)
|
|
31
|
+
|
|
32
|
+
A reliable Python library for numerically evaluating mathematical expressions in MathJSON format. Perfect for applications that need to safely execute user-provided formulas, calculate dynamic equations, or process mathematical data.
|
|
33
|
+
|
|
34
|
+
**What is MathJSON?** MathJSON represents mathematical expressions as JSON arrays, like `["Add", 1, 2, 3]` for 1+2+3. This format is safe, structured, and easy to generate programmatically.
|
|
35
|
+
|
|
36
|
+
Inspired by [CortexJS Compute Engine](https://cortexjs.io/compute-engine/) though designed as an independent implementation focused on our specific use cases.
|
|
37
|
+
|
|
38
|
+
## Table of Contents
|
|
39
|
+
- [Installation](#installation)
|
|
40
|
+
- [Quick Start](#quick-start)
|
|
41
|
+
- [Supported Operations](#supported-operations)
|
|
42
|
+
- [Error Handling](#error-handling)
|
|
43
|
+
- [Use Cases](#use-cases)
|
|
44
|
+
- [Testing](#testing)
|
|
45
|
+
- [Community](#community)
|
|
46
|
+
- [Contributing](#contributing)
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install mathjson-solver
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Requirements:** Python 3.7+
|
|
55
|
+
|
|
56
|
+
**Optional:** numpy (only required for `TrapezoidalIntegrate` function)
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from mathjson_solver import create_solver, MathJSONException
|
|
62
|
+
|
|
63
|
+
# Define variables and create solver
|
|
64
|
+
parameters = {"x": 2, "y": 3}
|
|
65
|
+
solver = create_solver(parameters)
|
|
66
|
+
|
|
67
|
+
# Evaluate expressions
|
|
68
|
+
basic_math = solver(["Add", "x", "y", 4])
|
|
69
|
+
print(basic_math) # 9 (because 2+3+4=9)
|
|
70
|
+
|
|
71
|
+
# More complex expressions
|
|
72
|
+
result = solver(["Multiply", ["Add", "x", 1], ["Subtract", "y", 1]])
|
|
73
|
+
print(result) # 6 (because (2+1) * (3-1) = 6)
|
|
74
|
+
|
|
75
|
+
# Handle errors gracefully
|
|
76
|
+
try:
|
|
77
|
+
solver(["Divide", 1, 0])
|
|
78
|
+
except MathJSONException as e:
|
|
79
|
+
print(f"Math error: {e}")
|
|
80
|
+
# Math error: Problem in Divide. ['Divide', 1, 0]. division by zero
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Supported Operations
|
|
84
|
+
|
|
85
|
+
The library supports a comprehensive set of mathematical operations:
|
|
86
|
+
|
|
87
|
+
* **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round
|
|
88
|
+
* **Trigonometry:** Sin, Cos, Tan, Arcsin, Arccos, Arctan
|
|
89
|
+
* **Logarithms:** Log, Log2, Log10, Exp
|
|
90
|
+
* **Comparison:** Equal, StrictEqual, NotEqual, Greater, GreaterEqual, Less, LessEqual
|
|
91
|
+
* **Logic & Sets:** Any, All, Not, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
|
|
92
|
+
* **Statistics:** Average, Max, Min, Median, Length
|
|
93
|
+
* **Arrays:** Array creation and manipulation with Map function
|
|
94
|
+
* **Control Flow:** If statements, Switch-Case, Constants definition
|
|
95
|
+
* **Type Conversion:** Int, Float, Str, IsDefined
|
|
96
|
+
* **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions
|
|
97
|
+
* **Advanced:** HasMatchingSublist, TrapezoidalIntegrate (requires numpy), Variable references
|
|
98
|
+
* **Constants:** Pi
|
|
99
|
+
|
|
100
|
+
[View complete documentation with examples →](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md)
|
|
101
|
+
|
|
102
|
+
## Error Handling
|
|
103
|
+
|
|
104
|
+
MathJSON Solver raises `MathJSONException` for invalid expressions or mathematical errors:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from mathjson_solver import create_solver, MathJSONException
|
|
108
|
+
|
|
109
|
+
solver = create_solver({})
|
|
110
|
+
|
|
111
|
+
# Handle specific math errors
|
|
112
|
+
try:
|
|
113
|
+
result = solver(["Sqrt", -1]) # Invalid: square root of negative
|
|
114
|
+
except MathJSONException as e:
|
|
115
|
+
print(f"Cannot evaluate: {e}")
|
|
116
|
+
|
|
117
|
+
# Handle malformed expressions
|
|
118
|
+
try:
|
|
119
|
+
result = solver(["UnknownFunction", 1, 2])
|
|
120
|
+
except MathJSONException as e:
|
|
121
|
+
print(f"Unsupported operation: {e}")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Use Cases
|
|
125
|
+
|
|
126
|
+
* **Dynamic Formulas:** Let users create custom calculations in web applications
|
|
127
|
+
* **Scientific Computing:** Evaluate mathematical models with variable parameters
|
|
128
|
+
* **Business Logic:** Process complex pricing rules or scoring algorithms
|
|
129
|
+
* **Data Processing:** Apply mathematical transformations to datasets
|
|
130
|
+
* **Health Applications:** Calculate medical scores, dosages, or risk assessments
|
|
131
|
+
|
|
132
|
+
## Testing
|
|
133
|
+
|
|
134
|
+
Install development dependencies and run tests:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Install pytest if not already installed
|
|
138
|
+
pip install pytest
|
|
139
|
+
|
|
140
|
+
# Run tests from project directory
|
|
141
|
+
pytest
|
|
142
|
+
|
|
143
|
+
# Run with coverage
|
|
144
|
+
pytest --cov=mathjson_solver
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Community
|
|
148
|
+
|
|
149
|
+
- **Questions & Discussion:** [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
150
|
+
- **Bug Reports & Feature Requests:** [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
151
|
+
- **Documentation:** [Complete Function Reference](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md)
|
|
152
|
+
|
|
153
|
+
## Contributing
|
|
154
|
+
|
|
155
|
+
We welcome contributions! Please feel free to:
|
|
156
|
+
- Report bugs or request features via [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
157
|
+
- Submit pull requests with improvements
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
[View license information](https://github.com/LongenesisLtd/mathjson-solver/blob/main/LICENSE)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
Made with ❤️ by [Longenesis](https://longenesis.com/team)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# MathJSON Solver
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/mathjson-solver/)
|
|
4
|
+
[](https://pepy.tech/projects/mathjson-solver)
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
|
|
7
|
+
A reliable Python library for numerically evaluating mathematical expressions in MathJSON format. Perfect for applications that need to safely execute user-provided formulas, calculate dynamic equations, or process mathematical data.
|
|
8
|
+
|
|
9
|
+
**What is MathJSON?** MathJSON represents mathematical expressions as JSON arrays, like `["Add", 1, 2, 3]` for 1+2+3. This format is safe, structured, and easy to generate programmatically.
|
|
10
|
+
|
|
11
|
+
Inspired by [CortexJS Compute Engine](https://cortexjs.io/compute-engine/) though designed as an independent implementation focused on our specific use cases.
|
|
12
|
+
|
|
13
|
+
## Table of Contents
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Quick Start](#quick-start)
|
|
16
|
+
- [Supported Operations](#supported-operations)
|
|
17
|
+
- [Error Handling](#error-handling)
|
|
18
|
+
- [Use Cases](#use-cases)
|
|
19
|
+
- [Testing](#testing)
|
|
20
|
+
- [Community](#community)
|
|
21
|
+
- [Contributing](#contributing)
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install mathjson-solver
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Requirements:** Python 3.7+
|
|
30
|
+
|
|
31
|
+
**Optional:** numpy (only required for `TrapezoidalIntegrate` function)
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from mathjson_solver import create_solver, MathJSONException
|
|
37
|
+
|
|
38
|
+
# Define variables and create solver
|
|
39
|
+
parameters = {"x": 2, "y": 3}
|
|
40
|
+
solver = create_solver(parameters)
|
|
41
|
+
|
|
42
|
+
# Evaluate expressions
|
|
43
|
+
basic_math = solver(["Add", "x", "y", 4])
|
|
44
|
+
print(basic_math) # 9 (because 2+3+4=9)
|
|
45
|
+
|
|
46
|
+
# More complex expressions
|
|
47
|
+
result = solver(["Multiply", ["Add", "x", 1], ["Subtract", "y", 1]])
|
|
48
|
+
print(result) # 6 (because (2+1) * (3-1) = 6)
|
|
49
|
+
|
|
50
|
+
# Handle errors gracefully
|
|
51
|
+
try:
|
|
52
|
+
solver(["Divide", 1, 0])
|
|
53
|
+
except MathJSONException as e:
|
|
54
|
+
print(f"Math error: {e}")
|
|
55
|
+
# Math error: Problem in Divide. ['Divide', 1, 0]. division by zero
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Supported Operations
|
|
59
|
+
|
|
60
|
+
The library supports a comprehensive set of mathematical operations:
|
|
61
|
+
|
|
62
|
+
* **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round
|
|
63
|
+
* **Trigonometry:** Sin, Cos, Tan, Arcsin, Arccos, Arctan
|
|
64
|
+
* **Logarithms:** Log, Log2, Log10, Exp
|
|
65
|
+
* **Comparison:** Equal, StrictEqual, NotEqual, Greater, GreaterEqual, Less, LessEqual
|
|
66
|
+
* **Logic & Sets:** Any, All, Not, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
|
|
67
|
+
* **Statistics:** Average, Max, Min, Median, Length
|
|
68
|
+
* **Arrays:** Array creation and manipulation with Map function
|
|
69
|
+
* **Control Flow:** If statements, Switch-Case, Constants definition
|
|
70
|
+
* **Type Conversion:** Int, Float, Str, IsDefined
|
|
71
|
+
* **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions
|
|
72
|
+
* **Advanced:** HasMatchingSublist, TrapezoidalIntegrate (requires numpy), Variable references
|
|
73
|
+
* **Constants:** Pi
|
|
74
|
+
|
|
75
|
+
[View complete documentation with examples →](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md)
|
|
76
|
+
|
|
77
|
+
## Error Handling
|
|
78
|
+
|
|
79
|
+
MathJSON Solver raises `MathJSONException` for invalid expressions or mathematical errors:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from mathjson_solver import create_solver, MathJSONException
|
|
83
|
+
|
|
84
|
+
solver = create_solver({})
|
|
85
|
+
|
|
86
|
+
# Handle specific math errors
|
|
87
|
+
try:
|
|
88
|
+
result = solver(["Sqrt", -1]) # Invalid: square root of negative
|
|
89
|
+
except MathJSONException as e:
|
|
90
|
+
print(f"Cannot evaluate: {e}")
|
|
91
|
+
|
|
92
|
+
# Handle malformed expressions
|
|
93
|
+
try:
|
|
94
|
+
result = solver(["UnknownFunction", 1, 2])
|
|
95
|
+
except MathJSONException as e:
|
|
96
|
+
print(f"Unsupported operation: {e}")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Use Cases
|
|
100
|
+
|
|
101
|
+
* **Dynamic Formulas:** Let users create custom calculations in web applications
|
|
102
|
+
* **Scientific Computing:** Evaluate mathematical models with variable parameters
|
|
103
|
+
* **Business Logic:** Process complex pricing rules or scoring algorithms
|
|
104
|
+
* **Data Processing:** Apply mathematical transformations to datasets
|
|
105
|
+
* **Health Applications:** Calculate medical scores, dosages, or risk assessments
|
|
106
|
+
|
|
107
|
+
## Testing
|
|
108
|
+
|
|
109
|
+
Install development dependencies and run tests:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Install pytest if not already installed
|
|
113
|
+
pip install pytest
|
|
114
|
+
|
|
115
|
+
# Run tests from project directory
|
|
116
|
+
pytest
|
|
117
|
+
|
|
118
|
+
# Run with coverage
|
|
119
|
+
pytest --cov=mathjson_solver
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Community
|
|
123
|
+
|
|
124
|
+
- **Questions & Discussion:** [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
125
|
+
- **Bug Reports & Feature Requests:** [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
126
|
+
- **Documentation:** [Complete Function Reference](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md)
|
|
127
|
+
|
|
128
|
+
## Contributing
|
|
129
|
+
|
|
130
|
+
We welcome contributions! Please feel free to:
|
|
131
|
+
- Report bugs or request features via [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
132
|
+
- Submit pull requests with improvements
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
[View license information](https://github.com/LongenesisLtd/mathjson-solver/blob/main/LICENSE)
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
Made with ❤️ by [Longenesis](https://longenesis.com/team)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import numbers
|
|
2
|
-
from typing import Union
|
|
2
|
+
from typing import Union, Any
|
|
3
3
|
from functools import reduce
|
|
4
4
|
import math
|
|
5
5
|
from copy import deepcopy
|
|
@@ -8,6 +8,14 @@ import logging
|
|
|
8
8
|
import traceback
|
|
9
9
|
import datetime
|
|
10
10
|
|
|
11
|
+
NUMPY_AVAILABLE = False
|
|
12
|
+
try:
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
NUMPY_AVAILABLE = True
|
|
16
|
+
except ImportError:
|
|
17
|
+
pass
|
|
18
|
+
|
|
11
19
|
NoneType = type(None)
|
|
12
20
|
|
|
13
21
|
|
|
@@ -46,6 +54,8 @@ def is_numeric(x):
|
|
|
46
54
|
float(x)
|
|
47
55
|
except ValueError:
|
|
48
56
|
return False
|
|
57
|
+
except TypeError:
|
|
58
|
+
return False
|
|
49
59
|
else:
|
|
50
60
|
return True
|
|
51
61
|
|
|
@@ -141,6 +151,16 @@ def comparison_safe_converter(x):
|
|
|
141
151
|
return x
|
|
142
152
|
|
|
143
153
|
|
|
154
|
+
def comparison_safe_converter_for_pairs(
|
|
155
|
+
v1, v2
|
|
156
|
+
) -> (Union[str, float], Union[str, float]):
|
|
157
|
+
if is_numeric(v1):
|
|
158
|
+
v1 = float(v1)
|
|
159
|
+
if is_numeric(v2):
|
|
160
|
+
v2 = float(v2)
|
|
161
|
+
return v1, v2
|
|
162
|
+
|
|
163
|
+
|
|
144
164
|
def create_mathjson_solver(solver_parameters):
|
|
145
165
|
def f(s, *args):
|
|
146
166
|
if args:
|
|
@@ -160,10 +180,15 @@ def create_mathjson_solver(solver_parameters):
|
|
|
160
180
|
tmp = 0
|
|
161
181
|
for i, x in enumerate(s[1:]):
|
|
162
182
|
res = f(x, c)
|
|
183
|
+
if is_numeric(res):
|
|
184
|
+
res = float(res)
|
|
163
185
|
if i == 0:
|
|
164
186
|
tmp = res
|
|
165
187
|
else:
|
|
166
|
-
|
|
188
|
+
try:
|
|
189
|
+
tmp = tmp + res
|
|
190
|
+
except TypeError:
|
|
191
|
+
pass
|
|
167
192
|
|
|
168
193
|
# if isinstance(res, list):
|
|
169
194
|
# l_res.append(sum([xx for xx in res[1:]]))
|
|
@@ -180,15 +205,25 @@ def create_mathjson_solver(solver_parameters):
|
|
|
180
205
|
# tmp = tmp + x
|
|
181
206
|
# return tmp
|
|
182
207
|
|
|
208
|
+
# def Sum(s):
|
|
209
|
+
# l_res = []
|
|
210
|
+
# for x in s[1:]:
|
|
211
|
+
# res = f(x, c)
|
|
212
|
+
# if isinstance(res, list):
|
|
213
|
+
# l_res.append(sum([xx for xx in res[1:]]))
|
|
214
|
+
# else:
|
|
215
|
+
# l_res.append(res)
|
|
216
|
+
# return sum(l_res)
|
|
217
|
+
|
|
183
218
|
def Sum(s):
|
|
184
|
-
l_res = []
|
|
219
|
+
l_res = ["Array"]
|
|
185
220
|
for x in s[1:]:
|
|
186
221
|
res = f(x, c)
|
|
187
222
|
if isinstance(res, list):
|
|
188
|
-
l_res.append(
|
|
223
|
+
l_res.append(Add(["Array"] + [xx for xx in res[1:]]))
|
|
189
224
|
else:
|
|
190
225
|
l_res.append(res)
|
|
191
|
-
return
|
|
226
|
+
return Add(l_res)
|
|
192
227
|
|
|
193
228
|
def Max(s):
|
|
194
229
|
if isinstance(s[1], str):
|
|
@@ -222,7 +257,6 @@ def create_mathjson_solver(solver_parameters):
|
|
|
222
257
|
|
|
223
258
|
def Length(s):
|
|
224
259
|
if isinstance(s[1], str):
|
|
225
|
-
|
|
226
260
|
return len([x for x in f(s[1], c)][1:])
|
|
227
261
|
else:
|
|
228
262
|
return len([x for x in s[1][1:]])
|
|
@@ -352,6 +386,24 @@ def create_mathjson_solver(solver_parameters):
|
|
|
352
386
|
return not f(s[1])
|
|
353
387
|
|
|
354
388
|
def Map(s):
|
|
389
|
+
"""
|
|
390
|
+
["Map", list, function, more parameters]
|
|
391
|
+
The `function` must accept at least one parameter. That is for the current loop element.
|
|
392
|
+
The `more parameters` are for any additional parameters that function might have.
|
|
393
|
+
"""
|
|
394
|
+
z = f(s[1], c)
|
|
395
|
+
if isinstance(z, list):
|
|
396
|
+
retlist = ["Array"]
|
|
397
|
+
for x in z[1:]:
|
|
398
|
+
try:
|
|
399
|
+
the_function_name = s[2][0]
|
|
400
|
+
ss = [the_function_name, x] + s[3:]
|
|
401
|
+
retlist.append(f(ss, c))
|
|
402
|
+
except MathJSONException:
|
|
403
|
+
retlist.append(x)
|
|
404
|
+
return retlist
|
|
405
|
+
|
|
406
|
+
def StrictMap(s):
|
|
355
407
|
"""
|
|
356
408
|
["Map", list, function, more parameters]
|
|
357
409
|
The `function` must accept at least one parameter. That is for the current loop element.
|
|
@@ -366,6 +418,22 @@ def create_mathjson_solver(solver_parameters):
|
|
|
366
418
|
retlist.append(f(ss, c))
|
|
367
419
|
return retlist
|
|
368
420
|
|
|
421
|
+
def Filter(s):
|
|
422
|
+
"""
|
|
423
|
+
["Filter", list, function, more parameters]
|
|
424
|
+
The `function` must accept at least one parameter. That is for the current loop element.
|
|
425
|
+
The `more parameters` are for any additional parameters that function might have.
|
|
426
|
+
"""
|
|
427
|
+
z = f(s[1], c)
|
|
428
|
+
if isinstance(z, list):
|
|
429
|
+
retlist = ["Array"]
|
|
430
|
+
for x in z[1:]:
|
|
431
|
+
the_function_name = s[2][0]
|
|
432
|
+
ss = [the_function_name, x] + s[3:]
|
|
433
|
+
if f(ss, c):
|
|
434
|
+
retlist.append(x)
|
|
435
|
+
return retlist
|
|
436
|
+
|
|
369
437
|
def HasMatchingSublist(s):
|
|
370
438
|
"""
|
|
371
439
|
["HasMatchingSublist", list, required_match_count, position, contiguous, function, more parameters]
|
|
@@ -438,6 +506,108 @@ def create_mathjson_solver(solver_parameters):
|
|
|
438
506
|
# Todo: This does not work
|
|
439
507
|
return s[1] in c.keys()
|
|
440
508
|
|
|
509
|
+
def Greater(s):
|
|
510
|
+
v1, v2 = comparison_safe_converter_for_pairs(f(s[1], c), f(s[2], c))
|
|
511
|
+
try:
|
|
512
|
+
return v1 > v2
|
|
513
|
+
except TypeError:
|
|
514
|
+
return False
|
|
515
|
+
|
|
516
|
+
def GreaterEqual(s):
|
|
517
|
+
v1, v2 = comparison_safe_converter_for_pairs(f(s[1], c), f(s[2], c))
|
|
518
|
+
try:
|
|
519
|
+
return v1 >= v2
|
|
520
|
+
except TypeError:
|
|
521
|
+
return False
|
|
522
|
+
|
|
523
|
+
def Less(s):
|
|
524
|
+
v1, v2 = comparison_safe_converter_for_pairs(f(s[1], c), f(s[2], c))
|
|
525
|
+
try:
|
|
526
|
+
return v1 < v2
|
|
527
|
+
except TypeError:
|
|
528
|
+
return False
|
|
529
|
+
|
|
530
|
+
def LessEqual(s):
|
|
531
|
+
v1, v2 = comparison_safe_converter_for_pairs(f(s[1], c), f(s[2], c))
|
|
532
|
+
try:
|
|
533
|
+
return v1 <= v2
|
|
534
|
+
except TypeError:
|
|
535
|
+
return False
|
|
536
|
+
|
|
537
|
+
# sin, cos, tan, arcsin, arccos, arctan
|
|
538
|
+
def Sin(s):
|
|
539
|
+
return math.sin(f(s[1], c))
|
|
540
|
+
|
|
541
|
+
def Arcsin(s):
|
|
542
|
+
return math.asin(f(s[1], c))
|
|
543
|
+
|
|
544
|
+
def Cos(s):
|
|
545
|
+
return math.cos(f(s[1], c))
|
|
546
|
+
|
|
547
|
+
def Arccos(s):
|
|
548
|
+
return math.acos(f(s[1], c))
|
|
549
|
+
|
|
550
|
+
def Tan(s):
|
|
551
|
+
return math.tan(f(s[1], c))
|
|
552
|
+
|
|
553
|
+
def Arctan(s):
|
|
554
|
+
return math.atan(f(s[1], c))
|
|
555
|
+
|
|
556
|
+
def Pi(s):
|
|
557
|
+
return math.pi
|
|
558
|
+
|
|
559
|
+
def Variable(s):
|
|
560
|
+
"""
|
|
561
|
+
["Variable", variable_name]
|
|
562
|
+
The `variable_name` must be a string.
|
|
563
|
+
"""
|
|
564
|
+
variable_name = s[1]
|
|
565
|
+
if variable_name in c:
|
|
566
|
+
return f(c[variable_name], c)
|
|
567
|
+
else:
|
|
568
|
+
raise KeyError(f"Variable '{variable_name}' is not defined")
|
|
569
|
+
|
|
570
|
+
def Function(s):
|
|
571
|
+
"""
|
|
572
|
+
["Function", function_expression, parameters]
|
|
573
|
+
The `function_name` must be a callable function.
|
|
574
|
+
The `parameters` are the arguments to be passed to the function.
|
|
575
|
+
"""
|
|
576
|
+
function_expression = s[1]
|
|
577
|
+
arguments = s[2:]
|
|
578
|
+
return 0
|
|
579
|
+
# return f(function_expression, c) function_name(*parameters)
|
|
580
|
+
|
|
581
|
+
def TrapezoidalIntegrate(s):
|
|
582
|
+
"""
|
|
583
|
+
["TrapezoidalIntegrate", function_expression, start, end, n, variable]
|
|
584
|
+
"""
|
|
585
|
+
if not NUMPY_AVAILABLE:
|
|
586
|
+
raise ImportError(
|
|
587
|
+
"TrapezoidalIntegrate requires 'numpy'. Install with 'pip install numpy'."
|
|
588
|
+
)
|
|
589
|
+
function_expression = s[1]
|
|
590
|
+
start = f(s[2], c)
|
|
591
|
+
end = f(s[3], c)
|
|
592
|
+
n = f(s[4], c)
|
|
593
|
+
variable = s[5]
|
|
594
|
+
|
|
595
|
+
t = np.linspace(start, end, n + 1)
|
|
596
|
+
|
|
597
|
+
# Calculate the integral using the trapezoidal rule
|
|
598
|
+
|
|
599
|
+
values = []
|
|
600
|
+
for x in t:
|
|
601
|
+
variable_name = variable[1]
|
|
602
|
+
variable_value = x
|
|
603
|
+
c[variable_name] = variable_value
|
|
604
|
+
values.append(f(function_expression, c))
|
|
605
|
+
h = (end - start) / n
|
|
606
|
+
# print("values=", values)
|
|
607
|
+
return h * (0.5 * values[0] + np.sum(values[1:-1]) + 0.5 * values[-1])
|
|
608
|
+
|
|
609
|
+
# return total_area
|
|
610
|
+
|
|
441
611
|
constructs = {
|
|
442
612
|
"Sum": Sum,
|
|
443
613
|
"Add": Add,
|
|
@@ -461,15 +631,22 @@ def create_mathjson_solver(solver_parameters):
|
|
|
461
631
|
"Log": lambda s: math.log(f(s[1], c)),
|
|
462
632
|
"Log2": lambda s: math.log2(f(s[1], c)),
|
|
463
633
|
"Log10": lambda s: math.log10(f(s[1], c)),
|
|
634
|
+
"Ln": lambda s: math.log(f(s[1], c)),
|
|
464
635
|
# "Equal": lambda s: f"{f(s[1], c)}" == f"{f(s[2], c)}",
|
|
465
636
|
"Equal": lambda s: comparison_safe_converter(f(s[1], c))
|
|
466
637
|
== comparison_safe_converter(f(s[2], c)),
|
|
467
638
|
"StrictEqual": lambda s: f(s[1], c) == f(s[2], c),
|
|
468
|
-
"Greater": lambda s: f(s[1], c) > f(s[2], c),
|
|
469
|
-
"
|
|
470
|
-
"
|
|
471
|
-
"
|
|
472
|
-
"
|
|
639
|
+
# "Greater": lambda s: f(s[1], c) > f(s[2], c),
|
|
640
|
+
"Greater": Greater,
|
|
641
|
+
# "GreaterEqual": lambda s: f(s[1], c) >= f(s[2], c),
|
|
642
|
+
"GreaterEqual": GreaterEqual,
|
|
643
|
+
# "Less": lambda s: f(s[1], c) < f(s[2], c),
|
|
644
|
+
"Less": Less,
|
|
645
|
+
# "LessEqual": lambda s: f(s[1], c) <= f(s[2], c),
|
|
646
|
+
"LessEqual": LessEqual,
|
|
647
|
+
# "NotEqual": lambda s: f(s[1], c) != f(s[2], c),
|
|
648
|
+
"NotEqual": lambda s: comparison_safe_converter(f(s[1], c))
|
|
649
|
+
!= comparison_safe_converter(f(s[2], c)),
|
|
473
650
|
"Abs": lambda s: abs(f(s[1], c)),
|
|
474
651
|
"Round": lambda s: (
|
|
475
652
|
round(f(s[1], c), f(s[2], c))
|
|
@@ -500,6 +677,8 @@ def create_mathjson_solver(solver_parameters):
|
|
|
500
677
|
# "IsDefined": lambda s: s[1] in c,
|
|
501
678
|
"IsDefined": IsDefined,
|
|
502
679
|
"Map": Map,
|
|
680
|
+
"StrictMap": StrictMap,
|
|
681
|
+
"Filter": Filter,
|
|
503
682
|
"HasMatchingSublist": HasMatchingSublist,
|
|
504
683
|
"Strptime": Strptime,
|
|
505
684
|
"Strftime": Strftime,
|
|
@@ -509,6 +688,16 @@ def create_mathjson_solver(solver_parameters):
|
|
|
509
688
|
"TimeDeltaHours": TimeDeltaHours,
|
|
510
689
|
"TimeDeltaMinutes": TimeDeltaMinutes,
|
|
511
690
|
"TimeDeltaDays": TimeDeltaDays,
|
|
691
|
+
"Function": Function,
|
|
692
|
+
"Variable": Variable,
|
|
693
|
+
"TrapezoidalIntegrate": TrapezoidalIntegrate,
|
|
694
|
+
"Sin": Sin,
|
|
695
|
+
"Cos": Cos,
|
|
696
|
+
"Tan": Tan,
|
|
697
|
+
"Arcsin": Arcsin,
|
|
698
|
+
"Arccos": Arccos,
|
|
699
|
+
"Arctan": Arctan,
|
|
700
|
+
"Pi": Pi,
|
|
512
701
|
}
|
|
513
702
|
if s[0] in constructs:
|
|
514
703
|
try:
|
|
@@ -563,6 +752,7 @@ def extract_variables(s: Union[list, int, float, str], li: set, ignore_list: set
|
|
|
563
752
|
"Log",
|
|
564
753
|
"Log2",
|
|
565
754
|
"Log10",
|
|
755
|
+
"Ln",
|
|
566
756
|
"Equal",
|
|
567
757
|
"Greater",
|
|
568
758
|
"GreaterEqual",
|
|
@@ -603,6 +793,16 @@ def extract_variables(s: Union[list, int, float, str], li: set, ignore_list: set
|
|
|
603
793
|
"TimeDeltaHours",
|
|
604
794
|
"TimeDeltaMinutes",
|
|
605
795
|
"TimeDeltaDays",
|
|
796
|
+
"Function",
|
|
797
|
+
"Variable",
|
|
798
|
+
"TrapezoidalIntegrate",
|
|
799
|
+
"Sin",
|
|
800
|
+
"Cos",
|
|
801
|
+
"Tan",
|
|
802
|
+
"Arcsin",
|
|
803
|
+
"Arccos",
|
|
804
|
+
"Arctan",
|
|
805
|
+
"Pi",
|
|
606
806
|
]
|
|
607
807
|
if isinstance(s, str):
|
|
608
808
|
if s in ignore_list:
|