mathai 0.7.8__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mathai/simplify.py CHANGED
@@ -15,9 +15,9 @@ def convert_to_basic(node):
15
15
  return node
16
16
 
17
17
  def clear_div(eq, denom):
18
-
18
+
19
19
  lst = factor_generation(eq)
20
-
20
+
21
21
  if tree_form("d_0") in lst:
22
22
  return tree_form("d_0"), True
23
23
 
@@ -32,16 +32,16 @@ def clear_div(eq, denom):
32
32
  eq2 = []
33
33
  eq3 = []
34
34
  for item in lst:
35
- if frac(item) is not None:#"v_" not in str_form(item):
35
+ if frac(item) is not None:
36
36
  eq2.append(item)
37
37
  else:
38
38
  eq3.append(item)
39
-
39
+
40
40
  if eq3 == []:
41
41
  return product(eq2), True
42
42
  return product(eq3), sign
43
43
  lst4 = []
44
-
44
+
45
45
  for item in lst:
46
46
  if item.name == "f_pow":
47
47
  tmp = frac(item.children[1])
@@ -49,73 +49,18 @@ def clear_div(eq, denom):
49
49
  lst4.append(item)
50
50
  else:
51
51
  lst4.append(item)
52
-
52
+
53
53
  lst2 = []
54
54
  for item in lst4:
55
- if frac(item) is None:#"v_" in str_form(item):
55
+ if frac(item) is None:
56
56
  lst2.append(item)
57
-
57
+
58
58
  if lst2 == []:
59
59
  return product(lst4), sign
60
60
  return product(lst2), sign
61
- '''
62
- def multiply_node(eq):
63
- if not eq.name.startswith("f_"):
64
- return eq
65
- if eq.name == "f_mul":
66
- con = 1
67
- eq2 = TreeNode("f_mul", [])
68
- for i in range(len(eq.children)-1,-1,-1):
69
- if frac(eq.children[i]) is not None:
70
- con = con * frac(eq.children[i])
71
- else:
72
- eq2.children.append(eq.children[i])
73
- if con == 0:
74
- return tree_form("d_0")
75
- eq2.name = eq.name
76
- eq = eq2
77
61
 
78
- lst = {}
79
- for child in eq.children:
80
- power = tree_form("d_1")
81
- con2 = ""
82
- if child.name == "f_pow":
83
- con2 = child.children[0]
84
- power = child.children[1]
85
- else:
86
- con2 = child
87
- if con2 in lst.keys():
88
- lst[con2] = lst[con2] + power
89
- else:
90
- lst[con2] = power
91
- eq3 = TreeNode("f_mul", [])
92
-
93
- for kv in lst.keys():
94
- tmp3 = lst[kv]
95
- if tmp3 == tree_form("d_1"):
96
- eq3.children.append(kv)
97
- elif tmp3 == tree_form("d_0"):
98
- continue
99
- else:
100
- eq3.children.append(kv ** tmp3)
101
-
102
- tmp3 = frac_to_tree(con)
103
- if tmp3 != tree_form("d_1"):
104
- eq3.children.append(tmp3)
105
- eq = eq3
106
- eq4 = TreeNode(eq.name, [])
107
- if eq.children == []:
108
- return tree_form("d_1")
109
- if len(eq.children) == 1:
110
- eq4 = eq.children[0]
111
- eq = eq4
112
- return TreeNode(eq.name, [multiply_node(child) for child in eq.children])
113
- '''
114
62
  def multiply_node(equation):
115
- """
116
- Iterative version of multiply_node without using TreeNode as dict key.
117
- """
118
- # Stack: (node, child_index, partially_processed_children)
63
+
119
64
  if equation is None:
120
65
  return None
121
66
  stack = [(equation, 0, [])]
@@ -123,13 +68,11 @@ def multiply_node(equation):
123
68
  while stack:
124
69
  node, child_index, processed_children = stack.pop()
125
70
 
126
- # If all children processed
127
71
  if child_index >= len(node.children):
128
72
  node.children = processed_children
129
73
 
130
- # Only process multiplication nodes
131
74
  if node.name == "f_mul":
132
- # Step 1: combine numeric constants
75
+
133
76
  con = 1
134
77
  new_children = []
135
78
  for child in reversed(node.children):
@@ -141,7 +84,7 @@ def multiply_node(equation):
141
84
 
142
85
  if con == 0:
143
86
  node = tree_form("d_0")
144
- # Return to parent
87
+
145
88
  if stack:
146
89
  parent, idx, parent_children = stack.pop()
147
90
  parent_children.append(node)
@@ -152,8 +95,6 @@ def multiply_node(equation):
152
95
 
153
96
  node.children = new_children
154
97
 
155
- # Step 2: combine powers of same base iteratively
156
- # Instead of using dict, we collect (base, exponent) in a list
157
98
  base_powers = []
158
99
  for child in node.children:
159
100
  if child.name == "f_pow":
@@ -162,17 +103,15 @@ def multiply_node(equation):
162
103
  base = child
163
104
  power = tree_form("d_1")
164
105
 
165
- # Look for existing base in base_powers (by structural equality)
166
106
  found = False
167
107
  for i, (b, p) in enumerate(base_powers):
168
- if b == base: # structural equality check
108
+ if b == base:
169
109
  base_powers[i] = (b, p + power)
170
110
  found = True
171
111
  break
172
112
  if not found:
173
113
  base_powers.append((base, power))
174
114
 
175
- # Step 3: rebuild multiplication node
176
115
  new_mul = TreeNode("f_mul", [])
177
116
  for base, power in base_powers:
178
117
  if power == tree_form("d_1"):
@@ -182,12 +121,10 @@ def multiply_node(equation):
182
121
  else:
183
122
  new_mul.children.append(TreeNode("f_pow", [base, power]))
184
123
 
185
- # Step 4: add numeric constant
186
124
  con_tree = frac_to_tree(con)
187
125
  if con_tree != tree_form("d_1"):
188
126
  new_mul.children.append(con_tree)
189
127
 
190
- # Step 5: simplify trivial cases
191
128
  if not new_mul.children:
192
129
  node = tree_form("d_1")
193
130
  elif len(new_mul.children) == 1:
@@ -195,100 +132,22 @@ def multiply_node(equation):
195
132
  else:
196
133
  node = new_mul
197
134
 
198
- # Return node to parent
199
135
  if stack:
200
136
  parent, idx, parent_children = stack.pop()
201
137
  parent_children.append(node)
202
138
  stack.append((parent, idx + 1, parent_children))
203
139
  else:
204
- return node # fully processed root
140
+ return node
205
141
 
206
142
  else:
207
- # Push current node back to continue with next child
143
+
208
144
  stack.append((node, child_index, processed_children))
209
- # Push next child to stack
145
+
210
146
  child = node.children[child_index]
211
147
  stack.append((child, 0, []))
