Spaces:
Runtime error
Runtime error
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
|
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 |
-
|
34 |
"""
|
35 |
if a == 0:
|
36 |
if b == 0:
|
37 |
-
|
|
|
38 |
# Linear equation: bx + c = 0 -> x = -c/b
|
39 |
-
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
elif delta == 0:
|
48 |
x1 = -b / (2*a)
|
49 |
-
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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=
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
)
|