Macaulay2 / Macaulay2/M2

integralClosure of an ideal can be intractable where the same closure via integralClosure(I, d) is instant

Open
#4,631 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bugs directory
Dominant language
Macaulay2
Stars
435
Forks
297
Avg merge
4d 20h
Merged PRs (30d)
11

Description

This issue was triaged from [`bugs/mike/1-integralClosureIdeal.m2`](https://github.com/Macaulay2/M2/blob/388c1ff0ce30d83751dea7bc7eac77fdc1305dd7/bugs/mike/1-integralClosureIdeal.m2), one of the 857 files removed from the pre-GitHub `bugs/` tree by [`d2c8d27826`](https://github.com/Macaulay2/M2/commit/d2c8d27826) and catalogued in [#36](https://github.com/Macaulay2/M2/issues/36). **The commentary below was written by Claude (Claude Opus 5, via Claude Code)**, not by @d-torrance, whose account posted it -- please weigh it accordingly.

The original file, verbatim (151 lines)

```m2
-- Some possibly good test examples for integralClosure of ideals.
-- MES: Also: some bugs/unpleasant-isms DE found while playing with this

end
restart
load "integralClosureIdeal.m2"

kk=ZZ/101
S=kk[a,b]
integralClosure(ideal(a^3,b^7),2)
i=ideal"a4,a3b,ab3,b4"
integralClosure i
integralClosure (i^2) == i^2 -- i^2 is already integrally closed
-- this line above doesn't seem to finish in small time

-- the timings here refer to some older version of integral closure.
S=kk[a,b,c]
integralClosure ideal(a^2,b^3,c^3) -- OLD: 4th rad takes 45 sec. Then done.
time integralClosure ideal(a^3,b^3,c^3)
-- OLD 4th rad takes 70 sec, 5th rad much longer.
-- NEW 4th rad takes 1 sec, 5th rad 23 sec
time integralClosure(ideal(a^3,b^4,c^5),1)
-- OLD: third (?) rad comp 60 sec. 4th much longer.
-- NEW: fourth rad comp 1 sec. 5th takes 439 sec.

---------------
--Huneke's question (related to "evolutions"):
--If f has isolated singularity, is
--f \in mm*integralClosureIdeal(J(f))
--where mm is the maximal ideal and J(f) is the
--ideal generated by the partial derivatives of f?
--This is known to be true in 2 variables, and
--it's also known if f is quasi-homogeneous.
--Further, it's known that
--f \in integralClosureIdeal(mm*J(f))

restart
kk=ZZ/32003
S=kk[a,b,c]
mm=ideal vars S
--S=QQ[x,y]
f=ideal(matrix{{a^3}}+random(S^1, S^{-4})) -- smallest non-qhom ex we could find in 3 vars.
toString f
ideal(-2136*a^4+9349*a^3*b-5609*a^2*b^2-15802*a*b^3-11250*b^4+8735*a^3*c-9489*a^2*b*c-371*a*b^2*c-14212*b
^3*c+13529*a^2*c^2-545*a*b*c^2-1270*b^2*c^2-2519*a*c^3-1415*b*c^3+626*c^4+a^3)

f= ideal (y^4-2*x^3*y^2-4*x^5*y+x^6-x^7)
f = trim ideal( random(S^1, S^{-3})+random(S^1, S^{-5}))

f = ideal (a^2+a^3+b^2+c^2) -- this is an example
f = ideal (a^2+a^3+b^2+a*b*c+c^2) -- this is an example

J = ideal jacobian f
substitute(J:f, kk) -- check local quasi-homogeneity!

ReesJ=(flattenRing reesAlgebra(J))_0
P=ideal oo
betti res P
Q=trim(P+ minors (2,jacobian P))
codim Q
betti Q

Q1=trim(P+ideal randomMinors(1,2,jacobian P))
betti Q1
time decompose Q1
--radical Q1

vasconcelos (ideal(a,b,c),a)
R1=ringFromFractions(oo, Variable=>z)
R1ring = target (R1_0)
P1=trim ideal R1ring

codim P1
Q2=trim(P1+ideal randomMinors(1,3,jacobian P1))
codim Q2
betti Q1

time decompose Q2
--radical Q1

vasconcelos (ideal(a,b,c),a)
R1=ringFromFractions(oo, Variable=>z)
R1ring = target (R1_0)
P1=trim ideal R1ring

JJ = J -- in the integral closed case
--gens f%J -- f is not in J, so not quasi-homogeneous THIS IS WRONG -- NEED TO LOOK AT IT LOCALLY
JJ=integralClosureOfIdeal J

Slocal = (coefficientRing S){gens S}
fl=substitute(f,Slocal)
JJl=substitute(JJ,Slocal)
mml=substitute(mm,Slocal)
Jl=substitute(J,Slocal)
(gens fl) % (mml*JJl)
(gens fl) % JJl

J:f;

--integralClosureOfIdeal(mm*J)--can't compute this -- just finding the minors the first time is
--very slow (9 variables, codim 5, the 5 x 5's of a 9 x ?? matrix...)
betti res (mm*J)

R4 = kk[a..d]
F = ((super basis(5,ideal(a,b,c))) * random(R4^55, R4^1))_(0,0)
R = kk[a,b,c]
f = sub(F,{d=>1})
f = sub(f,R)
f = ideal f
-------------
restart

--Some bugs:

viewHelp random -- documentation for "random" is peculiar

--truncate(3,Rbar^1)
--viewHelp truncate
--DOCUMENTATION OF "TRUNCATE" CLAIMS THERE'S A BUG

--BASIS problems:

restart
kk=ZZ/101
S=kk[a,b]
R=kk[c,d]
f=map(R,S,{c,d^2})
P=R^1/(ideal vars R)^3
--M=map(P,S^1,{{1_R}}) -- gives error
--M.RingMap=f
B=basis(P)

B=basis(P,SourceRing => S)
keys B -- "RingMap" is a key
B.RingMap => f --returns f, does NOT set the key
B.RingMap -- thinks the map of rings is 0.
kernel B

matrix"c,d3"
keys oo

source B
coimage B

--N=coker matrix{{a*b}}
--map(P,N,{{1_R}}) -- gives error
```

### Where it stands today

`integralClosure I` can be intractable where `integralClosure(J, d)` returning the same ideal is instant,
because the one-argument form always passes the ideal it is handed straight to the Rees algebra.

Over `ZZ/101[a,b]`, with `i = ideal(a^4, a^3*b, a*b^3, b^4)`:

```m2
i2 = i^2; -- 9 monomial generators, a^8 .. b^8
integralClosure i2 -- no result after 240 seconds
integralClosure(i, 2) -- 0.26 seconds
```

Both compute the same ideal. The second argument of `integralClosure(Ideal, ZZ)` is the power, so
`integralClosure(i, 2)` *is* the integral closure of `i^2`, and it comes back with

```
ideal(b^8, a*b^7, a^2*b^6, a^3*b^5, a^4*b^4, a^5*b^3, a^6*b^2, a^7*b, a^8)
```

which is `i^2` itself — so the answer to the whole question is that `i^2` is already integrally closed,
reached instantly by one entry point and not at all by the other.

For a check on what the second argument means, independent of this example, the closure of
`ideal(a^3, b^7)^2 = ideal(a^6, a^3*b^7, b^14)` is the monomials `a^i*b^j` with `i/6 + j/14 >= 1`, and that is
exactly what `integralClosure(ideal(a^3,b^7), 2)` returns:

```m2
i1 : integralClosure(ideal(a^3,b^7), 2)

o1 = ideal (a^6, a^5*b^3, a^4*b^5, a^3*b^7, a^2*b^10, a*b^12, b^14)
```

### Where the difference comes from

The one-argument and two-argument forms are both thin wrappers on the same three-argument method:

https://github.com/Macaulay2/M2/blob/development/M2/Macaulay2/packages/IntegralClosure.m2#L873-L875

So `integralClosure i2` runs `integralClosure(i2, (i2)_0, 1)` while `integralClosure(i, 2)` runs
`integralClosure(i, i_0, 2)`. That method trims its input and hands it to `integralClosureOfIdeal`, which
builds `reesAlgebra(I, a)` and takes the integral closure of *that* ring. The two calls therefore differ in
the size of the ring being normalized: a Rees algebra on `i2`'s 9 generators with denominator `a^8`, against
one on `i`'s 4 generators with denominator `a^4`. Reading the source, that is where the cost goes — this is
not a profile, and the slow call was never allowed to finish, so it is possible the expense lies elsewhere
inside the normalization.

Two smaller observations from the same runs:

* `integralClosure(i2, 1)` also fails to finish in 240 s, which is consistent with the above: it is the same
call as `integralClosure i2`.
* `integralClosure i` itself is instant (0.25 s), returning `ideal(b^4, a*b^3, a^2*b^2, a^3*b, a^4)`. The
difficulty appears with the squared generating set, not with the ring or the field.

### Why this is worth an issue rather than a note about expected cost

`i` is a monomial ideal in two variables whose closure is itself. Nothing about the input suggests it is
hard, a user has no way to tell an intractable call from a hung one, and the cheap route is only reachable if
you happen to know the ideal is a power *and* know that the `ZZ` argument means the exponent. A caller
holding `i2` and not its square root has no way in at all.

### Where this came from

Cataloguing the `bugs/` directory removed in d2c8d27826 (#36). `bugs/mike/1-integralClosureIdeal.m2` is a
scratch file of `integralClosure` examples; the line

```m2
integralClosure (i^2) == i^2 -- i^2 is already integrally closed
-- this line above doesn't seem to finish in small time
```

records the same observation, undated but from a file whose surrounding timings are annotated
"the timings here refer to some older version of integral closure".

`open` · disposition `issue` · source of truth: [`bug-triage/catalog.tsv`](https://github.com/d-torrance/M2/blob/bug-triage/bug-triage/catalog.tsv)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the three-argument method in M2/Macaulay2/packages/IntegralClosure.m2 around lines 873-875, then reproduce the timings for i, i^2, integralClosure(i^2), and integralClosure(i, 2) over ZZ/101[a,b]. Trace where the Rees algebra is built and determine whether the divergent cost can be addressed. Done should include a documented or tested resolution for equivalent calls.

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.