mathjson-solver 1.16.1__tar.gz → 1.18.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.
Files changed (30) hide show
  1. {mathjson_solver-1.16.1/src/mathjson_solver.egg-info → mathjson_solver-1.18.0}/PKG-INFO +21 -9
  2. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/README.md +20 -7
  3. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/setup.cfg +2 -2
  4. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/setup.py +2 -2
  5. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/src/mathjson_solver/__main__.py +153 -14
  6. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0/src/mathjson_solver.egg-info}/PKG-INFO +21 -9
  7. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/src/mathjson_solver.egg-info/SOURCES.txt +5 -2
  8. mathjson_solver-1.16.1/tests/test_CumulativeProduct.py → mathjson_solver-1.18.0/tests/test_cumulative.py +11 -0
  9. mathjson_solver-1.18.0/tests/test_datetime.py +219 -0
  10. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_equal.py +5 -0
  11. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_gail_model.py +1 -1
  12. mathjson_solver-1.18.0/tests/test_reduce_simple.py +209 -0
  13. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_simple_cases.py +6 -0
  14. mathjson_solver-1.18.0/tests/test_state_tuples_reduce.py +180 -0
  15. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_with_pytest.py +10 -72
  16. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/LICENSE +0 -0
  17. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/pyproject.toml +0 -0
  18. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/src/mathjson_solver/__init__.py +0 -0
  19. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/src/mathjson_solver.egg-info/dependency_links.txt +0 -0
  20. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/src/mathjson_solver.egg-info/top_level.txt +0 -0
  21. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_TrapezoidalIntegratel.py +0 -0
  22. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_atindex.py +0 -0
  23. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_exceptions.py +0 -0
  24. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_extract_variables.py +0 -0
  25. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_findinterval.py +0 -0
  26. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_interpolate.py +0 -0
  27. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_range.py +0 -0
  28. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_scalars.py +0 -0
  29. {mathjson_solver-1.16.1 → mathjson_solver-1.18.0}/tests/test_sets.py +0 -0
  30. /mathjson_solver-1.16.1/tests/test_Slice.py → /mathjson_solver-1.18.0/tests/test_slice.py +0 -0
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathjson-solver
3
- Version: 1.16.1
3
+ Version: 1.18.0
4
4
  Summary: Utilities for MathJSON evaluation
5
5
  Home-page: https://github.com/LongenesisLtd/mathjson-solver
6
6
  Author: Martins Mednis
7
7
  Author-email: mrt@mednis.info
8
8
  Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: MIT License
11
10
  Classifier: Operating System :: OS Independent
12
11
  Requires-Python: >=3.6
13
12
  Description-Content-Type: text/markdown
@@ -33,8 +32,6 @@ A reliable Python library for numerically evaluating mathematical expressions in
33
32
 
34
33
  **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
34
 
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
35
  ## Table of Contents
