mathai 2.2.4__tar.gz → 2.2.6__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 (57) hide show
  1. {mathai-2.2.4 → mathai-2.2.6}/PKG-INFO +36 -16
  2. {mathai-2.2.4 → mathai-2.2.6}/README.md +35 -14
  3. {mathai-2.2.4 → mathai-2.2.6}/mathai/__init__.py +1 -1
  4. {mathai-2.2.4 → mathai-2.2.6}/mathai/electronic.py +27 -206
  5. {mathai-2.2.4 → mathai-2.2.6}/mathai/graphics.py +1 -19
  6. {mathai-2.2.4 → mathai-2.2.6}/mathai/inverse.py +24 -13
  7. {mathai-2.2.4 → mathai-2.2.6}/mathai/linear.py +27 -11
  8. {mathai-2.2.4 → mathai-2.2.6}/mathai.egg-info/PKG-INFO +36 -16
  9. {mathai-2.2.4 → mathai-2.2.6}/mathai.egg-info/requires.txt +0 -1
  10. {mathai-2.2.4 → mathai-2.2.6}/setup.py +2 -3
  11. {mathai-2.2.4 → mathai-2.2.6}/mathai/apart.py +0 -0
  12. {mathai-2.2.4 → mathai-2.2.6}/mathai/base.py +0 -0
  13. {mathai-2.2.4 → mathai-2.2.6}/mathai/decision.py +0 -0
  14. {mathai-2.2.4 → mathai-2.2.6}/mathai/diff.py +0 -0
  15. {mathai-2.2.4 → mathai-2.2.6}/mathai/expand.py +0 -0
  16. {mathai-2.2.4 → mathai-2.2.6}/mathai/factor.py +0 -0
  17. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/differentiation.marshal +0 -0
  18. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/integration.marshal +0 -0
  19. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/integration_trig.marshal +0 -0
  20. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/is_integrate_subs.marshal +0 -0
  21. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/lambda_compress.marshal +0 -0
  22. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/lambda_expand.marshal +0 -0
  23. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/lambda_reduce.marshal +0 -0
  24. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/limit_infinity.marshal +0 -0
  25. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/matrix_vectorization_calculus.marshal +0 -0
  26. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/power_rule.marshal +0 -0
  27. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/quadratic.marshal +0 -0
  28. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/statistics_1.marshal +0 -0
  29. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/statistics_2.marshal +0 -0
  30. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/test.marshal +0 -0
  31. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula/trigonometry_misc.marshal +0 -0
  32. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula_compiler.py +0 -0
  33. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula_data.py +0 -0
  34. {mathai-2.2.4 → mathai-2.2.6}/mathai/formula_interpretor.py +0 -0
  35. {mathai-2.2.4 → mathai-2.2.6}/mathai/fraction.py +0 -0
  36. {mathai-2.2.4 → mathai-2.2.6}/mathai/integrate.py +0 -0
  37. {mathai-2.2.4 → mathai-2.2.6}/mathai/lambda_calculus.py +0 -0
  38. {mathai-2.2.4 → mathai-2.2.6}/mathai/limit.py +0 -0
  39. {mathai-2.2.4 → mathai-2.2.6}/mathai/logic.py +0 -0
  40. {mathai-2.2.4 → mathai-2.2.6}/mathai/matrix.py +0 -0
  41. {mathai-2.2.4 → mathai-2.2.6}/mathai/ml.py +0 -0
  42. {mathai-2.2.4 → mathai-2.2.6}/mathai/mlscalar.py +0 -0
  43. {mathai-2.2.4 → mathai-2.2.6}/mathai/ode.py +0 -0
  44. {mathai-2.2.4 → mathai-2.2.6}/mathai/parser.py +0 -0
  45. {mathai-2.2.4 → mathai-2.2.6}/mathai/pde.py +0 -0
  46. {mathai-2.2.4 → mathai-2.2.6}/mathai/printeq.py +0 -0
  47. {mathai-2.2.4 → mathai-2.2.6}/mathai/qm.py +0 -0
  48. {mathai-2.2.4 → mathai-2.2.6}/mathai/simplify.py +0 -0
  49. {mathai-2.2.4 → mathai-2.2.6}/mathai/statistics.py +0 -0
  50. {mathai-2.2.4 → mathai-2.2.6}/mathai/test.py +0 -0
  51. {mathai-2.2.4 → mathai-2.2.6}/mathai/tool.py +0 -0
  52. {mathai-2.2.4 → mathai-2.2.6}/mathai/trig.py +0 -0
  53. {mathai-2.2.4 → mathai-2.2.6}/mathai/univariate_inequality.py +0 -0
  54. {mathai-2.2.4 → mathai-2.2.6}/mathai.egg-info/SOURCES.txt +0 -0
  55. {mathai-2.2.4 → mathai-2.2.6}/mathai.egg-info/dependency_links.txt +0 -0
  56. {mathai-2.2.4 → mathai-2.2.6}/mathai.egg-info/top_level.txt +0 -0
  57. {mathai-2.2.4 → mathai-2.2.6}/setup.cfg +0 -0
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathai
3
- Version: 2.2.4
3
+ Version: 2.2.6
4
4
  Summary: Mathematics solving Ai tailored to NCERT
5
5
  Home-page: https://github.com/infinity390/mathai
6
6
  Requires-Python: >=3.7
7
7
  Description-Content-Type: text/markdown
8
8
  Requires-Dist: more_itertools
9
- Requires-Dist: schemdraw
10
9
  Dynamic: description
11
10
  Dynamic: description-content-type
12
11
  Dynamic: home-page
@@ -438,7 +437,6 @@ wire_4 = Edge((4, 9))
438
437
  edge_list = [wire_1, wire_2, wire_3, wire_4,ohm_5, ohm_6, ohm_7, ohm_8, ohm_8_2, ohm_10, ohm_11, ohm_20]
439
438
  graph = CircuitGraph(10, edge_list, {})
