Macaulay2 / Macaulay2/M2

homogenize(Module,RingElement,List) does not homogenize the module, unlike the two-argument form

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

Description

`homogenize` has two `Module` overloads that give different answers for the same module, even when the weights supplied are the ring's own standard grading.

```m2
i1 : S = ZZ/32003[x,y,z,h];

i2 : M = module ideal(x^2-y, x^3-z);

i3 : first entries gens homogenize(M, h)

2 2
o3 = {y - x*z, x*y - z*h, x - y*h}

o3 : List

i4 : first entries gens homogenize(M, h, {1,1,1,1})

2 3 2
o4 = {x - y*h, x - z*h }

o4 : List

i5 : homogenize(M, h) == homogenize(M, h, {1,1,1,1})

o5 = false
```

`o3` is the homogenization of the module. `o4` is the generator-wise homogenization, which is strictly smaller — it is missing `y^2 - x*z`, and no error is reported.

With `{1,1,1,1}` on a standardly graded ring the weighted homogenization *is* the standard one, so these two calls have to agree.

## Where

`M2/Macaulay2/m2/matrix2.m2`, four lines apart:

```m2
homogenize(Module,RingElement) := Module => (M,z) -> (
if isFreeModule M then M
else subquotient(
if M.?generators then homogenize(generators gb M.generators,z), -- gb
if M.?relations then homogenize(generators gb M.relations,z)))

homogenize(Module,RingElement,List) := Module => (M,z,wts) -> (
if isFreeModule M then M
else subquotient(
if M.?generators then homogenize(M.generators,z,wts), -- no gb
if M.?relations then homogenize(M.relations,z,wts)))
```

#207 (2014) is a two-line diff that added `generators gb` to the two-argument form only.

## How you reach it silently

There is no `(homogenize, Ideal, RingElement, List)` method at all — `homogenize(I, h, {1,1,1,1})` fails with `error: no method found for applying homogenize to:`.

So the only route to a weighted homogenization of an ideal is `ideal homogenize(module I, z, wts)`, which goes through the un-fixed path and returns a subideal of the right answer with no diagnostic. That is precisely the missing-saturation mistake #207 existed to remove.

The documentation lists both `Module` overloads under one node with a single description — "so that the result is homogeneous with respect to the given list `w` of integers provided as weights" — with nothing to indicate that one saturates and the other does not. `homogenize-doc.m2` also carries this, commented out in the key list:

```m2
(homogenize, Ideal, RingElement),
--(homogenize, Ideal, RingElement, List), ??
```

so the missing overload was noticed at some point and left open.

## This may not be a two-line fix

Copying `generators gb` into the weighted overload would not be sound in general. Homogenizing a Gröbner basis yields the homogenization of the ideal only when the basis is computed with respect to an order compatible with the grading being homogenized against, and `gb M.generators` uses the ring's own monomial order, which knows nothing about `wts`. Deciding what the weighted case should do — and whether `(homogenize, Ideal, RingElement, List)` should exist — needs someone with an opinion on the intended semantics.

The `{1,1,1,1}` disagreement above stands regardless of how that is settled.

## Scope

The `Matrix` overloads are entry-wise in both the two- and three-argument forms, which is correct for a matrix, so they are unaffected; the only weighted caller among the distributed packages, `gfanInterface.m2:3257`, uses the `Matrix` form. Exposure is to code calling `homogenize(module I, z, wts)` directly.

Worth carrying over from #205, Thomas Kahle's own caveat when he first proposed the two-argument change:

> There may be code outside of the M2 repository that uses the old behavior… There may be code in the Macaulay2 repository that works around the old behavior, that code would call "gb" twice now.

## Background

This came out of triaging [`bugs/dan/0.5-homogenize-ideal`](https://github.com/Macaulay2/M2/blob/d2c8d278264348116ac4c1feeb95150699e3e11b~1/bugs/dan/0.5-homogenize-ideal) — one line, "homogenize(Ideal) should homogenize the ideal, not just its generators" — from the pre-GitHub `bugs/` tree that #36 is about. That file is settled as fixed: #207 is exactly its ask, and its commit message says so almost word for word. Checking *which* code #207 changed is what surfaced the overload it left behind.

Neither #205 nor #207 mentions the three-argument form anywhere in its discussion, so this looks overlooked rather than decided. #875, the other `homogenize` weights bug, is unrelated — it concerns a tower ring with `DegreeRank => 0` passing the wrong weight vector to `rawHomogenize`.

Found while triaging `bugs/dan/0.5-homogenize-ideal`, part of [#36](https://github.com/Macaulay2/M2/issues/36); catalog: [`bug-triage/catalog.tsv`](https://github.com/d-torrance/M2/blob/bug-triage/bug-triage/catalog.tsv). It is not itself a `bugs/` file, so it carries no `bugs directory` label. Investigated and written with AI assistance (Claude Code) — the text above is not @d-torrance's own writing, but he reviewed it before filing.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reproducing the standard-weight disagreement in M2/Macaulay2/m2/matrix2.m2, then compare the two homogenize overloads and read the related changes in #205 and #207. Review homogenize-doc.m2 and decide the intended semantics for weighted modules and the missing Ideal overload. Done means the behavior and API are agreed, implemented consistently, and documented.

Written by the indexing model from the issue text.

Assessment

Domain
tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.