mathjson-solver 1.11.0__tar.gz → 1.12.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.
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.2
2
+ Name: mathjson-solver
3
+ Version: 1.12.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: project-url
22
+ Dynamic: requires-python
23
+ Dynamic: summary
24
+
25
+ # MathJSON Solver
26
+
27
+ [![PyPI](https://img.shields.io/pypi/v/mathjson-solver.svg)](https://pypi.org/project/mathjson-solver/)
28
+ [![PyPI Downloads](https://static.pepy.tech/badge/mathjson-solver/month)](https://pepy.tech/projects/mathjson-solver)
29
+ ![Coverage](https://img.shields.io/badge/coverage-93-green)
30
+
31
+ _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions, like `["Add", 1, 2]`. It is developed by [Longenesis](https://longenesis.com/team) to enable numerical evaluation of user provided mathematical expressions in Longenesis digital health products. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
32
+
33
+ Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
34
+ [![Gitter](https://badges.gitter.im/mathjson-solver/community.svg)](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
35
+
36
+ ## How to use
37
+ ```python
38
+ from mathjson_solver import create_solver
39
+
40
+ parameters = {"x": 2, "y": 3}
41
+ expression = ["Add", "x", "y", 4]
42
+
43
+ solver = create_solver(parameters)
44
+ answer = solver(expression)
45
+
46
+ print(answer)
47
+ # 9, because 2+3+4=9
48
+ ```
49
+
50
+ ## Currently supported constructs
51
+ Find the full list of supported constructs in the [docs/README.md](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md).
52
+
53
+
54
+ ## Exception handling
55
+
56
+ A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
57
+ ```python
58
+ from mathjson_solver import create_solver, MathJSONException
59
+
60
+ solver = create_solver({})
61
+ try:
62
+ solver(["Divide", 1, 0])
63
+ except MathJSONException:
64
+ pass
65
+ # invoke your own exception logger here
66
+ ```
67
+
68
+ Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
69
+
70
+
71
+ ## How to run tests
72
+ Make sure you have `pytest` installed. Then `cd` into project directory and run:
73
+ ```bash
74
+ pytest
75
+ ```
76
+
77
+ ## Contributing Code
78
+
79
+ We welcome your contributions in the form of pull requests.
80
+
81
+ 1. Fork the repo;
82
+ 2. Make improvements;
83
+ 3. Make a pull request to share your improvements with the community and to include it into official release.
@@ -0,0 +1,59 @@
1
+ # MathJSON Solver
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/mathjson-solver.svg)](https://pypi.org/project/mathjson-solver/)
4
+ [![PyPI Downloads](https://static.pepy.tech/badge/mathjson-solver/month)](https://pepy.tech/projects/mathjson-solver)
5
+ ![Coverage](https://img.shields.io/badge/coverage-93-green)
6
+
7
+ _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions, like `["Add", 1, 2]`. It is developed by [Longenesis](https://longenesis.com/team) to enable numerical evaluation of user provided mathematical expressions in Longenesis digital health products. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
8
+
9
+ Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
10
+ [![Gitter](https://badges.gitter.im/mathjson-solver/community.svg)](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
11
+
12
+ ## How to use
13
+ ```python
14
+ from mathjson_solver import create_solver
15
+
16
+ parameters = {"x": 2, "y": 3}
17
+ expression = ["Add", "x", "y", 4]
18
+
19
+ solver = create_solver(parameters)
20
+ answer = solver(expression)
21
+
22
+ print(answer)
23
+ # 9, because 2+3+4=9
24
+ ```
25
+
26
+ ## Currently supported constructs
27
+ Find the full list of supported constructs in the [docs/README.md](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md).
28
+
29
+
30
+ ## Exception handling
31
+
32
+ A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
33
+ ```python
34
+ from mathjson_solver import create_solver, MathJSONException
35
+
36
+ solver = create_solver({})
37
+ try:
38
+ solver(["Divide", 1, 0])
39
+ except MathJSONException:
40
+ pass
41
+ # invoke your own exception logger here
42
+ ```
43
+
44
+ Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
45
+
46
+
47
+ ## How to run tests
48
+ Make sure you have `pytest` installed. Then `cd` into project directory and run:
49
+ ```bash
50
+ pytest
51
+ ```
52
+
53
+ ## Contributing Code
54
+
55
+ We welcome your contributions in the form of pull requests.
56
+
57
+ 1. Fork the repo;
58
+ 2. Make improvements;
59
+ 3. Make a pull request to share your improvements with the community and to include it into official release.
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = mathjson-solver
3
- version = 1.11.0
3
+ version = 1.12.0
4
4
  author = Martins Mednis
5
5
  author_email = mrt@mednis.info
6
6
  description = Utilities for MathJSON evaluation
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="mathjson-solver",
8
- version="1.11.0",
8
+ version="1.12.0",
9
9
  author="Martins Mednis",
10
10
  author_email="mrt@mednis.info",
11
11
  description="Utilities for MathJSON evaluation",
@@ -1,4 +1,5 @@
1
1
  import numbers
2
+ from types import NoneType
2
3
  from typing import Union
3
4
  from functools import reduce
4
5
  import math
@@ -26,17 +27,17 @@ class MathJSONException(Exception):
26
27
  return f"Problem in {self.construct}. {self.expr}. {m}"
27
28
 
28
29
 
29
- def requires_array(func):
30
- def inner1(*args, **kwargs):
31
- try:
32
- if args[0][1][0] == "Array" and len(args[0][1]) > 0:
33
- return func(*args, **kwargs)
34
- else:
35
- raise ValueError(f"'{func.__name__}' should receive a list")
36
- except TypeError:
37
- raise ValueError(f"'{func.__name__}' really should receive a list")
30
+ # def requires_array(func):
31
+ # def inner1(*args, **kwargs):
32
+ # try:
33
+ # if args[0][1][0] == "Array" and len(args[0][1]) > 0:
34
+ # return func(*args, **kwargs)
35
+ # else:
36
+ # raise ValueError(f"'{func.__name__}' should receive a list")
37
+ # except TypeError:
38
+ # raise ValueError(f"'{func.__name__}' really should receive a list")
38
39
 
39
- return inner1
40
+ # return inner1
40
41
 
41
42
 
42
43
  def is_numeric(x):
@@ -92,40 +93,51 @@ def has_matching_sublist(
92
93
  return count >= required_match_count
93
94
 
94
95
 
95
- def has_sublist2(
96
- *,
97
- my_list: list,
98
- required_match_count: int,
99
- position: int,
100
- contiguous: bool,
101
- condition: callable,
102
- ) -> bool:
103
- if contiguous:
104
- # Check for contiguous matches based on position
105
- if position == 0:
106
- # Check if the beginning of the list matches
107
- count = sum(1 for x in my_list[:required_match_count] if condition(x))
108
- return count == required_match_count
109
- elif position > 0:
110
- # Skip the first `position` elements
111
- count = sum(
112
- 1
113
- for x in my_list[position : position + required_match_count]
114
- if condition(x)
115
- )
116
- return count == required_match_count
117
- elif position == -1:
118
- # Check if the end of the list matches
119
- count = sum(1 for x in my_list[-required_match_count:] if condition(x))
120
- return count == required_match_count
121
- elif position < -1:
122
- # Skip the last `abs(position)` elements
123
- count = sum(1 for x in my_list[:position] if condition(x))
124
- return count == required_match_count
125
- else:
126
- # Check for non-contiguous matches
127
- count = sum(1 for x in my_list if condition(x))
128
- return count >= required_match_count
96
+ # def has_sublist2(
97
+ # *,
98
+ # my_list: list,
99
+ # required_match_count: int,
100
+ # position: int,
101
+ # contiguous: bool,
102
+ # condition: callable,
103
+ # ) -> bool:
104
+ # if contiguous:
105
+ # # Check for contiguous matches based on position
106
+ # if position == 0:
107
+ # # Check if the beginning of the list matches
108
+ # count = sum(1 for x in my_list[:required_match_count] if condition(x))
109
+ # return count == required_match_count
110
+ # elif position > 0:
111
+ # # Skip the first `position` elements
112
+ # count = sum(
113
+ # 1
114
+ # for x in my_list[position : position + required_match_count]
115
+ # if condition(x)
116
+ # )
117
+ # return count == required_match_count
118
+ # elif position == -1:
119
+ # # Check if the end of the list matches
120
+ # count = sum(1 for x in my_list[-required_match_count:] if condition(x))
121
+ # return count == required_match_count
122
+ # elif position < -1:
123
+ # # Skip the last `abs(position)` elements
124
+ # count = sum(1 for x in my_list[:position] if condition(x))
125
+ # return count == required_match_count
126
+ # else:
127
+ # # Check for non-contiguous matches
128
+ # count = sum(1 for x in my_list if condition(x))
129
+ # return count >= required_match_count
130
+
131
+
132
+ def comparison_safe_converter(x):
133
+ if type(x) in [int, float, str]:
134
+ return f"{x}"
135
+ elif type(x) in [bool, NoneType]:
136
+ if x:
137
+ return True
138
+ else:
139
+ return False
140
+ return x
129
141
 
130
142
 
131
143
  def create_mathjson_solver(solver_parameters):
@@ -177,14 +189,12 @@ def create_mathjson_solver(solver_parameters):
177
189
  l_res.append(res)
178
190
  return sum(l_res)
179
191
 
180
- # @requires_array
181
192
  def Max(s):
182
193
  if isinstance(s[1], str):
183
194
  return max([f(x, c) for x in f(s[1], c) if is_numeric(f(x, c))])
184
195
  else:
185
196
  return max([f(x, c) for x in s[1][1:] if is_numeric(f(x, c))])
186
197
 
187
- # @requires_array
188
198
  def Min(s):
189
199
  if isinstance(s[1], str):
190
200
  return min([f(x, c) for x in f(s[1], c) if is_numeric(f(x, c))])
@@ -203,14 +213,12 @@ def create_mathjson_solver(solver_parameters):
203
213
  except ZeroDivisionError:
204
214
  return None
205
215
 
206
- # @requires_array
207
216
  def Median(s):
208
217
  if isinstance(s[1], str):
209
218
  return median([f(x, c) for x in f(s[1], c) if is_numeric(f(x, c))])
210
219
  else:
211
220
  return median([f(x, c) for x in s[1][1:] if is_numeric(f(x, c))])
212
221
 
213
- # @requires_array
214
222
  def Length(s):
215
223
  if isinstance(s[1], str):
216
224
 
@@ -218,11 +226,9 @@ def create_mathjson_solver(solver_parameters):
218
226
  else:
219
227
  return len([x for x in s[1][1:]])
220
228
 
221
- # @requires_array
222
229
  def Any(s):
223
230
  return any([f(x, c) for x in s[1][1:]])
224
231
 
225
- # @requires_array
226
232
  def All(s):
227
233
  return all([f(x, c) for x in s[1][1:]])
228
234
 
@@ -397,6 +403,26 @@ def create_mathjson_solver(solver_parameters):
397
403
  def TimeDeltaWeeks(s):
398
404
  return datetime.timedelta(weeks=f(s[1], c))
399
405
 
406
+ # def Equal(s):
407
+ # a = comparison_safe_converter(f(s[1], c))
408
+ # b = comparison_safe_converter(f(s[2], c))
409
+ # return a == b
410
+ # if type(a) in [int, float, str]:
411
+ # a = f"{a}"
412
+ # elif type(a) in [bool, NoneType]:
413
+ # if a:
414
+ # a = True
415
+ # else:
416
+ # a = None
417
+
418
+ # if is_numeric(a):
419
+
420
+ # lambda s: f"{f(s[1], c)}" == f"{f(s[2], c)}",
421
+
422
+ def IsDefined(s):
423
+ # Todo: This does not work
424
+ return s[1] in c.keys()
425
+
400
426
  constructs = {
401
427
  "Sum": Sum,
402
428
  "Add": Add,
@@ -419,7 +445,10 @@ def create_mathjson_solver(solver_parameters):
419
445
  "Log": lambda s: math.log(f(s[1], c)),
420
446
  "Log2": lambda s: math.log2(f(s[1], c)),
421
447
  "Log10": lambda s: math.log10(f(s[1], c)),
422
- "Equal": lambda s: f(s[1], c) == f(s[2], c),
448
+ # "Equal": lambda s: f"{f(s[1], c)}" == f"{f(s[2], c)}",
449
+ "Equal": lambda s: comparison_safe_converter(f(s[1], c))
450
+ == comparison_safe_converter(f(s[2], c)),
451
+ "StrictEqual": lambda s: f(s[1], c) == f(s[2], c),
423
452
  "Greater": lambda s: f(s[1], c) > f(s[2], c),
424
453
  "GreaterEqual": lambda s: f(s[1], c) >= f(s[2], c),
425
454
  "Less": lambda s: f(s[1], c) < f(s[2], c),
@@ -452,7 +481,8 @@ def create_mathjson_solver(solver_parameters):
452
481
  "Float": Float,
453
482
  "Str": Str,
454
483
  "Not": Not,
455
- "IsDefined": lambda s: s[1] in c,
484
+ # "IsDefined": lambda s: s[1] in c,
485
+ "IsDefined": IsDefined,
456
486
  "Map": Map,
457
487
  "HasMatchingSublist": HasMatchingSublist,
458
488
  "Strptime": Strptime,
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.2
2
+ Name: mathjson-solver
3
+ Version: 1.12.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: project-url
22
+ Dynamic: requires-python
23
+ Dynamic: summary
24
+
25
+ # MathJSON Solver
26
+
27
+ [![PyPI](https://img.shields.io/pypi/v/mathjson-solver.svg)](https://pypi.org/project/mathjson-solver/)
28
+ [![PyPI Downloads](https://static.pepy.tech/badge/mathjson-solver/month)](https://pepy.tech/projects/mathjson-solver)
29
+ ![Coverage](https://img.shields.io/badge/coverage-93-green)
30
+
31
+ _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions, like `["Add", 1, 2]`. It is developed by [Longenesis](https://longenesis.com/team) to enable numerical evaluation of user provided mathematical expressions in Longenesis digital health products. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
32
+
33
+ Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
34
+ [![Gitter](https://badges.gitter.im/mathjson-solver/community.svg)](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
35
+
36
+ ## How to use
37
+ ```python
38
+ from mathjson_solver import create_solver
39
+
40
+ parameters = {"x": 2, "y": 3}
41
+ expression = ["Add", "x", "y", 4]
42
+
43
+ solver = create_solver(parameters)
44
+ answer = solver(expression)
45
+
46
+ print(answer)
47
+ # 9, because 2+3+4=9
48
+ ```
49
+
50
+ ## Currently supported constructs
51
+ Find the full list of supported constructs in the [docs/README.md](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md).
52
+
53
+
54
+ ## Exception handling
55
+
56
+ A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
57
+ ```python
58
+ from mathjson_solver import create_solver, MathJSONException
59
+
60
+ solver = create_solver({})
61
+ try:
62
+ solver(["Divide", 1, 0])
63
+ except MathJSONException:
64
+ pass
65
+ # invoke your own exception logger here
66
+ ```
67
+
68
+ Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
69
+
70
+
71
+ ## How to run tests
72
+ Make sure you have `pytest` installed. Then `cd` into project directory and run:
73
+ ```bash
74
+ pytest
75
+ ```
76
+
77
+ ## Contributing Code
78
+
79
+ We welcome your contributions in the form of pull requests.
80
+
81
+ 1. Fork the repo;
82
+ 2. Make improvements;
83
+ 3. Make a pull request to share your improvements with the community and to include it into official release.
@@ -16,6 +16,7 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
16
16
  ({}, ["Sum", ["Array", 1, 1], 4, 3], 9),
17
17
  ({}, ["Sum", ["Array", 2, 4, 3]], 9),
18
18
  ({"a": 2}, ["Sum", "a", 4, 3], 9),
19
+ ({"a": ["Array", 1, 1]}, ["Sum", "a"], 2),
19
20
  ({"a": ["Array", 1, 1]}, ["Sum", "a", 4, 3], 9),
20
21
  ({}, ["Subtract", 10, 5, 2], 3),
21
22
  ({}, ["Add", 5, 4, ["Negate", 3]], 6),
@@ -36,6 +37,38 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
36
37
  ({}, ["Equal", 10, 12], False),
37
38
  ({}, ["Equal", "aaa", "aaa"], True),
38
39
  ({}, ["Equal", "aaa", "baa"], False),
40
+ ({}, ["Equal", "aaa", 11], False),
41
+ ({}, ["Equal", None, "1"], False),
42
+ ({}, ["Equal", 1, "1"], True),
43
+ ({}, ["Equal", None, False], True),
44
+
45
+ ({}, ["StrictEqual", 1, "1"], False),
46
+ ({}, ["StrictEqual", 10, 10], True),
47
+ ({}, ["StrictEqual", 10, 12], False),
48
+ ({}, ["StrictEqual", "aaa", "aaa"], True),
49
+ ({}, ["StrictEqual", "aaa", "baa"], False),
50
+ ({}, ["StrictEqual", "aaa", 11], False),
51
+ ({}, ["StrictEqual", None, "1"], False),
52
+ ({}, ["Equal", None, False], True),
53
+
54
+
55
+ ({}, ["Greater", 1, 2], False),
56
+ ({}, ["Greater", 2, -2], True),
57
+ ({}, ["GreaterEqual", 1, 1], True),
58
+ ({}, ["GreaterEqual", 2, 1], True),
59
+ ({}, ["GreaterEqual", 0, 0], True),
60
+ ({}, ["GreaterEqual", 1, 2], False),
61
+ ({}, ["Less", 1, 1], False),
62
+ ({}, ["Less", 1, 2], True),
63
+ ({}, ["LessEqual", 1, 1], True),
64
+ ({}, ["LessEqual", 1, 2], True),
65
+ # NotEqual
66
+ ({}, ["NotEqual", 1, 1], False),
67
+ ({}, ["NotEqual", 1, 2], True),
68
+ ({}, ["NotEqual", "aaa", "bbb"], True),
69
+ ({}, ["NotEqual", "aaa", 0], True),
70
+ # ({"a": 12}, ["IsDefined", "a"], True),
71
+ ({"a": 12}, ["IsDefined", "b"], False),
39
72
  ({}, ["Abs", -3.5], 3.5),
40
73
  ({}, ["Round", -5.123456, 2], -5.12),
41
74
  ({}, ["Round", -5.123456, 0], -5),
@@ -103,6 +136,12 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
103
136
  ({"color": "green"}, ["Switch", "color", 0, ["blue", 10], ["red", 30]], 0),
104
137
  ({"color": "green"}, ["Switch", "undefined", 0, ["blue", 10], ["red", 30]], 0),
105
138
  ({}, ["If", [["Equal", 1, 0], 10], [["Equal", 2, 2], 20], 9000], 20),
139
+ # # The following tests that If don't fail on incompatible data types
140
+ # ({}, ["If", [["Equal", 1, "1"], 10], [["Equal", "1", "1"], 20], -1], 20),
141
+
142
+ # ({"a": 1}, ["If", [["Equal", "a", "1"], 10], [["Equal", "a", 1], 20], -1], 20),
143
+ # ({"a": 1}, ["If", [["Equal", "a", 1], 10], [["Equal", "a", "1"], 20], -1], 10),
144
+
106
145
  ({"a": 10, "b": 10}, ["If", [["Equal", "a", "b"], 10], 9000], 10),
107
146
  ({"a": 10, "b": 20}, ["If", [["Equal", "a", "b"], 10], 9000], 9000),
108
147
  ({"a": 10}, ["If", [["Equal", "a", "b"], 10], 9000], 9000),
@@ -116,6 +155,7 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
116
155
  ({"a": ["Array", 2, 1, 3, 5, 2]}, ["Min", "a"], 1),
117
156
  ({}, ["Median", ["Array", 1, 2, 3, 5, 2]], 2),
118
157
  ({"a": ["Array", 1, 2, 3, 5, 2]}, ["Median", "a"], 2),
158
+ ({}, ["Average", ["Array", 2, "three", 4, "6"]], 4),
119
159
  ({}, ["Average", ["Array", 1, 2, 3, 5, 2]], 2.6),
120
160
  (
121
161
  {},
@@ -1,274 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: mathjson-solver
3
- Version: 1.11.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: project-url
22
- Dynamic: requires-python
23
- Dynamic: summary
24
-
25
- # MathJSON Solver
26
-
27
- [![Gitter](https://badges.gitter.im/mathjson-solver/community.svg)](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
28
-
29
- _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions. It was created by [Longenesis](https://longenesis.com/team) to add numerical evaluation capability of user generated mathematical expressions in Longenesis digital health products and later released as open source project. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
30
-
31
- Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
32
-
33
-
34
- ## How to use
35
- ```python
36
- from mathjson_solver import create_solver
37
-
38
- parameters = {"x": 2, "y": 3}
39
- expression = ["Add", "x", "y", 4]
40
-
41
- solver = create_solver(parameters)
42
- answer = solver(expression)
43
-
44
- print(answer)
45
- # 9, because 2+3+4=9
46
- ```
47
-
48
- ## Currently supported constructs
49
- * `Add` - Iteratively adds up the given values. Compatible with time delta.
50
- * `Sum` - Internally uses python's `sum`. Not compatible with time delta.
51
- * `Subtract` -
52
- * `Constants` -
53
- * `Switch` -
54
- * `If` -
55
- * `Multiply` -
56
- * `Divide` -
57
- * `Negate` -
58
- * `Power` -
59
- * `Root` -
60
- * `Sqrt` -
61
- * `Square` -
62
- * `Exp` -
63
- * `Log` -
64
- * `Log2` -
65
- * `Log10` -
66
- * `Equal` -
67
- * `Greater` -
68
- * `GreaterEqual` -
69
- * `Less` -
70
- * `LessEqual` -
71
- * `NotEqual` -
72
- * `Abs` -
73
- * `Round` -
74
- * `Max` -
75
- * `Min` -
76
- * `Average` - Internally tries to convert strings to numbers, making calculation of average from `[2, 4 ,"6"]` actually possible. Also, it ignores un-convertible elements so arrays like `[2, "three", 4 ,"6"]` don't crash the solver.
77
- * `Median` -
78
- * `Length` -
79
- * `Any` -
80
- * `All` -
81
- * `Array` -
82
- * `In` -
83
- * `Not_in` -
84
- * `Contains_any_of` -
85
- * `Contains_all_of` -
86
- * `Contains_none_of` -
87
- * `NotIn` -
88
- * `ContainsAnyOf` -
89
- * `ContainsAllOf` -
90
- * `ContainsNoneOf` -
91
- * `Int` -
92
- * `Float` -
93
- * `Str` -
94
- * `Not` -
95
- * `IsDefined` - Checks if a value is in parameters.
96
- * `Map` -
97
- * `HasMatchingSublist` -
98
- * `Strptime` -
99
- * `Strftime` -
100
- * `Today` -
101
- * `Now` -
102
- * `TimeDeltaWeeks` -
103
- * `TimeDeltaHours` -
104
- * `TimeDeltaMinutes` -
105
- * `TimeDeltaDays` -
106
-
107
- ## Examples
108
- ```python
109
- ["Add", 2, 4, 3] # 2+4+3=9
110
- ["Subtract", 10, 5, 2] # 10-5-2=3
111
- ["Add", 5, 4, ["Negate", 3]] # 5+4+(-3)=6
112
- ["Multiply", 2, 3, 4] # 2*3*4=24
113
- ["Divide", 10, 5] # 10/5=2.0
114
- ["Divide", 10, 4] # 10/4=2.5
115
- ["Power", 2, 3] # 2^3=8
116
- ["Root", 9, 2] # √9=3.0
117
- ["Root", 8, 3] # ∛8=2.0
118
- ["Sqrt", 9] # √9=3.0
119
- ["Square", 4] # 4^2=16
120
- ["Exp", 2] # e^2≅7.389
121
- ["Divide", 10, ["Add", 2+3]] # 10/(2+3)=10/5=2
122
- ["Log", 2.7183] # ln(2.7183)≅1.0000
123
- ["Log2", 8] # log2(8)=3.0
124
- ["Log10", 1000] # log10(1000)=3.0
125
- ["Equal", 10, 10] # 10==10 = True
126
- ["Equal", 10, 12] # 10==12 = False
127
- ["Abs", -3.5] # |-3.5| = 3.5
128
- ["Round", -5.123456, 2] # -5.12
129
- ["Round", -5.123456, 0] # -5.0
130
- ["Round", -5.123456] # -5
131
- ["Array", 1, 2] # ["Array", 1, 2]
132
-
133
- ["Max", ["Array", 1, 2, 3, 5, 2]] # 5
134
- ["Max", ["Array", 1, 2, ["Sum", 2, 4, 3], 5, 2]] # 9
135
- ["Median", ["Array", 1, 2, 3, 5, 2]] # 2
136
- ["Average", ["Array", 1, 2, 3, 5, 2]] # 2.6
137
- ["Average", ["Array"]] # None
138
-
139
- ["Length", ["Array", 1, 2, 3, 5, 2, 9]] # 6
140
- ["Length", ["Array"]] # 0
141
- ["Any", ["Array", 0, 0, False, 0, 0]] # False
142
- ["Any", ["Array", 0, 1, False, 0, 0]] # True
143
- ["All", ["Array", 0, 1, False, 0, 0]] # False
144
- ["All", ["Array", 0, 1, False, "", 0]] # False
145
- ["All", ["Array", 2, 1, True, "zz", 2]] # True
146
- ["Int", "12"] # 12
147
- ["Int", "12.2"] # 12
148
- ["Float", "12.2"] # 12.2
149
- ["Str", 12] # "12"
150
- ["Str", "12"] # "12"
151
- ["Str", "aabb"] # "aabb"
152
- ["Not", True] # False
153
- ["Not", 0] # True
154
-
155
- ["In", 2, ["Array", 1, 2, 3]] # True
156
- ["In", 4, ["Array", 1, 2, 3]] # False
157
- ["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 3, 4, 5, 6]] # True
158
- ["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 4, 5, 6]] # False
159
- ["ContainsAllOf", ["Array", 1, 2, 3], ["Array", 1, 2, 3]] # True
160
- ["ContainsAllOf", ["Array", 1, 2], ["Array", 1, 2, 3]] # False
161
- ```
162
-
163
- ### Constants
164
- ```
165
- [
166
- "Constants",
167
- ["constant_name1", <expression>],
168
- ["constant_name2", <expression>],
169
- ["constant_name3", <expression>],
170
- ...,
171
- <expression>
172
- ]
173
- ```
174
-
175
- `Constants` construct consists of keyword "Constants" followed by arbitrary number of name&value pairs. The last element in `Constants` construct is the expression to calculate using the defined constants.
176
-
177
- The following example has two constants defined - `x=10` and `y=20`. Then the sum of these two constants is calculated and returned.
178
-
179
-
180
- ```python
181
- [
182
- "Constants",
183
- ["x", 10],
184
- ["y", 20],
185
- ["Add","x", "y"]
186
- ]
187
- ```
188
-
189
-
190
- ### If statement
191
- ```
192
- [
193
- "If",
194
- [
195
- <true-or-false-expression>,
196
- <expression-to-calculate>
197
- ],
198
- [
199
- <elseif-true-or-false-expression>,
200
- <expression-to-calculate>
201
- ],
202
- ...,
203
- <else-expression-to-calculate>
204
- ]
205
- ```
206
-
207
- Example
208
- ```python
209
- [
210
- "If",
211
- [
212
- ["Equal", 1, 0],
213
- 10
214
- ],
215
- [
216
- ["Equal", 2, 2],
217
- 20
218
- ],
219
- 9000
220
- ]
221
- ```
222
- This construct translates to:
223
- ```
224
- if 1 == 0 then 10
225
- elif 2 == 2 then 20
226
- else 9000
227
- ```
228
-
229
- `If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
230
-
231
- ### Switch-Case statement
232
- ```
233
- ["Switch", <on-expression>, <default-result-expression>, [<case1-expression>, <result-expression>], ...],
234
- ```
235
-
236
- `Switch` construct consists of keyword "Switch" followed by expression whose value will be compared to _Cases'_ values. Then comes the default value. Then follows arbitrary number of _Cases_.
237
-
238
- Example
239
- ```python
240
- ["Switch", "color", 100, ["red", 10], ["blue", 20], ["green", 30]],
241
- ```
242
- The expression in this example will make solver to look for a constant (or a parameter) with the name "color". If "color" is "red", expression evaluates to 10, if "blue" - to 20, if "green" - to 30. Otherwise to 100. Please note that "color" here is a valid expression that evaluates to the actual value of "color" whether it is a parameter or constant.
243
-
244
-
245
- ## Exception handling
246
-
247
- A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
248
- ```python
249
- from mathjson_solver import create_solver, MathJSONException
250
-
251
- solver = create_solver({})
252
- try:
253
- solver(["Divide", 1, 0])
254
- except MathJSONException:
255
- pass
256
- # invoke your own exception logger here
257
- ```
258
-
259
- Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
260
-
261
-
262
- ## How to run tests
263
- Make sure you have `pytest` installed. Then `cd` into project directory and run:
264
- ```bash
265
- pytest
266
- ```
267
-
268
- ## Contributing Code
269
-
270
- We welcome your contributions in the form of pull requests.
271
-
272
- 1. Fork the repo;
273
- 2. Make improvements;
274
- 3. Make a pull request to share your improvements with the community and to include it into official release.
@@ -1,250 +0,0 @@
1
- # MathJSON Solver
2
-
3
- [![Gitter](https://badges.gitter.im/mathjson-solver/community.svg)](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
4
-
5
- _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions. It was created by [Longenesis](https://longenesis.com/team) to add numerical evaluation capability of user generated mathematical expressions in Longenesis digital health products and later released as open source project. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
6
-
7
- Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
8
-
9
-
10
- ## How to use
11
- ```python
12
- from mathjson_solver import create_solver
13
-
14
- parameters = {"x": 2, "y": 3}
15
- expression = ["Add", "x", "y", 4]
16
-
17
- solver = create_solver(parameters)
18
- answer = solver(expression)
19
-
20
- print(answer)
21
- # 9, because 2+3+4=9
22
- ```
23
-
24
- ## Currently supported constructs
25
- * `Add` - Iteratively adds up the given values. Compatible with time delta.
26
- * `Sum` - Internally uses python's `sum`. Not compatible with time delta.
27
- * `Subtract` -
28
- * `Constants` -
29
- * `Switch` -
30
- * `If` -
31
- * `Multiply` -
32
- * `Divide` -
33
- * `Negate` -
34
- * `Power` -
35
- * `Root` -
36
- * `Sqrt` -
37
- * `Square` -
38
- * `Exp` -
39
- * `Log` -
40
- * `Log2` -
41
- * `Log10` -
42
- * `Equal` -
43
- * `Greater` -
44
- * `GreaterEqual` -
45
- * `Less` -
46
- * `LessEqual` -
47
- * `NotEqual` -
48
- * `Abs` -
49
- * `Round` -
50
- * `Max` -
51
- * `Min` -
52
- * `Average` - Internally tries to convert strings to numbers, making calculation of average from `[2, 4 ,"6"]` actually possible. Also, it ignores un-convertible elements so arrays like `[2, "three", 4 ,"6"]` don't crash the solver.
53
- * `Median` -
54
- * `Length` -
55
- * `Any` -
56
- * `All` -
57
- * `Array` -
58
- * `In` -
59
- * `Not_in` -
60
- * `Contains_any_of` -
61
- * `Contains_all_of` -
62
- * `Contains_none_of` -
63
- * `NotIn` -
64
- * `ContainsAnyOf` -
65
- * `ContainsAllOf` -
66
- * `ContainsNoneOf` -
67
- * `Int` -
68
- * `Float` -
69
- * `Str` -
70
- * `Not` -
71
- * `IsDefined` - Checks if a value is in parameters.
72
- * `Map` -
73
- * `HasMatchingSublist` -
74
- * `Strptime` -
75
- * `Strftime` -
76
- * `Today` -
77
- * `Now` -
78
- * `TimeDeltaWeeks` -
79
- * `TimeDeltaHours` -
80
- * `TimeDeltaMinutes` -
81
- * `TimeDeltaDays` -
82
-
83
- ## Examples
84
- ```python
85
- ["Add", 2, 4, 3] # 2+4+3=9
86
- ["Subtract", 10, 5, 2] # 10-5-2=3
87
- ["Add", 5, 4, ["Negate", 3]] # 5+4+(-3)=6
88
- ["Multiply", 2, 3, 4] # 2*3*4=24
89
- ["Divide", 10, 5] # 10/5=2.0
90
- ["Divide", 10, 4] # 10/4=2.5
91
- ["Power", 2, 3] # 2^3=8
92
- ["Root", 9, 2] # √9=3.0
93
- ["Root", 8, 3] # ∛8=2.0
94
- ["Sqrt", 9] # √9=3.0
95
- ["Square", 4] # 4^2=16
96
- ["Exp", 2] # e^2≅7.389
97
- ["Divide", 10, ["Add", 2+3]] # 10/(2+3)=10/5=2
98
- ["Log", 2.7183] # ln(2.7183)≅1.0000
99
- ["Log2", 8] # log2(8)=3.0
100
- ["Log10", 1000] # log10(1000)=3.0
101
- ["Equal", 10, 10] # 10==10 = True
102
- ["Equal", 10, 12] # 10==12 = False
103
- ["Abs", -3.5] # |-3.5| = 3.5
104
- ["Round", -5.123456, 2] # -5.12
105
- ["Round", -5.123456, 0] # -5.0
106
- ["Round", -5.123456] # -5
107
- ["Array", 1, 2] # ["Array", 1, 2]
108
-
109
- ["Max", ["Array", 1, 2, 3, 5, 2]] # 5
110
- ["Max", ["Array", 1, 2, ["Sum", 2, 4, 3], 5, 2]] # 9
111
- ["Median", ["Array", 1, 2, 3, 5, 2]] # 2
112
- ["Average", ["Array", 1, 2, 3, 5, 2]] # 2.6
113
- ["Average", ["Array"]] # None
114
-
115
- ["Length", ["Array", 1, 2, 3, 5, 2, 9]] # 6
116
- ["Length", ["Array"]] # 0
117
- ["Any", ["Array", 0, 0, False, 0, 0]] # False
118
- ["Any", ["Array", 0, 1, False, 0, 0]] # True
119
- ["All", ["Array", 0, 1, False, 0, 0]] # False
120
- ["All", ["Array", 0, 1, False, "", 0]] # False
121
- ["All", ["Array", 2, 1, True, "zz", 2]] # True
122
- ["Int", "12"] # 12
123
- ["Int", "12.2"] # 12
124
- ["Float", "12.2"] # 12.2
125
- ["Str", 12] # "12"
126
- ["Str", "12"] # "12"
127
- ["Str", "aabb"] # "aabb"
128
- ["Not", True] # False
129
- ["Not", 0] # True
130
-
131
- ["In", 2, ["Array", 1, 2, 3]] # True
132
- ["In", 4, ["Array", 1, 2, 3]] # False
133
- ["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 3, 4, 5, 6]] # True
134
- ["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 4, 5, 6]] # False
135
- ["ContainsAllOf", ["Array", 1, 2, 3], ["Array", 1, 2, 3]] # True
136
- ["ContainsAllOf", ["Array", 1, 2], ["Array", 1, 2, 3]] # False
137
- ```
138
-
139
- ### Constants
140
- ```
141
- [
142
- "Constants",
143
- ["constant_name1", <expression>],
144
- ["constant_name2", <expression>],
145
- ["constant_name3", <expression>],
146
- ...,
147
- <expression>
148
- ]
149
- ```
150
-
151
- `Constants` construct consists of keyword "Constants" followed by arbitrary number of name&value pairs. The last element in `Constants` construct is the expression to calculate using the defined constants.
152
-
153
- The following example has two constants defined - `x=10` and `y=20`. Then the sum of these two constants is calculated and returned.
154
-
155
-
156
- ```python
157
- [
158
- "Constants",
159
- ["x", 10],
160
- ["y", 20],
161
- ["Add","x", "y"]
162
- ]
163
- ```
164
-
165
-
166
- ### If statement
167
- ```
168
- [
169
- "If",
170
- [
171
- <true-or-false-expression>,
172
- <expression-to-calculate>
173
- ],
174
- [
175
- <elseif-true-or-false-expression>,
176
- <expression-to-calculate>
177
- ],
178
- ...,
179
- <else-expression-to-calculate>
180
- ]
181
- ```
182
-
183
- Example
184
- ```python
185
- [
186
- "If",
187
- [
188
- ["Equal", 1, 0],
189
- 10
190
- ],
191
- [
192
- ["Equal", 2, 2],
193
- 20
194
- ],
195
- 9000
196
- ]
197
- ```
198
- This construct translates to:
199
- ```
200
- if 1 == 0 then 10
201
- elif 2 == 2 then 20
202
- else 9000
203
- ```
204
-
205
- `If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
206
-
207
- ### Switch-Case statement
208
- ```
209
- ["Switch", <on-expression>, <default-result-expression>, [<case1-expression>, <result-expression>], ...],
210
- ```
211
-
212
- `Switch` construct consists of keyword "Switch" followed by expression whose value will be compared to _Cases'_ values. Then comes the default value. Then follows arbitrary number of _Cases_.
213
-
214
- Example
215
- ```python
216
- ["Switch", "color", 100, ["red", 10], ["blue", 20], ["green", 30]],
217
- ```
218
- The expression in this example will make solver to look for a constant (or a parameter) with the name "color". If "color" is "red", expression evaluates to 10, if "blue" - to 20, if "green" - to 30. Otherwise to 100. Please note that "color" here is a valid expression that evaluates to the actual value of "color" whether it is a parameter or constant.
219
-
220
-
221
- ## Exception handling
222
-
223
- A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
224
- ```python
225
- from mathjson_solver import create_solver, MathJSONException
226
-
227
- solver = create_solver({})
228
- try:
229
- solver(["Divide", 1, 0])
230
- except MathJSONException:
231
- pass
232
- # invoke your own exception logger here
233
- ```
234
-
235
- Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
236
-
237
-
238
- ## How to run tests
239
- Make sure you have `pytest` installed. Then `cd` into project directory and run:
240
- ```bash
241
- pytest
242
- ```
243
-
244
- ## Contributing Code
245
-
246
- We welcome your contributions in the form of pull requests.
247
-
248
- 1. Fork the repo;
249
- 2. Make improvements;
250
- 3. Make a pull request to share your improvements with the community and to include it into official release.
@@ -1,274 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: mathjson-solver
3
- Version: 1.11.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: project-url
22
- Dynamic: requires-python
23
- Dynamic: summary
24
-
25
- # MathJSON Solver
26
-
27
- [![Gitter](https://badges.gitter.im/mathjson-solver/community.svg)](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
28
-
29
- _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions. It was created by [Longenesis](https://longenesis.com/team) to add numerical evaluation capability of user generated mathematical expressions in Longenesis digital health products and later released as open source project. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
30
-
31
- Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
32
-
33
-
34
- ## How to use
35
- ```python
36
- from mathjson_solver import create_solver
37
-
38
- parameters = {"x": 2, "y": 3}
39
- expression = ["Add", "x", "y", 4]
40
-
41
- solver = create_solver(parameters)
42
- answer = solver(expression)
43
-
44
- print(answer)
45
- # 9, because 2+3+4=9
46
- ```
47
-
48
- ## Currently supported constructs
49
- * `Add` - Iteratively adds up the given values. Compatible with time delta.
50
- * `Sum` - Internally uses python's `sum`. Not compatible with time delta.
51
- * `Subtract` -
52
- * `Constants` -
53
- * `Switch` -
54
- * `If` -
55
- * `Multiply` -
56
- * `Divide` -
57
- * `Negate` -
58
- * `Power` -
59
- * `Root` -
60
- * `Sqrt` -
61
- * `Square` -
62
- * `Exp` -
63
- * `Log` -
64
- * `Log2` -
65
- * `Log10` -
66
- * `Equal` -
67
- * `Greater` -
68
- * `GreaterEqual` -
69
- * `Less` -
70
- * `LessEqual` -
71
- * `NotEqual` -
72
- * `Abs` -
73
- * `Round` -
74
- * `Max` -
75
- * `Min` -
76
- * `Average` - Internally tries to convert strings to numbers, making calculation of average from `[2, 4 ,"6"]` actually possible. Also, it ignores un-convertible elements so arrays like `[2, "three", 4 ,"6"]` don't crash the solver.
77
- * `Median` -
78
- * `Length` -
79
- * `Any` -
80
- * `All` -
81
- * `Array` -
82
- * `In` -
83
- * `Not_in` -
84
- * `Contains_any_of` -
85
- * `Contains_all_of` -
86
- * `Contains_none_of` -
87
- * `NotIn` -
88
- * `ContainsAnyOf` -
89
- * `ContainsAllOf` -
90
- * `ContainsNoneOf` -
91
- * `Int` -
92
- * `Float` -
93
- * `Str` -
94
- * `Not` -
95
- * `IsDefined` - Checks if a value is in parameters.
96
- * `Map` -
97
- * `HasMatchingSublist` -
98
- * `Strptime` -
99
- * `Strftime` -
100
- * `Today` -
101
- * `Now` -
102
- * `TimeDeltaWeeks` -
103
- * `TimeDeltaHours` -
104
- * `TimeDeltaMinutes` -
105
- * `TimeDeltaDays` -
106
-
107
- ## Examples
108
- ```python
109
- ["Add", 2, 4, 3] # 2+4+3=9
110
- ["Subtract", 10, 5, 2] # 10-5-2=3
111
- ["Add", 5, 4, ["Negate", 3]] # 5+4+(-3)=6
112
- ["Multiply", 2, 3, 4] # 2*3*4=24
113
- ["Divide", 10, 5] # 10/5=2.0
114
- ["Divide", 10, 4] # 10/4=2.5
115
- ["Power", 2, 3] # 2^3=8
116
- ["Root", 9, 2] # √9=3.0
117
- ["Root", 8, 3] # ∛8=2.0
118
- ["Sqrt", 9] # √9=3.0
119
- ["Square", 4] # 4^2=16
120
- ["Exp", 2] # e^2≅7.389
121
- ["Divide", 10, ["Add", 2+3]] # 10/(2+3)=10/5=2
122
- ["Log", 2.7183] # ln(2.7183)≅1.0000
123
- ["Log2", 8] # log2(8)=3.0
124
- ["Log10", 1000] # log10(1000)=3.0
125
- ["Equal", 10, 10] # 10==10 = True
126
- ["Equal", 10, 12] # 10==12 = False
127
- ["Abs", -3.5] # |-3.5| = 3.5
128
- ["Round", -5.123456, 2] # -5.12
129
- ["Round", -5.123456, 0] # -5.0
130
- ["Round", -5.123456] # -5
131
- ["Array", 1, 2] # ["Array", 1, 2]
132
-
133
- ["Max", ["Array", 1, 2, 3, 5, 2]] # 5
134
- ["Max", ["Array", 1, 2, ["Sum", 2, 4, 3], 5, 2]] # 9
135
- ["Median", ["Array", 1, 2, 3, 5, 2]] # 2
136
- ["Average", ["Array", 1, 2, 3, 5, 2]] # 2.6
137
- ["Average", ["Array"]] # None
138
-
139
- ["Length", ["Array", 1, 2, 3, 5, 2, 9]] # 6
140
- ["Length", ["Array"]] # 0
141
- ["Any", ["Array", 0, 0, False, 0, 0]] # False
142
- ["Any", ["Array", 0, 1, False, 0, 0]] # True
143
- ["All", ["Array", 0, 1, False, 0, 0]] # False
144
- ["All", ["Array", 0, 1, False, "", 0]] # False
145
- ["All", ["Array", 2, 1, True, "zz", 2]] # True
146
- ["Int", "12"] # 12
147
- ["Int", "12.2"] # 12
148
- ["Float", "12.2"] # 12.2
149
- ["Str", 12] # "12"
150
- ["Str", "12"] # "12"
151
- ["Str", "aabb"] # "aabb"
152
- ["Not", True] # False
153
- ["Not", 0] # True
154
-
155
- ["In", 2, ["Array", 1, 2, 3]] # True
156
- ["In", 4, ["Array", 1, 2, 3]] # False
157
- ["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 3, 4, 5, 6]] # True
158
- ["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 4, 5, 6]] # False
159
- ["ContainsAllOf", ["Array", 1, 2, 3], ["Array", 1, 2, 3]] # True
160
- ["ContainsAllOf", ["Array", 1, 2], ["Array", 1, 2, 3]] # False
161
- ```
162
-
163
- ### Constants
164
- ```
165
- [
166
- "Constants",
167
- ["constant_name1", <expression>],
168
- ["constant_name2", <expression>],
169
- ["constant_name3", <expression>],
170
- ...,
171
- <expression>
172
- ]
173
- ```
174
-
175
- `Constants` construct consists of keyword "Constants" followed by arbitrary number of name&value pairs. The last element in `Constants` construct is the expression to calculate using the defined constants.
176
-
177
- The following example has two constants defined - `x=10` and `y=20`. Then the sum of these two constants is calculated and returned.
178
-
179
-
180
- ```python
181
- [
182
- "Constants",
183
- ["x", 10],
184
- ["y", 20],
185
- ["Add","x", "y"]
186
- ]
187
- ```
188
-
189
-
190
- ### If statement
191
- ```
192
- [
193
- "If",
194
- [
195
- <true-or-false-expression>,
196
- <expression-to-calculate>
197
- ],
198
- [
199
- <elseif-true-or-false-expression>,
200
- <expression-to-calculate>
201
- ],
202
- ...,
203
- <else-expression-to-calculate>
204
- ]
205
- ```
206
-
207
- Example
208
- ```python
209
- [
210
- "If",
211
- [
212
- ["Equal", 1, 0],
213
- 10
214
- ],
215
- [
216
- ["Equal", 2, 2],
217
- 20
218
- ],
219
- 9000
220
- ]
221
- ```
222
- This construct translates to:
223
- ```
224
- if 1 == 0 then 10
225
- elif 2 == 2 then 20
226
- else 9000
227
- ```
228
-
229
- `If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
230
-
231
- ### Switch-Case statement
232
- ```
233
- ["Switch", <on-expression>, <default-result-expression>, [<case1-expression>, <result-expression>], ...],
234
- ```
235
-
236
- `Switch` construct consists of keyword "Switch" followed by expression whose value will be compared to _Cases'_ values. Then comes the default value. Then follows arbitrary number of _Cases_.
237
-
238
- Example
239
- ```python
240
- ["Switch", "color", 100, ["red", 10], ["blue", 20], ["green", 30]],
241
- ```
242
- The expression in this example will make solver to look for a constant (or a parameter) with the name "color". If "color" is "red", expression evaluates to 10, if "blue" - to 20, if "green" - to 30. Otherwise to 100. Please note that "color" here is a valid expression that evaluates to the actual value of "color" whether it is a parameter or constant.
243
-
244
-
245
- ## Exception handling
246
-
247
- A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
248
- ```python
249
- from mathjson_solver import create_solver, MathJSONException
250
-
251
- solver = create_solver({})
252
- try:
253
- solver(["Divide", 1, 0])
254
- except MathJSONException:
255
- pass
256
- # invoke your own exception logger here
257
- ```
258
-
259
- Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
260
-
261
-
262
- ## How to run tests
263
- Make sure you have `pytest` installed. Then `cd` into project directory and run:
264
- ```bash
265
- pytest
266
- ```
267
-
268
- ## Contributing Code
269
-
270
- We welcome your contributions in the form of pull requests.
271
-
272
- 1. Fork the repo;
273
- 2. Make improvements;
274
- 3. Make a pull request to share your improvements with the community and to include it into official release.