Examples

This section contains computations for various examples from this preprint. To follow along, first run the following (in a Sage shell):

>>> import grobnercrystals as gcs

Example 1.5 (Double Bruhat Ideals)

First, we define our polynomial ring R and ideal I.

>>> R = gcs.PolRing(4,4)
>>> gens = [R.Z[0,0],R.Z[[0,1,2],[0,1,2]].determinant(),R.Z[[1,2,3],[1,2,3]].determinant(),R.Z[3,3]]
>>> gens
[z11, -z13*z22*z31 + z12*z23*z31 + z13*z21*z32 - z11*z23*z32 - z12*z21*z33 + z11*z22*z33, -z24*z33*z42 + z23*z34*z42 + z24*z32*z43 - z22*z34*z43 - z23*z32*z44 + z22*z33*z44, z44]
>>> I = gcs.BIdeal(gens,R)

We can check that I is stable under \((GL_1\times GL_2\times GL_1)\times (GL_1\times GL_2\times GL_1)\) by running the following commands. L denotes the Levi datum associated to this group, defined in Section 2.

>>> L = [[0,1,3,4],[0,1,3,4]]
>>> gcs.check_action(I,L)
True

To compute the Hilbert series of \(R/I\) (or, equivalently, the character) up to degree 2, run:

>>> hilb = I.hilb_exp(2)

hilb is a grobnercrystals.SplitPoly object. The Hilbert series is stored in hilb.poly:

>>> hilb.poly
x2*y1 + x3*y1 + x4*y1 + x1*y2 + x2*y2 + x3*y2 + x4*y2 + x1*y3 + x2*y3 + x3*y3 + x4*y3 + x1*y4 + x2*y4 + x3*y4 + 1

To find the split-Schur expansion of hilb, we can run:

>>> hilb.expand(x='s',y='s',I=L[0],J=L[1])
'1*s[0]s[1, 0]s[0]s[1]s[0, 0]s[0] + 1*s[0]s[0, 0]s[1]s[1]s[0, 0]s[0] + 1*s[1]s[0, 0]s[0]s[0]s[1, 0]s[0] + 1*s[0]s[1, 0]s[0]s[0]s[1, 0]s[0] + 1*s[0]s[0, 0]s[1]s[0]s[1, 0]s[0] + 1*s[1]s[0, 0]s[0]s[0]s[0, 0]s[1] + 1*s[0]s[1, 0]s[0]s[0]s[0, 0]s[1] + 1*s[0]s[0, 0]s[0]s[0]s[0, 0]s[0]'

Example 2.1 (Crystal operators)

First, we need to import numpy.

>>> import numpy as np

Define the numpy matrix M by:

>>> M = np.matrix([[1,1,2],[2,3,1]])
>>> M
matrix([[1, 1, 2],
        [2, 3, 1]])

To see the result of applying the row lowering operator \(f_1^{row}\) to \(M\), run:

>>> gcs.f(M,1,'r')
matrix([[0, 1, 2],
        [3, 3, 1]])

Note that gcs.f() does not modify M:

>>> M
matrix([[1, 1, 2],
        [2, 3, 1]])

To see the result of applying the column raising operator \(e_2^{col}\) to \(M\), run:

>>> gcs.e(M,2,'c')
matrix([[1, 1, 2],
        [2, 4, 0]])

If the output of a crystal operator is the empty symbol, gcs.e() and gcs.f() return None:

>>> A = np.matrix([[0,1],[1,0]])
>>> A
matrix([[0, 1],
        [1, 0]])
>>> type(gcs.f(A,1,'r'))
<class 'NoneType'>

Example 2.9 (Another non-bicrystalline ideal)

First, define I and R.

>>> R = gcs.PolRing(4,4)
>>> gens = [R.Z[0,0],R.Z[[0,1,2],[0,1,2]].determinant(),R.Z[[1,2,3],[0,1,2]].determinant(),R.Z[3,0]]
>>> gens
[z11, -z13*z22*z31 + z12*z23*z31 + z13*z21*z32 - z11*z23*z32 - z12*z21*z33 + z11*z22*z33, -z23*z32*z41 + z22*z33*z41 + z23*z31*z42 - z21*z33*z42 - z22*z31*z43 + z21*z32*z43, z41]
>>> I = gcs.BIdeal(gens,R)

We can check that I carries a \((GL_1\times GL_2\times GL_1)\times (GL_1\times GL_2\times GL_1)\) action by running:

>>> L = [[0,1,3,4],[0,1,3,4]]
>>> gcs.check_action(I,L)
True

To check whether I is bicrystalline under any term order, run:

>>> I.bicrystalline(L[0],L[1])
False

Running

>>> I.bicrystalline(L[0],L[1],detailed_output=True)

will print counterexamples for each initial ideal.

Example 3.8 (Test set algorithm)

First, define I and R:

>>> R = gcs.PolRing(2,3)
>>> gens = [R.Z[0,2]^2,R.Z[0,2]*R.Z[1,2],R.Z[1,2]^2]
>>> gens
[z13^2, z13*z23, z23^2]
>>> I = gcs.BIdeal(gens,R)

