counting / maths /equations /solve_quadratic.py
spagestic's picture
feat: enhance Gradio interfaces for cubic, polynomial, quadratic, and simultaneous equation solvers with detailed descriptions and examples
f6cc900
"""
Solve the quadratic equation ax^2 + bx + c = 0.
"""
import cmath
from fractions import Fraction
import sympy as sp
import gradio as gr
import numpy as np
def solve_quadratic(a: float, b: float, c: float, return_format: str = "string"):
if a == 0:
if b == 0:
result = "Not a valid equation (a and b cannot both be zero)." if c != 0 else "Infinite solutions (0 = 0)"
return result if return_format == "string" else {"error": result}
root = -c/b
if return_format == "string":
return f"Linear equation: x = {root}"
else:
return {"roots": (root, None), "vertex": None}
vertex_x = -b / (2 * a)
vertex_y = c - (b**2 / (4 * a))
vertex = (vertex_x, vertex_y)
delta = b**2 - 4*a*c
# Surd form using sympy
if return_format == "surd":
x1 = (-b + sp.sqrt(delta)) / (2*a)
x2 = (-b - sp.sqrt(delta)) / (2*a)
return {
"roots": (sp.simplify(x1), sp.simplify(x2)),
"vertex": vertex,
"discriminant": delta
}
if return_format == "dict":
# Use numpy.roots for quadratic
roots = np.roots([a, b, c])
# Ensure two roots (may be complex)
if len(roots) == 1:
roots = (roots[0], None)
else:
roots = tuple(roots)
# Try to convert to Fraction if real
roots_fmt = []
for r in roots:
if r is not None and np.isreal(r):
roots_fmt.append(Fraction(r.real).limit_denominator())
else:
roots_fmt.append(r)
return {"roots": tuple(roots_fmt), "vertex": vertex}
if delta > 0:
x1 = (-b + delta**0.5) / (2*a)
x2 = (-b - delta**0.5) / (2*a)
try:
x1_frac = Fraction(x1).limit_denominator()
x2_frac = Fraction(x2).limit_denominator()
return f"Two distinct real roots: x1 = {x1_frac}, x2 = {x2_frac}\nVertex at: {vertex}"
except:
return f"Two distinct real roots: x1 = {x1}, x2 = {x2}\nVertex at: {vertex}"
elif delta == 0:
x1 = -b / (2*a)
try:
x1_frac = Fraction(x1).limit_denominator()
return f"One real root (repeated): x = {x1_frac}\nVertex at: {vertex}"
except:
return f"One real root (repeated): x = {x1}\nVertex at: {vertex}"
else:
real_part = -b / (2*a)
imag_part = (-delta)**0.5 / (2*a)
return f"Two complex roots: x1 = {real_part} + {imag_part}i, x2 = {real_part} - {imag_part}i\nVertex at: {vertex}"
def quadratic_solver_wrapper(a, b, c, return_format):
result = solve_quadratic(a, b, c, return_format=return_format)
if return_format == "dict":
if "error" in result:
return result["error"]
roots = result["roots"]
vertex = result["vertex"]
output = ""
sign_b = "+" if b >= 0 else ""
sign_c = "+" if c >= 0 else ""
output += f"Equation: {a}{sign_b} {b}x {sign_c} {c} = 0\n\n"
if roots[1] is None:
output += f"Root: {roots[0]}\n"
else:
output += f"Root 1: {roots[0]}\n"
output += f"Root 2: {roots[1]}\n"
if vertex:
output += f"\nVertex: ({vertex[0]}, {vertex[1]})"
return output
else:
return result
solve_quadratic_interface = gr.Interface(
fn=quadratic_solver_wrapper,
inputs=[
gr.Number(label="a (coefficient of x²)"),
gr.Number(label="b (coefficient of x)"),
gr.Number(label="c (constant)"),
gr.Radio(
choices=["string", "dict", "surd"],
value="dict",
label="Output Format",
info="'string' for text output, 'dict' for formatted output, 'surd' for exact roots"
)
],
outputs="text",
title="Quadratic Equation Solver",
description="""
Solve ax² + bx + c = 0 and find the vertex. Enter the coefficients for your quadratic equation and select the output format.
Example: For x² - 3x + 2 = 0, enter a=1, b=-3, c=2.
Output format:
- 'string': plain text
- 'dict': formatted output
- 'surd': exact roots (if possible)
""",
examples=[
[1, -3, 2, "dict"],
[2, 4, -6, "string"],
[1, 2, 1, "surd"]
]
)
def plot_quadratic(a, b, c):
import numpy as np
import matplotlib.pyplot as plt
result = solve_quadratic(a, b, c, return_format="dict")
vertex_x = -b / (2*a) if a != 0 else 0
vertex_y = c - (b**2 / (4*a)) if a != 0 else 0
fig, ax = plt.subplots(figsize=(8, 6))
if a != 0:
if "roots" in result and result["roots"][0] is not None and result["roots"][1] is not None:
root1 = result["roots"][0].real if hasattr(result["roots"][0], "real") else float(result["roots"][0])
root2 = result["roots"][1].real if hasattr(result["roots"][1], "real") else float(result["roots"][1])
x_min = min(root1, root2, vertex_x) - 2
x_max = max(root1, root2, vertex_x) + 2
else:
x_min = vertex_x - 5
x_max = vertex_x + 5
x = np.linspace(x_min, x_max, 1000)
y = a * (x**2) + b * x + c
ax.plot(x, y, 'b-', label=f'f(x) = {a}x² + {b}x + {c}')
ax.plot(vertex_x, vertex_y, 'ro', label=f'Vertex: ({vertex_x:.2f}, {vertex_y:.2f})')
if "roots" in result:
roots = result["roots"]
if roots[0] is not None and (isinstance(roots[0], (int, float)) or (hasattr(roots[0], "imag") and roots[0].imag == 0)):
root1 = float(roots[0].real if hasattr(roots[0], "real") else roots[0])
ax.plot(root1, 0, 'go', label=f'Root 1: {root1:.2f}')
if roots[1] is not None and (isinstance(roots[1], (int, float)) or (hasattr(roots[1], "imag") and roots[1].imag == 0)):
root2 = float(roots[1].real if hasattr(roots[1], "real") else roots[1])
ax.plot(root2, 0, 'go', label=f'Root 2: {root2:.2f}')
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
ax.grid(True, alpha=0.3)
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.set_title(f'Graph of f(x) = {a}x² + {b}x + {c}')
ax.legend()
else:
if b != 0:
x = np.linspace(-5, 5, 100)
y = b * x + c
ax.plot(x, y, 'b-', label=f'f(x) = {b}x + {c} (Linear)')
root = -c/b
ax.plot(root, 0, 'go', label=f'Root: {root:.2f}')
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
ax.grid(True, alpha=0.3)
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.set_title(f'Graph of f(x) = {b}x + {c} (Linear)')
ax.legend()
else:
x = np.linspace(-5, 5, 100)
y = c * np.ones_like(x)
ax.plot(x, y, 'b-', label=f'f(x) = {c} (Constant)')
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
ax.grid(True, alpha=0.3)
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.set_title(f'Graph of f(x) = {c} (Constant)')
ax.legend()
return fig
quadratic_visualizer_interface = gr.Interface(
fn=plot_quadratic,
inputs=[
gr.Number(label="a (coefficient of x²)", value=1),
gr.Number(label="b (coefficient of x)", value=0),
gr.Number(label="c (constant)", value=0)
],
outputs=gr.Plot(),
title="Quadratic Function Visualizer",
description="""
Visualize the graph of a quadratic function f(x) = ax² + bx + c, including its vertex and real roots (if any).
Example: For f(x) = x² - 4x + 3, enter a=1, b=-4, c=3.
""",
examples=[
[1, -4, 3],
[2, 0, -8],
[1, 2, 1]
]
)