212
- '''
213
- def addition_node(eq):
214
- if not eq.name.startswith("f_"):
215
- return eq
216
- if eq.name == "f_add":
217
- con = 0
218
- eq2 = TreeNode("f_add", [])
219
- for i in range(len(eq.children)-1,-1,-1):
220
- n = frac(eq.children[i])
221
- if n is not None:
222
- con = con + n
223
- else:
224
- eq2.children.append(eq.children[i])
225
- eq2.name = eq.name
226
- eq = eq2
227
148
 
228
- lst = {}
229
- for child in eq.children:
230
- power = TreeNode("f_mul", [])
231
- con2 = None
232
- con3 = TreeNode("f_mul", [])
233
- power2 = None
234
-
235
- if child.name == "f_mul":
236
- for i in range(len(child.children)):
237
- if "v_" not in str_form(child.children[i]):
238
- if child.children[i] != tree_form("d_0"):
239
- power.children.append(child.children[i])
240
- else:
241
- if child.children[i] != tree_form("d_1"):
242
- con3.children.append(child.children[i])
243
- if len(con3.children) == 0:
244
- con2 = tree_form("d_1")
245
- elif len(con3.children) == 1:
246
- con2 = con3.children[0]
247
- else:
248
- con2 = con3
249
- else:
250
- con2 = child
251
-
252
- if power.children == []:
253
- power2 = tree_form("d_1")
254
- elif len(power.children) == 1:
255
- power2 = power.children[0]
256
- else:
257
- power2 = power
258
-
259
- if con2 in lst.keys():
260
- lst[con2] = lst[con2] + power2
261
- else:
262
- lst[con2] = power2
263
- eq3 = TreeNode("f_add", [])
264
-
265
- for kv in lst.keys():
266
- tmp3 = lst[kv]
267
- if tmp3 == tree_form("d_1"):
268
- eq3.children.append(kv)
269
- elif tmp3 == tree_form("d_0"):
270
- continue
271
- else:
272
- eq3.children.append(kv * tmp3)
273
-
274
- eq = eq3
275
- eq4 = None
276
- tmp3 = frac_to_tree(con)
277
- if tmp3 != tree_form("d_0"):
278
- eq.children.append(tmp3)
279
- if eq.children == []:
280
- return tree_form("d_0")
281
- if len(eq.children) == 1:
282
- eq4 = eq.children[0]
283
- eq = eq4
284
- return TreeNode(eq.name, [addition_node(child) for child in eq.children])
285
- '''
286
149
  def addition_node(equation):
287
- """
288
- Iterative version of addition_node.
289
- Combines constants and like terms in addition nodes.
290
- """
291
- # Stack: (node, child_index, partially_processed_children)
150
+
292
151
  if equation is None:
293
152
  return None
294
153
  stack = [(equation, 0, [])]
@@ -296,13 +155,11 @@ def addition_node(equation):
296
155
  while stack:
297
156
  node, child_index, processed_children = stack.pop()
298
157
 
299
- # If all children are processed
300
158
  if child_index >= len(node.children):
301
159
  node.children = processed_children
302
160
 
303
- # Only process addition nodes
304
161
  if node.name == "f_add":
305
- # Step 1: combine numeric constants
162
+
306
163
  con = 0
307
164
  new_children = []
308
165
  for child in reversed(node.children):
@@ -314,11 +171,9 @@ def addition_node(equation):
314
171
 
315
172
  node.children = new_children
316
173
 
317
- # Step 2: combine like terms iteratively
318
- # We store (base, power) pairs in a list (avoid dict/hash)
319
174
  base_terms = []
320
175
  for child in node.children:
321
- # Decompose child into base and multiplier
176
+
322
177
  power_node = TreeNode("f_mul", [])
323
178
  base_node = None
324
179
  mul_node = TreeNode("f_mul", [])
@@ -326,10 +181,10 @@ def addition_node(equation):
326
181
 
327
182
  if child.name == "f_mul":
328
183
  for c in child.children:
329
- if frac(c) is not None: # constant part
184
+ if frac(c) is not None:
330
185
  if c != tree_form("d_0"):
331
186
  power_node.children.append(c)
332
- else: # variable part
187
+ else:
333
188
  if c != tree_form("d_1"):
334
189
  mul_node.children.append(c)
335
190
  if len(mul_node.children) == 0:
@@ -348,7 +203,6 @@ def addition_node(equation):
348
203
  else:
349
204
  multiplier_node = power_node
350
205
 
351
- # Combine like terms structurally
352
206
  found = False
353
207
  for i, (b, m) in enumerate(base_terms):
354
208
  if b == base_node:
@@ -358,7 +212,6 @@ def addition_node(equation):
358
212
  if not found:
359
213
  base_terms.append((base_node, multiplier_node))
360
214
 
361
- # Step 3: rebuild addition node
362
215
  new_add = TreeNode("f_add", [])
363
216
  for base, multiplier in base_terms:
364
217
  if multiplier == tree_form("d_1"):
@@ -368,12 +221,10 @@ def addition_node(equation):
368
221
  else:
369
222
  new_add.children.append(base * multiplier)
370
223
 
371
- # Step 4: add numeric constant
372
224
  con_tree = frac_to_tree(con)
373
225
  if con_tree != tree_form("d_0"):
