spagestic commited on
Commit
aa584c9
·
1 Parent(s): f1254bd

Enhance quadratic solver and interfaces:

Browse files

- Update `solve_quadratic` to support output formatting (string/dict) and include vertex calculation.
- Add `quadratic_solver_wrapper` for Gradio interface to format results.
- Introduce `plot_quadratic` function for visualizing quadratic functions with roots and vertex.
- Modify Gradio interfaces to use new functionalities and improve user interaction.
- Change flagging mode to manual for ODE interfaces in differential equations and operations research.

maths/middleschool/algebra.py CHANGED
@@ -1,6 +1,8 @@
1
  """
2
  Basic algebra operations for middle school level.
3
  """
 
 
4
 
5
  def solve_linear_equation(a, b):
6
  """
@@ -20,7 +22,7 @@ def evaluate_expression(a, b, c, x):
20
  return a * (x ** 2) + b * x + c
21
 
22
 
23
- def solve_quadratic(a: float, b: float, c: float) -> str:
24
  """
25
  Solve the quadratic equation ax^2 + bx + c = 0.
26
 
@@ -28,29 +30,66 @@ def solve_quadratic(a: float, b: float, c: float) -> str:
28
  a: Coefficient of x^2.
29
  b: Coefficient of x.
30
  c: Constant term.
 
 
31
 
32
  Returns:
33
- A string representing the solutions.
34
  """
35
  if a == 0:
36
  if b == 0:
37
- return "Not a valid equation (a and b cannot both be zero)." if c != 0 else "Infinite solutions (0 = 0)"
 
38
  # Linear equation: bx + c = 0 -> x = -c/b
39
- return f"Linear equation: x = {-c/b}"
40
-
 
 
 
 
 
 
 
 
 
 
41
  delta = b**2 - 4*a*c
42
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  if delta > 0:
44
  x1 = (-b + delta**0.5) / (2*a)
45
  x2 = (-b - delta**0.5) / (2*a)
46
- return f"Two distinct real roots: x1 = {x1}, x2 = {x2}"
 
 
 
 
 
 
47
  elif delta == 0:
48
  x1 = -b / (2*a)
49
- return f"One real root (repeated): x = {x1}"
 
 
 
 
50
  else: # delta < 0
51
  real_part = -b / (2*a)
52
  imag_part = (-delta)**0.5 / (2*a)
53
- return f"Two complex roots: x1 = {real_part} + {imag_part}i, x2 = {real_part} - {imag_part}i"
54
 
55
 
56
  def simplify_radical(number: int) -> str:
 
1
  """
2
  Basic algebra operations for middle school level.
3
  """
4
+ import cmath
5
+ from fractions import Fraction
6
 
7
  def solve_linear_equation(a, b):
8
  """
 
22
  return a * (x ** 2) + b * x + c
23
 
24
 
25
+ def solve_quadratic(a: float, b: float, c: float, return_format: str = "string"):
26
  """
27
  Solve the quadratic equation ax^2 + bx + c = 0.
28
 
 
30
  a: Coefficient of x^2.
31
  b: Coefficient of x.
32
  c: Constant term.
33
+ return_format: Format of return value - "string" for human-readable string
34
+ or "dict" for dictionary with roots and vertex.
35
 
36
  Returns:
37
+ Either a string representing the solutions or a dictionary with roots and vertex.
38
  """
39
  if a == 0:
40
  if b == 0:
41
+ result = "Not a valid equation (a and b cannot both be zero)." if c != 0 else "Infinite solutions (0 = 0)"
42
+ return result if return_format == "string" else {"error": result}
43
  # Linear equation: bx + c = 0 -> x = -c/b
44
+ root = -c/b
45
+ if return_format == "string":
46
+ return f"Linear equation: x = {root}"
47
+ else:
48
+ return {"roots": (root, None), "vertex": None}
49
+
50
+ # Calculate vertex
51
+ vertex_x = -b / (2 * a)
52
+ vertex_y = c - (b**2 / (4 * a))
53
+ vertex = (vertex_x, vertex_y)
54
+
55
+ # Calculate discriminant and roots
56
  delta = b**2 - 4*a*c
