mathjson-solver 1.8.0__tar.gz → 1.9.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mathjson-solver
3
- Version: 1.8.0
3
+ Version: 1.9.0
4
4
  Summary: Utilities for MathJSON evaluation
5
5
  Home-page: https://github.com/LongenesisLtd/mathjson-solver
6
6
  Author: Martins Mednis
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = mathjson-solver
3
- version = 1.8.0
3
+ version = 1.9.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.8.0",
8
+ version="1.9.0",
9
9
  author="Martins Mednis",
10
10
  author_email="mrt@mednis.info",
11
11
  description="Utilities for MathJSON evaluation",
@@ -47,6 +47,86 @@ def is_numeric(x):
47
47
  return True
48
48
 
49
49
 
50
+ def has_matching_sublist(
51
+ *,
52
+ my_list: list,
53
+ required_match_count: int,
54
+ position: int,
55
+ contiguous: bool,
56
+ conditions: list[bool],
57
+ ) -> bool:
58
+ if contiguous:
59
+ # Check for contiguous matches based on position
60
+ if position == 0:
61
+ # Check if the beginning of the list matches
62
+ count = sum(
63
+ 1
64
+ for i in range(min(required_match_count, len(my_list)))
65
+ if conditions[i]
66
+ )
67
+ return count == required_match_count
68
+ elif position > 0:
69
+ # Skip the first `position` elements
70
+ count = sum(
71
+ 1
72
+ for i in range(position, position + required_match_count)
73
+ if i < len(my_list) and conditions[i]
74
+ )
75
+ return count == required_match_count
76
+ elif position == -1:
77
+ # Check if the end of the list matches
78
+ count = sum(
79
+ 1
80
+ for i in range(len(my_list) - required_match_count, len(my_list))
81
+ if conditions[i]
82
+ )
83
+ return count == required_match_count
84
+ elif position < -1:
85
+ # Skip the last `abs(position)` elements
86
+ count = sum(1 for i in range(len(my_list) + position) if conditions[i])
87
+ return count == required_match_count
88
+ else:
89
+ # Check for non-contiguous matches
90
+ count = sum(1 for i in range(len(my_list)) if conditions[i])
91
+ return count >= required_match_count
92
+
93
+
94
+ def has_sublist2(
95
+ *,
96
+ my_list: list,
97
+ required_match_count: int,
98
+ position: int,
99
+ contiguous: bool,
100
+ condition: callable,
101
+ ) -> bool:
102
+ if contiguous:
103
+ # Check for contiguous matches based on position
104
+ if position == 0:
105
+ # Check if the beginning of the list matches
106
+ count = sum(1 for x in my_list[:required_match_count] if condition(x))
107
+ return count == required_match_count
108
+ elif position > 0:
109
+ # Skip the first `position` elements
110
+ count = sum(
111
+ 1
112
+ for x in my_list[position : position + required_match_count]
113
+ if condition(x)
114
+ )
115
+ return count == required_match_count
116
+ elif position == -1:
117
+ # Check if the end of the list matches
118
+ count = sum(1 for x in my_list[-required_match_count:] if condition(x))
119
+ return count == required_match_count
120
+ elif position < -1:
121
+ # Skip the last `abs(position)` elements
122
+ count = sum(1 for x in my_list[:position] if condition(x))
123
+ return count == required_match_count
124
+ else:
125
+ # Check for non-contiguous matches
126
+ count = sum(1 for x in my_list if condition(x))
127
+ return count >= required_match_count
128
+
129
+
50
130
  def create_mathjson_solver(solver_parameters):
51
131
  def f(s, *args):
52
132
  if args:
@@ -61,6 +141,16 @@ def create_mathjson_solver(solver_parameters):
61
141
  def Arr(s):
62
142
  return s
63
143
 
144
+ def Sum(s):
145
+ l_res = []
146
+ for x in s[1:]:
147
+ res = f(x, c)
148
+ if isinstance(res, list):
149
+ l_res.append(sum([xx for xx in res[1:]]))
150
+ else:
151
+ l_res.append(res)
152
+ return sum(l_res)
153
+
64
154
  # @requires_array
65
155
  def Max(s):
66
156
  if isinstance(s[1], str):
@@ -214,9 +304,48 @@ def create_mathjson_solver(solver_parameters):
214
304
  def Not(s):
215
305
  return not f(s[1])
216
306
 
307
+ def Map(s):
308
+ """
309
+ ["Map", list, function, more parameters]
310
+ The `function` must accept at least one parameter. That is for the current loop element.
311
+ The `more parameters` are for any additional parameters that function might have.
312
+ """
313
+ z = f(s[1], c)
314
+ if isinstance(z, list):
315
+ retlist = ["Array"]
316
+ for x in z[1:]:
317
+ the_function_name = s[2][0]
318
+ ss = [the_function_name, x] + s[3:]
319
+ retlist.append(f(ss, c))
320
+ return retlist
321
+
322
+ def HasMatchingSublist(s):
323
+ """
324
+ ["HasMatchingSublist", list, required_match_count, position, contiguous, function, more parameters]
325
+ """
326
+ the_list = f(s[1], c)[1:]
327
+ required_match_count = f(s[2], c)
328
+ position = f(s[3], c)
329
+ contiguous = f(s[4], c)
330
+ conditions = []
331
+
332
+ for i, x in enumerate(the_list):
333
+ the_function_name = s[5][0]
334
+ ss = [the_function_name, x] + s[6:]
335
+ conditions.append(f(ss, c))
336
+ pass
337
+
338
+ return has_matching_sublist(
339
+ my_list=the_list,
340
+ required_match_count=required_match_count,
341
+ position=position,
342
+ contiguous=contiguous,
343
+ conditions=conditions,
344
+ )
345
+
217
346
  constructs = {
218
- "Add": lambda s: sum([f(x, c) for x in s[1:]]),
219
- "Sum": lambda s: sum([f(x, c) for x in s[1:]]),
347
+ "Sum": Sum,
348
+ "Add": Sum,
220
349
  "Subtract": lambda s: reduce(
221
350
  lambda a, b: a - b, [f(x, c) for x in s[1:]]
222
351
  ),
@@ -270,6 +399,8 @@ def create_mathjson_solver(solver_parameters):
270
399
  "Str": Str,
271
400
  "Not": Not,
272
401
  "IsDefined": lambda s: s[1] in c,
402
+ "Map": Map,
403
+ "HasMatchingSublist": HasMatchingSublist,
273
404
  }
