Skip to content

Genus-2 rational-points Magma adapter (RationalPointsGenus2) #79

Description

@roed-math

Goal

Add the genus-two Magma adapter on top of the core runner (#76): for y^2 = f(x) with deg f in {5, 6} and concrete integer coefficients, call Magma V2.29's RationalPointsGenus2 intrinsic on the hyperelliptic curve and turn its three return values — the point set, the "these are all of them" flag, and the height bound — into a SolutionSet whose claim is decided by that flag and nothing else. When the flag is true the result is a conditional determination of the affine rational solutions; when it is false the result is a partial witness list, or today's fallback when there is nothing to witness. Opt-in only (solve(..., use_magma=True, domain="QQ") / --use-magma).

There is no hand-built Chabauty pipeline in this adapter. The previous design assembled a Jacobian / rank-bound / Chabauty sequence out of intrinsics whose signatures it never pinned, and derived its completeness claim from flags this repository would have had to infer; that is replaced in full by the single pinned intrinsic below, whose exact signature, parameter defaults, return values and documented failure modes are quoted from the handbook here.

Target base

Dependencies

Pinned external API

Magma version floor: V2.29. There is no earlier-version fallback path in
this adapter; on an older Magma the call errors and the standard fallback
runs. The adapter records the Magma version reported by the run in its
Evidence.

Quoted verbatim from the Magma V2.29 Handbook (footer: V2.29, 3 August
2026
), chapter Hyperelliptic Curves, section Points, subsection
Enumeration and Counting Points, at
https://magma.maths.usyd.edu.au/magma/handbook/text/1613
(fetched and read 2026-08-09). Cite the section title, not only the page
number: in the current V2.29 printing text/1612 is the Function Field page
of the same chapter and this subsection sits one page later, so a bare page
number drifts between printings.

PointsGenus2(C) : CrvHyp -> SetIndx, BoolElt, RngIntElt
RationalPointsGenus2(C) : CrvHyp -> SetIndx, BoolElt, RngIntElt
    Bound1: RngIntElt                   Default: 1000
    Bound2: RngIntElt                   Default: 20000
    Fast: BoolElt                       Default: false
    RankBound: RngIntElt                Default: Infinity()
    PrimeCutoff: RngIntElt              Default: 10000

For a curve C over Q of the form y^2 = f(x) try to determine the set of
rational points

This returns a set of rational points on the curve, a flag indicating whether
we know that these are all the points, and if this is not the case, a number
such that all the points of (multiplicative x-coordinate) height up to that
bound are included in the set.

Bound1 is an argument passed to RationalPoints.

The handbook continues, in the same paragraph, that Bound2 is passed to a
second RationalPoints call which is made after the first search for small
points has failed and after the routine's own local-solubility test has
passed; that Fast makes the routine use smaller bounds in its call to
MordellWeilGroupGenus2 for the search on 2-coverings, so that it fails
faster instead of triggering a time-intensive search for rational points on
2-coverings; and that PrimeCutoff is passed on to TwoCoverDescent. Those
sentences are paraphrased rather than quoted only so that this issue does not
put a solubility phrase into the repository's own claim vocabulary — nothing
in the adapter depends on them, and this adapter makes no local-solubility
claim of its own
.

The handbook's description of what the routine does internally, and of how it
can fail, is quoted verbatim:

This function uses a combination of techniques:

i)   search for (relatively small) points,
ii)  test for everywhere local solubility,
iii) two-cover descent,
iv)  degree 2 and 3 elliptic subcovers of rank zero,
v)   computation of generators of a finite-index subgroup of the
     Mordell-Weil group,
vi)  Chabauty when the rank is at most 1,
vii) a check whether the curve has rational divisors of odd degree,
viii)if the rank is at least 2 and no points were found, a Mordell-Weil
     sieve computation.

The two possible failure modes are:

i)  failure to determine the rank
ii) rank is at least 2 and rational points exist; in these cases the result
    is false, and it returns the set of rational points up to the height
    bound for the search.