57
+
58
+ if return_format == "dict":
59
+ # Use cmath for complex roots
60
+ discriminant = cmath.sqrt(b**2 - 4*a*c)
61
+ root1 = (-b + discriminant) / (2 * a)
62
+ root2 = (-b - discriminant) / (2 * a)
63
+
64
+ # Convert to fraction if possible
65
+ if root1.imag == 0 and root2.imag == 0:
66
+ root1 = Fraction(root1.real).limit_denominator()
67
+ root2 = Fraction(root2.real).limit_denominator()
68
+
69
+ return {"roots": (root1, root2), "vertex": vertex}
70
+
71
+ # For string format, handle different cases
72
  if delta > 0:
73
  x1 = (-b + delta**0.5) / (2*a)
74
  x2 = (-b - delta**0.5) / (2*a)
75
+ # Try to convert to fractions for cleaner display
76
+ try:
77
+ x1_frac = Fraction(x1).limit_denominator()
78
+ x2_frac = Fraction(x2).limit_denominator()
79
+ return f"Two distinct real roots: x1 = {x1_frac}, x2 = {x2_frac}\nVertex at: {vertex}"
80
+ except:
81
+ return f"Two distinct real roots: x1 = {x1}, x2 = {x2}\nVertex at: {vertex}"
82
  elif delta == 0:
83
  x1 = -b / (2*a)
84
+ try:
85
+ x1_frac = Fraction(x1).limit_denominator()
86
+ return f"One real root (repeated): x = {x1_frac}\nVertex at: {vertex}"
87
+ except:
88
+ return f"One real root (repeated): x = {x1}\nVertex at: {vertex}"
89
  else: # delta < 0
90
  real_part = -b / (2*a)
91
  imag_part = (-delta)**0.5 / (2*a)
92
+ return f"Two complex roots: x1 = {real_part} + {imag_part}i, x2 = {real_part} - {imag_part}i\nVertex at: {vertex}"
93
 
94
 
95
  def simplify_radical(number: int) -> str:
maths/middleschool/algebra_interface.py CHANGED
@@ -1,5 +1,8 @@
1
  import gradio as gr
2
- from maths.middleschool.algebra import solve_linear_equation, evaluate_expression, solve_quadratic, simplify_radical, polynomial_operations
 
 
 
3
 
4
  # Middle School Math Tab
