<?xml version="1.0" encoding="utf-8" standalone="no"?><?xml-stylesheet href="/mathmlc2p.xsl" type="text/xsl"?><html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>staggered_linear_basis</title>
</head>
<body>
<tt>
# implementation of the Staggered Linear Basis Algorithm of Gebauer and M\&quot;oller<br/>
# &quot;Buchberger's algorithm and Staggered Linear Bases&quot;<br/>
# in Proceedings of SYMSAC 1986 (Waterloo/Ontario), pages 218--221<br/>
# ACM Press, 1986<br/>
<br/>
# Originally from <a href="http://www.math.usm.edu/perry/Research/staggered_linear_basis.py">http://www.math.usm.edu/perry/Research/staggered_linear_basis.py</a><br/>
# small changes for JAS compatibility, changes are labled with JAS<br/>
# $Id: staggered_linear_basis.py 4986 2014-11-17 23:03:07Z kredel $<br/>
<br/>
# usage: staglinbasis(F) where F is a list of polynomials<br/>
# result: groebner basis of F<br/>
# example:<br/>
#   sage: R = PolynomialRing(GF(32003),x,5)<br/>
#   sage: I = sage.rings.ideal.Cyclic(R,5).homogenize()<br/>
#   sage: F = list(I.gens())<br/>
#   sage: B = staglinbasis(F)<br/>
#   &gt;&gt; reduction to zero: (9, 12, x1*x2*x3^3*x4^2) x2<br/>
#   &gt;&gt; reduction to zero: (7, 12, x1*x2*x3^3*x4^2) x2<br/>
#   &gt;&gt; reduction to zero: (5, 12, x1^2*x3^3*x4^2) x1<br/>
#   ... [more omitted]<br/>
#   &gt;&gt; 32 reductions to zero<br/>
#   sage: len(B)<br/>
#   &gt;&gt; 42<br/>
<br/>
# minimal_pair<br/>
# used to select a minimal critical pair from a list;<br/>
# form of the list is (i,j,t) where t=lcm(lt(g[i]),lt(g[j]));<br/>
# chosen by smallest lcm<br/>
# inputs: list of pairs P<br/>
# outputs: minimal pair in P<br/>
def minimal_pair(P):<br/>
  result = P.pop()<br/>
  P.add(result)<br/>
  for p in P:<br/>
    if p[2] &lt; result[2]:<br/>
      result = p<br/>
  return result<br/>
<br/>
# spol<br/>
# compute the s-polynomial corresponding to the critical pair p<br/>
# inputs: critical pair p, basis G<br/>
# outputs: s-polynomial<br/>
def spol(p,G):<br/>
  i,j,tij = p<br/>
  R = G[i].parent() # JAS<br/>
  ti = R.monomial_quotient(tij,G[i].lm())<br/>
  tj = R.monomial_quotient(tij,G[j].lm())<br/>
  return ti*G[i] - tj*G[j]<br/>
<br/>
# monid_quotient<br/>
# computes the quotient I:J of the monomial ideals I and J<br/>
# for each tI in I, and for each tJ in J, it computes lcm(tI,tJ)/tJ<br/>
# this corresponds to computing the u's such that uv is in I for each v in J<br/>
# note that the ideals must be simplified for this to work correctly<br/>
# (see below)<br/>
# inputs: lists of monomials I and J (generators of ideals)<br/>
# outputs: list of monomials that generate I:J<br/>
def monid_quotient(I,J,R): # JAS<br/>
  result = set()<br/>
  for tI in I:<br/>
    # R = tI.parent() #JAS<br/>
    for tJ in J:<br/>
      u = R.monomial_quotient(tI.lcm(tJ),tJ).lm() # JAS<br/>
      if not any(R.monomial_divides(t,u) for t in result):<br/>
        result.add(u)<br/>
  return result<br/>
<br/>
# monid_add<br/>
# expands the monomial ideal I by the monomial t<br/>
# simplifies the result<br/>
# inputs: list of monomials I (generators of ideal), monomial t<br/>
# outputs: simplified I+(t)<br/>
def monid_add(I,t):<br/>
  result = set()<br/>
  R = t.parent()<br/>
  for u in I:<br/>
    if not(R.monomial_divides(t,u)) and not(R.monomial_divides(u,t)):<br/>
      result.add(u)<br/>
  if not any(R.monomial_divides(u,t) for u in result):<br/>
    result.add(t)<br/>
  return result<br/>
