Polynomial Evaluation

As a first feature to mention, obviously these polynomials are evaluated as functions.


In [1]:
import chaospy

q0, q1 = chaospy.variable(2)
expansion = chaospy.polynomial([1, q0**2, q0*q1])

expansion, expansion(2), expansion(q1=3)


Out[1]:
(polynomial([1, q0**2, q0*q1]),
 polynomial([1, 4, 2*q1]),
 polynomial([1, q0**2, 3*q0]))

If the polynomials indeterminants are all evaluate, the polynomial will return an appropriate numpy array instead of a polynomial one.


In [2]:
expansion(2, 3), expansion(q0=2, q1=3)


Out[2]:
(array([1, 4, 6]), array([1, 4, 6]))

The polynomials are vectorized and support vectorized input:


In [3]:
import numpy

expansion(q1=numpy.arange(4))


Out[3]:
polynomial([[1, 1, 1, 1],
            [q0**2, q0**2, q0**2, q0**2],
            [0, q0, 2*q0, 3*q0]])

The input can be a mix of scalars and arrays, as long as the shapes together can be joined together in a common compatible shape:


In [4]:
expansion([0, 1, 2], 3)


Out[4]:
array([[1, 1, 1],
       [0, 1, 4],
       [0, 3, 6]])

Which also support most basic numpy.dtype.


In [5]:
expansion(1), expansion(2.), expansion(3j)


Out[5]:
(polynomial([1, 1, q1]),
 polynomial([1.0, 4.0, 2.0*q1]),
 polynomial([(1+0j), (-9+0j), 3j*q1]))

On top of this, it is also possible to pass simple polynomials as arguments. This allows for variable substitution. For example, to swap two dimensions, one could simply do the following:


In [6]:
expansion(q0=q1, q1=q0)


Out[6]:
polynomial([1, q1**2, q0*q1])

Or to insert full polynomial substitutions:


In [7]:
expansion(q1=1-q1**3)


Out[7]:
polynomial([1, q0**2, -q0*q1**3+q0])

Compatibility with Numpy

The polynomial objects are for the most part quitenumpy compliant, in the sense that they identify and behave very much like numpy.ndarray.

Some of the compliance stems from features in numpy that was introduced in version 1.17. chaospy works just fine for lower versions as well, however for some examples below functions on form numpy.some_func(some_poly) will need to be done with the equivalent chaospy.some_func(some_poly).


In [8]:
from packaging.version import parse
assert parse(numpy.__version__) >= parse("1.17"), (
    "numpy version >=1.17 required for some of this")
isinstance(chaospy.variable(), numpy.ndarray)


Out[8]:
True

This allows you (for the most part) to manipulate the polynomial in the same way as an array:


In [9]:
expansion/2-q1


Out[9]:
polynomial([-q1+0.5, 0.5*q0**2-q1, 0.5*q0*q1-q1])

It also support manipulation using numpy functions and methods:


In [10]:
numpy.sum(expansion, axis=0)


Out[10]:
polynomial(q0*q1+q0**2+1)

Obviously, the support towards numpy has it's limits. Some functions will likely never work as expected:


In [11]:
try:
    numpy.sin(expansion)
except Exception as err:
    error = err.args[0]
error


Out[11]:
"ufunc '<ufunc 'sin'>' not supported."

The list of supported functions is large and growing. The list of supported functions is listed here: https://numpoly.readthedocs.io/en/master/array_function.html