Piranha polynomials and series

In Piranha a series is a collection of terms where a sum operation is implied between terms. Each term, in turn, is a pair made of a coefficient and a key. The key uniquely identifies a term in a series, in the sense that no terms with equivalent key can exist inside the same series (e.g., the terms 7*x and 6*x would be compressed into the single term 13*x in a polynomial).

Piranha implements so far three different key types: monomial (here meaning a product of powers of symbolic variables, where the powers are not limited to being integral values), trigonometric monomials (e.g., objects of the type “cos(2*x-y)”) and divisors (e.g., objects of the type 1/[(x-y)**n*(x+2*y)**m]). A coefficient type can be any type that satisfies a few basic requirements (e.g., it must support basic arithmetic operations). Piranha provides some useful coefficient types such as arbitrary-precision integrals/rationals/reals:

Monomials are used to define polynomials, trigonometric monomials are used to define Poisson series, and divisors are used to define divisor series. I will talk a bit about polynomials because they are the simplest symbolic objects. So, in order to define a polynomial over ℤ in Piranha you could do something like this:

using p_type = polynomial<integer,monomial<int>>;

Here we are selecting “integer” as coefficient type and monomial<int> as key type. monomial<int> represents monomial as arrays of type int. If you need more range for the exponents you could do:

using p_type = polynomial<integer,monomial<long>>;

Or if you need unlimited exponents:

using p_type = polynomial<integer,monomial<integer>>;

If you want to define polynomials over ℚ you could do:

using p_type = polynomial<rational,monomial<int>>;

Once you have defined your polynomial type, you can construct polynomials in a variety of ways. For example:

p_type p{1};

will do the expected thing and create a polynomial with zero variables, and a single term with coefficient 1. If you do:

p_type x{"x"};

x will be a polynomial in 1 variable, “x”, with one term with coefficient 1 and monomial x**1. All series types support basic arithmetic:

p_type x{"x"}, y{"y"};
std::cout << x+2*y  << '\n'; // This will print "x+2y" or "2y+x"
std::cout << (x+y)*(x-y)  << '\n'; // This will print "x**2-y**2" or "y**2-x**2"

Division is supported only wrt to scalar (that is, there is no true polynomial division algorithm implemented in Piranha at the moment).

Degree truncation

For truncated power series, you might be interested in Piranha’s truncated multiplication:

p_type x{"x"}, y{"y"};
p_type::set_auto_truncate_degree(2);
std::cout << (x*y + x*x*x) << '\n';
// This will print only x*y, the term x**3 has been discarded.

Polynomials have a static method set_auto_truncate_degree() that sets a global variable indicating the maximum total degree allowed during polynomial multiplication. All terms generated by a polynomial multiplication of degree higher than 2 will be discarded. The truncation degree can also be specified only for certain variables:

p_type x{"x"}, y{"y"};
p_type::set_auto_truncate_degree(2,{"x"});
std::cout << (x*x*y + x*x*x) << '\n';
// This will print only x*x*y, the term x**3 has been discarded.

That is, we want to discard all terms whose degree in x is higher than 2.

Instead of automatically truncating, the AuDI project uses a dedicated polynomial object which embeds the maximum degree allowed.

Performance

Piranha has also another format to represent monomials, called k_monomial, that compresses an array of integral values into a single integral (a bit like bit packing in low-level C programming):

using p_type = polynomial<integer,k_monomial>;

This provides the best performance, but the exponents range and number of possible variables representable in a monomial are limited.

Internally, Piranha stores the collection of terms using a hash table and it is thus optimised to deal with large sparse multivariate polynomials. That is, Piranha will probably be suboptimal with respect to a dense univariate representation if all you want to do is to represent the MacLaurin expansion of sin(x). Please see this page with recent benchmarks on Piranha’s performance when multiplying very large polynomials:

http://bluescarni.github.io/new-series-multipliers-in-piranha.html