Bases of multivariate polynomials

Viviane Pons, Paris-Est Marne-la-Vallée

Sage-Days Montreal 2012


What is a multivariate polynomials in Sage ?

{{{id=1| var('x,y') POL. = QQ[x,y] POL /// Multivariate Polynomial Ring in x, y over Rational Field }}}

We obtain polynomials in x and y, we create an element:

{{{id=2| pol= x^2*y +x pol /// x^2*y + x }}}

How do we add a variable ?

{{{id=3| var('z') pol = x^2*y + x + z pol.parent() /// Symbolic Ring }}}

We are not in the polynomial ring anymore, we have to change the space...

{{{id=4| POL. = QQ[x,y,z] pol = POL(pol) pol.parent() /// Multivariate Polynomial Ring in x, y, z over Rational Field }}}

What if I don't know how many variables I need ? What if I don't want to declare all my variables ?

How to crate a polynomial ring in ANY finite number of variables ?

{{{id=11| A = AbstractPolynomialRing(QQ) A /// The abstract ring of multivariate polynomials on x over Rational Field }}} {{{id=14| A.an_element() /// x[0, 0, 0] + 2*x[1, 0, 0] + x[1, 2, 3] + 3*x[2, 0, 0] }}} {{{id=138| A.an_element().parent() /// The ring of multivariate polynomials on x over Rational Field with 3 variables on the monomial basis }}} {{{id=15| A.an_element().to_expr() /// x1*x2^2*x3^3 + 3*x1^2 + 2*x1 + 1 }}}

A polynomial is a formal sum of vectors: the monomial exponents

$x^v = x_1^{v_1} x_2^{v_2} \dots x_n^{v_n}$

where $v = (v_1,v_2, \dots, v_n) \in \mathbb{Z}^n$

Let us see how we create elements:

{{{id=16| m = A.monomial_basis() pol = m[2,1] + m[1,1,3] + m[0,2,2,4] pol /// x[1, 1, 3, 0] + x[2, 1, 0, 0] + x[0, 2, 2, 4] }}}

We used $m$, which is a basis of $A$. It is the monomial basis, we shall see other bases later.

Where is our polynomial living ?

{{{id=19| pol.parent() /// The ring of multivariate polynomials on x over Rational Field with 4 variables on the monomial basis }}}

The space contains both the basis and the number of variables. But we didn't have to specify the number of variables in advance. Plus, we can do operations on polynomials with a different number of variables.

{{{id=20| pol2 = m[2] pol2 /// x[2] }}} {{{id=21| pol2.parent() /// The ring of multivariate polynomials on x over Rational Field with 1 variable on the monomial basis }}} {{{id=22| pol + pol2 /// x[1, 1, 3, 0] + x[2, 0, 0, 0] + x[2, 1, 0, 0] + x[0, 2, 2, 4] }}} {{{id=23| (pol + pol2).parent() /// The ring of multivariate polynomials on x over Rational Field with 4 variables on the monomial basis }}}

The program choses the space with the more variables to compute.

Actions on vectors

Our main objects are the vectors, what simple operations can we do on vectors ?

$v.s_i = [v_1, \dots, v_{i+1}, v_{i}, \dots, v_n], 1 \leq i \leq n-1$

$v.s_i^B = v.s_i^C = [v_1, \dots, -v_i, \dots, v_n], 1 \leq i \leq n$

$v.s_i^D = [v_1, \dots, -v_i, - v_{i-1}, \dots, v_n], 2 \leq i \leq n$

The family $(s_1, \dots, s_{n-1})$ generates the Weyl group of type $A$ (i.e. the permutations of $(1,\dots,n)$).

The same way, $(s_1, \dots, s_{n-1}, s_n^B)$ generates the Weyl group of type $B$ or $C$ and $(s_1, \dots, s_{n-1}, s_n^D)$, the Weyl group of type $D$.

The operation define an action of these group on polynomials.

{{{id=36| pol = m[1] + m[2,1,1] + m[0,0,1] pol /// x[1, 0, 0] + x[2, 1, 1] + x[0, 0, 1] }}} {{{id=37| pol.si(1) /// x[1, 2, 1] + x[0, 1, 0] + x[0, 0, 1] }}} {{{id=139| pol.si(3) /// x[1, 0, 0, 0] + x[2, 1, 0, 1] + x[0, 0, 0, 1] }}}

We use the $s_i$ operators to define divided differences.

$$f\partial_i = \frac{f - f^{s_i}}{x_i - x_{i+1}}$$

{{{id=136| pol /// x[1, 0, 0] + x[2, 1, 1] + x[0, 0, 1] }}} {{{id=40| pol.divided_difference(1) /// x[0, 0, 0] + x[1, 1, 1] }}} {{{id=44| pol = m[5,1] pol /// x[5, 1] }}} {{{id=45| pol.divided_difference(1) /// x[1, 4] + x[2, 3] + x[3, 2] + x[4, 1] }}}

If $v_i > v_{i+1}$,

$$x^v\partial_i = \sum_{k=v_{i+1}}^{v_{i}-1} x^{[\dots, k, v_i-k,\dots]}$$

{{{id=46| pol.divided_difference(1,"C") /// x[-4, 1] + x[-2, 1] + x[2, 1] + x[4, 1] + x[0, 1] }}}

This sum can be defined directly by the Weyl group and the definition is type free.

What do we use divided differences for ?

{{{id=47| pol = m[1,4,2] pol /// x[1, 4, 2] }}} {{{id=48| pol = pol.divided_difference(1) pol /// -x[1, 3, 2] - x[2, 2, 2] - x[3, 1, 2] }}} {{{id=49| pol = pol.divided_difference(2) pol /// -x[1, 2, 2] + x[3, 1, 1] }}} {{{id=50| pol = pol.divided_difference(1) pol /// x[1, 1, 2] + x[1, 2, 1] + x[2, 1, 1] }}}

We have applied the maximal divided difference.

$[3,2,1] = s_1 s_2 s_1$

$\partial_{(321)} = \partial_1 \partial_2 \partial_1$

We obtain a symmetric function, and more precisely a Schur function.

{{{id=64| SF = SymmetricFunctions(QQ) schur = SF.schur() s = schur[2,1,1] var('x1,x2,x3') s = s.expand(3,[x1,x2,x3]) s /// x1^2*x2*x3 + x1*x2^2*x3 + x1*x2*x3^2 }}} {{{id=65| bool(s == pol.to_expr()) /// True }}}

Schur functions are fundamental in the symmetric functions theory. They are a basis of the ring of symmetric functions.

Now, how can we use divided differences to create a generalization of this basis for non symmetric polynomials.

Let us define dominant polynomials by: $x^\lambda$ with $\lambda_1 \geq \lambda_2 \geq \dots \geq \lambda_n$ and let us apply divided differences on these polynomials.

{{{id=51| dominant = m[4,2,1] Y231 = dominant.divided_difference(1) Y212 = Y231.divided_difference(2) Y112 = Y212.divided_difference(1) Y411 = dominant.divided_difference(2) Y131 = Y411.divided_difference(1) pols = [dominant, Y231, Y411, Y212, Y131, Y112] /// }}} {{{id=53| G = Graph() for pol in pols: G.add_vertex(pol) G.add_edge(pols[0], pols[1], 'd1') G.add_edge(pols[1], pols[3], 'd2') G.add_edge(pols[3], pols[5], 'd1') G.add_edge(pols[0], pols[2], 'd2') G.add_edge(pols[2], pols[4], 'd1') G.add_edge(pols[4], pols[5], 'd2') pos = {} pos[pols[0]] = (1,3) pos[pols[1]] = (0,2) pos[pols[2]] = (2,2) pos[pols[3]] = (0,1) pos[pols[4]] = (2,1) pos[pols[5]] = (1,0) G.plot(pos = pos, edge_labels=True, vertex_size = 0) /// }}}

Each polynomial of the graph is given by the dominant polynomial and a product of divided differences. This information can be coded in a signle vector, and we obtain the Schubert polynomials.

{{{id=69| Schub = A.schubert_basis_on_vectors() pols = [Schub(pol) for pol in pols] G = Graph() for pol in pols: G.add_vertex(pol) G.add_edge(pols[0], pols[1], 'd1') G.add_edge(pols[1], pols[3], 'd2') G.add_edge(pols[3], pols[5], 'd1') G.add_edge(pols[0], pols[2], 'd2') G.add_edge(pols[2], pols[4], 'd1') G.add_edge(pols[4], pols[5], 'd2') pos = {} pos[pols[0]] = (1,3) pos[pols[1]] = (0,2) pos[pols[2]] = (2,2) pos[pols[3]] = (0,1) pos[pols[4]] = (2,1) pos[pols[5]] = (1,0) G.plot(pos = pos, edge_labels=True, vertex_size = 0) /// }}}

$$Y_\lambda = x^\lambda$$

si $\lambda_1 \geq \lambda_2 \geq \dots \geq \lambda_n$. Et :

$$Y_{\dots, v_{i+1},v_{i}-1, \dots} = Y_v \partial_i$$

si $v_i > v_{i+1}$

They are a triangular basis of the multivariate polynomials.

{{{id=71| Schub = A.schubert_basis_on_vectors() Schub /// The ring of multivariate polynomials on x over Rational Field on the Schubert basis of type A (indexed by vectors) }}} {{{id=74| pol = A.an_element() pol /// x[0, 0, 0] + 2*x[1, 0, 0] + x[1, 2, 3] + 3*x[2, 0, 0] }}} {{{id=75| Schub(pol) /// Y(0, 0, 0) + 2*Y(1, 0, 0) + Y(1, 2, 3) - Y(1, 3, 2) + 3*Y(2, 0, 0) - Y(2, 1, 3) + Y(2, 3, 1) + Y(3, 1, 2) - Y(3, 2, 1) + Y(4, 1, 1) }}}

When the index vector is anti-dominant, then the corresponding Schubert polynomial is equal to a Schur function.

Other divided differences give other bases

We have defined $\partial_i$ but there are other divided differences, here are the one called isobaric:

$$f \pi_i :=\frac{x_i f - x_{i+1}f^{s_i}}{x_i - x_{i+1}} = (fx_i)\partial_i $$

$$f \hat{\pi}_i = \frac{x_{i+1}f - x_{i+1}f^{s_i}}{x_i - x_{i+1}} = (f\partial_i)x_{i+1}$$

which give new basis:

Grothendieck polynomials

{{{id=76| Groth = A.grothendieck_positive_basis_on_vectors() Groth /// The ring of multivariate polynomials on x over Rational Field on the Grothendieck basis of type A, with positive exposants (indexed by vectors) }}}

Key polynomials (or Demazure) :

{{{id=80| Dem = A.demazure_basis_on_vectors() Dem /// The ring of multivariate polynomials on x over Rational Field on the Demazure basis of type A (indexed by vectors) }}} {{{id=81| DemHat = A.demazure_hat_basis_on_vectors() DemHat /// The ring of multivariate polynomials on x over Rational Field on the Demazure hat basis of type A (indexed by vectors) }}}

These basis are also generalization of the Schur functions. They appear in numerous problems linked to geometry and representation theory.

Key polynomials also exist in type B,C or D.

{{{id=105| DemB = A.demazure_basis_on_vectors("B") DemB /// The ring of multivariate polynomials on x over Rational Field on the Demazure basis of type B (indexed by vectors) }}} {{{id=106| cleB = DemB[1,-2] cleB /// K(1, -2) }}} {{{id=107| cleB.expand() /// x(1, 0) + x(1, -2) + x(1, -1) + x(1, 1) + x(1, 2) + x(2, 0) + x(2, -1) + x(2, 1) }}}

They form a triangular basis of Laurent polynomials (i.e. allowing negative exponents).

{{{id=108| DemB(m[-2,2] + m[-1]) /// K(-2, 2) + K(-1, 0) - K(-1, 1) - K(-1, 2) + K(1, 1) - K(2, -2) + K(2, -1) - K(0, -1) + K(0, 1) }}}

The developed patch allows to work with all these bases and more : any definition that relies on divided differences can be implemented and used to define a new family.

Polynomials in two sets of variables

One can give a refined defintion of Schubert and Grothendieck polynomials in two sets of variables.

{{{id=110| D = DoubleAbstractPolynomialRing(QQ) D /// The abstract ring of multivariate polynomials on x over The abstract ring of multivariate polynomials on y over Rational Field }}} {{{id=112| D.an_element() /// y[0]*x[0, 0, 0] + 2*y[0]*x[1, 0, 0] + y[0]*x[1, 2, 3] + 3*y[0]*x[2, 0, 0] }}} {{{id=113| mx = D.monomial_basis() my = D.base_ring().monomial_basis() pol = mx[1,1,2]*my[0,1] + mx[2,2] * my[1,2,1] pol /// (y[0,1])*x[1, 1, 2] + (y[1,2,1])*x[2, 2, 0] }}} {{{id=114| pol.to_expr() /// x1^2*x2^2*y1*y2^2*y3 + x1*x2*x3^2*y2 }}}

Here is a definition od the dominant polynomials

$$Y_\lambda = \prod_{i=1}^n \prod_{j=1}^{\lambda_i} (x_i - y_j)$$

$$G_\lambda = \prod_{i=1}^n \prod_{j=1}^{\lambda_i} (1 - y_j x_i^{-1})$$

We then apply the divided differences to obtain Schubert polynomials and isobaric divided differences to obtain the Grothendieck polynomials.

The polynomials in one set of variables are obtained by specializing the variables $y$.

{{{id=116| DSchub = D.double_schubert_basis_on_vectors() DSchub /// The ring of multivariate polynomials on x over The abstract ring of multivariate polynomials on y over Rational Field on the Double Schubert basis of type A (indexed by vectors) }}} {{{id=119| dpol = DSchub[1,2] dpol /// y[0]*YY(1, 2) }}} {{{id=131| dpol.expand() /// (-y(2,1,0)-y(2,0,1))*x(0, 0) + (y(1,1,0)+y(1,0,1)+y(2,0,0))*x(1, 0) + (-2*y(1,0,0)-y(0,1,0)-y(0,0,1))*x(1, 1) + y[0]*x(1, 2) + (-y[1])*x(2, 0) + y[0]*x(2, 1) + (y(1,1,0)+y(1,0,1)+y(2,0,0))*x(0, 1) + (-y[1])*x(0, 2) }}}

Double Schubert polynomial index by increasing vector are a refinement of Schur functions and can be used to detect some properties and give a better understanding of these objetcs.

{{{id=124| dpol = DSchub[0,1,2] dpol /// y[0]*YY(0, 1, 2) }}} {{{id=135| SF = SymmetricFunctions(QQ) schur = SF.schur() var('x1,x2,x3') s = schur[2,1] s.expand(3,[x1,x2,x3]) /// x1^2*x2 + x1*x2^2 + x1^2*x3 + 2*x1*x2*x3 + x2^2*x3 + x1*x3^2 + x2*x3^2 }}} {{{id=123| dpol.expand() /// (-y(1,1,1,0)-y(1,1,0,1)-y(1,2,0,0)-y(2,1,0,0)-y(2,0,1,0)-y(2,0,0,1)-y(0,2,1,0)-y(0,2,0,1))*x(0, 0, 0) + (2*y(1,1,0,0)+y(1,0,1,0)+y(1,0,0,1)+y(2,0,0,0)+y(0,1,1,0)+y(0,1,0,1)+y(0,2,0,0))*x(1, 0, 0) + (-2*y(1,0,0,0)-2*y(0,1,0,0)-y(0,0,1,0)-y(0,0,0,1))*x(1, 1, 0) + 2*y[0]*x(1, 1, 1) + y[0]*x(1, 2, 0) + (-2*y(1,0,0,0)-2*y(0,1,0,0)-y(0,0,1,0)-y(0,0,0,1))*x(1, 0, 1) + y[0]*x(1, 0, 2) + (-y(1,0)-y(0,1))*x(2, 0, 0) + y[0]*x(2, 1, 0) + y[0]*x(2, 0, 1) + (2*y(1,1,0,0)+y(1,0,1,0)+y(1,0,0,1)+y(2,0,0,0)+y(0,1,1,0)+y(0,1,0,1)+y(0,2,0,0))*x(0, 1, 0) + (-2*y(1,0,0,0)-2*y(0,1,0,0)-y(0,0,1,0)-y(0,0,0,1))*x(0, 1, 1) + y[0]*x(0, 1, 2) + (-y(1,0)-y(0,1))*x(0, 2, 0) + y[0]*x(0, 2, 1) + (2*y(1,1,0,0)+y(1,0,1,0)+y(1,0,0,1)+y(2,0,0,0)+y(0,1,1,0)+y(0,1,0,1)+y(0,2,0,0))*x(0, 0, 1) + (-y(1,0)-y(0,1))*x(0, 0, 2) }}} {{{id=125| var('x1,x2,x3,y1,y2,y6') expr = dpol.expand().to_expr() expr /// -(y1 + y2)*x1^2 - (y1 + y2)*x2^2 - (y1 + y2)*x3^2 - (2*y1 + 2*y2 + y3 + y4)*x1*x2 - (2*y1 + 2*y2 + y3 + y4)*x1*x3 - (2*y1 + 2*y2 + y3 + y4)*x2*x3 + x1^2*x2 + x1^2*x3 + x1*x2^2 + 2*x1*x2*x3 + x1*x3^2 + x2^2*x3 + x2*x3^2 - y1^2*y2 - y1^2*y3 - y1^2*y4 - y1*y2^2 - y1*y2*y3 - y1*y2*y4 - y2^2*y3 - y2^2*y4 + (y1^2 + 2*y1*y2 + y1*y3 + y1*y4 + y2^2 + y2*y3 + y2*y4)*x1 + (y1^2 + 2*y1*y2 + y1*y3 + y1*y4 + y2^2 + y2*y3 + y2*y4)*x2 + (y1^2 + 2*y1*y2 + y1*y3 + y1*y4 + y2^2 + y2*y3 + y2*y4)*x3 }}} {{{id=127| expr2 = expr.subs(x1=y1).subs(x2=y2).subs(x3=y6) /// }}} {{{id=128| expr2 /// -(y1 + y2)*y1^2 - (y1 + y2)*y2^2 - (y1 + y2)*y6^2 - (2*y1 + 2*y2 + y3 + y4)*y1*y2 - (2*y1 + 2*y2 + y3 + y4)*y1*y6 - (2*y1 + 2*y2 + y3 + y4)*y2*y6 - y1^2*y3 - y1^2*y4 + y1^2*y6 - y1*y2*y3 - y1*y2*y4 + 2*y1*y2*y6 + y1*y6^2 - y2^2*y3 - y2^2*y4 + y2^2*y6 + y2*y6^2 + (y1^2 + 2*y1*y2 + y1*y3 + y1*y4 + y2^2 + y2*y3 + y2*y4)*y1 + (y1^2 + 2*y1*y2 + y1*y3 + y1*y4 + y2^2 + y2*y3 + y2*y4)*y2 + (y1^2 + 2*y1*y2 + y1*y3 + y1*y4 + y2^2 + y2*y3 + y2*y4)*y6 }}} {{{id=129| expr2.expand() /// 0 }}}

{{{id=137| show(dpol) ///
\newcommand{\Bold}[1]{\mathbf{#1}}B_{0}B_{e_{1} + 2e_{2}}
}}} {{{id=140| /// }}}