440
439
  print(compute(find_resistance(graph, 0, 9)))
441
- draw_circuit(graph, start=0, end=9, scale=3.0, grid_size=30)
442
440
  ```
443
441
 
444
442
  #### Output
@@ -450,7 +448,29 @@ done
450
448
  8.66474543707973
451
449
  ```
452
450
 
453
- #### Example Demonstration 11 (engineering graphics)
451
+ #### Example Demonstration 11 (resistors in parallel)
452
+ ```python
453
+ from mathai import *
454
+ load_formula_from_file()
455
+ wire_1 = Edge((1, 3))
456
+ wire_2 = Edge((2, 3))
457
+ ohm_r1 = Edge((0, 1), "resistor", parse("x"))
458
+ ohm_r2 = Edge((0, 2), "resistor", parse("y"))
459
+ edge_list = [wire_1, ohm_r1, ohm_r2, wire_2]
460
+ graph = CircuitGraph(4, edge_list, {})
461
+ print(fraction(find_resistance(graph, 0, 3)))
462
+ ```
463
+
464
+ #### Output
465
+
466
+ ```
467
+ loading formulas from file...
468
+ done
469
+
470
+ (x*y)/(x+y)
471
+ ```
472
+
473
+ #### Example Demonstration 12 (engineering graphics)
454
474
  ```python
455
475
  from mathai import *
456
476
  # (z,y) is dash, a'b' is front view
@@ -467,7 +487,7 @@ solve_graphics_string("15 25 0 None None None None None None 30*pi/180 0 50 None
467
487
  print()
468
488
  solve_graphics_string("0 -25 0 None None None None None None None 0 55 None 75") # 11.17
469
489
  print()
470
- solve_graphics_string("25 50 0 -30 None None None None None None 0 50 None 80") # 11.19
490
+ solve_graphics_string("25 50 0 -30 None None None None None None 0 None None 80") # 11.19
471
491
  ```
472
492
 
473
493
  #### Output
@@ -477,14 +497,14 @@ Ay : 20
477
497
  Az : 0
478
498
  Bx : 30
479
499
  By : 20+(60*sin(((2*pi)/9)))
480
- Bz : 60*abs(cos(((2*pi)/9)))
500
+ Bz : 60*sqrt((1-(sin(((2*pi)/9))^2)))
481
501
  Bx-Ax : 0
482
502
  By-Ay : 60*sin(((2*pi)/9))
483
- Bz-Az : 60*abs(cos(((2*pi)/9)))
503
+ Bz-Az : 60*sqrt((1-(sin(((2*pi)/9))^2)))
484
504
  inclination_with_VP : 0
485
505
  inclination_with_HP : (2*pi)/9
486
506
  front_view_length : 60
487
- top_view_length : 60*abs(cos(((2*pi)/9)))
507
+ top_view_length : sqrt((3600-(3600*(sin(((2*pi)/9))^2))))
488
508
  line_length : 60
489
509
 
490
510
  Ax : 20
@@ -520,16 +540,16 @@ line_length : 100/(3^-(-1/2))
520
540
  Ax : 0
521
541
  Ay : -25
522
542
  Az : 0
523
- Bx : 75*sin(arccos((11/15)))
543
+ Bx : 5*sqrt(104)
524
544
  By : -25
525
545
  Bz : 55
526
- Bx-Ax : 75*sin(arccos((11/15)))
546
+ Bx-Ax : 5*sqrt(104)
527
547
  By-Ay : 0
528
548
  Bz-Az : 55
529
- inclination_with_VP : arccos((11/15))
549
+ inclination_with_VP : arcsin((sqrt(104)/15))
530
550
  inclination_with_HP : 0
531
551
  front_view_length : 55
532
- top_view_length : sqrt((3025+(5625*(sin(arccos((11/15)))^2))))
552
+ top_view_length : 75
533
553
  line_length : 75
534
554
 
535
555
  Ax : 25
@@ -537,14 +557,14 @@ Ay : 50
537
557
  Az : 0
538
558
  Bx : -30
539
559
  By : 50
540
- Bz : 80*abs(cos(arcsin((-11/16))))
560
+ Bz : 5*sqrt(135)
541
561
  Bx-Ax : -55
542
562
  By-Ay : 0
543
- Bz-Az : 80*abs(cos(arcsin((-11/16))))
563
+ Bz-Az : 5*sqrt(135)
544
564
  inclination_with_VP : arcsin((-11/16))
545
565
  inclination_with_HP : 0
546
- front_view_length : 50
547
- top_view_length : sqrt((3025+(6400*(cos(arcsin((-11/16)))^2))))
566
+ front_view_length : sqrt(3375)
567
+ top_view_length : 80
548
568
  line_length : 80
549
569
  ```
550
570
 
@@ -422,7 +422,6 @@ wire_4 = Edge((4, 9))
422
422
  edge_list = [wire_1, wire_2, wire_3, wire_4,ohm_5, ohm_6, ohm_7, ohm_8, ohm_8_2, ohm_10, ohm_11, ohm_20]
423
423
  graph = CircuitGraph(10, edge_list, {})
424
424
  print(compute(find_resistance(graph, 0, 9)))
425
- draw_circuit(graph, start=0, end=9, scale=3.0, grid_size=30)
426
425
  ```
427
426
 
428
427
  #### Output
@@ -434,7 +433,29 @@ done
434
433
  8.66474543707973
435
434
  ```
436
435
 
437
- #### Example Demonstration 11 (engineering graphics)
436
+ #### Example Demonstration 11 (resistors in parallel)
437
+ ```python
438
+ from mathai import *
439
+ load_formula_from_file()
440
+ wire_1 = Edge((1, 3))
441
+ wire_2 = Edge((2, 3))
442
+ ohm_r1 = Edge((0, 1), "resistor", parse("x"))
443
+ ohm_r2 = Edge((0, 2), "resistor", parse("y"))
444
+ edge_list = [wire_1, ohm_r1, ohm_r2, wire_2]
445
+ graph = CircuitGraph(4, edge_list, {})
446
+ print(fraction(find_resistance(graph, 0, 3)))
447
+ ```
448
+
449
+ #### Output
450
+
451
+ ```
452
+ loading formulas from file...
453
+ done
454
+
455
+ (x*y)/(x+y)
456
+ ```
457
+
458
+ #### Example Demonstration 12 (engineering graphics)
438
459
  ```python