We can compute a test set for \(e_1^{row}\) and graded reverse lexicographic order (‘GRevLex’ in Macaulay2) by running:

>>> M = I.test_set(['e',1,'r'])
>>> len(M)
196

To specify a different term order, for instance, Macaulay2’s ‘Lex’ term order, we could run:

>>> M1 = I.test_set(['e',1,'r'],to='Lex')

In this case, the initial ideals under ‘Lex’ and ‘GRevLex’ are the same, so the test sets are also the same:

>>> len(M1)
196

To compute a minimal test set for \(e_1^{row}\), we can run:

>>> M2 = I.min_test_set(['e',1,'r'])
>>> len(M2)
11

Example 5.9 (Nilpotent matrix Hessenberg variety)

First, define I and R:

>>> R = gcs.PolRing(4,2)
>>> M = matrix([[0,R.Z[0,0],R.Z[0,1]],[0,R.Z[1,0],R.Z[1,1]],[0,R.Z[2,0],R.Z[2,1]],[R.Z[0,0],R.Z[3,0],R.Z[3,1]]])
>>> M
[  0 z11 z12]
[  0 z21 z22]
[  0 z31 z32]
[z11 z41 z42]
>>> gens = gcs.minors(M,3)
>>> gens
[0, -z11*z12*z21 + z11^2*z22, -z11*z12*z31 + z11^2*z32, -z11*z22*z31 + z11*z21*z32]
>>> gens = gens[1:]
>>> gens
[-z11*z12*z21 + z11^2*z22, -z11*z12*z31 + z11^2*z32, -z11*z22*z31 + z11*z21*z32]
>>> I = gcs.BIdeal(gens,R)

We can check that I is stable under the action of \((GL_1\times GL_2\times GL_1)\times (GL_1\times GL_1)\):

>>> L = [[0,1,3,4],[0,1,2]]
>>> gcs.check_action(I,L)
True

The lead terms of the initial ideal of I under ‘GRevLex’ are:

>>> I.gb_lts()
[z11*z22*z31, z11*z12*z31, z11*z12*z21]

We can verify that I is indeed bicrystalline under ‘GRevLex’:

>>> I.bicrystalline(L[0],L[1],use_to='GRevLex')
True

Under ‘Lex’ order, the lead terms of the initial ideal are:

>>> I.gb_lts(to='Lex')
[z11*z21*z32, z11^2*z32, z11^2*z22]

We can verify that I is not bicrystalline under ‘Lex’:

>>> I.bicrystalline(L[0],L[1],use_to='Lex')
False
>>> I.bicrystalline(L[0],L[1],use_to='Lex',detailed_output=True)
Checking initial ideal  [array([[1, 0],
       [1, 0],
       [0, 1],
       [0, 0]]), array([[2, 0],
       [0, 0],
       [0, 1],
       [0, 0]]), array([[2, 0],
       [0, 1],
       [0, 0],
       [0, 0]])]
largest degree for rows: 2
largest degree for cols: 0
Checking degree: 0
Not bicrystalline (row raising operator 2):
[[1 0]
 [1 0]
 [0 1]
 [0 0]]
[[1 0]
 [1 1]
 [0 0]
 [0 0]]
Ideal is not bicrystalline for this term order: Lex
False

Example 6.20 (matrix matroid ideal, continued)

First, define I and R:

>>> R = gcs.PolRing(2,6)
>>> gens = gcs.minors(R.Z[[0,1],[0,1,2]],2) + gcs.minors(R.Z[[0,1],[3,4]],2) + gcs.minors(R.Z[[0,1],[5]],1)
>>> gens
>>> [-z12*z21 + z11*z22, -z13*z21 + z11*z23, -z13*z22 + z12*z23,-z15*z24 + z14*z25, z16, z26]
>>> I = gcs.BIdeal(gens,R)

We can see the first few terms in the character by running:

