Numpy functions¶
The numpoly
concept of arrays is taken from numpy. But it goes a bit
deeper than just inspiration. The base class numpoly.ndpoly
is a
direct subclass of numpy.ndarray
:
>>> issubclass(numpoly.ndpoly, numpy.ndarray)
True
The intentions is to have a library that is fast with the respect of the number of coefficients, as it leverages numpy’s speed where possible.
In addition numpoly
is designed to be behave both as you would expect as a
polynomial, but also, where possible, to behave as a numpy numerical array.
In practice this means that numpoly
provides a lot functions that also
exists in numpy, which does about the same thing. If one of these
numpoly
function is provided with a numpy.ndarray
object, the
returned values is the same as if provided to the numpy function with the
same name. For example numpoly.transpose()
:
>>> num_array = numpy.array([[1, 2], [3, 4]])
>>> numpoly.transpose(num_array)
polynomial([[1, 3],
[2, 4]])
And this works the other way around as well. If a polynomial is provided to the
numpy function, it will behave the same way as if it was provided to the
numpoly
equivalent. So following the same example, we can use
numpy.transpose()
to transpose numpoly.ndpoly
polynomials:
>>> q0, q1 = numpoly.variable(2)
>>> poly_array = numpoly.polynomial([[1, q0-1], [q1**2, 4]])
>>> numpy.transpose(poly_array)
polynomial([[1, q1**2],
[q0-1, 4]])
Though the overlap in functionality between numpy and numpoly
is large,
there are still lots of functionality which is specific for each of them.
The most obvious, in the case of numpoly
features not found in numpy is
the ability to evaluate the polynomials:
>>> poly = q1**2-q0
>>> poly
polynomial(q1**2-q0)
>>> poly(4, 4)
12
>>> poly(4)
polynomial(q1**2-4)
>>> poly([1, 2, 3])
polynomial([q1**2-1, q1**2-2, q1**2-3])
Function compatibility¶
The numpy library comes with a large number of functions for manipulating
numpy.ndarray
objects. Many of these functions are supported
numpoly
as well.
For numpy version >=1.17, the numpy library introduced dispatching of its
functions to subclasses. This means that functions in numpoly
with the
same name as a numpy counterpart, it will work the same irrespectively if the
function used was from numpy or numpoly
, as the former will pass any
job to the latter.
For example:
>>> poly = numpoly.variable()**numpy.arange(4)
>>> poly
polynomial([1, q0, q0**2, q0**3])
>>> numpoly.sum(poly, keepdims=True)
polynomial([q0**3+q0**2+q0+1])
>>> numpy.sum(poly, keepdims=True)
polynomial([q0**3+q0**2+q0+1])
For earlier versions of numpy, the last line will not work and will instead raise an error.
In addition, not everything is possible to support, and even within the list of
supported functions, not all use cases can be covered. Bit if such an
unsupported edge case is encountered, an numpoly.FeatureNotSupported
error should be raised, so it should be obvious when they happen.
As a developer note, numpoly
aims at being backwards compatible with
numpy as far as possible when it comes to the functions it provides. This
means that all functions below should as far as possible mirror the behavior
their numpy counterparts, and for polynomial constant, they should be
identical (except for the object type). Function that provides behavior not
covered by numpy should be placed elsewhere.