439
460
  from mathai import *
440
461
  # (z,y) is dash, a'b' is front view
@@ -451,7 +472,7 @@ solve_graphics_string("15 25 0 None None None None None None 30*pi/180 0 50 None
451
472
  print()
452
473
  solve_graphics_string("0 -25 0 None None None None None None None 0 55 None 75") # 11.17
453
474
  print()
454
- solve_graphics_string("25 50 0 -30 None None None None None None 0 50 None 80") # 11.19
475
+ solve_graphics_string("25 50 0 -30 None None None None None None 0 None None 80") # 11.19
455
476
  ```
456
477
 
457
478
  #### Output
@@ -461,14 +482,14 @@ Ay : 20
461
482
  Az : 0
462
483
  Bx : 30
463
484
  By : 20+(60*sin(((2*pi)/9)))
464
- Bz : 60*abs(cos(((2*pi)/9)))
485
+ Bz : 60*sqrt((1-(sin(((2*pi)/9))^2)))
465
486
  Bx-Ax : 0
466
487
  By-Ay : 60*sin(((2*pi)/9))
467
- Bz-Az : 60*abs(cos(((2*pi)/9)))
488
+ Bz-Az : 60*sqrt((1-(sin(((2*pi)/9))^2)))
468
489
  inclination_with_VP : 0
469
490
  inclination_with_HP : (2*pi)/9
470
491
  front_view_length : 60
471
- top_view_length : 60*abs(cos(((2*pi)/9)))
492
+ top_view_length : sqrt((3600-(3600*(sin(((2*pi)/9))^2))))
472
493
  line_length : 60
473
494
 
474
495
  Ax : 20
@@ -504,16 +525,16 @@ line_length : 100/(3^-(-1/2))
504
525
  Ax : 0
505
526
  Ay : -25
506
527
  Az : 0
507
- Bx : 75*sin(arccos((11/15)))
528
+ Bx : 5*sqrt(104)
508
529
  By : -25
509
530
  Bz : 55
510
- Bx-Ax : 75*sin(arccos((11/15)))
531
+ Bx-Ax : 5*sqrt(104)
511
532
  By-Ay : 0
512
533
  Bz-Az : 55
513
- inclination_with_VP : arccos((11/15))
534
+ inclination_with_VP : arcsin((sqrt(104)/15))
514
535
  inclination_with_HP : 0
515
536
  front_view_length : 55
516
- top_view_length : sqrt((3025+(5625*(sin(arccos((11/15)))^2))))
537
+ top_view_length : 75
517
538
  line_length : 75
518
539
 
519
540
  Ax : 25
@@ -521,14 +542,14 @@ Ay : 50
521
542
  Az : 0
522
543
  Bx : -30
523
544
  By : 50
524
- Bz : 80*abs(cos(arcsin((-11/16))))
545
+ Bz : 5*sqrt(135)
525
546
  Bx-Ax : -55
526
547
  By-Ay : 0
527
- Bz-Az : 80*abs(cos(arcsin((-11/16))))
548
+ Bz-Az : 5*sqrt(135)
528
549
  inclination_with_VP : arcsin((-11/16))
529
550
  inclination_with_HP : 0
530
- front_view_length : 50
531
- top_view_length : sqrt((3025+(6400*(cos(arcsin((-11/16)))^2))))
551
+ front_view_length : sqrt(3375)
552
+ top_view_length : 80
532
553
  line_length : 80
533
554
  ```
534
555
 
@@ -7,7 +7,7 @@ from .qm import hydrogen_gse, helium_gse, power_rule
7
7
 
8
8
  from .lambda_calculus import lambda_expand, lambda_compress, lambda_reduce
9
9
 
10
- from .electronic import Edge, CircuitGraph, find_resistance, draw_circuit
10
+ from .electronic import Edge, CircuitGraph, find_resistance
11
11
 
12
12
  from .linear import linear_solve
13
13
 
@@ -1,4 +1,3 @@
1
- import random
2
1
  import copy
3
2
  from .base import *
4
3
  from .simplify import simplify
@@ -12,6 +11,7 @@ class Edge:
12
11
  self.value = value
13
12
  self.edge = tuple(edge) if edge else None
14
13
  self.current = None
14
+ self.voltage = None
15
15
  class CircuitGraph:
16
16
  def __init__(self, node_count=0, edge_list=None, connection=None):
17
17
  self.node_count = node_count
@@ -26,7 +26,7 @@ class CircuitGraph:
26
26
  if edge.edge:
27
27
  self.node_count = max(self.node_count, max(edge.edge) + 1)
28
28
  self.connection = copy.deepcopy(connection) if connection else {}
29
- self.variable_list = [TreeNode(f"v_{i}") for i in range(26)]
29
+ self.variable_list = [TreeNode(f"v_{i}") for i in range(6,26)]
30
30
  self.complete_connection()
31
31
  def complete_connection(self):
32
32
  for i in range(self.node_count):
@@ -174,19 +174,21 @@ class CircuitGraph:
174
174
  missing = [i for i, edge in enumerate(self.edge_list) if edge.current is None]
175
175
  if missing:
176
176
  raise ValueError(f"Could not determine currents: {missing}")
177
- def find_resistance(circuit, start, end):
177
+ def find_resistance(circuit, start=None, end=None, compute_current_only=False):
178
178
  circuit = copy.deepcopy(circuit)
179
- if start == end:
179
+ if start == end and start is not None and end is not None:
180
180
  return TreeNode("d_0")
181
- new_node = circuit.node_count
182
- circuit.node_count += 1
183
- cell = Edge((end, new_node), "cell", TreeNode("d_1"))
184
- wire = Edge((new_node, start), "wire")
185
- circuit.edge_list.append(cell)
186
- cell_idx = len(circuit.edge_list) - 1
187
- circuit.edge_list.append(wire)
181
+ cell_idx = None
182
+ if not compute_current_only:
183
+ new_node = circuit.node_count
184
+ circuit.node_count += 1
185
+ cell = Edge((end, new_node), "cell", TreeNode("d_1"))
186
+ wire = Edge((new_node, start), "wire")
187
+ circuit.edge_list.append(cell)
188
+ cell_idx = len(circuit.edge_list) - 1
189
+ circuit.edge_list.append(wire)
188
190
  circuit.complete_connection()
189
- circuit.assign_currents(cell_idx)
191
+ circuit.assign_currents()
190
192
  cycles = circuit.all_simple_cycle()
191
193
  equations = []
192
194
  for cycle in cycles:
@@ -200,210 +202,29 @@ def find_resistance(circuit, start, end):
200
202
  [TreeNode("f_eq", [equation, TreeNode("d_0")]) for equation in equations]
201
203
  )
