Source code for numpoly.poly_function.call

"""Evaluate polynomial by inserting new values in to the indeterminants."""
from __future__ import annotations
from typing import Dict, Sequence, Optional, Union
import logging

import numpy
import numpoly

from ..baseclass import ndpoly, PolyLike


[docs]def call( poly: PolyLike, args: Sequence[Optional[PolyLike]] = (), kwargs: Dict[str, PolyLike] = None, ) -> Union[numpy.ndarray, ndpoly]: """ Evaluate polynomial by inserting new values in to the indeterminants. Equivalent to calling the polynomial or using the ``__call__`` method. Args: poly: Polynomial to evaluate. args: Argument to evaluate indeterminants. Ordered positional by ``poly.indeterminants``. None values indicate that a variable is not to be evaluated, creating a partial evaluation. kwargs: Same as ``args``, but positioned by name. Return: Evaluated polynomial. If the resulting array does not contain any indeterminants, an array is returned instead of a polynomial. Example: >>> q0, q1 = numpoly.variable(2) >>> poly = numpoly.polynomial([[q0, q0-1], [q1, q1+q0]]) >>> numpoly.call(poly) polynomial([[q0, q0-1], [q1, q1+q0]]) >>> poly polynomial([[q0, q0-1], [q1, q1+q0]]) >>> numpoly.call(poly, (1, 0)) array([[1, 0], [0, 1]]) >>> numpoly.call(poly, (1,), {"q1": [0, 1, 2]}) array([[[1, 1, 1], [0, 0, 0]], <BLANKLINE> [[0, 1, 2], [1, 2, 3]]]) >>> numpoly.call(poly, (q1,)) polynomial([[q1, q1-1], [q1, 2*q1]]) >>> numpoly.call(poly, kwargs={"q1": q0-1, "q0": 2*q1}) polynomial([[2*q1, 2*q1-1], [q0-1, 2*q1+q0-1]]) """ logger = logging.getLogger(__name__) poly = numpoly.aspolynomial(poly) kwargs = kwargs if kwargs else {} parameters = dict(zip(poly.names, poly.indeterminants)) if kwargs: parameters.update(kwargs) for arg, name in zip(args, poly.names): if name in kwargs: raise TypeError(f"multiple values for argument '{name}'") if arg is not None: parameters[name] = arg extra_args = [key for key in parameters if key not in poly.names] if extra_args: raise TypeError(f"unexpected keyword argument '{extra_args[0]}'") # There can only be one shape: ones = numpy.ones((), dtype=int) for value in parameters.values(): ones = ones * numpy.ones(numpoly.polynomial(value).shape, dtype=int) shape = poly.shape + ones.shape logger.debug("poly shape: %s", poly.shape) logger.debug("parameter common shape: %s", ones.shape) logger.debug("output shape: %s", shape) # main loop: out = numpy.zeros((), dtype=int) for exponent, coefficient in zip(poly.exponents, poly.coefficients): term = ones for power, name in zip(exponent, poly.names): term = term * parameters[name] ** power if isinstance(term, numpoly.ndpoly): tmp = numpoly.outer(coefficient, term) else: tmp = numpy.outer(coefficient, term) out = out + tmp.reshape(shape) if isinstance(out, numpoly.ndpoly): if out.isconstant(): out = out.tonumpy() else: out, _ = numpoly.align_indeterminants(out, poly.indeterminants) return out