# Piranha Polynomials & Iterators

### Overview

I worked on wrapping Piranha polynomials within SymEngine this week. It felt much more interesting than wrapping Flint polynomials, mainly because I was reading the Piranha’s source and was in direct touch with the author of the library. Many thanks to @bluescarni who helped me getting familiar with it. As before, I’ll briefly summarize the work I did this week along with my progress.

### Piranha Polynomials

Piranha’s polynomial class is the `piranha::polynomial` class. It’s templatized as follows:

``````template<typename Cf, typename Key>
class polynomial : power_series< ... >
``````

There are two major differences about Piranha Polynomials and SymEngine polynomials. Firstly, it uses a custom unordered map implementation called `hash_set` for storing it’s degree-coefficient pairs. `hash_set` has been internally optimized for polynomial manipulations in general. On a side note, this makes SymEngine have all three types of polynomial representations too! Secondly, Piranha does not distinguish between univariate polynomials and multivariate polynomials. All polynomials are multivariate polynomials, univariate polynomials being a special case (with just one element in it’s `symbol_set`).

Here, `Cf` is the class for storing the coefficients, while `Key` are the monomials themselves. Unlike Flint, we can use any integer class as the coefficient class for the polynomials. So, the first question was wether to use `piranha::integer` (and use implicit conversions like I did in Flint polynomials) or `SymEngine::integer_class` as the integer class for Piranha polynomials. After a brief discussion with Isuru, we decided to go with SymEngine’s integers. The `Key` class used is `piranha::monomial<uint>`, which means it will store one `unsigned int` per symbol (representing the degree, in each monomial).

### SymEngine’s integers in `piranha::polynomial`

For an integer class to be usable as the `Cf` it should have some basic properties like, default constructibility, copy constructibility, `nothrow` destructibility, `nothrow` move assignability and `nothrow` move constructibility. As of yet, `mpz_wrapper`, `fmpz_wrapper` and `mpz_class` did not pass the `nothrow` checks. All that had to bee done was that I had to add `noexcept` to the wrappers we had already written. This allowed `mpz_wrapper` and `fmpz_wrapper` to be used as coefficients in Piranha polynomials. Ofcourse, Piranha’s own integer class passes all these checks too.

Currently, there is no solution for having `mpz_class` as the coefficient class for polynomials. Firstly, these gmpxx integers methods have not been marked `nothrow` yet. There is a forum post on how it can be added, and actually has been added in the development version but hasn’t been released yet. Another reason is that `mpz_class` uses expression templates for improved performance. This means that unlike normal integers, any arithmetic operation does not necessarily return the same integer class.

``````int a, b;
is_a<int>(a+b); 		// true

mpz_class a, b;
is_a<mpz_class>(a+b);	// false
``````

The reason it cannot be used within Piranha is that Piranha checks the coefficient type after each operation so that it knows what ring the polynomial belongs to. Here, it will be unable to detect what the ring is, as the returned coefficient will be an expression template. Thus, it was decided that the integer class `mpz_class` can’t be used alongside Piranha with SymEngine. So, the following became invalid, on which a warning is thrown and the class is changed to `mpz_wrapper` :

``````cmake -DWITH_PIRANHA=yes -DINTEGER_CLASS=gmpxx
``````

All the work on Piranha polynomials and the `cmake` changes can be found in #980.

### Iterators

Currently this is what the `print` functions for our univariate integer polynomials looked like :

``````string print(const UIntPoly& p)
{
for(auto it = p.dict_.begin(); it != p.dict_.end(); ++it)
{
// use it->first and it->second
}
}

string print(const UIntPolyFlint& p)
{
for(auto it = p.degree(); it >= 0; --it)
{
// use it and p.get_coeff(it)
}
}
``````

These methods are very similar and do not deserve to be separate functions. All that was needed to unify these methods was to have iterators for each of the three classes, and then we can have use the same code for many functions like `print`, `as_symbolic` and `derivative`. This also called for a new base class to be made, `UIntPolyBase` from which these three integer polynomials inherit and it itself inherits from the original base class `UPolyBase`.

I stuck with the syntax of `it->first` and `it->second` for the unified iterators. Which means `operator*` needed to return a `std::pair<uint, integer_class>`. So, for SymEngine polynomials all I needed to do was return iterators to the internal dictionary and that was it. Not going into too much technicality, for Flint and Piranha I used custom iterators which had `operator++` defined on them and returned a pair whenever `it->` or `*it` was called on them. They basically iterated over the degree and returned only for non-zero coefficients for both the libraries. The actual implementation of the iterator scheme can be seen in #985.

Initially I was happy with this approach and was able to write (unifying the three) :

``````string print(const UIntPolyBase& p)
{
for(auto it = p.dict_.begin(); it != p.dict_.end(); ++it)
{
// use it->first and it->second
}
}
``````

Isuru pointed out that instead of returning the `integer_class` in the pair, we should return a reference to it. Now, this made sense but was a bit tricky to implement. Also the iterator could no longer return reference like `const integer_class&`, as Flint did not even store it’s coefficients as `integer_class`. To tackle this, another template parameter had to be added to the custom iterator class which determined the second term of the pair (which was supposed to be the reference to the coefficient in the internal storage of the polynomial). Also, I had to dig in to the Flint documentation and ask Piranha’s author, for knowing how I could get `const` references to the coefficients in internal storage. After this was finally implemented, there was a new `get_coeff_ref` method, which does not copy but returns a reference to the required coefficient. The only downside to all this was that instead of `it->second` I had to use `to_integer_class(it->second)` everywhere in the common functions.

### Miscellaneous Work

• I saw that in SymEngine, there were lots of redundant header file includes in many files. I wrote a short python script which makes a header dependency tree, and automatically removes header includes which are not needed. After some manual inspection of the changes I pushed in #981. It was really amazing to see the script flag more than 500 lines of redundant includes. The PR has not been merged yet, though.

I will be working on higher level functionality like `gcd` in the coming week. Will keep you guys posted.

Laters!