202
204
  equations = simplify(fraction(simplify(equations)))
203
- equations = linear_solve(equations)
205
+ const_list = []
206
+ for item in circuit.edge_list:
207
+ if item.edge_type == "resistor":
208
+ const_list += [TreeNode(item) for item in vlist(item.value)]
209
+ equations = linear_solve(equations, const_list)
204
210
  solutions = {}
205
211
  equation_list = equations.children if equations.name == "f_and" else [equations]
206
212
  for equation in equation_list:
207
- variables = vlist(equation)
213
+ variables = list(set(vlist(equation))-set([item.name for item in const_list]))
208
214
  if len(variables) != 1:
209
215
  continue
210
216
  variable = variables[0]
211
217
  solutions[variable] = inverse(equation.children[0], variable)
218
+ for index, item in enumerate(circuit.edge_list):
219
+ for v in vlist(circuit.edge_list[index].current):
220
+ if TreeNode(v) in const_list:
221
+ continue
222
+ circuit.edge_list[index].current = simplify(replace(circuit.edge_list[index].current, TreeNode(v), solutions[v]))
223
+ if compute_current_only:
224
+ return circuit
212
225
  current = circuit.edge_list[cell_idx].current
213
226
  for variable, value in solutions.items():
214
227
  if variable in vlist(current):
215
228
  current = replace(current, tree_form(variable), value)
216
229
  current = simplify(TreeNode("d_1")/current)
217
230
  return current