374
226
  new_add.children.append(con_tree)
375
227
 
376
- # Step 5: simplify trivial cases
377
228
  if not new_add.children:
378
229
  node = tree_form("d_0")
379
230
  elif len(new_add.children) == 1:
@@ -381,19 +232,18 @@ def addition_node(equation):
381
232
  else:
382
233
  node = new_add
383
234
 
384
- # Return node to parent
385
235
  if stack:
386
236
  parent, idx, parent_children = stack.pop()
387
237
  parent_children.append(node)
388
238
  stack.append((parent, idx + 1, parent_children))
389
239
  else:
390
- # Root node fully processed
240
+
391
241
  return node
392
242
 
393
243
  else:
394
- # Push current node back for next child
244
+
395
245
  stack.append((node, child_index, processed_children))
396
- # Push next child to stack
246
+
397
247
  child = node.children[child_index]
398
248
  stack.append((child, 0, []))
399
249
 
@@ -422,7 +272,7 @@ def other_node(eq):
422
272
  if eq.children[0].name == "f_abs" and eq.children[1].name.startswith("d_")\
423
273
  and int(eq.children[1].name[2:]) % 2 == 0:
424
274
  return eq.children[0].children[0] ** eq.children[1]
425
-
275
+
426
276
  if eq.children[0].name == "f_mul":
427
277
  n = frac(eq.children[1])
428
278
  if n is not None and n < 0 and n.numerator % 2 == 1 and n.denominator == 1:
@@ -517,7 +367,7 @@ def simplify(eq, basic=True):
517
367
  tmp2 = simplify(eq.children[0] - eq.children[1])
518
368
  tmp, denom = clear_div(tmp2, denom)
519
369
  tmp = simplify(tmp)
520
-
370
+
521
371
  value2 = eq.name[2:]
522
372
  if denom is False:
523
373
  value2 = {"ge":"le", "le":"ge", "gt":"lt", "lt":"gt", "eq":"eq"}[value2]
@@ -529,3 +379,4 @@ def simplify(eq, basic=True):
529
379
  eq = convert_to_basic(eq)
530
380
  eq = solve3(eq)
531
381
  return eq
382
+
mathai/structure.py CHANGED
@@ -2,7 +2,7 @@ import itertools
2
2
  from .simplify import simplify
3
3
  from .base import *
4
4
 
5
- def structure(equation, formula, formula_out=None, only_const=False):
5
+ def structure(equation, formula, formula_out=None, only_const=False, wrt=None):
6
6
  varlist = {}
7
7
  def helper(equation, formula):
8
8
  nonlocal varlist
@@ -60,7 +60,7 @@ def structure(equation, formula, formula_out=None, only_const=False):
60
60
  for item in lst(formula):
61
61
  varlist = {}
62
62
  if helper(equation, item):
63
- if only_const and any("v_" in str_form(varlist[key]) for key in varlist.keys()):
63
+ if only_const and any(contain(varlist[key], tree_form(wrt)) for key in varlist.keys()):
64
64
  continue
65
65
  if formula_out is None:
66
66
  return varlist
@@ -90,7 +90,7 @@ def transform_formula(equation, wrt, formula_list, var, expr):
90
90
  if var != "":
91
91
  p = True
92
92
  try:
93
- out = structure(equation.copy_tree(), copy.deepcopy(item[0]), copy.deepcopy(item[1]), p)
93
+ out = structure(equation.copy_tree(), copy.deepcopy(item[0]), copy.deepcopy(item[1]), p, wrt)
94
94
  if out is not None:
95
95
  out = simplify(out)
96
96
 
mathai/tool.py CHANGED
@@ -8,68 +8,58 @@ def poly_div(dividend_coeffs, divisor_coeffs):
8
8
  """
9
9
  Perform polynomial division using coefficients with symbolic simplification.
10
10
  """
11
- # Deep copy inputs using copy_tree()
11
+
12
12
  dividend = [item.copy_tree() for item in dividend_coeffs]
13
13
  divisor = [item.copy_tree() for item in divisor_coeffs]
