Math::Polynomial::ModInt - univariate polynomials over modular integers
This documentation refers to version 0.005 of Math::Polynomial::ModInt.
use Math::ModInt qw(mod);
use Math::Polynomial::ModInt qw(modpoly);
$p = modpoly(265, 3); # some polynomial modulo 3
$p = Math::Polynomial::ModInt->from_index(265, 3); # the same
$p = Math::Polynomial::ModInt->new(
mod(1, 3), mod(1, 3), mod(2, 3), mod(0, 3), mod(0, 3), mod(1, 3)
); # the same
$p = Math::Polynomial::ModInt->from_int_poly(
Math::Polynomial->new(1, 1, 2, 0, 0, 1), 3
); # the same
$q = $p->from_index(27); # x^3 (mod 3)
$t = $p->isa('Math::Polynomial'); # true
$s = $p->as_string; # '(x^5 + 2*x^2 + x + 1 (mod 3))'
$d = $p->degree; # 5
$i = $p->index; # 265
$b = $p->modulus; # 3
$n = $p->number_of_terms; # 4
$u = $p->lift; # x^5 + 2*x^2 + x + 1
$v = $p->centerlift; # x^5 - x^2 + x + 1
$z = $p->first_root; # undef
$m = $p->is_irreducible; # true
$r = modpoly(131, 3); # x^4 + x^3 - x^2 + x - 1
$x = $r->first_root; # mod(2, 3)
$c = $r->is_irreducible; # false
$f = $r->lambda_reduce(2); # - x - 1 (mod 3)
Math::Polynomial::ModInt is a subclass of Math::Polynomial for modular integer coefficient spaces. It adds domain-specific methods and stringification options to the base class. Notably, it implements a bijection from unsigned integers to polynomials for a given modulus.
Math::Polynomial::ModInt->new(@coeff) creates a polynomial from its coefficients in ascending order of degrees. @coeff must have at least one value and all values must be Math::ModInt objects with the same modulus.
Other constructors defined in the parent class Math::Polynomial, like monomial and from_roots, are also valid. Note, however, that polynomial operations assuming that the coefficient space is a field, like interpolate and divmod, are safe to use only with prime moduli. Using them with a composite modulus may result in a "modulus not prime" exception.
As there are finitely many modular integer polynomials for any fixed modulus and degree, and countably many for any fixed modulus, they can be enumerated with an unsigned integer index. Indeed, a number written with base n digits is equivalent to a polynomial with modulo n coefficients. We call the number the index of the polynomial. Math::Polynomial::ModInt->from_index($index, $modulus) creates a polynomial from its index. $index can be a perl native integer or a Math::BigInt object.
The subroutine modpoly can be imported and used as a shortcut for the from_index constructor. modpoly($index, $modulus) is equivalent to Math::Polynomial::ModInt->from_index($index, $modulus), then.
It is also possible to create a modular integer polynomial from an integer polynomial and a modulus. Math::Polynomial::ModInt->from_int_poly($poly, $modulus), where $poly is a Math::Polynomial object with integer coefficients and $modulus is a positive integer, does this.
When called as an object method, the modulus argument of this constructor can be omitted. $p->from_index($index) is equivalent to $p->from_index($index, $p->modulus), then. If a modulus is specified, it takes precedence over the invocant. Thus, $p->from_index($index, $modulus) is equivalent to Math::Polynomial::ModInt->from_index($index, $modulus).
Similarly, $p->from_int_poly($intpoly) is equivalent to $p->from_int_poly($intpoly, $p->modulus).
All operators of the parent module Math::Polynomial, as far as they do not involve division, are valid for Math::Polynomial::ModInt objects, too. Notably, addition, subtraction, and multiplication of modular integer polynomials is valid and indeed handled by the parent class. Invalid operations will yield exceptions from Math::ModInt.
If the modulus is a prime number, division is valid in the coefficient space and thus all operators, including divmod and gcd, are safe.
Additionally, a number of comparison operators are defined for modular integer polynomials only. Currently, these are implemented in the Math::Polynomial::ModInt::Order helper module rather than as overloaded operators, for reasons explained there.
In addition to properties defined in the parent module Math::Polynomial, like degree, coeff, and is_monic, some properties specific for modular integer polynomials are defined.
$p->index calculates the index of a modular integer polynomial $p, as defined above. Cf. "from_index".
Note that the index grows exponentially with the degree of the polynomial and is thus represented as a Math::BigInt object.
$p->modulus returns the modulus common to all coefficients of the modular integer polynomial $p.
$p->number_of_terms returns the number of non-zero coefficients of the modular integer polynomial $p. Recent versions of the parent module also have this method.
$p->lambda_reduce($lambda) generates a polynomial of degree lambda or lower from a high-degree polynomial in this way: Remove the highest degree coefficient (for degree n) and add it to the coefficient of degree n - lambda, and repeat until the degree of the remaining polynomial is less or equal to lambda.
If lambda happens to be a multiple of the Carmichael totient of the modulus, which will be one less than the modulus if the modulus is a prime number, the reduced polynomial will evaluate point-wise equivalent to the original polynomial.
$p->first_root returns the root with the smallest non-negative residue of the polynomial, if such roots exist, otherwise undef. As currently implemented, this operation will be time-consuming for large moduli.
If $p is a modular integer polynomial with prime modulus, $p->is_irreducible returns a boolean value telling if the polynomial is irreducibe. An irreducible polynomial is a non-constant polynomial that is not a product of two or more other non-constant polynomials.
Irreducibility is mostly of interest for prime moduli, where factorization is always unique. This method therefore is implemented for prime moduli only. Note, however, that primality of the modulus is not explicitly checked, as this can be done beforehand once and would unnecessarily slow down operations on several polynomials with the same modulus. As currently implemented, the method may either return a meaningless result or throw a 'modulus is not prime' exception when called with a non-prime modulus.
For conversion to a string, the whole string configuration functionality of the parent module can be employed. For convenience, the default string configuration for Math::Polynomial::ModInt is already adapted to a more terse representation, so that the modulus is only written once. $p->as_string could return '(x^5 + 2*x^2 + x + 1 (mod 3))', for example.
'(x^5 + 2*x^2 + x + 1 (mod 3))'
The lift method is a reverse operation to from_int_poly. $p->lift returns a Math::Polynomial object with integer coefficients with values ranging from zero to the modulus minus one. It is equivalent to the Math::Polynomial::ModInt object $p in the sense that from_int_poly would turn it back to $p.
The centerlift method is an alternative to lift with the only difference that the integer values of the coefficients range from minus half of the modulus, rounded up, to plus half of the modulus, rounded down, if the modulus is odd, or minus half of the modulus, plus one, to plus half of the modulus, if it is even.
All lifting methods may be used together with tree conversions to get yet more string representations of polynomials, if so desired.
Dealing with Math::ModInt objects can generally trigger exceptions from Math::ModInt::Event. Mixing different moduli or dividing non-coprime elements could be causes. These exceptions will correctly be propagated as failures of code calling Math::Polynomial::ModInt in general, but in some situations Math::Polynomial may be blamed.
Other error conditions, like using non-integers or non-objects where they would be expected, are not rigorously checked and may yield unreliable behavior rather than error messages.
The error conditions that are actually reported are these:
modulus not prime
A method only defined for prime moduli, like is_irreducible, has been called inappropriately. Note that this is not always detected and the result might be just wrong in such cases.
modulus must be greater than one
A constructor was called with an inappropriate modulus of zero or one. Polynomials indexing uses the modulus as the base of a numeral system with coefficients acting as digits. This is implemented and actually useful for bases greater than one only.
A method needing the multiplicative inverse of a coefficient, like monize, has been called where that coefficient had no inverse. This can occur with coefficients that are not coprime to the modulus.
usage error: modulus parameter missing
The from_index or from_int_poly constructors have been used with insufficient information as to the value of the modulus. They should be either invoked with an explicit modulus (recommended) or as an object method.
This library uses Math::ModInt (version 0.012 and up) for modular integer calculations and Math::Polynomial (version 1.015 and up) for polynomial arithmetic, as well as Carp (any version) for diagnostic messages. The minimal required perl version is 5.6.
The toolbox of algebraic operations is by no means complete. Irreducibility checking is based on Berlekamp's factorization algorithm but full factorization is not yet implemented. It is intended to be added in one of the next releases.
Some applications of modular integer polynomials will be provided by the Math::GaloisField hierarchy of modules rather than in this package. Math::Polynomial::ModInt is meant for basic stuff that can more or less be expected in a sub-class of Math::Polynomial, while algebraic field properties are more appropriate in the other package. For example, division means polynomial division with remainder here, and proper division governed by field arithmetic there.
Ideally (pun not intended), the element type Math::Polynomial::ModInt with non-prime moduli should have a corresponding space type like Math::PolynomialRing::ModInt, where more algebraic ring stuff could have a home. It is not yet planned, though, but some tidbits could make an appearance in the Math::Polynomial::ModInt examples collection in the meantime.
Most of the time, method arguments are not rigourosly checked to make sense. Cf. Diagnostics.
Some calculations, like root finding and checking for irreducibility, can be time-consuming. Operations involving large integer numbers will be faster if Math::BigInt::GMP is installed. So far, this package is pure perl only. An XS version may be added eventually, but not in the near future.
Bug reports and more suggestions are always welcome — please submit them through the github issue tracker, https://github.com/mhasch/perl-Math-Polynomial-ModInt/issues.
Math::GaloisField (sooner or later to be published)
Martin Becker, <becker-cpan-mp (at) cozap.com>
<becker-cpan-mp (at) cozap.com>
Contributions to this library are welcome (see the CONTRIBUTING file).
Copyright (c) 2013-2022 by Martin Becker, Blaubeuren.
This library is free software; you can distribute it and/or modify it under the terms of the Artistic License 2.0 (see the LICENSE file).
This library is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.
To install Math::Polynomial::ModInt, copy and paste the appropriate command in to your terminal.
perl -MCPAN -e shell
For more information on module installation, please visit the detailed CPAN module installation guide.