218
- import random
219
- import schemdraw
220
- import schemdraw.elements as elm
221
-
222
-
223
- def on_segment(p, a, b):
224
- """Returns True if point p lies exactly on the line segment a-b."""
225
- # Collinearity check (cross product == 0)
226
- cross = (p[0] - a[0]) * (b[1] - a[1]) - (p[1] - a[1]) * (b[0] - a[0])
227
- if abs(cross) > 1e-6:
228
- return False
229
- # Bounding box check
230
- if min(a[0], b[0]) <= p[0] <= max(a[0], b[0]) and \
231
- min(a[1], b[1]) <= p[1] <= max(a[1], b[1]):
232
- return True
233
- return False
234
-
235
-
236
- def segments_conflict_exact(a, b, c, d):
237
- """
238
- Checks if segment ab conflicts with cd (intersects or overlaps),
239
- ignoring shared endpoints unless they perfectly overlap.
240
- """
241
- def ccw(p, q, r):
242
- return (q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0])
243
-
244
- c1, c2 = ccw(a, b, c), ccw(a, b, d)
245
- c3, c4 = ccw(c, d, a), ccw(c, d, b)
246
-
247
- # 1. True geometric intersection (lines cross)
248
- if ((c1 > 0 and c2 < 0) or (c1 < 0 and c2 > 0)) and \
249
- ((c3 > 0 and c4 < 0) or (c3 < 0 and c4 > 0)):
250
- return True
251
-
252
- # 2. Collinear overlap (one point lies strictly inside the other segment)
253
- if on_segment(c, a, b) and c != a and c != b: return True
254
- if on_segment(d, a, b) and d != a and d != b: return True
255
- if on_segment(a, c, d) and a != c and a != d: return True
256
- if on_segment(b, c, d) and b != c and b != d: return True
257
-
258
- # 3. Identical overlapping segments
259
- if (a == c and b == d) or (a == d and b == c):
260
- return True
261
-
262
- return False
263
-
264
-
265
- def get_all_candidate_routes(p1, p2):
266
- """Generates all valid orthogonal straight line and 1-bend L-routes."""
267
- x1, y1 = p1
268
- x2, y2 = p2
269
-
270
- # Collinear (Straight line along single axis)
271
- if x1 == x2 or y1 == y2:
272
- return [[p1, p2]]
273
-
274
- # Standard L-shapes (Horizontal-first or Vertical-first)
275
- return [
276
- [p1, (x1, y2), p2],
277
- [p1, (x2, y1), p2]
278
- ]
279
-
280
-
281
- def route_to_segments(route):
282
- return [(route[i], route[i + 1]) for i in range(len(route) - 1)]
283
-
284
-
285
- def check_route_conflict(route, placed_routes, node_positions, u, v):
286
- """Validates that a new route does not cross placed routes or run over unrelated nodes."""
287
- segs = route_to_segments(route)
288
-
289
- # 1. Check against already placed routes
290
- for placed_route in placed_routes:
291
- placed_segs = route_to_segments(placed_route)
292
- for a, b in segs:
293
- for c, d in placed_segs:
294
- if segments_conflict_exact(a, b, c, d):
295
- return True
296
-
297
- # 2. Check against nodes (prevent line from running through an unrelated node)
298
- for node, pos in node_positions.items():
299
- if node == u or node == v:
300
- continue # Permitted to touch its own endpoints
301
- for a, b in segs:
302
- if on_segment(pos, a, b):
303
- return True
304
-
305
- return False
306
-
307
-
308
- def solve_routing(edges, node_positions):
309
- """DFS Backtracking to find a 100% collision-free route mapping for a given node layout."""
310
- placed_routes = []
311
-
312
- def backtrack(edge_idx):
313
- if edge_idx == len(edges):
314
- return True
315
-
316
- edge = edges[edge_idx]
317
- u, v = edge.edge
318
- p1, p2 = node_positions[u], node_positions[v]
319
-
320
- candidate_routes = get_all_candidate_routes(p1, p2)
321
- random.shuffle(candidate_routes)
322
-
323
- for route in candidate_routes:
324
- if not check_route_conflict(route, placed_routes, node_positions, u, v):
325
- placed_routes.append(route)
326
- if backtrack(edge_idx + 1):
327
- return True
328
- placed_routes.pop()
329
- return False
330
-
331
- if backtrack(0):
332
- return placed_routes
333
- return None
334
-
335
-
336
- def draw_circuit(graph, start=None, end=None, scale=3.0, grid_size=12, max_attempts=10000):
337
- """
338
- Renders a circuit using randomized grid placement and exact geometric backtracking.
339
- Guarantees strict L/straight paths without line intersections or bugs.
340
- """
341
- edges = graph.edge_list
342
- all_nodes = set()
343
- for edge in edges:
344
- all_nodes.add(edge.edge[0])
345
- all_nodes.add(edge.edge[1])
346
-
347
- nodes_list = sorted(list(all_nodes))
348
-
349
- best_positions = None
350
- best_routes = None
351
-
352
- # Search for a node configuration that allows a perfect non-intersecting layout
353
- for _ in range(max_attempts):
354
- # Generate random available grid locations
355
- available_cells = [
356
- (col * scale, -row * scale)
357
- for row in range(grid_size)
358
- for col in range(grid_size)
359
- ]
360
- random.shuffle(available_cells)
361
-
362
- current_positions = {node: available_cells[i] for i, node in enumerate(nodes_list)}
363
-
364
- # Attempt to perfectly route all edges
365
- routes = solve_routing(edges, current_positions)
366
-
367
- if routes is not None:
368
- best_positions = current_positions
369
- best_routes = routes
370
- break # Perfect layout found!
371
-
372
- if best_routes is None:
373
- raise RuntimeError("Failed to find a non-intersecting layout. Try increasing grid_size or max_attempts.")
374
-
375
- # Render Circuit Diagram with Schemdraw
376
- d = schemdraw.Drawing()
377
-
378
- for idx, edge in enumerate(edges):
379
- route = best_routes[idx]
380
- segs = route_to_segments(route)
381
- resistor = getattr(edge, "edge_type", "") == "resistor"
382
- value = getattr(edge, "value", "")
383
-
384
- for i, (p1, p2) in enumerate(segs):
385
- # Place resistor component on the last segment of the route
386
- if resistor and i == len(segs) - 1:
387
- lbl = f"{value} Ω" if value else ""
388
- d.add(
389
- elm.Resistor()
390
- .at(p1)
391
- .to(p2)
392
- .label(lbl)
393
- )
394
- else:
395
- d.add(elm.Line().at(p1).to(p2))
396
-
397
- # Draw Nodes
398
- for node, pos in best_positions.items():
399
- d.add(elm.Dot().at(pos))
400
-
401
- # Add Terminal Labels
402
- if start is not None and start in best_positions:
403
- d.add(elm.Label().at(best_positions[start]).label("Start", loc="left"))
404
-
405
- if end is not None and end in best_positions:
406
- d.add(elm.Label().at(best_positions[end]).label("End", loc="right"))
407
-
408
- d.draw()
409
- return d
@@ -4,10 +4,8 @@ from .simplify import simplify
4
4
  from .trig import trig0
5
5
  import itertools
6
6
  from .inverse import inverse
7
- from .formula_data import compile_formula
8
7
  from .expand import expand
9
8
  from .parser import parse
10
-
11
9
  def solve_graphics(Ax, Ay, Az, Bx, By, Bz, BAx, BAy, BAz, phi, theta, fvl, tvl, length):
12
10
  eq1 = TreeNode("f_eq", [TreeNode("v_6"), TreeNode("v_3") - TreeNode("v_0")])
13
11
  eq2 = TreeNode("f_eq", [TreeNode("v_7"), TreeNode("v_4") - TreeNode("v_1")])