>>> L = [[0,2],[0,1,2,3,4,5,6]]
>>> hilb = I.hilb_exp(3)
>>> hilb.expand(x='s',y='s',I=L[0],J=L[1])
'1*s[2, 0]s[2]s[0]s[0]s[0]s[0]s[0] + 1*s[2, 0]s[1]s[1]s[0]s[0]s[0]s[0] + 1*s[2, 0]s[1]s[0]s[1]s[0]s[0]s[0] + 1*s[2, 0]s[1]s[0]s[0]s[1]s[0]s[0] + 1*s[2, 0]s[1]s[0]s[0]s[0]s[1]s[0] + 1*s[2, 0]s[0]s[2]s[0]s[0]s[0]s[0] + 1*s[2, 0]s[0]s[1]s[1]s[0]s[0]s[0] + 1*s[2, 0]s[0]s[1]s[0]s[1]s[0]s[0] + 1*s[2, 0]s[0]s[1]s[0]s[0]s[1]s[0] + 1*s[2, 0]s[0]s[0]s[2]s[0]s[0]s[0] + 1*s[1, 1]s[1]s[0]s[0]s[1]s[0]s[0] + 1*s[1, 1]s[1]s[0]s[0]s[0]s[1]s[0] + 1*s[1, 1]s[0]s[1]s[0]s[1]s[0]s[0] + 1*s[2, 0]s[0]s[0]s[1]s[1]s[0]s[0] + 1*s[1, 1]s[0]s[1]s[0]s[0]s[1]s[0] + 1*s[1, 1]s[0]s[0]s[1]s[1]s[0]s[0] + 1*s[2, 0]s[0]s[0]s[1]s[0]s[1]s[0] + 1*s[2, 0]s[0]s[0]s[0]s[2]s[0]s[0] + 1*s[1, 1]s[0]s[0]s[1]s[0]s[1]s[0] + 1*s[2, 0]s[0]s[0]s[0]s[1]s[1]s[0] + 1*s[2, 0]s[0]s[0]s[0]s[0]s[2]s[0] + 1*s[1, 0]s[1]s[0]s[0]s[0]s[0]s[0] + 1*s[1, 0]s[0]s[1]s[0]s[0]s[0]s[0] + 1*s[1, 0]s[0]s[0]s[1]s[0]s[0]s[0] + 1*s[1, 0]s[0]s[0]s[0]s[1]s[0]s[0] + 1*s[1, 0]s[0]s[0]s[0]s[0]s[1]s[0] + 1*s[0, 0]s[0]s[0]s[0]s[0]s[0]s[0]'

We could get the same expansion in a slightly more readable form by specifying that the ‘y’ variables may be left as monomials:

>>> hilb.expand(x='s',y='m',I=L[0],J=L[1])
'1*s[2, 0]m[2, 0, 0, 0, 0, 0] + 1*s[2, 0]m[1, 1, 0, 0, 0, 0] + 1*s[2, 0]m[1, 0, 1, 0, 0, 0] + 1*s[2, 0]m[1, 0, 0, 1, 0, 0] + 1*s[2, 0]m[1, 0, 0, 0, 1, 0] + 1*s[2, 0]m[0, 2, 0, 0, 0, 0] + 1*s[2, 0]m[0, 1, 1, 0, 0, 0] + 1*s[2, 0]m[0, 1, 0, 1, 0, 0] + 1*s[2, 0]m[0, 1, 0, 0, 1, 0] + 1*s[2, 0]m[0, 0, 2, 0, 0, 0] + 1*s[1, 1]m[1, 0, 0, 1, 0, 0] + 1*s[1, 1]m[1, 0, 0, 0, 1, 0] + 1*s[1, 1]m[0, 1, 0, 1, 0, 0] + 1*s[2, 0]m[0, 0, 1, 1, 0, 0] + 1*s[1, 1]m[0, 1, 0, 0, 1, 0] + 1*s[1, 1]m[0, 0, 1, 1, 0, 0] + 1*s[2, 0]m[0, 0, 1, 0, 1, 0] + 1*s[2, 0]m[0, 0, 0, 2, 0, 0] + 1*s[1, 1]m[0, 0, 1, 0, 1, 0] + 1*s[2, 0]m[0, 0, 0, 1, 1, 0] + 1*s[2, 0]m[0, 0, 0, 0, 2, 0] + 1*s[1, 0]m[1, 0, 0, 0, 0, 0] + 1*s[1, 0]m[0, 1, 0, 0, 0, 0] + 1*s[1, 0]m[0, 0, 1, 0, 0, 0] + 1*s[1, 0]m[0, 0, 0, 1, 0, 0] + 1*s[1, 0]m[0, 0, 0, 0, 1, 0] + 1*s[0, 0]m[0, 0, 0, 0, 0, 0, 0, 0]'

Here, for instance, m[2,0,0,0,0,0] refers to the monomial \(y_1^2\).

We can see the non-standard monomials of I under ‘GRevLex’ by running:

>>> N = I.nstd_mons(2)
>>> N
[z11*z16, z12*z16, z13*z16, z14*z16, z15*z16, z16^2, z16*z21, z16*z22, z16*z23, z16*z24, z16*z25, z16*z26, z12*z21, z13*z21, z13*z22, z15*z24, z11*z26, z12*z26, z13*z26, z14*z26, z15*z26, z21*z26, z22*z26, z23*z26, z24*z26, z25*z26, z26^2]

We can also get the non-standard monomials of I as numpy arrays.

>>> NMat = I.nstd_mons_mats(4)
>>> NMat[0]
>>> array([[3, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0]])

We can use Sage’s RSK function to see that, for instance:

>>> [P,Q] = RSK(NMat[0].transpose())
>>> P
[[1, 1, 1, 1]]
>>> Q
[[1, 1, 1, 6]]

Since Q contains a 6, it violates condition (I) in this example.

Note

Sage’s conventions for RSK differ from our conventions. For a matrix M, if you run

>>> [P,Q] = RSK(M)

in Sage, P is what we would call in our notation the \(Q\) tableau. This is why, in the example above, we took the transpose of NMat[0] before applying RSK.