274
405
  if s[0] in constructs:
275
406
  try:
@@ -341,6 +472,8 @@ def extract_variables(s: Union[list, int, float, str], li: set, ignore_list: set
341
472
  "Str",
342
473
  "Not",
343
474
  "IsDefined",
475
+ "Map",
476
+ "HasMatchingSublist",
344
477
  ]
345
478
  if isinstance(s, str):
346
479
  if s in ignore_list:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mathjson-solver
3
- Version: 1.8.0
3
+ Version: 1.9.0
4
4
  Summary: Utilities for MathJSON evaluation
5
5
  Home-page: https://github.com/LongenesisLtd/mathjson-solver
6
6
  Author: Martins Mednis
@@ -13,6 +13,10 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
13
13
  [
14
14
  ({}, ["Add", 2, 4, 3], 9),
15
15
  ({}, ["Sum", 2, 4, 3], 9),
16
+ ({}, ["Sum", ["Array", 1, 1], 4, 3], 9),
17
+ ({}, ["Sum", ["Array", 2, 4, 3]], 9),
18
+ ({"a": 2}, ["Sum", "a", 4, 3], 9),
19
+ ({"a": ["Array", 1, 1]}, ["Sum", "a", 4, 3], 9),
16
20
  ({}, ["Subtract", 10, 5, 2], 3),
17
21
  ({}, ["Add", 5, 4, ["Negate", 3]], 6),
18
22
  ({}, ["Multiply", 2, 3, 4], 24),
@@ -168,6 +172,93 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
168
172
  ({}, ["Not", True], False),
169
173
  ({}, ["Not", 0], True),
170
174
  ({}, ["Not", ["In", 2, ["Array", 1, 2, 3]]], False),
175
+ ({}, ["Array", 2, 4, 3], ["Array", 2, 4, 3]),
176
+ ({}, ["Map", ["Array", 1, 2, 3], ["Square"]], ["Array", 1, 4, 9]),
177
+ ({}, ["Map", ["Array", 1, 2, 3], ["Power"], 2], ["Array", 1, 4, 9]),
178
+ (
179
+ {},
180
+ ["Map", ["Array", 1, 2, 3], ["GreaterEqual"], 2],
181
+ ["Array", False, True, True],
182
+ ),
183
+ # ["HasMatchingSublist", list, required_match_count, position, contiguous, function, more parameters]
184
+ (
185
+ {},
186
+ [
187
+ "HasMatchingSublist",
188
+ ["Array", 1, 2, 3, 4, 5, 6],
189
+ 3,
190
+ 0,
191
+ True,
192
+ ["GreaterEqual"],
193
+ 1,
194
+ ],
195
+ True, # first 3 elements are greater than 3
196
+ ),
197
+ (
198
+ {},
199
+ [
200
+ "HasMatchingSublist",
201
+ ["Array", 1, 2, 3, 4, 5, 6],
202
+ 3,
203
+ 0,
204
+ True,
205
+ ["GreaterEqual"],
206
+ 2,
207
+ ],
208
+ False, # first 3 elements are greater than 3 - False
209
+ ),
210
+ (
211
+ {},
212
+ [
213
+ "HasMatchingSublist",
214
+ ["Array", 1, 2, 3, 4, 5, 6],
215
+ 3,
216
+ 0,
217
+ False, # anywhere
218
+ ["GreaterEqual"],
219
+ 4,
220
+ ],
221
+ True,
222
+ ),
223
+ (
224
+ {},
225
+ [
226
+ "HasMatchingSublist",
227
+ ["Array", 1, 2, 3, 4, 5, 6],
228
+ 4,
229
+ 0,
230
+ False, # anywhere
231
+ ["GreaterEqual"],
232
+ 4,
233
+ ],
234
+ False,
235
+ ),
236
+ (
237
+ {},
238
+ [
239
+ "HasMatchingSublist",
240
+ ["Array", 1, 2, 3, 4, 5, 6],
241
+ 3,
242
+ -1,
243
+ True,
244
+ ["GreaterEqual"],
245
+ 4,
246
+ ],
247
+ True,
248
+ ),
249
+ (
250
+ {},
251
+ [
252
+ "HasMatchingSublist",
253
+ ["Array", 1, 2, 3, 4, 5, 6],
254
+ 5,
255
+ -1,
256
+ True,
257
+ ["GreaterEqual"],
258
+ 4,
259
+ ],
260
+ False,
261
+ ),
171
262
  ],
172
263
  )
173
264
  def test_solver_simple(parameters, expression, expected_result):
File without changes