# Toric Ideal of Point Configuration Yielding Whole Ring?

So I am trying to find the toric ideal of a point configuration given by the lattice points contained within a family of polytopes I am studying to assess regularity/unimodularity of triangulations of the point configuration (I'm attempting to follow the guidelines specified in Bernd Sturmfels' text Grobner Bases and Convex Polytopes). I know that toric ideals are supposed to be prime and their reduced Grobner bases are generated by binomials, but for whatever reason, the ToricIdeal() sage function is indicating that the corresponding ideal is the entire ring, which should definitely not be the case.

For example, say that we're looking at the point configuration given by the lattice points (1,0), (0,1), (0,0), (0,-1), (-1,-1), (-1,-2), (-2,-3). Inputting these points as columns in a matrix and computing the toric ideal as indicated in the sage documentation should be as simple as:

A = matrix([[1,0,0,0,-1,-1,-2],[0,1,0,-1,-1,-2,-3]])
IA = ToricIdeal(A); IA


However, when I run this I get the following output:

Ideal (1) of Multivariate Polynomial Ring in z0, z1, z2, z3, z4, z5, z6 over Rational Field


I cannot determine why this is the case. For some context, I asked a colleague to compute the toric ideal using Macaulay2, and that program indicated that the toric ideal is generated by z2 - 1, z1*z3 - 1, z0*z1*z4 - 1, z0*z1^2*z5 - 1, z0^2*z1^3*z6 - 1, z0^4*z1^7*z2*z3*z4*z5*z6 - 1 which seems far more reasonable. Any idea if my input is incorrect or misguided? I'm having a similar issue on another project when attempting to compute toric ideals of point configurations comprised of the vertices of order polytopes. Without the correct toric ideal, I cannot compute a corresponding Grobner basis to assess regularity or unimodularity. Any help is greatly appreciated. Thank you.

edit retag close merge delete

with the notation of the answer by @rburing, you probably need

sage: IA._naive_ideal(IA.ring()).groebner_basis()
[z0*z1*z6 - z5, z1*z3 - 1, z3^2 - z0*z5, z0*z4 - z3, z3*z4 - z5, z4^2 - z1*z6, z1*z5 - z4, z3*z5 - z0*z6, z4*z5 - z6, z5^2 - z3*z6, z2 - 1]


the difference with the Macaulay2 answer is probably due to a different monomial order used. (In Sage computation it's the default order used).

Unfortunately our Macaulay2 insterface is brokek atm: https://doc.sagemath.org/html/en/refe...

( 2020-06-09 12:54:24 +0200 )edit
( 2020-06-09 13:38:43 +0200 )edit

Thank you so much!

( 2020-06-09 17:13:11 +0200 )edit

Sort by » oldest newest most voted

In the terms used by the documentation on Toric ideals, it seems that you want the "naive ideal".

This is implemented (but hidden):

sage: IA._naive_ideal(IA.ring())
Ideal (-z2 + 1, -z1*z3 + 1, -z0*z1*z4 + 1, -z1*z5 + z4, z4*z5 - z6) of Multivariate Polynomial Ring in z0, z1, z2, z3, z4, z5, z6 over Rational Field


This is the same as the ideal obtained by your colleague:

sage: IA.ring().inject_variables()
sage: IA._naive_ideal(IA.ring()) == IA.ring().ideal(z2 - 1, z1*z3 - 1, z0*z1*z4 - 1, z0*z1^2*z5 - 1, z0^2*z1^3*z6 - 1, z0^4*z1^7*z2*z3*z4*z5*z6 - 1)
True


According to the source code, the (non-naive) toric ideal is computed from the naive one as follows:

ring = self._init_ring('neglex')
J = self._naive_ideal(ring)
if J.is_zero():
return J
for i in range(0,self.nvariables()):
J = self._ideal_quotient_by_variable(ring, J, i)
return J


where _ideal_quotient_by_variable computes $(J:x_i^\infty)$.

I'm not an expert on toric ideals so I cannot judge who is naive here. Maybe it is a matter of conventions?

more

That 'neglex' order (a local order, not a proper Groebner basis order) looks out of place there. Without it, the saturations of the naive ideal with x_i are already done, so the answer shoud be the same as the naive ideal.

( 2020-06-09 12:33:47 +0200 )edit

Awesome, thank you so much! I think this will work well for my purposes. Greatly appreciate it!

( 2020-06-09 17:15:15 +0200 )edit

Not sure if this is useful for anyone, but I wrote another implementation that obtains the appropriate naive ideal using the basis for kernel of the point configuration matrix. The answer is the same as _naive_ideal() method.

from sage.rings.polynomial.polydict import ETuple
R = PolynomialRing(QQ, 'z', 7, order='invlex')
z = R.gens()
IA = ToricIdeal([[1,0,0,0,-1,-1,-2],[0,1,0,-1,-1,-2,-3]])
A = IA.A()
V = A.right_kernel();B = V.basis_matrix()
gens = []
for i in range(B.nrows()):
u = ETuple(list(B[i]));other = ETuple([0]*len(u))
uplus = tuple(u.combine_to_positives(other)[1])
uminus = tuple(u.combine_to_positives(other)[2])
gens.append(R.monomial(*uplus) - R.monomial(*uminus))
I = ideal(gens)
GB = I.groebner_basis()

( 2020-06-09 17:52:17 +0200 )edit
2

The naive ideal is not in general enough. See for example the comment about the twisted cubic in the documentation, so in general it is necessary to saturate.

( 2020-06-09 19:24:39 +0200 )edit

I believe I have some more insight as to why this issue was happening. Since I want to consider toric ideals in the context of a lattice polytope $P$, my point configuration matrix should have had a row of $1$'s appended to the bottom since I'm really looking at the polytope embedded at height $1$ in the cone over $P$ (${\rm cone}(P)$). I was operating in the wrong dimension! Generating the whole ring makes sense with the setup in my original problem statement since two of the lattice points are the standard basis vectors. I made this realization because the ideal should be homogenenous as the polytope given as the convex hull of those $7$ points is IDP but several of the generators contained a constant term. So, I should have had something more along the lines of

R = PolynomialRing(QQ, 'z', 7, order='lex')
z = R.gens()
IA = ToricIdeal([[1,0,0,0,-1,-1,-2],[0,1,0,-1,-1,-2,-3],[1,1,1,1,1,1,1]],polynomial_ring=R)

more