From 262cbec98247b79b536680a8b63a563af4dac029 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 9 Aug 2026 16:26:07 -0400 Subject: [PATCH] =?UTF-8?q?Family:=20mordell=20=E2=80=94=20Mordell=20equat?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One family: **Mordell equation** (`mordell`) — P1, algorithmic. - Standard form: `y^2 = x^3 + k` - Parent: `elliptic-weierstrass` - Examples: `y^2 = x^3 - 2` Contents: the registry entry, its `docs/FAMILIES.md` section, its rows in the classification corpus, its solver and solver-layer tests. References cited (the claim each one supports): - `GebelPethoZimmer1998` — the method, with tables for |k| <= 10^4 - `BennettGhadermarzi2015` — complete tables for |k| <= 10^7 Independent of every other family PR: it needs only the registry backbone it is based on. Part of the series that splits #1 into reviewable pieces: 1. `01-bibliography` — packaging, docs, annotated bibliography 2. `02-parsing` — equation strings to a term model 3. `03-registry` — the YAML family registry (3 seed families) 4. `04-matchers` — shape recognizers 5. `05-classify` — the classification pipeline 6. `06-solvers` — solver framework, two seed solvers, and the CLI 7. `07..09-backbone` — the 23 parent families of the DAG, by depth 8. one PR per remaining family (38 of them, mutually independent) 9. `99-polish` — restore the full doctests and tighten the invariants --- .../data/families/mordell.yaml | 27 +++++++++++++++++++ diophantine_classifier/solvers.py | 1 + docs/FAMILIES.md | 10 +++++++ tests/test_classify.py | 14 ++++++++++ tests/test_solvers.py | 14 ++++++++++ 5 files changed, 66 insertions(+) create mode 100644 diophantine_classifier/data/families/mordell.yaml diff --git a/diophantine_classifier/data/families/mordell.yaml b/diophantine_classifier/data/families/mordell.yaml new file mode 100644 index 0000000..87a7885 --- /dev/null +++ b/diophantine_classifier/data/families/mordell.yaml @@ -0,0 +1,27 @@ +# Family: Mordell 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: mordell +name: Mordell equation +priority: 1 +status: algorithmic +class: genus1 +form: y^2 = x^3 + k +parents: +- elliptic-weierstrass +matcher: true +lmfdb: ec.q +methods: +- elliptic logarithms +- tabulated for |k| <= 10^7 +software: + sage: EllipticCurve([0,0,0,0,k]).integral_points() +code: + sage: EllipticCurve([0, 0, 0, 0, {k}]).integral_points(both_signs=True) +examples: +- y^2 = x^3 - 2 +references: +- key: GebelPethoZimmer1998 + why: the method, with tables for |k| <= 10^4 +- key: BennettGhadermarzi2015 + why: complete tables for |k| <= 10^7 diff --git a/diophantine_classifier/solvers.py b/diophantine_classifier/solvers.py index b2aa55c..ddf2ef5 100644 --- a/diophantine_classifier/solvers.py +++ b/diophantine_classifier/solvers.py @@ -1161,6 +1161,7 @@ def rec(k_left, target, minimum, acc): "binary-qf-representation": _solve_bqf, "quadratic-form-zero": _solve_qf_zero, "legendre": _solve_legendre, + "mordell": _solve_weierstrass, "elliptic-weierstrass": _solve_weierstrass, "thue": _solve_thue, "egyptian-fractions": _solve_egyptian, diff --git a/docs/FAMILIES.md b/docs/FAMILIES.md index 86434cf..dc3bb9e 100644 --- a/docs/FAMILIES.md +++ b/docs/FAMILIES.md @@ -146,6 +146,16 @@ by the elliptic-logarithm method once generators are known. **References.** Mordell 1922; Siegel 1929; Baker 1968; Gebel–Pethő–Zimmer 1994; Stroeker–Tzanakis 1994; Cremona, *Algorithms for Modular Elliptic Curves*. +### `mordell` — Mordell equation — P1, algorithmic* +**Form.** y² = x³ + k, k ≠ 0. +**Status.** Finitely many integral points (Mordell/Siegel), effective (Baker; +best bounds Stark, Juricevic); completely tabulated for |k| ≤ 10⁷ +(Gebel–Pethő–Zimmer for 10⁴; Bennett–Ghadermarzi for 10⁷). +**Software.** Sage: `EllipticCurve([0,0,0,0,k]).integral_points()`; Magma ditto; +Bennett–Ghadermarzi online tables. +**References.** Mordell 1913; Gebel–Pethő–Zimmer, "On Mordell's equation" (Compositio 110, 1998); +Bennett–Ghadermarzi, "Mordell's equation: a classical approach" (LMS JCM 18, 2015). + ### `cubic-surface` — Cubic surfaces / del Pezzo — P3, research **Form.** F(x, y, z, w) = 0 cubic (e.g. diagonal ax³+by³+cz³+dw³ = 0). **Status.** Rational points conjecturally dense once one exists (unirationality); diff --git a/tests/test_classify.py b/tests/test_classify.py index e3d6386..f8755ec 100644 --- a/tests/test_classify.py +++ b/tests/test_classify.py @@ -23,6 +23,9 @@ ("x^2 + x*y + y^2 + z^2 = 14", "", "quadratic-form-representation"), ("x^2 + y^2 - z^2 + 3*x - 7 = 0", "", "quadric"), # genus one + ("y^2 = x^3 - 2", "", "mordell"), + ("y^2 = x^3 + k", "k", "mordell"), + ("x^3 = y^2 - 2", "", "mordell"), ("y^2 + y = x^3 - x^2 - 10*x - 20", "", "elliptic-weierstrass"), # higher-genus curves and binary forms ("x^3 + 2*y^3 = 11", "", "thue"), @@ -60,6 +63,12 @@ def test_reducible(): assert sorted(c.slug for c in cls.components) == ["univariate", "univariate"] +def test_mordell_data(): + cls = classify("y^2 = x^3 - 2") + assert cls.data["k"] == "-2" + assert "elliptic-weierstrass" in cls.lineage + + def test_parametric_quadratic_form_classifies(): """A parametric quadratic form must classify, not raise (matchers._gram).""" cls = classify("x^2 + y^2 = D*z^2", params="D") @@ -73,6 +82,11 @@ def test_gen_fermat_regimes(): assert hyperbolic.data["regime"] == "hyperbolic" +def test_params_as_list(): + cls = classify("y^2 = x^3 + k", params=["k"]) + assert cls.slug == "mordell" + + def test_match_lookup_by_slug(): cls = classify("3*x + 5*y = 1") assert cls.match_for("linear").slug == "linear" diff --git a/tests/test_solvers.py b/tests/test_solvers.py index 1b8b095..5874895 100644 --- a/tests/test_solvers.py +++ b/tests/test_solvers.py @@ -67,6 +67,13 @@ def test_univariate(): assert [t[0] for t in s.solutions] == [2, 3] +def test_mordell_integral_points(): + s = solve("y^2 = x^3 - 2") + # unknowns are ordered (y, x) by appearance in the input + assert set(s.solutions) == {(5, 3), (-5, 3)} + assert s.complete + + def test_thue(): s = solve("x^3 + 2*y^3 = 11") assert (3, -2) in s.solutions @@ -207,6 +214,13 @@ def capture(cls, match): assert "coeffs" not in seen["data"] # ... not the linear match's +def test_curve_role_reversal_is_transported_back(): + S = solve("u^2 = v^3 - 2") + assert S.variables == ("u", "v") + assert sorted(S.solutions) == [(-5, 3), (5, 3)] + assert_valid_solutions("u^2 = v^3 - 2", S.solutions) + + def test_component_of_a_rational_equation_keeps_the_parent_conditions(): """(x - 2)(x - y)/y = 0 factors; y != 0 still binds each component.""" cls = classify("(x - 2)*(x - y)/y = 0")