example-projects/examples/everything_function/scripts/algebra_roots.py

116 lines
3.6 KiB
Python
Raw Normal View History

"""Find the roots of a polynomial by *asking* the model for them.
Compare against numpy's actual numerical root finder. For nice polynomials
with integer roots, the AI often gets there. For uglier ones, it makes
plausible-looking guesses that don't quite check out. Both behaviors are
interesting and both are what you should expect from a system that
"reasons" by predicting the most likely next characters.
"""
from __future__ import annotations
import numpy as np
from ai_function import ask
def format_polynomial(coeffs: list[float]) -> str:
"""Render coefficients as a readable expression like '2x^3 - 5x + 1'."""
terms = []
degree = len(coeffs) - 1
for i, c in enumerate(coeffs):
if c == 0:
continue
power = degree - i
# Coefficient formatting: drop trailing zeros, keep sign in front.
abs_str = f"{abs(c):g}"
sign = "+" if c > 0 else "-"
if power == 0:
body = abs_str
else:
coef = "" if abs_str == "1" else abs_str
var = "x" if power == 1 else f"x^{power}"
body = f"{coef}{var}"
terms.append(f"{sign} {body}")
if not terms:
return "0"
expr = " ".join(terms)
# Drop the leading "+ " if positive.
if expr.startswith("+ "):
expr = expr[2:]
elif expr.startswith("- "):
expr = "-" + expr[2:]
return expr
def ai_polynomial_roots(coeffs: list[float]) -> str:
"""Same shape as numpy.roots: pass coefficients high-degree to low-degree."""
polynomial = format_polynomial(coeffs)
return ask(
"Find the real roots of the polynomial. Output only a Python list of "
"numbers rounded to 3 decimal places, like [1.0, -2.0]. No explanation.\n"
"Polynomial: x^2 - 5x + 6\n"
"Roots: [2.0, 3.0]\n"
"Polynomial: x^2 - 4\n"
"Roots: [-2.0, 2.0]\n"
"Polynomial: x^3 - 6x^2 + 11x - 6\n"
"Roots: [1.0, 2.0, 3.0]\n"
f"Polynomial: {polynomial}\n"
"Roots: "
)
def py_polynomial_roots(coeffs: list[float]) -> list[float]:
return sorted(np.roots(coeffs).real.round(3).tolist())
def _run_one(coeffs: list[float]) -> None:
print(f" coefficients: {coeffs}")
print(f" polynomial: {format_polynomial(coeffs)}")
ai_out = ai_polynomial_roots(coeffs)
py_out = py_polynomial_roots(coeffs)
print(f" AI says: {ai_out}")
print(f" numpy says: {py_out}")
print()
def _canned_examples() -> None:
cases = [
[1, -7, 12], # roots 3, 4
[1, 0, -9], # roots -3, 3
[1, -6, 11, -6], # roots 1, 2, 3
[2, -3, -11, 6], # roots 3, -2, 0.5
]
for coeffs in cases:
_run_one(coeffs)
def _interactive() -> None:
print("--- interactive ---")
print(
"Enter polynomial coefficients high-degree to low-degree, separated by "
"commas or spaces. Example: `1, -7, 12` is x^2 - 7x + 12. 'q' to quit.\n"
)
while True:
try:
raw = input("coefficients > ").strip()
except (EOFError, KeyboardInterrupt):
print()
return
if raw.lower() in {"q", "quit", "exit"}:
return
try:
coeffs = [float(p) for p in raw.replace(",", " ").split() if p]
except ValueError:
print(" could not parse those as numbers, try again")
continue
if len(coeffs) < 2:
print(" need at least 2 coefficients (a linear polynomial)")
continue
_run_one(coeffs)
if __name__ == "__main__":
_canned_examples()
_interactive()