5
  solve_linear_equation_interface = gr.Interface(
@@ -26,16 +29,63 @@ evaluate_expression_interface = gr.Interface(
26
  description="Evaluate ax² + bx + c for a given value of x"
27
  )
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  solve_quadratic_interface = gr.Interface(
30
- fn=solve_quadratic,
31
  inputs=[
32
  gr.Number(label="a (coefficient of x²)"),
33
  gr.Number(label="b (coefficient of x)"),
34
- gr.Number(label="c (constant)")
 
 
 
 
 
 
35
  ],
36
  outputs="text",
37
  title="Quadratic Equation Solver",
38
- description="Solve ax² + bx + c = 0"
39
  )
40
 
41
  simplify_radical_interface = gr.Interface(
@@ -67,3 +117,130 @@ polynomial_interface = gr.Interface(
67
  title="Polynomial Operations",
68
  description="Add, subtract, or multiply two polynomials. Enter coefficients in descending order of power."
69
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ from maths.middleschool.algebra import (
3
+ solve_linear_equation, evaluate_expression, solve_quadratic,
4
+ simplify_radical, polynomial_operations
5
+ )
6
 
7
  # Middle School Math Tab
8
  solve_linear_equation_interface = gr.Interface(
 
29
  description="Evaluate ax² + bx + c for a given value of x"
30
  )
31
 
32
+ def quadratic_solver_wrapper(a, b, c, return_format):
33
+ """Wrapper function for the quadratic solver to format the output nicely for Gradio."""
34
+ result = solve_quadratic(a, b, c, return_format=return_format)
35
+
36
+ if return_format == "dict":
37
+ # Format the dictionary output for display
38
+ if "error" in result:
39
+ return result["error"]
40
+
41
+ roots = result["roots"]
42
+ vertex = result["vertex"]
43
+
44
+ # Create a nicely formatted output
45
+ output = ""
46
+
47
+ # Format the equation
48
+ sign_b = "+" if b >= 0 else ""
49
+ sign_c = "+" if c >= 0 else ""
50
+ output += f"Equation: {a}x² {sign_b} {b}x {sign_c} {c} = 0\n\n"
51
+
52
+ # Format roots
53
+ if roots[1] is None: # Linear equation case
54
+ output += f"Root: {roots[0]}\n"
55
+ else:
56
+ # Check if roots are complex
57
+ if isinstance(roots[0], complex) or isinstance(roots[1], complex):
58
+ output += f"Root 1: {roots[0]}\n"
59
+ output += f"Root 2: {roots[1]}\n"
60
+ else:
61
+ output += f"Root 1: {roots[0]}\n"
62
+ output += f"Root 2: {roots[1]}\n"
63
+
64
+ # Format vertex
65
+ if vertex:
66
+ output += f"\nVertex: ({vertex[0]}, {vertex[1]})"
67
+
68
+ return output
69
+ else:
70
+ # String format is already formatted well
71
+ return result
72
+
73
  solve_quadratic_interface = gr.Interface(
74
+ fn=quadratic_solver_wrapper,
75
  inputs=[
76
  gr.Number(label="a (coefficient of x²)"),
77
  gr.Number(label="b (coefficient of x)"),
78
+ gr.Number(label="c (constant)"),
79
+ gr.Radio(
80
+ choices=["string", "dict"],
81
+ value="dict",
82
+ label="Output Format",
83
+ info="'string' for text output, 'dict' for formatted output with roots and vertex"
84
+ )
85
  ],
86
  outputs="text",
87
  title="Quadratic Equation Solver",
88
+ description="Solve ax² + bx + c = 0 and find vertex"
89
  )
90
 
91
  simplify_radical_interface = gr.Interface(
 
117
  title="Polynomial Operations",
118
  description="Add, subtract, or multiply two polynomials. Enter coefficients in descending order of power."
119
  )
120
+
121
+ # Add an interactive visualizer for quadratic functions
122
+ def plot_quadratic(a, b, c):
123
+ """Plot the quadratic function f(x) = ax^2 + bx + c with its vertex and roots."""
124
+ import numpy as np
125
+ import matplotlib.pyplot as plt
126
+
127
+ # Calculate vertex
128
+ vertex_x = -b / (2*a) if a != 0 else 0
129
+ vertex_y = c - (b**2 / (4*a)) if a != 0 else 0
130
+
131
+ # Calculate roots (if they exist)
132
+ result = solve_quadratic(a, b, c, return_format="dict")
133
+
134
+ # Create the plot
135
+ fig, ax = plt.subplots(figsize=(8, 6))
136
+
137
+ # Calculate appropriate x range based on vertex and roots
138
+ if a != 0:
139
+ # Find appropriate range based on vertex and/or roots
140
+ if "roots" in result and result["roots"][0] is not None and result["roots"][1] is not None:
141
+ # Extract real parts of roots
142
+ root1 = result["roots"][0].real if hasattr(result["roots"][0], "real") else float(result["roots"][0])
143
+ root2 = result["roots"][1].real if hasattr(result["roots"][1], "real") else float(result["roots"][1])
144
+ x_min = min(root1, root2, vertex_x) - 2
145
+ x_max = max(root1, root2, vertex_x) + 2
146
+ else:
147
+ # No roots or only one root - use vertex
148
+ x_min = vertex_x - 5
149
+ x_max = vertex_x + 5
150
+
151
+ x = np.linspace(x_min, x_max, 1000)
152
+ y = a * (x**2) + b * x + c
153
+
154
+ # Plot the function
155
+ ax.plot(x, y, 'b-', label=f'f(x) = {a}x² + {b}x + {c}')
156
+
157
+ # Plot the vertex
158
+ ax.plot(vertex_x, vertex_y, 'ro', label=f'Vertex: ({vertex_x:.2f}, {vertex_y:.2f})')
159
+
160
+ # Plot the roots if they exist and are real
161
+ if "roots" in result:
162
+ roots = result["roots"]
163
+ if roots[0] is not None and (isinstance(roots[0], (int, float)) or
164
+ (hasattr(roots[0], "imag") and roots[0].imag == 0)):
165
+ root1 = float(roots[0].real if hasattr(roots[0], "real") else roots[0])
166
+ ax.plot(root1, 0, 'go', label=f'Root 1: {root1:.2f}')
167
+
168
+ if roots[1] is not None and (isinstance(roots[1], (int, float)) or
169
+ (hasattr(roots[1], "imag") and roots[1].imag == 0)):
170
+ root2 = float(roots[1].real if hasattr(roots[1], "real") else roots[1])
171
+ ax.plot(root2, 0, 'go', label=f'Root 2: {root2:.2f}')
172
+
173
+ # Plot x and y axes
174
+ ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
175
+ ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
176
+
177
+ # Add grid
178
+ ax.grid(True, alpha=0.3)
179
+
180
+ # Set labels and title
181
+ ax.set_xlabel('x')
182
+ ax.set_ylabel('f(x)')
183
+ ax.set_title(f'Graph of f(x) = {a}x² + {b}x + {c}')
184
+
185
+ # Add legend
186
+ ax.legend()
187
+ else:
188
+ # Handle linear case or invalid case
189
+ if b != 0: # Linear function
190
+ x = np.linspace(-5, 5, 100)
191
+ y = b * x + c
192
+ ax.plot(x, y, 'b-', label=f'f(x) = {b}x + {c} (Linear)')
193
+
194
+ # Plot the root if it exists
195
+ root = -c/b
196
+ ax.plot(root, 0, 'go', label=f'Root: {root:.2f}')
197
+
198
+ # Plot axes
199
+ ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
200
+ ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
201
+
202
+ ax.grid(True, alpha=0.3)
203
+ ax.set_xlabel('x')
204
+ ax.set_ylabel('f(x)')
205
+ ax.set_title(f'Graph of f(x) = {b}x + {c} (Linear)')
206
+ ax.legend()
207
+ else: # Constant function
208
+ x = np.linspace(-5, 5, 100)
209
+ y = c * np.ones_like(x)
210
+ ax.plot(x, y, 'b-', label=f'f(x) = {c} (Constant)')
211
+
212
+ ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
213
+ ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
214
+
215
+ ax.grid(True, alpha=0.3)
216
+ ax.set_xlabel('x')
217
+ ax.set_ylabel('f(x)')
218
+ ax.set_title(f'Graph of f(x) = {c} (Constant)')
219
+ ax.legend()
220
+
221
+ return fig
222
+
223
+ quadratic_visualizer_interface = gr.Interface(
224
+ fn=plot_quadratic,
225
+ inputs=[
226
+ gr.Number(label="a (coefficient of x²)", value=1),
227
+ gr.Number(label="b (coefficient of x)", value=0),
228
+ gr.Number(label="c (constant)", value=0)
229
+ ],
230
+ outputs=gr.Plot(),
231
+ title="Quadratic Function Visualizer",
232
+ description="Visualize the graph of a quadratic function f(x) = ax² + bx + c with its vertex and roots"
233
+ )
234
+
235
+ # Create the main Gradio application that combines all interfaces
236
+ algebra_app = gr.TabbedInterface(
237
+ [solve_linear_equation_interface, evaluate_expression_interface,
238
+ solve_quadratic_interface, quadratic_visualizer_interface,
239
+ simplify_radical_interface, polynomial_interface],
240
+ ["Linear Solver", "Expression Evaluator", "Quadratic Solver",
241
+ "Quadratic Visualizer", "Radical Simplifier", "Polynomials"]
242
+ )
243
+
244
+ # Allow the Gradio interface to be run directly or imported
245
+ if __name__ == "__main__":
246
+ algebra_app.launch()
maths/university/differential_equations_interface.py CHANGED
@@ -117,7 +117,7 @@ first_order_ode_interface = gr.Interface(
117
  "WARNING: Uses eval() for the ODE function string - potential security risk. " \
118
  "For systems, `y` in lambda is `[y1, y2, ...]`, return `[dy1/dt, dy2/dt, ...]`. " \
119
  "Example (Damped Oscillator): ODE: lambda t, y: [y[1], -0.5*y[1] - y[0]], y0: 1,0, Timespan: 0,20",
120
- allow_flagging="never"
121
  )
122
 
123
  # --- Gradio Interface for Second-Order ODEs ---
@@ -150,7 +150,7 @@ second_order_ode_interface = gr.Interface(
150
  description="Solves d²y/dt² = f(t, y, dy/dt). " \
151
  "WARNING: Uses eval() for the ODE function string - potential security risk. " \
152
  "Example (Pendulum): ODE: lambda t, y, dy_dt: -9.81/1.0 * math.sin(y), y0: math.pi/4, dy0/dt: 0, Timespan: 0,10",
153
- allow_flagging="never"
154
  )
155
 
156
  # Example usage for testing (can be removed)
 
117
  "WARNING: Uses eval() for the ODE function string - potential security risk. " \
118
  "For systems, `y` in lambda is `[y1, y2, ...]`, return `[dy1/dt, dy2/dt, ...]`. " \
119
  "Example (Damped Oscillator): ODE: lambda t, y: [y[1], -0.5*y[1] - y[0]], y0: 1,0, Timespan: 0,20",
120
+ flagging_mode="manual"
121
  )
122
 
123
  # --- Gradio Interface for Second-Order ODEs ---
 
150
  description="Solves d²y/dt² = f(t, y, dy/dt). " \
151
  "WARNING: Uses eval() for the ODE function string - potential security risk. " \
152
  "Example (Pendulum): ODE: lambda t, y, dy_dt: -9.81/1.0 * math.sin(y), y0: math.pi/4, dy0/dt: 0, Timespan: 0,10",
153
+ flagging_mode="manual"
154
  )
155
 
156
  # Example usage for testing (can be removed)
maths/university/operations_research/operations_research_interface.py CHANGED
@@ -230,7 +230,7 @@ branch_and_bound_interface = gr.Interface(
230
  True #maximize
231
  ]
232
  ],
233
- allow_flagging="never"
234
  )
235
 
236
  # --- Simplex Solver (with Steps) Interface ---
@@ -357,7 +357,7 @@ simplex_solver_interface = gr.Interface(
357
  "0,None;0,None" # x1-x2 <=1, -x1+x2 <=1
358
  ]
359
  ],
360
- allow_flagging="never"
361
  )
362
 
363
  # --- Dual Simplex Interface ---
@@ -477,5 +477,5 @@ dual_simplex_interface = gr.Interface(
477
  "max", "1,1", "-2,-1;-1,-2", "<=,<=", "-10,-10"
478
  ]
479
  ],
480
- allow_flagging="never"
481
  )
 
230
  True #maximize
231
  ]
232
  ],
233
+ flagging_mode="manual"
234
  )
235
 
236
  # --- Simplex Solver (with Steps) Interface ---
 
357
  "0,None;0,None" # x1-x2 <=1, -x1+x2 <=1
358
  ]
359
  ],
360
+ flagging_mode="manual"
361
  )
362
 
363
  # --- Dual Simplex Interface ---
 
477
  "max", "1,1", "-2,-1;-1,-2", "<=,<=", "-10,-10"
478
  ]
479
  ],
480
+ flagging_mode="manual"
481
  )