39
36
  - [Installation](#installation)
40
37
  - [Quick Start](#quick-start)
@@ -80,21 +77,32 @@ except MathJSONException as e:
80
77
  # Math error: Problem in Divide. ['Divide', 1, 0]. division by zero
81
78
  ```
82
79
 
80
+ **Think Functional:** MathJSON Solver embraces functional programming principles. Instead of writing loops and modifying variables, you compose expressions that transform data. Functions like `Map`, `Reduce`, and `Filter` let you process arrays elegantly, while immutable operations ensure predictable, side-effect-free calculations. Don't worry if you're new to functional programming — the examples will guide you naturally into this powerful paradigm.
81
+
82
+ ```python
83
+ # Functional approach: transform data with expressions
84
+ solver(["Map", ["Array", 1, 2, 3, 4], ["Multiply"], 2]) # [2, 4, 6, 8]
85
+ solver(["Reduce", ["Array", 1, 2, 3, 4], 0, ["Add", "acc", "item"],
86
+ ["Variable", "acc"], ["Variable", "item"], ["Variable", "i"]]) # 10
87
+ ```
88
+
83
89
  ## Supported Operations
84
90
 
85
91
  The library supports a comprehensive set of mathematical operations:
86
92
 
87
- * **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round
93
+ * **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round, Floor, Ceil
88
94
  * **Trigonometry:** Sin, Cos, Tan, Arcsin, Arccos, Arctan
89
95
  * **Logarithms:** Log, Log2, Log10, Exp
90
96
  * **Comparison:** Equal, StrictEqual, NotEqual, Greater, GreaterEqual, Less, LessEqual
91
- * **Logic & Sets:** Any, All, Not, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
97
+ * **Logic & Sets:** Any, All, Not, And, Or, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
92
98
  * **Statistics:** Average, Max, Min, Median, Length
93
- * **Arrays:** Array creation and manipulation with Map function
99
+ * **Functional Programming:** Map, Reduce, Filter
100
+ * **Arrays:** Array creation, GenerateRange, AtIndex, Slice, Appended, CumulativeSum, CumulativeProduct
94
101
  * **Control Flow:** If statements, Switch-Case, Constants definition
95
102
  * **Type Conversion:** Int, Float, Str, IsDefined
96
- * **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions
97
- * **Advanced:** HasMatchingSublist, TrapezoidalIntegrate (requires numpy), Variable references
103
+ * **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions (Weeks, Days, Hours, Minutes)
104
+ * **Integration:** TrapezoidalIntegrate (requires numpy), Interp, FindIntervalIndex, Variable references
105
+ * **Advanced:** HasMatchingSublist for pattern matching
98
106
  * **Constants:** Pi
99
107
 
100
108
  [View complete documentation with examples →](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md)
@@ -161,6 +169,10 @@ We welcome contributions! Please feel free to:
161
169
 
162
170
  [View license information](https://github.com/LongenesisLtd/mathjson-solver/blob/main/LICENSE)
163
171
 
172
+ ## References
173
+
174
+ This implementation was inspired by the [CortexJS Compute Engine](https://cortexjs.io/compute-engine/), though designed as an independent implementation focused on our specific use cases.
175
+
164
176
  ---
165
177
 
166
178
  Made with ❤️ by [Longenesis](https://longenesis.com/team)
@@ -8,8 +8,6 @@ A reliable Python library for numerically evaluating mathematical expressions in
8
8
 
9
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
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
11
  ## Table of Contents
14
12
  - [Installation](#installation)
15
13
  - [Quick Start](#quick-start)
@@ -55,21 +53,32 @@ except MathJSONException as e:
55
53
  # Math error: Problem in Divide. ['Divide', 1, 0]. division by zero
56
54
  ```
57
55
 
56
+ **Think Functional:** MathJSON Solver embraces functional programming principles. Instead of writing loops and modifying variables, you compose expressions that transform data. Functions like `Map`, `Reduce`, and `Filter` let you process arrays elegantly, while immutable operations ensure predictable, side-effect-free calculations. Don't worry if you're new to functional programming — the examples will guide you naturally into this powerful paradigm.
57
+
58
+ ```python
59
+ # Functional approach: transform data with expressions
60
+ solver(["Map", ["Array", 1, 2, 3, 4], ["Multiply"], 2]) # [2, 4, 6, 8]
61
+ solver(["Reduce", ["Array", 1, 2, 3, 4], 0, ["Add", "acc", "item"],
62
+ ["Variable", "acc"], ["Variable", "item"], ["Variable", "i"]]) # 10
63
+ ```
64
+
58
65
  ## Supported Operations
59
66
 
60
67
  The library supports a comprehensive set of mathematical operations:
61
68
 
62
- * **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round
69
+ * **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round, Floor, Ceil
63
70
  * **Trigonometry:** Sin, Cos, Tan, Arcsin, Arccos, Arctan
64
71
  * **Logarithms:** Log, Log2, Log10, Exp
65
72
  * **Comparison:** Equal, StrictEqual, NotEqual, Greater, GreaterEqual, Less, LessEqual
66
- * **Logic & Sets:** Any, All, Not, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
73
+ * **Logic & Sets:** Any, All, Not, And, Or, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
67
74
  * **Statistics:** Average, Max, Min, Median, Length
68
- * **Arrays:** Array creation and manipulation with Map function
75
+ * **Functional Programming:** Map, Reduce, Filter
76
+ * **Arrays:** Array creation, GenerateRange, AtIndex, Slice, Appended, CumulativeSum, CumulativeProduct
69
77
  * **Control Flow:** If statements, Switch-Case, Constants definition
70
78
  * **Type Conversion:** Int, Float, Str, IsDefined
71
- * **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions
72
- * **Advanced:** HasMatchingSublist, TrapezoidalIntegrate (requires numpy), Variable references
79
+ * **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions (Weeks, Days, Hours, Minutes)
80
+ * **Integration:** TrapezoidalIntegrate (requires numpy), Interp, FindIntervalIndex, Variable references
81
+ * **Advanced:** HasMatchingSublist for pattern matching
73
82
  * **Constants:** Pi
74
83
 
75
84
  [View complete documentation with examples →](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md)
@@ -136,6 +145,10 @@ We welcome contributions! Please feel free to:
136
145
 
137
146
  [View license information](https://github.com/LongenesisLtd/mathjson-solver/blob/main/LICENSE)
138
147
 
148
+ ## References
149
+
150
+ This implementation was inspired by the [CortexJS Compute Engine](https://cortexjs.io/compute-engine/), though designed as an independent implementation focused on our specific use cases.
151
+
139
152
  ---
140
153
 
141
154
  Made with ❤️ by [Longenesis](https://longenesis.com/team)
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = mathjson-solver
3
- version = 1.16.1
3
+ version = 1.18.0
4
4
  author = Martins Mednis
5
5
  author_email = mrt@mednis.info
6
6
  description = Utilities for MathJSON evaluation
@@ -11,8 +11,8 @@ project_urls =
11
11
  Bug Tracker = https://github.com/LongenesisLtd/mathjson-solver/issues
12
12
  classifiers =
13
13
  Programming Language :: Python :: 3
14
- License :: OSI Approved :: MIT License
15
14
  Operating System :: OS Independent
15
+ license_expr = MIT
16
16
 
17
17
  [options]
18
18
  package_dir =
@@ -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.16.1",
8
+ version="1.18.0",
9
9
  author="Martins Mednis",
10
10
  author_email="mrt@mednis.info",
11
11
  description="Utilities for MathJSON evaluation",
@@ -15,9 +15,9 @@ setuptools.setup(
15
15
  project_urls={
16
16
  "Bug Tracker": "https://github.com/LongenesisLtd/mathjson-solver/issues",
17
17
  },
18
+ license_expr="MIT",
18
19
  classifiers=[
19
20
  "Programming Language :: Python :: 3",
20
- "License :: OSI Approved :: MIT License",
21
21
  "Operating System :: OS Independent",
22
22
  ],
23
23
  package_dir={"": "src"},
@@ -17,6 +17,22 @@ except ImportError:
17
17
  NoneType = type(None)
18
18
 
19
19
 
20
+ def _try_parse_datetime(value):
21
+ """Try to parse a string as datetime or date. Returns original value if not parseable."""
22
+ if isinstance(value, (datetime.datetime, datetime.date)):
23
+ return value
24
+ if isinstance(value, str):
25
+ try:
26
+ return datetime.datetime.fromisoformat(value)
27
+ except ValueError:
28
+ pass
29
+ try:
30
+ return datetime.date.fromisoformat(value)
31
+ except ValueError:
32
+ pass
33
+ return value
34
+
35
+
20
36
  # def find_interpolation_bounds(
21
37
  # l: list, target: int | float
22
38
  # ) -> Union[Union[int, float], tuple[Union[int, float], Union[int, float]]]:
@@ -70,6 +86,16 @@ def _CumulativeProduct(l: list) -> list:
70
86
  return res
71
87
 
72
88
 
89
+ def _CumulativeSum(l: list) -> list:
90
+ res = []
91
+ for i, x in enumerate(l):
92
+ if i == 0:
93
+ res.append(x)
94
+ else:
95
+ res.append(reduce(lambda a, b: a + b, l[: i + 1]))
96
+ return res
97
+
98
+
73
99
  def find_interpolation_bounds_indexes(
74
100
  l: list, target: int | float
75
101
  ) -> Union[Union[int, float], tuple[Union[int, float], Union[int, float]]]:
@@ -284,16 +310,19 @@ def create_mathjson_solver(solver_parameters):
284
310
  if i == 0:
285
311
  tmp = res
286
312
  else:
313
+ # Handle datetime string + timedelta
314
+ if isinstance(res, datetime.timedelta):
315
+ tmp = _try_parse_datetime(tmp)
316
+ elif isinstance(tmp, datetime.timedelta):
317
+ res = _try_parse_datetime(res)
287
318
  try:
288
319
  tmp = tmp + res
289
320
  except TypeError:
290
321
  pass
291
322
 
292
- # if isinstance(res, list):
293
- # l_res.append(sum([xx for xx in res[1:]]))
294
- # else:
295
- # l_res.append(res)
296
-
323
+ # Convert datetime result back to string
324
+ if isinstance(tmp, (datetime.datetime, datetime.date)):
325
+ return tmp.isoformat()
297
326
  return tmp
298
327
 
299
328
  # tmp = 0
@@ -324,6 +353,22 @@ def create_mathjson_solver(solver_parameters):
324
353
  l_res.append(res)
325
354
  return Add(l_res)
326
355
 
356
+ def Subtract(s):
357
+ values = [f(x, c) for x in s[1:]]
358
+ # Convert datetime strings if we're dealing with timedelta
359
+ converted = []
360
+ for i, v in enumerate(values):
361
+ if isinstance(v, datetime.timedelta):
362
+ converted.append(v)
363
+ elif any(isinstance(other, datetime.timedelta) for other in values):
364
+ converted.append(_try_parse_datetime(v))
365
+ else:
366
+ converted.append(v)
367
+ result = reduce(lambda a, b: a - b, converted)
368
+ if isinstance(result, (datetime.datetime, datetime.date)):
369
+ return result.isoformat()
370
+ return result
371
+
327
372
  def Max(s):
328
373
  if isinstance(s[1], str):
329
374
  return max([f(x, c) for x in f(s[1], c) if is_numeric(f(x, c))])
@@ -360,10 +405,16 @@ def create_mathjson_solver(solver_parameters):
360
405
  return len([x for x in s[1][1:]])
361
406
 
362
407
  def Any(s):
363
- return any([f(x, c) for x in s[1][1:]])
408
+ evaluated = f(s[1], c)
409
+ if isinstance(evaluated, list) and evaluated[0] == "Array":
410
+ return any([f(x, c) for x in evaluated[1:]])
411
+ raise ValueError("Parameter 1 must be an array.")
364
412
 
365
413
  def All(s):
366
- return all([f(x, c) for x in s[1][1:]])
414
+ evaluated = f(s[1], c)
415
+ if isinstance(evaluated, list) and evaluated[0] == "Array":
416
+ return all([f(x, c) for x in evaluated[1:]])
417
+ raise ValueError("Parameter 1 must be an array.")
367
418
 
368
419
  def Int(s):
369
420
  try:
@@ -374,6 +425,12 @@ def create_mathjson_solver(solver_parameters):
374
425
  def Float(s):
375
426
  return float(f(s[1], c))
376
427
 
428
+ def Floor(s):
429
+ return math.floor(f(s[1], c))
430
+
431
+ def Ceil(s):
432
+ return math.ceil(f(s[1], c))
433
+
377
434
  def Constants(s):
378
435
  for x in s[1:-1]:
379
436
  c[x[0]] = f(x[1], c)
@@ -556,18 +613,18 @@ def create_mathjson_solver(solver_parameters):
556
613
  def Strptime(s):
557
614
  datetime_str = f(s[1], c)
558
615
  parameters = f(s[2], c)
559
- return datetime.datetime.strptime(datetime_str, parameters)
616
+ return datetime.datetime.strptime(datetime_str, parameters).isoformat()
560
617
 
561
618
  def Strftime(s):
562
- dt = f(s[1], c)
619
+ dt = _try_parse_datetime(f(s[1], c))
563
620
  parameters = f(s[2], c)
564
621
  return dt.strftime(parameters)
565
622
 
566
623
  def Now(s):
567
- return datetime.datetime.now()
624
+ return datetime.datetime.now().isoformat()
568
625
 
569
626
  def Today(s):
570
- return datetime.date.today()
627
+ return datetime.date.today().isoformat()
571
628
 
572
629
  def TimeDeltaDays(s):
573
630
  return datetime.timedelta(days=f(s[1], c))
@@ -629,6 +686,26 @@ def create_mathjson_solver(solver_parameters):
629
686
  except TypeError:
630
687
  return False
631
688
 
689
+ def BooleanAnd(s):
690
+ """
691
+ Boolean AND operation.
692
+ ["And", condition1, condition2, ...]
693
+ """
694
+ for x in s[1:]:
695
+ if not f(x, c):
696
+ return False
697
+ return True
698
+
699
+ def BooleanOr(s):
700
+ """
701
+ Boolean OR operation.
702
+ ["Or", condition1, condition2, ...]
703
+ """
704
+ for x in s[1:]:
705
+ if f(x, c):
706
+ return True
707
+ return False
708
+
632
709
  # sin, cos, tan, arcsin, arccos, arctan
633
710
  def Sin(s):
634
711
  return math.sin(f(s[1], c))
@@ -840,6 +917,18 @@ def create_mathjson_solver(solver_parameters):
840
917
  return ["Array"] + _CumulativeProduct(array)
841
918
  # return _CumulativeProduct(array)
842
919
 
920
+ def CumulativeSum(s):
921
+ """
922
+ ["CumulativeSum", array]
923
+ The `array` must be an array of numeric values.
924
+ """
925
+ array = f(s[1], c)
926
+ if not (isinstance(array, list) and array[0] == "Array"):
927
+ raise ValueError("Parameter 1 must be an array.")
928
+ array = [f(x, c) for x in array[1:]]
929
+ return ["Array"] + _CumulativeSum(array)
930
+ # return
931
+
843
932
  def Interp(s):
844
933
  """
845
934
  ["Interp", x_array, y_array, target_x]
@@ -900,12 +989,53 @@ def create_mathjson_solver(solver_parameters):
900
989
 
901
990
  # return total_area
902
991
 
992
+ def Reduce(s):
993
+ """
994
+ ["Reduce", list, initial_value, function, str_name_of_accumulator, str_name_of_current, str_name_of_index]
995
+ """
996
+ the_list = f(s[1], c)[1:]
997
+ initial_value = f(s[2], c)
998
+ function_expression = s[3]
999
+
1000
+ _accumulator = s[4]
1001
+ name_accumulator = _accumulator[1]
1002
+
1003
+ _current = s[5]
1004
+ name_current = _current[1]
1005
+
1006
+ _index = s[6]
1007
+ name_index = _index[1]
1008
+
1009
+ c[name_accumulator] = initial_value
1010
+
1011
+ for i, x in enumerate(the_list):
1012
+ c[name_current] = x
1013
+ c[name_index] = i
1014
+ c[name_accumulator] = f(function_expression, c)
1015
+
1016
+ return c[name_accumulator]
1017
+
1018
+ def Appended(s):
1019
+ """
1020
+ ["Appended", array, value]
1021
+ The `array` must be an array of values.
1022
+ The `value` is the value to append to the array.
1023
+ """
1024
+ array = f(s[1], c)
1025
+
1026
+ if not (isinstance(array, list) and array[0] == "Array"):
1027
+ raise ValueError("Parameter 1 must be an array.")
1028
+
1029
+ value = f(s[2], c)
1030
+
1031
+ array = [x for x in array[1:]]
1032
+ array.append(value)
1033
+ return ["Array"] + array
1034
+
903
1035
  constructs = {
904
1036
  "Sum": Sum,
905
1037
  "Add": Add,
906
- "Subtract": lambda s: reduce(
907
- lambda a, b: a - b, [f(x, c) for x in s[1:]]
908
- ),
1038
+ "Subtract": Subtract,
909
1039
  "Constants": Constants,
910
1040
  "Switch": Switch,
911
1041
  "StrictSwitch": StrictSwitch,
@@ -939,6 +1069,8 @@ def create_mathjson_solver(solver_parameters):
939
1069
  # "NotEqual": lambda s: f(s[1], c) != f(s[2], c),
940
1070
  "NotEqual": lambda s: comparison_safe_converter(f(s[1], c))
941
1071
  != comparison_safe_converter(f(s[2], c)),
1072
+ "And": BooleanAnd,
1073
+ "Or": BooleanOr,
942
1074
  "Abs": lambda s: abs(f(s[1], c)),
943
1075
  "Round": lambda s: (
944
1076
  round(f(s[1], c), f(s[2], c))
@@ -964,6 +1096,8 @@ def create_mathjson_solver(solver_parameters):
964
1096
  "ContainsNoneOf": Contains_none_of,
965
1097
  "Int": Int,
966
1098
  "Float": Float,
1099
+ "Floor": Floor,
1100
+ "Ceil": Ceil,
967
1101
  "Str": Str,
968
1102
  "Not": Not,
969
1103
  # "IsDefined": lambda s: s[1] in c,
@@ -992,9 +1126,12 @@ def create_mathjson_solver(solver_parameters):
992
1126
  "AtIndex": AtIndex,
993
1127
  "Slice": Slice,
994
1128
  "CumulativeProduct": CumulativeProduct,
1129
+ "CumulativeSum": CumulativeSum,
995
1130
  "Interp": Interp,
996
1131
  "FindIntervalIndex": FindIntervalIndex,
997
1132
  "TrapezoidalIntegrate": TrapezoidalIntegrate,
1133
+ "Reduce": Reduce,
1134
+ "Appended": Appended,
998
1135
  "Sin": Sin,
999
1136
  "Cos": Cos,
1000
1137
  "Tan": Tan,
@@ -1066,6 +1203,8 @@ def extract_variables(s: Union[list, int, float, str], li: set, ignore_list: set
1066
1203
  "Less",
1067
1204
  "LessEqual",
1068
1205
  "NotEqual",
1206
+ "And",
1207
+ "Or",
1069
1208
  "Abs",
1070
1209
  "Round",
1071
1210
  "Max",
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathjson-solver
3
- Version: 1.16.1
3
+ Version: 1.18.0
4
4
  Summary: Utilities for MathJSON evaluation
5
5
  Home-page: https://github.com/LongenesisLtd/mathjson-solver
6
6
  Author: Martins Mednis
7
7
  Author-email: mrt@mednis.info
8
8
  Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: MIT License
11
10
  Classifier: Operating System :: OS Independent
12
11
  Requires-Python: >=3.6
13
12
  Description-Content-Type: text/markdown
@@ -33,8 +32,6 @@ A reliable Python library for numerically evaluating mathematical expressions in
33
32
 
34
33
  **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
34
 
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
35
  ## Table of Contents
39
36
  - [Installation](#installation)
40
37
  - [Quick Start](#quick-start)
@@ -80,21 +77,32 @@ except MathJSONException as e:
80
77
  # Math error: Problem in Divide. ['Divide', 1, 0]. division by zero
81
78
  ```
82
79
 
80
+ **Think Functional:** MathJSON Solver embraces functional programming principles. Instead of writing loops and modifying variables, you compose expressions that transform data. Functions like `Map`, `Reduce`, and `Filter` let you process arrays elegantly, while immutable operations ensure predictable, side-effect-free calculations. Don't worry if you're new to functional programming — the examples will guide you naturally into this powerful paradigm.
81
+
82
+ ```python
83
+ # Functional approach: transform data with expressions
84
+ solver(["Map", ["Array", 1, 2, 3, 4], ["Multiply"], 2]) # [2, 4, 6, 8]
85
+ solver(["Reduce", ["Array", 1, 2, 3, 4], 0, ["Add", "acc", "item"],
86
+ ["Variable", "acc"], ["Variable", "item"], ["Variable", "i"]]) # 10
87
+ ```
88
+
83
89
  ## Supported Operations
84
90
 
85
91
  The library supports a comprehensive set of mathematical operations:
86
92
 
87
- * **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round
93
+ * **Arithmetic:** Add, Sum, Subtract, Multiply, Divide, Negate, Power, Square, Root, Sqrt, Abs, Round, Floor, Ceil
88
94
  * **Trigonometry:** Sin, Cos, Tan, Arcsin, Arccos, Arctan
89
95
  * **Logarithms:** Log, Log2, Log10, Exp
90
96
  * **Comparison:** Equal, StrictEqual, NotEqual, Greater, GreaterEqual, Less, LessEqual
91
- * **Logic & Sets:** Any, All, Not, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
97
+ * **Logic & Sets:** Any, All, Not, And, Or, In, NotIn, ContainsAnyOf, ContainsAllOf, ContainsNoneOf
92
98
  * **Statistics:** Average, Max, Min, Median, Length
93
- * **Arrays:** Array creation and manipulation with Map function
99
+ * **Functional Programming:** Map, Reduce, Filter
100
+ * **Arrays:** Array creation, GenerateRange, AtIndex, Slice, Appended, CumulativeSum, CumulativeProduct
94
101
  * **Control Flow:** If statements, Switch-Case, Constants definition
95
102
  * **Type Conversion:** Int, Float, Str, IsDefined
96
- * **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions
97
- * **Advanced:** HasMatchingSublist, TrapezoidalIntegrate (requires numpy), Variable references
103
+ * **Date/Time:** Strptime, Strftime, Today, Now, TimeDelta functions (Weeks, Days, Hours, Minutes)
104
+ * **Integration:** TrapezoidalIntegrate (requires numpy), Interp, FindIntervalIndex, Variable references
105
+ * **Advanced:** HasMatchingSublist for pattern matching
98
106
  * **Constants:** Pi
99
107
 
100
108
  [View complete documentation with examples →](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md)
@@ -161,6 +169,10 @@ We welcome contributions! Please feel free to:
161
169
 
162
170
  [View license information](https://github.com/LongenesisLtd/mathjson-solver/blob/main/LICENSE)
163
171
 
172
+ ## References
173
+
174
+ This implementation was inspired by the [CortexJS Compute Engine](https://cortexjs.io/compute-engine/), though designed as an independent implementation focused on our specific use cases.
175
+
164
176
  ---
165
177
 
166
178
  Made with ❤️ by [Longenesis](https://longenesis.com/team)
@@ -9,10 +9,10 @@ src/mathjson_solver.egg-info/PKG-INFO
9
9
  src/mathjson_solver.egg-info/SOURCES.txt
10
10
  src/mathjson_solver.egg-info/dependency_links.txt
11
11
  src/mathjson_solver.egg-info/top_level.txt
12
- tests/test_CumulativeProduct.py
13
- tests/test_Slice.py
14
12
  tests/test_TrapezoidalIntegratel.py
15
13
  tests/test_atindex.py
14
+ tests/test_cumulative.py
15
+ tests/test_datetime.py
16
16
  tests/test_equal.py
17
17
  tests/test_exceptions.py
18
18
  tests/test_extract_variables.py
@@ -20,7 +20,10 @@ tests/test_findinterval.py
20
20
  tests/test_gail_model.py
21
21
  tests/test_interpolate.py
22
22
  tests/test_range.py
23
+ tests/test_reduce_simple.py
23
24
  tests/test_scalars.py
24
25
  tests/test_sets.py
25
26
  tests/test_simple_cases.py
27
+ tests/test_slice.py
28
+ tests/test_state_tuples_reduce.py
26
29
  tests/test_with_pytest.py
@@ -16,3 +16,14 @@ def test_CumulativeProduct1():
16
16
  solver = create_solver(parameters)
17
17
  # assert solver(expression) == expected_result
18
18
  assert solver(expression) == expected_result
19
+
20
+
21
+ def test_CumulativeSum1():
22
+ parameters = {"test_array": ["Array", 1, 2, 3, 4, 5]}
23
+
24
+ expression = ["CumulativeSum", "test_array"]
25
+
26
+ expected_result = ["Array", 1, 3, 6, 10, 15]
27
+ solver = create_solver(parameters)
28
+ # assert solver(expression) == expected_result
29
+ assert solver(expression) == expected_result