14
-
15
- # Remove leading zeros
14
+
16
15
  while len(dividend) > 1 and simplify(dividend[0]) == 0:
17
16
  dividend.pop(0)
18
17
  while len(divisor) > 1 and simplify(divisor[0]) == 0:
19
18
  divisor.pop(0)
20
-
21
- # Validate divisor
19
+
22
20
  if len(divisor) == 0 or simplify(divisor[0]) == 0:
23
21
  raise ValueError("Invalid divisor")
24
-
22
+
25
23
  if len(dividend) < len(divisor):
26
24
  return [tree_form("d_0")], [item.copy_tree() for item in dividend]
27
-
28
- # Calculate degrees
25
+
29
26
  deg_p = len(dividend) - 1
30
27
  deg_q = len(divisor) - 1
31
28
  deg_quot = deg_p - deg_q
32
-
33
- # Initialize quotient (highest degree first)
29
+
34
30
  quotient = [tree_form("d_0")] * (deg_quot + 1)
35
-
36
- # Working dividend - keep original structure
31
+
37
32
  working_dividend = [item.copy_tree() for item in dividend]
38
-
39
- # Long division - align by current leading terms
33
+
40
34
  for k in range(deg_quot, -1, -1):
41
- # Remove leading zeros from working dividend
35
+
42
36
  while len(working_dividend) > 1 and simplify(working_dividend[0]) == 0:
43
37
  working_dividend.pop(0)
44
-
38
+
45
39
  if len(working_dividend) == 0 or simplify(working_dividend[0]) == 0:
46
40
  continue
47
-
48
- # Calculate quotient term for degree k
41
+
49
42
  leading_ratio = simplify(working_dividend[0] / divisor[0])
50
43
  quotient[k] = leading_ratio
51
-
52
- # Subtract leading_ratio * divisor (aligned at leading terms)
44
+
53
45
  new_dividend = []
54
46
  for i in range(max(len(working_dividend), len(divisor))):
55
47
  dividend_term = working_dividend[i] if i < len(working_dividend) else tree_form("d_0")
56
48
  divisor_term = simplify(leading_ratio * divisor[i]) if i < len(divisor) else tree_form("d_0")
57
49
  result = simplify(dividend_term - divisor_term)
58
50
  new_dividend.append(result)
59
-
51
+
60
52
  working_dividend = new_dividend
61
-
62
- # Remainder is terms with degree < deg_q (last deg_q terms of final dividend)
53
+
63
54
  remainder = working_dividend[-(deg_q):] if len(working_dividend) > deg_q else working_dividend
64
55
  while len(remainder) > 1 and simplify(remainder[0]) == 0:
65
56
  remainder.pop(0)
66
57
  if not remainder:
67
58
  remainder = [tree_form("d_0")]
68
-
69
- # Clean quotient trailing zeros
59
+
70
60
  while len(quotient) > 1 and simplify(quotient[-1]) == 0:
71
61
  quotient.pop()
72
-
62
+
73
63
  return quotient, remainder
74
64
 
75
65
  def unpoly(eq, var):
@@ -80,7 +70,7 @@ def unpoly(eq, var):
80
70
 
81
71
  def longdiv(p, q, p_min=0, q_min=0):
82
72
  p, q = simplify(p), simplify(q)
83
-
73
+
84
74
  var = set(vlist(p)) & set(vlist(q))
85
75
  if len(var) > 0:
86
76
  var = list(var)[0]
@@ -114,7 +104,7 @@ def enclose_const(eq):
114
104
  nonlocal alloclst, dic
115
105
  if frac(eq) is not None:
116
106
  return eq
117
-
107
+
118
108
  if "v_" not in str_form(eq):
119
109
  if eq not in dic.keys():
120
110
  n = alloclst.pop(0)
@@ -161,3 +151,4 @@ def poly(eq, to_compute, m=10):
161
151
  final.append(substitute_val(item, 0, to_compute)/tree_form("d_"+str(math.factorial(index))))
162
152
 
163
153
  return [expand(simplify(item)) for item in final][::-1]
154
+