@@ -17,52 +15,36 @@ def solve_graphics(Ax, Ay, Az, Bx, By, Bz, BAx, BAy, BAz, phi, theta, fvl, tvl,
17
15
  eq6 = TreeNode("f_eq", [TreeNode("v_8"), (TreeNode("d_1") - TreeNode("v_9").fx("sin")**2 - TreeNode("v_10").fx("sin")**2).fx("sqrt") * TreeNode("v_13")])
18
16
  eq7 = TreeNode("f_eq", [TreeNode("v_12")**2, (TreeNode("v_3") - TreeNode("v_0"))**2 + (TreeNode("v_5") - TreeNode("v_2"))**2])
19
17
  eq8 = TreeNode("f_eq", [TreeNode("v_11")**2, (TreeNode("v_4") - TreeNode("v_1"))**2 + (TreeNode("v_5") - TreeNode("v_2"))**2])
20
-
21
18
  q = operation("f_and", [eq1, eq2, eq3, eq4, eq5, eq6, eq7, eq8])
22
19
  lst = [Ax, Ay, Az, Bx, By, Bz, BAx, BAy, BAz, phi, theta, fvl, tvl, length]
23
20
  name = "Ax Ay Az Bx By Bz Bx-Ax By-Ay Bz-Az inclination_with_VP inclination_with_HP front_view_length top_view_length line_length".split(" ")
24
-
25
21
  solution = {}
26
22
  for index, item in enumerate(lst):
27
23
  if item is not None:
28
24
  solution[f"v_{index}"] = item
29
-
30
- fx = compile_formula("sin(x)^2 1-cos(x)^2 _ _ _ _ _ _ _ 2")
31
25
  q = simplify(q)
32
-
33
26
  done = True
34
27
  while done:
35
28
  done = False
36
29
  for i in range(len(q.children)):
37
30
  item = q.children[i]
38
- # Replace known variables
39
31
  for key, item2 in solution.items():
40
32
  item = replace(item, TreeNode(key), item2)
41
-
42
- # Apply trig identities during simplification
43
- item = fraction(expand(trig0(fx(simplify(item)))))
33
+ item = fraction(expand(trig0(simplify(item))))
44
34
  q.children[i] = item
45
-
46
- # Solvable equation check
47
35
  vars_in_item = vlist(item)
48
36
  if len(vars_in_item) == 1:
49
37
  target_var = vars_in_item[0]
50
- # Pass the full equation node (or LHS - RHS) so inverse() has both sides
51
38
  solution[target_var] = inverse(item.children[0], target_var)
52
39
  done = True
53
40
  break
54
-
55
- # Map back to readable parameter names safely
56
41
  final_solution = {}
57
42
  for i, param_name in enumerate(name):
58
43
  var_key = f"v_{i}"
59
44
  if var_key in solution:
60
45
  final_solution[param_name] = simplify(expand(solution[var_key]))
61
-
62
46
  return final_solution
63
-
64
47
  def solve_graphics_string(s):
65
- # Use s.split() to handle arbitrary whitespace cleanly
66
48
  s_parsed = [None if item == "None" else parse(item) for item in s.split()]
67
49
  for key, item in solve_graphics(*s_parsed).items():
68
50
  print(f"{key} : {item}")
@@ -1,23 +1,25 @@
1
1
  from .base import *
2
2
  from .simplify import simplify
3
3
  from .expand import expand
4
- def inverse(rhs,term, sign=None):
4
+ import copy
5
+ def inverse(rhs, term, sign=None):
5
6
  term = tree_form(term)
6
7
  lhs = tree_form("d_0")
8
+ rhs = copy.deepcopy(rhs)
7
9
  count = 15
8
- while not rhs==term:
10
+ while not rhs == term:
9
11
  if rhs.name == "f_add":
10
- if all(term in factor_generation(child) for child in rhs.children):
11
- newrhs = simplify(expand(rhs*term**-1))
12
+ if rhs.children and all(term in factor_generation(child) for child in rhs.children):
13
+ newrhs = simplify(expand(rhs * term**-1))
12
14
  if not contain(newrhs, term):
13
15
  rhs = term * newrhs
14
16
  else:
15
- for i in range(len(rhs.children)-1,-1,-1):
17
+ for i in range(len(rhs.children) - 1, -1, -1):
16
18
  if not contain(rhs.children[i], term):
17
19
  lhs = lhs - rhs.children[i]
18
20
  rhs.children.pop(i)
19
21
  elif rhs.name == "f_mul":
20
- for i in range(len(rhs.children)-1,-1,-1):
22
+ for i in range(len(rhs.children) - 1, -1, -1):
21
23
  if not contain(rhs.children[i], term):
22
24
  lhs = lhs * rhs.children[i]**-1
23
25
  if sign is not None:
@@ -26,11 +28,17 @@ def inverse(rhs,term, sign=None):
26
28
  if compute(rhs.children[i]**-1) < 0:
27
29
  sign = not sign
28
30
  rhs.children.pop(i)
29
- elif rhs.name == "f_pow" and contain(rhs.children[0], term):
30
- lhs = lhs ** (tree_form("d_1")/rhs.children[1])
31
+ elif rhs.name == "f_pow" and contain(rhs.children[0], term) and not contain(rhs.children[1], term):
32
+ lhs = lhs ** (tree_form("d_1") / rhs.children[1])
33
+ if sign is not None:
34
+ if compute(rhs.children[1]) < 0:
35
+ sign = not sign
31
36
  rhs = copy.deepcopy(rhs.children[0])
37
+ elif rhs.name == "f_pow" and rhs.children[0].name == "s_e" and contain(rhs.children[1], term):
38
+ lhs = lhs.fx("log")
39
+ rhs = copy.deepcopy(rhs.children[1])
32
40
  elif rhs.name == "f_pow" and contain(rhs.children[1], term) and not contain(rhs.children[0], term):
33
- lhs = lhs.fx("log")/rhs.children[0].fx("log")
41
+ lhs = lhs.fx("log") / rhs.children[0].fx("log")
34
42
  rhs = copy.deepcopy(rhs.children[1])
35
43
  elif rhs.name == "f_sin" and contain(rhs.children[0], term):
36
44
  lhs = lhs.fx("arcsin")
@@ -40,27 +48,30 @@ def inverse(rhs,term, sign=None):
40
48
  rhs = copy.deepcopy(rhs.children[0])
41
49
  elif rhs.name == "f_arccos" and contain(rhs.children[0], term):
42
50
  lhs = lhs.fx("cos")
51
+ if sign is not None:
52
+ sign = not sign
43
53
  rhs = copy.deepcopy(rhs.children[0])
44
54
  elif rhs.name == "f_cos" and contain(rhs.children[0], term):
45
55
  lhs = lhs.fx("arccos")
56
+ if sign is not None:
57
+ sign = not sign
46
58
  rhs = copy.deepcopy(rhs.children[0])
47
59
  elif rhs.name == "f_log" and contain(rhs.children[0], term):
48
60
  lhs = tree_form("s_e")**lhs
49
61
  rhs = copy.deepcopy(rhs.children[0])
50
- elif rhs.name == "f_pow" and rhs.children[0].name == "s_e" and contain(rhs.children[1], term):
51
- lhs = lhs.fx("log")
52
- rhs = copy.deepcopy(rhs.children[1].fx("log"))
53
62
  elif rhs.name == "f_tan" and contain(rhs.children[0], term):
54
63
  lhs = lhs.fx("arctan")
55
64
  rhs = copy.deepcopy(rhs.children[0])
56
65
  elif rhs.name == "f_arctan" and contain(rhs.children[0], term):
57
66
  lhs = lhs.fx("tan")
58
67
  rhs = copy.deepcopy(rhs.children[0])
59
- if len(rhs.children) == 1:
68
+ if rhs.name in ["f_add", "f_mul"] and len(rhs.children) == 1:
60
69
  rhs = rhs.children[0]
61
70
  count -= 1
62
71
  if count == 0:
63
72
  return None
73
+ if contain(lhs, term):
74
+ return None
64
75
  if sign is None:
65
76
  return simplify(lhs)
66
77
  return simplify(lhs), sign
@@ -1,5 +1,6 @@
1
1
  from .inverse import inverse
2
2
  import itertools
3
+ import copy
3
4
  from .diff import diff
4
5
  from .simplify import simplify
5
6
  from .fraction import fraction
@@ -7,8 +8,10 @@ from .expand import expand
7
8
  from .base import *
8
9
  from .factor import factorconst
9
10
  from .tool import poly
11
+
10
12
  def ss(eq):
11
13
  return dowhile(eq, lambda x: fraction(simplify(x)))
14
+
12
15
  def rref(matrix, fxconst):
13
16
  rows, cols = len(matrix), len(matrix[0])
14
17
  lead = 0
@@ -32,25 +35,28 @@ def rref(matrix, fxconst):
32
35
  matrix[i] = [ss(m - lv * n) for m, n in zip(matrix[i], matrix[r])]
33
36
  lead += 1
34
37
  return matrix
38
+
35
39
  def linear(eqlist, fxconst):
36
40
  orig = [item.copy_tree() for item in eqlist]
37
- v2 = []
38
41
  vl = []
42
+
39
43
  def varlist(eq, fxconst):
40
44
  nonlocal vl
41
- nonlocal v2
42
- if eq.name[:2] == "v_" and fxconst(eq):
43
- vl.append(eq.name)
44
45
  if eq.name[:2] == "v_" and not fxconst(eq):
45
- v2.append(eq.name)
46
+ vl.append(eq.name)
46
47
  for child in eq.children:
47
48
  varlist(child, fxconst)
49
+
48
50
  for eq in eqlist:
49
51
  varlist(eq, fxconst)
50
- vl = v2
51
- vl = list(set(vl))
52
+
53
+ vl = sorted(list(set(vl)))
54
+
52
55
  if len(vl) > len(eqlist):
56
+ if len(eqlist) == 1:
57
+ return TreeNode("f_eq", [eqlist[0], tree_form("d_0")])
53
58
  return TreeNode("f_and", [TreeNode("f_eq", [x, tree_form("d_0")]) for x in eqlist])
59
+
54
60
  m = []
55
61
  for eq in eqlist:
56
62
  s = copy.deepcopy(eq)
@@ -60,36 +66,46 @@ def linear(eqlist, fxconst):
60
66
  s = replace(s, tree_form(v), tree_form("d_0"))
61
67
  row.append(s)
62
68
  m.append(row)
69
+
63
70
  for i in range(len(m)):
64
71
  for j in range(len(m[i])):
65
72
  m[i][j] = simplify(expand(m[i][j]))
73
+
66
74
  m = rref(m, fxconst)
75
+
67
76
  for i in range(len(m)):
68
77
  for j in range(len(m[i])):
69
78
  m[i][j] = fraction(m[i][j])
79
+
70
80
  output = []
71
81
  for index, row in enumerate(m):
72
- if not all(item == 0 for item in row[:-1]):
73
- output.append(summation([tree_form(vl[index2])*coeff for index2, coeff in enumerate(row[:-1])])+row[-1])
74
- elif row[-1] != 0:
82
+ if not all(item == tree_form("d_0") for item in row[:-1]):
83
+ output.append(summation([tree_form(vl[index2])*coeff for index2, coeff in enumerate(row[:-1])]) + row[-1])
84
+ elif row[-1] != tree_form("d_0"):
75
85
  return tree_form("s_false")
86
+
76
87
  if len(output) == 1:
77
88
  return TreeNode("f_eq", [output[0], tree_form("d_0")])
78
89
  if len(output) == 0:
79
90
  return tree_form("s_false")
80
91
  return TreeNode("f_and", [TreeNode("f_eq", [x, tree_form("d_0")]) for x in output])
92
+
81
93
  def linear_solve(eq, lst=None):
82
94
  eq = simplify(eq)
83
95
  eqlist = []
84
- if eq.name =="f_and" and all(child.name == "f_eq" and child.children[1] == tree_form("d_0") for child in eq.children):
96
+ if eq.name == "f_and" and all(child.name == "f_eq" and child.children[1] == tree_form("d_0") for child in eq.children):
85
97
  eqlist = [child.children[0] for child in eq.children]
98
+ elif eq.name == "f_eq" and eq.children[1] == tree_form("d_0"):
99
+ eqlist = [eq.children[0]]
86
100
  else:
87
101
  return eq
102
+
88
103
  out = None
89
104
  if lst is None:
90
105
  out = linear(copy.deepcopy(eqlist), lambda x: False)
91
106
  else:
92
107
  out = linear(copy.deepcopy(eqlist), lambda x: any(contain(x, item) for item in lst))
108
+
93
109
  if out is None:
94
110
  return None
95
111
  return simplify(out)
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mathai
3
- Version: 2.2.4
3
+ Version: 2.2.6
4
4
  Summary: Mathematics solving Ai tailored to NCERT
5
5
  Home-page: https://github.com/infinity390/mathai
6
6
  Requires-Python: >=3.7
7
7
  Description-Content-Type: text/markdown
8
8
  Requires-Dist: more_itertools
9
- Requires-Dist: schemdraw
10
9
  Dynamic: description
11
10
  Dynamic: description-content-type
12
11
  Dynamic: home-page
@@ -438,7 +437,6 @@ wire_4 = Edge((4, 9))
438
437
  edge_list = [wire_1, wire_2, wire_3, wire_4,ohm_5, ohm_6, ohm_7, ohm_8, ohm_8_2, ohm_10, ohm_11, ohm_20]
439
438
  graph = CircuitGraph(10, edge_list, {})
440
439
  print(compute(find_resistance(graph, 0, 9)))
441
- draw_circuit(graph, start=0, end=9, scale=3.0, grid_size=30)
442
440
  ```
443
441
 
444
442
  #### Output
@@ -450,7 +448,29 @@ done
450
448
  8.66474543707973
451
449
  ```
452
450
 
453
- #### Example Demonstration 11 (engineering graphics)
451
+ #### Example Demonstration 11 (resistors in parallel)
452
+ ```python
453
+ from mathai import *
454
+ load_formula_from_file()
455
+ wire_1 = Edge((1, 3))
456
+ wire_2 = Edge((2, 3))
457
+ ohm_r1 = Edge((0, 1), "resistor", parse("x"))
458
+ ohm_r2 = Edge((0, 2), "resistor", parse("y"))
459
+ edge_list = [wire_1, ohm_r1, ohm_r2, wire_2]
460
+ graph = CircuitGraph(4, edge_list, {})
461
+ print(fraction(find_resistance(graph, 0, 3)))
462
+ ```
463
+
464
+ #### Output
465
+
466
+ ```
467
+ loading formulas from file...
468
+ done
469
+
470
+ (x*y)/(x+y)
471
+ ```
472
+
473
+ #### Example Demonstration 12 (engineering graphics)
454
474
  ```python
455
475
  from mathai import *
456
476
  # (z,y) is dash, a'b' is front view
@@ -467,7 +487,7 @@ solve_graphics_string("15 25 0 None None None None None None 30*pi/180 0 50 None
467
487
  print()
468
488
  solve_graphics_string("0 -25 0 None None None None None None None 0 55 None 75") # 11.17
469
489
  print()
470
- solve_graphics_string("25 50 0 -30 None None None None None None 0 50 None 80") # 11.19
490
+ solve_graphics_string("25 50 0 -30 None None None None None None 0 None None 80") # 11.19
471
491
  ```
472
492
 
473
493
  #### Output
@@ -477,14 +497,14 @@ Ay : 20
477
497
  Az : 0
478
498
  Bx : 30
479
499
  By : 20+(60*sin(((2*pi)/9)))
480
- Bz : 60*abs(cos(((2*pi)/9)))
500
+ Bz : 60*sqrt((1-(sin(((2*pi)/9))^2)))
481
501
  Bx-Ax : 0
482
502
  By-Ay : 60*sin(((2*pi)/9))
483
- Bz-Az : 60*abs(cos(((2*pi)/9)))
503
+ Bz-Az : 60*sqrt((1-(sin(((2*pi)/9))^2)))
484
504
  inclination_with_VP : 0
485
505
  inclination_with_HP : (2*pi)/9
486
506
  front_view_length : 60
487
- top_view_length : 60*abs(cos(((2*pi)/9)))
507
+ top_view_length : sqrt((3600-(3600*(sin(((2*pi)/9))^2))))
488
508
  line_length : 60
489
509
 
490
510
  Ax : 20
@@ -520,16 +540,16 @@ line_length : 100/(3^-(-1/2))
520
540
  Ax : 0
521
541
  Ay : -25
522
542
  Az : 0
523
- Bx : 75*sin(arccos((11/15)))
543
+ Bx : 5*sqrt(104)
524
544
  By : -25
525
545
  Bz : 55
526
- Bx-Ax : 75*sin(arccos((11/15)))
546
+ Bx-Ax : 5*sqrt(104)
527
547
  By-Ay : 0
528
548
  Bz-Az : 55
529
- inclination_with_VP : arccos((11/15))
549
+ inclination_with_VP : arcsin((sqrt(104)/15))
530
550
  inclination_with_HP : 0
531
551
  front_view_length : 55
532
- top_view_length : sqrt((3025+(5625*(sin(arccos((11/15)))^2))))
552
+ top_view_length : 75
533
553
  line_length : 75
534
554
 
535
555
  Ax : 25
@@ -537,14 +557,14 @@ Ay : 50
537
557
  Az : 0
538
558
  Bx : -30
539
559
  By : 50
540
- Bz : 80*abs(cos(arcsin((-11/16))))
560
+ Bz : 5*sqrt(135)
541
561
  Bx-Ax : -55
542
562
  By-Ay : 0
543
- Bz-Az : 80*abs(cos(arcsin((-11/16))))
563
+ Bz-Az : 5*sqrt(135)
544
564
  inclination_with_VP : arcsin((-11/16))
545
565
  inclination_with_HP : 0
546
- front_view_length : 50
547
- top_view_length : sqrt((3025+(6400*(cos(arcsin((-11/16)))^2))))
566
+ front_view_length : sqrt(3375)
567
+ top_view_length : 80
548
568
  line_length : 80
549
569
  ```
550
570
 
@@ -1,2 +1 @@
1
1
  more_itertools
2
- schemdraw
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
  from pathlib import Path
3
3
  setup(
4
4
  name="mathai",
5
- version="2.2.4",
5
+ version="2.2.6",
6
6
  description="Mathematics solving Ai tailored to NCERT",
7
7
  long_description=Path("README.md").read_text(encoding="utf-8"),
8
8
  long_description_content_type="text/markdown",
@@ -13,7 +13,6 @@ setup(
13
13
  },
14
14
  python_requires=">=3.7",
15
15
  install_requires=[
16
- "more_itertools",
17
- "schemdraw"
16
+ "more_itertools"
18
17
  ],
19
18
  )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes