Macaulay2 / Macaulay2/M2

frac accepts a ring that is not a domain, giving a fraction field where multiplication is not associative

Open
#4,576 1 comment 0 reactions 0 assignees View on GitHub
bugs directory Core
Dominant language
Macaulay2
Stars
435
Forks
297
Avg merge
4d 20h
Merged PRs (30d)
11

Description

> **Written by Claude** (Claude Opus 5, via Claude Code), not by @d-torrance, whose account posted it -- please weigh it accordingly.

`frac` documents its argument as an integral domain:

```
i1 : help frac
* Inputs:
* R, a "ring", an integral domain
```

It does not check, and over a ring with nilpotents the result is not a ring in which multiplication is associative:

```m2
i1 : R = ZZ[t]/(t^4);

i2 : K = frac R;

i3 : u = sub(t, K);

i4 : u == 0

o4 = false

i5 : u^4 == 0

o5 = true

i6 : u * (1/u)

o6 = 1

i7 : (u^4) * (1/u)

o7 = 0

i8 : u^3 * (u * (1/u))

3
o8 = u
```

`o7` and `o8` are the same product, `u * u * u * u * (1/u)`, grouped two ways. Since `u^4` is zero and `u^3` is not, no consistent value exists — `1/u` should not have been constructed. The same thing happens over `QQ[x]/x^2` and, since #3177, over towers such as `frac(QQ[x]/x^2[y])`.

The guard that decides this never asks whether any quotient in the chain is prime:

https://github.com/Macaulay2/M2/blob/68351e766d3e7991cd8bc0aa3ceecad1d49e65b8/M2/Macaulay2/m2/enginering.m2#L335-L343

It recurses `QuotientRing → ambient` and `PolynomialRing → coefficientRing` and tests only what is at the bottom, so every quotient passes regardless of its ideal. That is what `frac EngineRing` consults before building the ring:

https://github.com/Macaulay2/M2/blob/68351e766d3e7991cd8bc0aa3ceecad1d49e65b8/M2/Macaulay2/m2/enginering.m2#L345-L351

Two notes on scope, so this is not mistaken for a regression:

- The single-quotient case is old. Before #3177 the check looked only one level down at `coefficientRing`, which for `QQ[a]/(a^2)` is `QQ` — so `frac(QQ[a]/(a^2))` was accepted then too. #3177 widened the check to walk the whole chain, which is what it set out to do, and towers came along with it.
- Where the base genuinely is a domain, the tower case works correctly. Over `frac((QQ[a]/(a^2-2))[y])`: `a^2 == 2`, `y*(1/y) == 1`, `(1/a)*a == 1`, `(y+a)/(y+a) == 1`.

A cheap check would be to require, for each quotient in the chain, that its ideal be prime — or, where that is too expensive to decide, to refuse rather than accept. `isPrime` on the defining ideal already answers it for the small cases above.

For the record, this is the live core of a note in the pre-GitHub `bugs/` tree, `bugs/mike/0-frac-bug` (being triaged in #36), which opens "Notice the nilpotent denominator in o5 below" over this very ring. That file's own transcript no longer reproduces — its `product l` is now `1` rather than a fraction with denominator `t` — so the specific symptom was fixed at some point while the cause was not.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in M2/Macaulay2/m2/enginering.m2 at the quotient-chain guard around lines 335–343 and the frac EngineRing check around lines 345–351. Trace how quotient ideals are handled, then use the QQ[x]/(x^2) and ZZ[t]/(t^4) examples from the issue to verify that invalid fraction rings are refused without changing valid domain towers.

Written by the indexing model from the issue text.

Assessment

Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.