<br/>
# simplify_monid<br/>
# simplifies the list of generators of the monomial ideal I<br/>
# by pruning redundant elements<br/>
# inputs: list of monomials I (generators of ideal)<br/>
# outputs: simplified I<br/>
def simplify_monid(I,R): # JAS<br/>
  result = set()<br/>
  for t in I:<br/>
    #R = t.parent() #JAS<br/>
    if not any(u != t and R.monomial_divides(u,t) for u in I):<br/>
      result.add(t)<br/>
  return result<br/>
<br/>
# staglinbasis<br/>
# computes the Groebner Basis of a polynomial ideal using the<br/>
# Staggered Linear Basis algorithm of Gebauer-Moeller<br/>
# inputs: list of polynomials F<br/>
# outputs: Groebner basis of F<br/>
def staglinbasis(F):<br/>
  # tracks the number of zero reductions<br/>
  num_zrs = 0<br/>
  # get polynomial ring<br/>
  R = F[0].parent()<br/>
  G = list(F) # JAS<br/>
  m = len(G)<br/>
  # Z is the set of monomial used to detect principal syzygies<br/>
  # in general, Z should be simplified anytime you modify it<br/>
  Z = [set([G[j].lm() for j in xrange(i)]) for i in xrange(m)]<br/>
  Z = [simplify_monid(ZI,R) for ZI in Z] # JAS<br/>
  # initial set of critical pairs<br/>
  P = set()<br/>
  for i in xrange(m-1):<br/>
    for j in xrange(i+1,m):<br/>
      tij = G[i].lm().lcm(G[j].lm())<br/>
      tj = R.monomial_quotient(tij,G[j].lm()) # JAS<br/>
      if not any(R.monomial_divides(t,tj) for t in Z[j]):<br/>
        P.add((i,j,tij))<br/>
  # main loop<br/>
  while len(P) != 0:<br/>
    # choose the pair w/smallest lcm<br/>
    p = minimal_pair(P)<br/>
    P.remove(p)<br/>
    # compute S-polynomial, reduce it<br/>
    s = spol(p,G)<br/>
    i,j,tij = p<br/>
    r = s.reduce(G)<br/>
    if r == 0:<br/>
      print &quot;reduction to zero:&quot;, p, R.monomial_quotient(tij,G[j].lm())<br/>
      num_zrs += 1<br/>
    else:<br/>
      # new polynomial; add to basis<br/>
      r = r.monic() # JAS #r *= r.lc()**(-1)<br/>
      G.append(r)<br/>
      # update ideals here, also below<br/>
      # need new ideal for G[-1]=r, essentially<br/>
      #   Znew = (Z[j] + t[i])):(lcm(t[i],t[j])/t[j]) + (t[1], ..., t[m])<br/>
      # where t[i] = lm(g[i])<br/>
      Znew = Z[j].copy() # JAS<br/>
      Znew.update([G[i].lm()])<br/>
      Znew = simplify_monid(Znew,R) #JAS<br/>
      tj = R.monomial_quotient(tij,G[j].lm()).lm() # JAS<br/>
      Znew = monid_quotient(Znew,[tj],R) # JAS<br/>
      Znew.update([g.lm() for g in G[:-1]])<br/>
      Znew = simplify_monid(Znew,R)<br/>
      Z.append(Znew)<br/>
      # compute new critical pairs w/new polynomial<br/>
      m = len(G) - 1<br/>
      for i in xrange(m):<br/>
        tim = G[i].lm().lcm(G[m].lm())<br/>
        tm = R.monomial_quotient(tim,G[m].lm())<br/>
        # don't add pairs detected by Z[m]<br/>
        if not any(R.monomial_divides(t,tm) for t in Z[m]):<br/>
          P.add((i,m,tim))<br/>
      # update Z[j]<br/>
      Z[j].add(R.monomial_quotient(tij,G[j].lm()).lm()) # JAS<br/>
      Z[j] = simplify_monid(Z[j],R) # JAS<br/>
      # prune pairs detected by new Z[j]<br/>
      Q = set()<br/>
      for (i,j,tij) in P:<br/>
        tj = R.monomial_quotient(tij,G[j].lm())<br/>
        if any(R.monomial_divides(t,tj) for t in Z[j]):<br/>
          Q.add((i,j,tij))<br/>
      P.difference_update(Q)<br/>
  print num_zrs, &quot;reductions to zero&quot;<br/>
  return G<br/>
</tt>
</body>
</html>
