Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions diophantine_classifier/data/families/ramanujan-nagell.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Family: Generalized Ramanujan-Nagell equation
# Schema: see data/families/README.md; prose documentation in docs/FAMILIES.md.
# References are keys into data/references.bib, each with a 'why' annotation.
slug: ramanujan-nagell
name: Generalized Ramanujan-Nagell equation
priority: 1
status: effective
class: expdioph
form: 'x^2 + d = k*b^n (classical: x^2 + 7 = 2^n)'
parents:
- polynomial-exponential
matcher: true
methods:
- hypergeometric method (Beukers)
- Baker + LLL (Petho-de Weger)
notes: 'Classical case: n in {3,4,5,7,15}. At most 2 solutions for general d (Beukers).'
examples:
- x^2 + 7 = 2^n
- x^2 + 11 = 3^n
references:
- key: Nagell1961
why: the proof that n lies in {3, 4, 5, 7, 15}
- key: Beukers1981
why: 'sharp bounds: at most two solutions of the generalized equation'
- key: deWeger1989
why: the Baker + LLL toolkit for concrete instances
25 changes: 25 additions & 0 deletions diophantine_classifier/solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,30 @@ def rec(k_left, target, minimum, acc):
"permutations give the rest", complete=True)


def _solve_ramanujan_nagell(cls, match):
r"""
The classical Ramanujan-Nagell equation ``x^2 + 7 = 2^n``.

EXAMPLES::

sage: from diophantine_classifier import solve
sage: solve("x^2 + 7 = 2^n").solutions
[(1, 3), (3, 4), (5, 5), (11, 7), (181, 15)]
"""
d, k, base = _zz(match.data, "d"), _zz(match.data, "k"), _zz(match.data, "base")
if (d, k, base) != (7, 1, 2):
raise SolverUnavailable(
"only the classical x^2 + 7 = 2^n is hardwired; general (d, k, b) "
"need a Baker + LLL computation (Petho-de Weger)")
pairs = [(ZZ(x), ZZ(n))
for x, n in [(1, 3), (3, 4), (5, 5), (11, 7), (181, 15)]]
return SolutionSet(
_normalized(match), pairs, "finite-complete",
"Nagell's theorem: n ∈ {3, 4, 5, 7, 15} (x > 0 shown; -x symmetric)",
complete=True)


#: dispatch table: family slug -> solver function
SOLVERS = {
"univariate": _solve_univariate,
"linear": _solve_linear,
Expand All @@ -1164,6 +1188,7 @@ def rec(k_left, target, minimum, acc):
"elliptic-weierstrass": _solve_weierstrass,
"thue": _solve_thue,
"egyptian-fractions": _solve_egyptian,
"ramanujan-nagell": _solve_ramanujan_nagell,
}


Expand Down
11 changes: 11 additions & 0 deletions docs/FAMILIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,17 @@ equations: a miscellany" (Int. J. Number Theory 11, 2015).

## 6. Polynomial–exponential equations

### `ramanujan-nagell` — (Generalized) Ramanujan–Nagell — P1, effective
**Form.** x² + d = k·bⁿ (classical: x² + 7 = 2ⁿ); more generally f(x) = k·bⁿ with
f quadratic.
**Status.** Classical case: exactly n ∈ {3,4,5,7,15} (conjectured Ramanujan 1913,
proved Nagell 1948). Generalized: at most 2 solutions apart from finitely many
explicit exceptional d (Apéry 1960, Beukers 1981 with sharp bounds — hypergeometric
method); fully effective; practical resolution via Baker + LLL (Pethő–de Weger).
**Software.** scripts via PARI/Sage (no standard intrinsic); de Weger's algorithms.
**References.** Ramanujan 1913; Nagell 1948; Apéry 1960; Beukers 1981;
de Weger, *Algorithms for Diophantine Equations* (1989).

### `power-values` — Power values of polynomials (Schinzel–Tijdeman) — P2, effective in n
**Form.** f(x) = c·yⁿ, f fixed polynomial with ≥ 2 distinct roots, n ≥ 2 unknown.
**Status.** n is effectively bounded (Schinzel–Tijdeman 1976); for each fixed n it
Expand Down
8 changes: 8 additions & 0 deletions tests/test_classify.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
# diagonal / surfaces
("x^4 + y^4 + z^4 = w^4", "", "equal-sums-like-powers"), # Elkies
# polynomial-exponential
("x^2 + 7 = 2^n", "", "ramanujan-nagell"),
("x^2 + 11 = 3^n", "", "ramanujan-nagell"),
("x^3 - 4 = y^n", "", "power-values"),
# unit fractions
("1/x + 1/y + 1/z = 1", "", "egyptian-fractions"),
Expand Down Expand Up @@ -73,6 +75,12 @@ def test_gen_fermat_regimes():
assert hyperbolic.data["regime"] == "hyperbolic"


def test_explain_smoke():
text = classify("x^2 + 7 = 2^n").explain()
assert "ramanujan-nagell" in text
assert "Nagell" in text or "1948" in text


def test_match_lookup_by_slug():
cls = classify("3*x + 5*y = 1")
assert cls.match_for("linear").slug == "linear"
Expand Down
6 changes: 6 additions & 0 deletions tests/test_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ def test_thue():
assert_valid_solutions("x^3 + 2*y^3 = 11", s.solutions)


def test_ramanujan_nagell():
s = solve("x^2 + 7 = 2^n")
assert (11, 7) in s.solutions and len(s.solutions) == 5
assert s.complete


def test_unavailable_carries_hints():
with pytest.raises(SolverUnavailable) as err:
solve("y^2 = x^7 + 3")
Expand Down