Symmetric Polynomials  V3.1
A C++ library for generating symmetric polynomials with relations
How to Use

Quick Demonstration

For a quick demonstration you may use the binaries found here. These are compiled from Demo.cpp using MSVC (Windows) and GCC (Linux). You can also compile these binaries yourself: For example, on Linux and from within the source folder use:

g++ Demo.cpp -std=c++17 -O3 -fopenmp -march=native -o Lin64.out 

Only the -std=c++17 flag is required; the other flags are for optimization.

Code examples

Namespaces

Everything in this library is under the namespace symmp (short for Symmetric Polynomials). The code examples that follow will assume we are using this namespace.
So start with:

using symmp;

Polynomials

To specify a polynomial ring such as \(\mathbf Z[x_1,...,x_n]\), \(|x_i|=1\), we use two template parameters:

  • The scalar type corresponding to the base ring. In our example, \(\mathbf Z\) can be represented by int64_t.
  • The "type of variables" used. In our example, we use StandardVariables which specify variables in degree \(1\), with names x_i (when printed to an output stream) and no relations. We shall explain alternatives in the next few subsections.

The zero element of \(\mathbf Z[x_1,...,x_n]\) can then be constructed by:

Poly<int, StandardVariables<>> p;

A nonzero monomial \(cx_1^{a_1}\cdots x_n^{a_n}\) is constructed by providing the exponent vector \([a_1,...,a_n]\) and the coefficient \(c\neq 0\).
For example,

p=Poly<int, StandardVariables<>>({0,1,4},7);

sets \(p=7x_2x_3^4\). Similarly,

auto t=Poly<int, StandardVariables<>>({1,1,2},-8);

sets \(t=-8x_1x_2x_3^2\).

Polynomials can be combined via the usual operators +,-,*; they can be raised to a nonnegative integer powers by ^.
For example:

p+=t;

sets \(p=-8x_1x_2x_3^2+7x_2x_3^4\) which can be verified by printing \(p\) to the console:

std::cout << p << "\n";

After that:

std::cout << (p+(p^2))<< "\n";

will print

$$-8x_1x_2x_3^2 + 7x_2x_3^4 + 64x_1^2x_2^2x_3^4 - 112x_1x_2^2x_3^6 + 49x_2^2x_3^8$$

which is exactly \(p+p^2\).

Attention
It is the user's responsibility to ensure that:
  • the polynomials being combined have the same number of variables.
  • the polynomial constructor is never used with \(0\) scalar coefficient (the \(0\) monomial is stored as the empty polynomial)

Symmetric Basis

We can substitute StandardVariables with ElementarySymmetricVariables which specify variables with names e_i, degrees \(|e_i|=i\) and no relations.

Example: The element \(q=-1.5e_1e_2\) of the graded ring \(\mathbf R[e_1,...,e_n], |e_i|=i\), can be defined as:

Poly<double, ElementarySymmetricVariables<>> q({ 2,3 }, -1.5);

For brevity let us use the following two typedefs:

typedef Poly<double, StandardVariables<>> x_poly_t;
typedef Poly<double, ElementarySymmetricVariables<>> e_poly_t;

Now we view

\[\mathbf R[e_1,...,e_n]=\mathbf R[x_1,...,x_n]^{\Sigma_n}\]

with \(e_i=\sigma_i\) being the elementary symmetric polynomials on the \(x_i\). To convert \(q\) from \(e_i\) variables to \(x_i\) variables we use the class SymmetricBasis :

SymmetricBasis<x_poly_t, e_poly_t> SB(2);

The 2 signifies that we are using two variables \(x_1,x_2\). Then:

auto qx=SB(q);
std::cout << qx;

will set the polynomial x_poly_t qx to be q transformed into the \(x_i\) variables (StandardVariables) and print

\[-1.5x_1^3x_2^5 -3x_1^4x_2^4 -1.5x_1^5x_2^3\]

We can perform the conversion the other way as well: given a polynomial on the \(x_i\) variables such as qx we can use the object same SB to transform qx into a polynomial on the \(e_i\) variables :

auto qe=SB(qx);
std::cout << qe;

which will print \(-1.5e_1e_2\).

Note
The two conversion maps are inverses i.e. q==qe evaluates to 1.

Twisted Chern Basis

We can generate

\[(\mathbf Z[x_1,...,x_n,y_1,...,y_n]/y_i^2=y_i)^{\Sigma_n}\]

by the \(\alpha_i, c_i, \gamma_{s,t}\) (see The Math).

The class TwistedChernBasis allows us to transform polynomials on \(x_i,y_i\) variables (HalfIdempotentVariables) into polynomials on the \(\alpha_i,c_i,\gamma_{s,i}\) (TwistedChernVariables).

Example:

typedef Poly<int, HalfIdempotentVariables<>> xy_poly_t;
typedef Poly<int, TwistedChernVariables<>>> chern_poly_t;
xy_poly_t r;
r.insert({ 1,0,1,0 }, 2);
r.insert({ 0,1,0,1 }, 2);
TwistedChernBasis<xy_poly_t, chern_poly_t> TCB(2);
std::cout << TCB(r) << "\n";

This sets r to be \(2x_1y_1+2x_2y_2\), transforms it into \(\gamma_{s,j}\) variables and prints the result:

\[-2\gamma_{1,1}+2\alpha_1 c_1\]

And indeed:

\[2x_1y_1+2x_2y_2=-2\gamma_{1,1}+2\alpha_1 c_1\]

If we perform the transformation again we get the original polynomial:

std::cout << TCB(TCB(r)) << "\n";

prints \(2x_1y_1+2x_2y_2\).

Attention
The argument 2 in the constructor of TCB is half the number of variables \(x_1,x_2,y_1,y_2\).

To print the relations amongst \(\alpha_i,c_i,\gamma_{s,j}\) use:

print_half_idempotent_relations<xy_poly_t, chern_poly_t>(3);

The \(3\) here corresponds to the half the number of variables: \(x_1,x_2,x_3,y_1,y_2,y_3\) and can be replaced by any positive integer.

Finally, Demo.cpp contains another function, pontryagin_via_chern. This prints the expressions of the twisted Pontryagin/symplectic classes:

\[\pi_{s,t}=\kappa_{s,t}=\sum_{1\le i_1< \cdots< i_s\le n\\ 1\le j_1< \cdots< j_t\le n\\ i_u\neq j_v}x^2_{i_1}....x^2_{i_s}y_{j_1}\cdots y_{j_t}\]

in terms of the \(\alpha_i,c_i,\gamma_{s,t}\). For example, try running

pontryagin_via_chern < xy_poly_t, chern_poly_t>(5);