The adapter does not know, and never claims, which of (i)–(viii) produced a
given answer.
It reads the second return value and nothing else. That is
the whole point of the redesign: the completeness claim rests on a flag the
intrinsic itself sets, not on a flag this repository would have had to infer.
The list above is quoted as the handbook's own account of the routine, not as
an assertion by this repository that any particular step ran.

Three further pinned facts used by the script and the decoder, each fetched
and read on 2026-08-09 from the same V2.29 handbook.

  • HyperellipticCurve(f) : RngUPolElt -> CrvHyp, chapter Hyperelliptic
    Curves
    , Creation Functions
    (https://magma.maths.usyd.edu.au/magma/handbook/text/1610): "Given two
    polynomials h and f ∈ R[x] where R is a field or integral domain, this
    function returns the nonsingular hyperelliptic curve C: y^2 + h(x)y = f(x).
    If h(x) is not given, then it is taken as zero. If R is an integral domain
    rather than a field, the base field of the curve is taken to be the field
    of fractions of R. An error is returned if the given curve C is singular."
    So an integer coefficient sequence is legitimate input and produces the
    curve over Q; a non-squarefree f errors inside the try.

  • Polynomial(Q) : [ RngElt ] -> RngUPolElt, chapter Univariate Polynomial
    Rings
    (https://magma.maths.usyd.edu.au/magma/handbook/text/231): "Given
    a sequence Q of elements from a ring R, create the polynomial over R whose
    coefficients are given by Q. This is equivalent to
    PolynomialRing(Universe(Q))!Q." The coefficient order is ascending,
    matching the magma_coeffs convention below. (This is also the call form
    the repository's own registry template already emits — re-verified today:
    classify("y^2 = x^5 - x + 1").code() is
    {'magma (hyperelliptic)': 'C := HyperellipticCurve(Polynomial([1, -1, 0, 0, 0, 1]));\nJ := Jacobian(C); RankBound(J);\n'}.)

  • Weighted-projective coordinates. The head of the same Points page
    states: "The hyperelliptic curve is embedded in a weighted projective space,
    with weights 1, g + 1, and 1, respectively on x, y and z. Therefore point
    triples satisfy the equivalence relation (x : y : z) = (μ x : μ^(g+1) y :
    μ z), and the points at infinity are then normalized to take the form
    (1 : y : 0)." For genus 2, g + 1 = 3, so a point (x : y : z) with
    z != 0 has affine coordinates

    (x/z,  y/z^3)
    

    and z == 0 marks a point at infinity. The same page documents
    Eltseq(P) : PtHyp -> SeqEnum under Access Operations: "Given a point P
    on a hyperelliptic curve, this returns a 3-element sequence consisting of
    the coordinates of the point P." (Verified against the handbook's own worked
    example on that page: for C: y^2 = x^6 + x^2 + 1 the call
    Points(C : Bound := 2) lists the point (-1 : -9 : 2), whose affine form
    under this rule is (-1/2, -9/8); checked exactly in Sage 10.7 during this
    edit, f(-1/2) = 81/64 = (-9/8)^2.)

Pinned module constants

POINT_SEARCH_BOUND1 = 1000     # -> Bound1
POINT_SEARCH_BOUND2 = 20000    # -> Bound2

These equal the intrinsic's documented V2.29 defaults. The adapter passes
them explicitly anyway, so that the exact search parameters appear in the
generated script and in the evidence command string, and so that a future
change to Magma's defaults cannot silently change what this repository
reports. Fast, RankBound and PrimeCutoff are not passed; their V2.29
defaults (false, Infinity(), 10000) are recorded here for the record
and are what any run of this adapter uses.

Supported inputs

Registered as MAGMA_SOLVERS["genus-two"] with

MAGMA_CAPABILITIES["genus-two"] = SolverCapability(
    slug="genus-two", domains=frozenset(("QQ",)),
    goals=frozenset(("enumerate", "exists", "find-one")),
    kinds=frozenset(("finite-complete", "empty", "witness")),
    completeness=frozenset(("conditional", "partial")),
    guards=(see "Guards" below))

genus-two has no entry in CAPABILITIES/SOLVERS today and gains none:
with use_magma=False the family still has no wired solver.

Input regime

y^2 = f(x), deg f in {5, 6}, all coefficients concrete integers,
rational points (effective domain QQ). Verified today (re-run against
Sage 10.7 on 85f8e0a):

classify("y^2 = x^5 - x + 1").data
  == {'f': 'x^5 - x + 1', 'genus': 2, 'x': 'x', 'y': 'y',
      'magma_coeffs': '[1, -1, 0, 0, 0, 1]'}
classify("y^2 = x^5 - x + 1").parsed.unknowns == ('y', 'x')

magma_coeffs is ascending (Polynomial([...]) order in Magma, as
pinned above). Match data values are stringified, so the list is read with
ast.literal_eval, each entry converted exactly with ZZ(...), and the
result passed through encode_int_list — the only path into the script.
data["x"]/data["y"] give the user's coordinate names; the assignment
built from them is ordered with _ordered(cls, assignment), so tuples follow
the unknowns' order of first appearance — for the fixture equation (y, x),
not (x, y).

Domain gate

Integral points on a genus-2 curve are a different problem with different
machinery, and this adapter never answers it. With the effective domain ZZ
or NN the capability check skips the Magma route and solve behaves
exactly as today (verified: SolverUnavailable("no automatic solver for family 'genus-two' yet — ...")).

Guards (each one declines: MagmaFailure, then the standard fallback)

  • any coefficient not a concrete integer (parametric input, or a rational
    coefficient);
  • deg f outside {5, 6}, or f not squarefree (the model is then not a
    smooth genus-2 curve, and HyperellipticCurve itself rejects it);
  • effective domain other than QQ.

Output and API contract

Script template

diophantine_classifier/data/magma/rational_points_genus2.m, assembled by

build_script("rational_points_genus2",
             coeffs=encode_int_list(ascending_coefficients),
             bound1=encode_int(POINT_SEARCH_BOUND1),
             bound2=encode_int(POINT_SEARCH_BOUND2))

on top of prelude.m. All three placeholders are filled only with typed
encoder output. The file is complete as written — there is nothing left to
fill in at implementation time:

// rational_points_genus2.m  (prelude.m is prepended)
coeffs := <<coeffs>>;                 // ascending integers, deg f in {5, 6}

try
    C := HyperellipticCurve(Polynomial(coeffs));
    pts, complete, bound := RationalPointsGenus2(
        C : Bound1 := <<bound1>>, Bound2 := <<bound2>>);
    entries := [];
    for P in pts do
        c := Eltseq(P);
        if c[3] eq 0 then
            Append(~entries, JSONObj(["kind"], ["infinite"]));
        else
            xx := c[1] / c[3];
            yy := c[2] / c[3]^3;             // weights are 1, g+1 = 3, 1
            Append(~entries,
                   JSONObj(["kind", "x", "y"],
                           ["affine",
                            JSONObj(["n", "d"],
                                    [JSONInt(Numerator(xx)),
                                     JSONInt(Denominator(xx))]),
                            JSONObj(["n", "d"],
                                    [JSONInt(Numerator(yy)),
                                     JSONInt(Denominator(yy))])]));
        end if;
    end for;
    DCEmit("ok", "",
           JSONObj(["points", "points_complete", "height_bound"],
                   [JSONList(entries),
                    complete select "true" else "false",
                    JSONInt(bound)]));
catch e
    DCEmit("error", "pipeline-error", JSONObj([], []));
end try;
quit;

For the fixture this renders literally and completely as

coeffs := [1, -1, 0, 0, 0, 1];

try
    C := HyperellipticCurve(Polynomial(coeffs));
    pts, complete, bound := RationalPointsGenus2(
        C : Bound1 := 1000, Bound2 := 20000);
    entries := [];
    for P in pts do
        c := Eltseq(P);
        if c[3] eq 0 then
            Append(~entries, JSONObj(["kind"], ["infinite"]));
        else
            xx := c[1] / c[3];
            yy := c[2] / c[3]^3;             // weights are 1, g+1 = 3, 1
            Append(~entries,
                   JSONObj(["kind", "x", "y"],
                           ["affine",
                            JSONObj(["n", "d"],
                                    [JSONInt(Numerator(xx)),
                                     JSONInt(Denominator(xx))]),
                            JSONObj(["n", "d"],
                                    [JSONInt(Numerator(yy)),
                                     JSONInt(Denominator(yy))])]));
        end if;
    end for;
    DCEmit("ok", "",
           JSONObj(["points", "points_complete", "height_bound"],
                   [JSONList(entries),
                    complete select "true" else "false",
                    JSONInt(bound)]));
catch e
    DCEmit("error", "pipeline-error", JSONObj([], []));
end try;
quit;

The rational leaves are built out of #76's own primitives — JSONObj over
two JSONInts — so that they land in exactly the {"n": ..., "d": ...}
shape the payload protocol specifies (#76 §2); no new emitter is introduced.

The try/catch wrapper is mandatory: a singular model, an unavailable
intrinsic (Magma older than V2.29), or any internal error becomes
status: "error" and the standard fallback, never a partial parse and never
a completeness claim.

Payload schema (data)

field type meaning
points array of objects each {"kind": "affine", "x": {"n": …, "d": …}, "y": {"n": …, "d": …}} or {"kind": "infinite"}
points_complete "true"/"false" the intrinsic's second return value: whether it knows the returned set is all of C(Q)
height_bound decimal string the intrinsic's third return value

Those three keys are the whole payload, and the decoder asserts that the
key set is exactly {"points", "points_complete", "height_bound"}. The four
invented fields of the previous design — an upper bound for the rank of the
Jacobian, a flag saying that bound was proved to be the rank, a flag saying a
Chabauty computation ran, and a flag saying the Mordell–Weil subgroup used was
saturated — are removed everywhere: from the script, from the schema, from
the branch logic, from assumptions, and from the fixtures.
RationalPointsGenus2 returns none of them, and this adapter reports only
what it is told.

Integers are decimal strings and rationals are {"n": …, "d": …} objects
(#76 §2); bare JSON numbers are rejected by the protocol.

height_bound is only meaningful when points_complete == "false" — the
handbook defines it as the bound reached in that case. It is recorded in the
payload unconditionally (it is what Magma returned) but is used only on the
incomplete branch; on the complete branch the adapter must not put it into
any scope or description string.

Parsing into a SolutionSet

  1. Decode each point. Entries with kind == "infinite" are dropped from
    the solution list
    — a point at infinity is a point of the projective
    curve, not a solution of the affine equation the user typed — and their
    count is recorded in the description. (For the fixture, deg f = 5, so
    there is exactly one rational point at infinity.)
  2. Decode affine coordinates exactly: QQ(n)/QQ(d) from the tagged objects,
    never through float or int(...).
  3. Build assignments {data["x"]: x, data["y"]: y} from the affine entries,
    order them with _ordered(cls, ...), sorted(set(...)) — so tuples come
    out in the unknowns' order of first appearance and are deduplicated and
    sorted.
  4. No pre-filtering: solvers._verified is the firewall; a point failing
    ParsedEquation.accepts raises InternalConsistencyError.
  5. representation is left to _derived_representation
    (PartialSearch(solutions, scope) for both the conditional and the
    witness case, EmptySet for an empty conditional result). It must not be
    overridden with a FiniteSet.

Result semantics — exactly three branches

(A) points_complete == "true".

kind         = "finite-complete"      # or "empty" when there is no affine point
completeness = "conditional"
assumptions  = ("the external Magma routine computed correctly",)
scope        = ("all rational solutions of the equation as typed; the "
                "curve's rational points at infinity are points of the "
                "projective model and are not solutions of it")
scope_info   = Scope(domain_scope="rational solutions of the affine equation",
                     ordering_convention="unknowns in order of first "
                                         "appearance in the input equation")

assumptions is exactly that one-element tuple, with that exact text — no
rank assumption, no saturation assumption, because the adapter no longer
inspects rank or saturation. conditional requires nonempty assumptions
(docs/SEMANTICS.md §3), and this entry supplies it. height_bound is not
mentioned anywhere on this branch.

(B) points_complete == "false" and at least one affine point.

kind         = "witness"
completeness = "partial"
assumptions  = ()
scope        = ("rational solutions of the affine equation whose "
                "x-coordinate has multiplicative height at most "
                f"{height_bound}; nothing is claimed beyond that height")
scope_info   = Scope(domain_scope="rational solutions of the affine equation",
                     ordering_convention="unknowns in order of first "
                                         "appearance in the input equation",
                     search_region=("RationalPointsGenus2(C : Bound1 := 1000, "
                                    "Bound2 := 20000), height bound "
                                    f"{height_bound}"))

The height in those strings is the payload's height_bound, decoded exactly
and rendered as a decimal integer — never POINT_SEARCH_BOUND1 or
POINT_SEARCH_BOUND2, which are inputs to the search, not the guarantee it
came back with. witness results are never proved (contract test).

(C) points_complete == "false" and no affine point.

The adapter raises MagmaFailure(..., outcome="cas-failure") with reason
"not-determined", so the caller gets today's behavior (which carries the
registry's runnable templates). It must not return an empty witness: a
user could read "no solutions found, completeness partial" as evidence that
the equation has no rational solutions, and this branch is exactly the case
where the intrinsic reports that it could not decide. Points at infinity in
the payload do not rescue this branch — they are not affine solutions.

No other combination produces a completeness claim, and there is no path on
which a blanket claim about the family is made.

Evidence

result.as_evidence(
    "Magma RationalPointsGenus2 (V2.29 genus-2 rational-point "
    "determination; completeness flag: " + points_complete + ")",
    command="rational_points_genus2([1, -1, 0, 0, 0, 1], "
            "Bound1=1000, Bound2=20000)",
    reference=("Stoll2011", "McCallumPoonen2012"))

where points_complete is the payload's own "true"/"false" enum string.
The evidence names the intrinsic that ran and the flag it returned. It does
not name Chabauty, a rank bound, a Mordell–Weil sieve or a descent as
having been performed: the adapter cannot observe which of the intrinsic's
internal techniques was decisive, and asserting one would be a claim the run
does not support. The references describe the family of methods the intrinsic
combines; they are attribution, not a statement about this run.

Stoll2011 ("Rational points on curves", cited today by general-curve) and
McCallumPoonen2012 (cited today by hyperelliptic, why: "the
Chabauty-Coleman method for rational points") both already resolve in
data/references.bib (re-verified today); CasselsFlynn1996 (already cited
by genus-two) may be added as a third for the explicit Jacobian arithmetic.
No bibliography change is required; any addition follows the standard rules
(author/title/journal/volume/year, nonempty why, doi verified at commit
time, url only for legally free copies, make references passing).

Failure and fallback semantics

Guard declined, executable missing, Magma older than V2.29 (the intrinsic is
undefined and the call errors), timeout, nonzero exit, status != "ok",
oversized output, unparseable payload, and branch (C) above all fall through
to today's behavior for this family: _local_emptiness still runs first, and
then

SolverUnavailable("no automatic solver for family 'genus-two' yet — magma: "
                  "full pipeline (Jacobian, RankBound, Chabauty); sage: "
                  "HyperellipticCurve; igusa_clebsch_invariants; "
                  "code[magma (hyperelliptic)]: C := HyperellipticCurve("
                  "Polynomial([1, -1, 0, 0, 0, 1]));\nJ := Jacobian(C); "
                  "RankBound(J);; no small local obstruction found either",
                  family="genus-two")           # outcome unsupported-family

is raised with "; the Magma route was attempted and did not produce a result (<outcome>): <reason>" appended (#76). The message above is today's
verbatim output for the fixture equation (re-verified during this edit — note
the template is inherited from the hyperelliptic ancestor, since genus-two
has no code: map of its own) and is what the equivalence test pins. Changing
the registry's inherited display template is out of scope here.

Acceptance criteria

Fixtures (deterministic, fake runner, no Magma)

Equation: y^2 = x^5 - x + 1 (the registry example for genus-two and the
#52 fixture), solved with domain="QQ".

The six affine points used in the payloads are genuine: f(0) = 1,
f(1) = 1, f(-1) = 1 (verified today), so (x, y) in {(0, ±1), (1, ±1), (-1, ±1)} all satisfy y^2 = x^5 - x + 1. The fixtures assert the adapter's
decoding, ordering, branch logic and verification — they do not assert that
this list is all of C(Q).

(i) Fake complete payload (required test 1). points_complete: "true",
height_bound: "0", points = the six affine points (each as
{"kind": "affine", "x": {"n": …, "d": "1"}, "y": {…}}) plus one
{"kind": "infinite"} entry. Assert:

  1. result.variables == ('y', 'x');
  2. result.solutions == [(-1, -1), (-1, 0), (-1, 1), (1, -1), (1, 0), (1, 1)] — payload (x, y) data reordered to the unknowns' order and
    sorted (verified: this is the sorted (y, x) list for those six points);
    the point at infinity is absent;
  3. "1 rational point at infinity" (or equivalent, exact wording pinned by
    the test) appears in result.description;
  4. result.kind == "finite-complete", result.completeness == "conditional", result.complete is False;
  5. result.assumptions == ("the external Magma routine computed correctly",)
    — exactly this one-element tuple;
  6. result.scope states that the claim is about rational solutions of the
    equation as typed and that points at infinity are not solutions of it;
    "height" does not appear in result.scope on this branch;
  7. exactly one Evidence with kind == "external-computation",
    software == "magma", version from the payload, every reference key
    resolvable in bibliography(), and "RationalPointsGenus2" in the
    evidence description;
  8. check_solver_contract(cls, result) (Core opt-in Magma process runner #76) passes;
    json.dumps(result.to_dict()) succeeds with schema_version == 3 and
    exact tagged rationals (decode_exact round-trips each coordinate).

(ii) Fake incomplete payload with the exact returned height (required
test 2)
. Same six affine points, points_complete: "false",
height_bound: "4096". Assert kind == "witness",
completeness == "partial", assumptions == (),
representation.form == "partial-search", the same six tuples, and that
"4096" appears in result.scope while neither "1000" nor "20000"
does — the guarantee is the height the intrinsic returned, not the search
bounds it was given. Assert result.scope_info.search_region contains both
the returned height and the two Bound values.

(iii) Complete payload containing only points at infinity (required test
3)
. points_complete: "true", points = a single {"kind": "infinite"}
entry, height_bound: "0". Assert kind == "empty",
completeness == "conditional",
assumptions == ("the external Magma routine computed correctly",),
representation.form == "empty", result.complete is False, and that
result.description records the one rational point at infinity — so the
emptiness is visibly emptiness of the affine equation and visibly rests on
the external completeness assumption, never on a proved statement.

(iv) Incomplete payload containing only points at infinity → fallback
(required test 4). Same payload with points_complete: "false",
height_bound: "4096". Assert the verbatim SolverUnavailable above with the
reason appended, outcome == "unsupported-family", family == "genus-two",
and that no SolutionSet with kind == "empty" is produced on this path.

(v) Exact coordinate decoding and first-appearance ordering (required
test 5)
. A payload point with genuinely non-integral coordinates, decoded
exactly and ordered by first appearance: take x = -1/2, y = -9/8 on
y^2 = x^6 + x^2 + 1 — the handbook's own example point (-1 : -9 : 2),
whose affine form under the weight-(1, 3, 1) rule is (-1/2, -9/8),
verified exactly in Sage 10.7 during this edit (f(-1/2) = 81/64 = (-9/8)^2;
f is squarefree of degree 6, so the curve is a legitimate genus-2 model for
this adapter). Assert that the payload objects {"n": "-1", "d": "2"} and
{"n": "-9", "d": "8"} decode to the exact QQ values, that the produced
tuple is (-9/8, -1/2) for unknown order ('y', 'x'), that json.dumps
round-trips them as tagged rationals, and that solvers._verified accepts
them. A second payload with the coordinates swapped (x = -9/8, y = -1/2,
not a point of that curve) must raise InternalConsistencyError, proving the
adapter does not pre-filter or silently reorder.

(vi) Real-Magma marked test on V2.29+ (required test 6). A
magma-marked test, skipped by default, runs the fixture curve against a real
install on V2.29 or newer: it asserts that the run's reported Magma
version is at least V2.29, that the three-value call signature works, that
points_complete parses as one of the two enum strings, and that every
returned affine point verifies against the equation. It never asserts a
particular point count and is never a substitute for the deterministic tests
above.

(vii) Malformed payload (invalid JSON between the sentinels) → the same
fallback, reason mentions cas-failure. Likewise a timeout
(magma_timeout=1, sleeping fake) → fallback, reason mentions
resource-exceeded; and status: "error" → fallback. A payload whose
points_complete is neither "true" nor "false", or whose height_bound
is not a decimal integer, is malformed → fallback, never a default guess.

(viii) Verification firewall. A payload affine point (x, y) = (2, 3)
f(2) = 32 - 2 + 1 = 31 while 3^2 = 9 (verified) — makes
solvers._verified raise InternalConsistencyError; the bad point appears in
no returned solution set, and the adapter does not pre-filter it away.

Script snapshot

(ix) The script generated for the fixture is asserted line-by-line
against the complete literal rendering above: it contains
coeffs := [1, -1, 0, 0, 0, 1];,
C := HyperellipticCurve(Polynomial(coeffs));,
RationalPointsGenus2(, Bound1 := 1000, Bound2 := 20000,
and the three-value assignment pts, complete, bound :=.

Two regression guards against the removed design, both stated positively so
that they cannot drift:

  • the decoder rejects any payload whose key set is not exactly
    {"points", "points_complete", "height_bound"} — in particular a payload
    carrying any of the four removed flags is malformed and takes the fallback,
    never a completeness claim;
  • Jacobian(, RankBound( and Chabauty occur nowhere in the generated
    script or in the adapter module. (They do still occur in the family's
    inherited SolverUnavailable hint text, which is today's verbatim registry
    template and is out of scope here; assert against the script and the module,
    not against that message.)

Unconditional and repository-wide

(x) With use_magma=False, and with DIOPHANTINE_CLASSIFIER_MAGMA
pointing at the fake, solve("y^2 = x^5 - x + 1", domain="QQ") and
solve("y^2 = x^5 - x + 1") raise the same SolverUnavailable messages as on
the pre-epic tree. Runs unconditionally.

(xi) domain="ZZ" with use_magma=True behaves exactly as today: the
capability gate skips the adapter and no process is started.

(xii) make test, make doctest, make coverage (100%) and
make registry-docs clean without Magma installed; every new function has
a Sage-convention docstring whose EXAMPLES pass sage -t without Magma.

Out of scope

  • Integral points on genus-2 curves (Baker's method / Magma's
    IntegralPoints), and every domain other than QQ.
  • Running, re-running or second-guessing any individual step the intrinsic
    performs internally — descent, Mordell–Weil computation, Chabauty, the
    Mordell–Weil sieve — and any attempt to upgrade a conditional
    determination to a proved one.
  • Tuning Bound1/Bound2 per input, or exposing them as user parameters;
    they are module constants here.
  • Passing Fast, RankBound or PrimeCutoff; their V2.29 defaults are
    recorded above and are what every run uses.
  • Reporting the points at infinity as solutions, or emitting a projective
    solution set. Their count goes in the description; the affine equation is
    what the user typed.
  • Genus-2 identification, Igusa invariants, geometric keys and curve tables —
    those are Genus 2: Igusa-invariant identification against curve tables #52.
  • Curves of genus other than 2, and models with rational non-integral
    coefficients.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions