Exemplo n.º 1
0
def gradient(poly):
    """
    Polynomial gradient operator.

    Args:
        poly (numpoly.ndpoly):
            Polynomial to differentiate. If polynomial vector is provided,
            the Jacobi-matrix is returned instead.

    Returns:
        Same as ``poly`` but with an extra first dimensions, one for each
        variable in ``poly.indeterminants``, filled with gradient values.

    Examples:
        >>> x, y = numpoly.symbols("x y")
        >>> poly = 5*x**5+4
        >>> numpoly.gradient(poly)
        polynomial([25*x**4])
        >>> poly = 4*x**3+2*y**2+3
        >>> numpoly.gradient(poly)
        polynomial([12*x**2, 4*y])
        >>> poly = numpoly.polynomial([1, x**3, x*y**2+1])
        >>> numpoly.gradient(poly)
        polynomial([[0, 3*x**2, y**2],
                    [0, 0, 2*x*y]])

    """
    poly = numpoly.aspolynomial(poly)
    polys = [diff(poly, diffvar)[numpy.newaxis] for diffvar in poly.names]
    return numpoly.concatenate(polys, axis=0)
Exemplo n.º 2
0
def gradient(poly: PolyLike) -> ndpoly:
    """
    Polynomial gradient operator.

    Args:
        poly:
            Polynomial to differentiate. If polynomial vector is provided,
            the Jacobi-matrix is returned instead.

    Returns:
        Same as ``poly`` but with an extra first dimensions, one for each
        variable in ``poly.indeterminants``, filled with gradient values.

    Examples:
        >>> q0 = numpoly.variable()
        >>> poly = 5*q0**5+4
        >>> numpoly.gradient(poly)
        polynomial([25*q0**4])
        >>> q0, q1 = numpoly.variable(2)
        >>> poly = 4*q0**3+2*q1**2+3
        >>> numpoly.gradient(poly)
        polynomial([12*q0**2, 4*q1])
        >>> poly = numpoly.polynomial([1, q0**3, q0*q1**2+1])
        >>> numpoly.gradient(poly)
        polynomial([[0, 3*q0**2, q1**2],
                    [0, 0, 2*q0*q1]])

    """
    poly = numpoly.aspolynomial(poly)
    polys = [
        derivative(poly, diffvar)[numpy.newaxis] for diffvar in poly.names
    ]
    return numpoly.concatenate(polys, axis=0)
Exemplo n.º 3
0
def decompose(poly: PolyLike) -> ndpoly:
    """
    Decompose a polynomial to component form.

    In array missing values are padded with 0 to make decomposition compatible
    with ``chaospy.sum(output, 0)``.

    Args:
        poly:
            Polynomial to decompose.

    Returns:
        Decomposed polynomial with ``poly.shape==(M,)+output.shape``,
        where ``M`` is the number of components in `poly`.

    Examples:
        >>> q0 = numpoly.variable()
        >>> poly = numpoly.polynomial([q0**2-1, 2])
        >>> poly
        polynomial([q0**2-1, 2])
        >>> numpoly.decompose(poly)
        polynomial([[-1, 2],
                    [q0**2, 0]])
        >>> numpoly.sum(numpoly.decompose(poly), 0)
        polynomial([q0**2-1, 2])

    """
    poly = numpoly.aspolynomial(poly)
    return numpoly.concatenate([
        numpoly.construct.polynomial_from_attributes(
            exponents=[expon],
            coefficients=[numpy.asarray(poly.values[key])],
            names=poly.indeterminants,
            retain_coefficients=True,
            retain_names=True,
        )[numpy.newaxis] for key, expon in zip(poly.keys, poly.exponents)
    ])
Exemplo n.º 4
0
def decompose(poly):
    """
    Decompose a polynomial to component form.

    In array missing values are padded with 0 to make decomposition compatible
    with ``chaospy.sum(ouput, 0)``.

    Args:
        poly (numpoly.ndpoly):
            Polynomial to decompose

    Returns:
        (numpoly.ndpoly):
            Decomposed polynomial with ``poly.shape==(M,)+output.shape``
            where ``M`` is the number of components in `poly`.

    Examples:
        >>> x = numpoly.symbols()
        >>> poly = numpoly.polynomial([x**2-1, 2])
        >>> poly
        polynomial([-1+q**2, 2])
        >>> numpoly.decompose(poly)
        polynomial([[-1, 2],
                    [q**2, 0]])
        >>> numpoly.sum(numpoly.decompose(poly), 0)
        polynomial([-1+q**2, 2])

    """
    return numpoly.concatenate([
        numpoly.construct.polynomial_from_attributes(
            exponents=[expon],
            coefficients=[poly[key]],
            names=poly.indeterminants,
            clean=False,
        )[numpy.newaxis] for key, expon in zip(poly.keys, poly.exponents)
    ])
Exemplo n.º 5
0
def compose_polynomial_array(
    arrays: Sequence[PolyLike],
    dtype: Optional[numpy.typing.DTypeLike] = None,
    allocation: Optional[int] = None,
) -> ndpoly:
    """
    Compose polynomial from array of arrays of polynomials.

    Backend for `numpoly.polynomial` when input is undetermined.

    Args:
        arrays:
            Input to be converted to a `numpoly.ndpoly` polynomial type.
        dtype:
            Data type used for the polynomial coefficients.
        allocation:
            The maximum number of polynomial exponents. If omitted, use
            length of exponents for allocation.

    Return:
        Polynomial based on input `arrays`.

    """
    oarrays = numpy.array(arrays, dtype=object)
    shape = oarrays.shape
    if not oarrays.size:
        return numpoly.ndpoly(shape=shape, dtype=dtype)
    if len(oarrays.shape) > 1:
        return numpoly.concatenate([
            numpoly.expand_dims(numpoly.aspolynomial(array, dtype=dtype),
                                axis=0) for array in arrays
        ],
                                   axis=0)

    oarrays = oarrays.flatten()
    indices = numpy.array(
        [isinstance(array, numpoly.ndpoly) for array in oarrays])
    oarrays[indices] = numpoly.align_indeterminants(*oarrays[indices])
    names = oarrays[indices][0] if numpy.any(indices) else None
    oarrays = oarrays.tolist()

    dtypes: List[numpy.typing.DTypeLike] = []
    keys: Set[Tuple[int, ...]] = {(0, )}
    for array in oarrays:
        if isinstance(array, numpoly.ndpoly):
            dtypes.append(array.dtype)
            keys = keys.union({
                tuple(int(k) for k in key)
                for key in array.exponents.tolist()
            })
        elif isinstance(array, (numpy.generic, numpy.ndarray)):
            dtypes.append(array.dtype)
        else:
            dtypes.append(type(array))

    if dtype is None:
        dtype = numpy.find_common_type(dtypes, [])
    length = max(1, max([len(key) for key in keys]))

    collection = {}
    for idx, array in enumerate(oarrays):
        if isinstance(array, numpoly.ndpoly):
            for key, value in zip(array.exponents, array.coefficients):
                key = tuple(key) + (0, ) * (length - len(key))
                if key not in collection:
                    collection[key] = numpy.zeros(len(oarrays), dtype=dtype)
                collection[key][idx] = value
        else:
            key = (0, ) * length
            if key not in collection:
                collection[key] = numpy.zeros(len(oarrays), dtype=dtype)
            collection[key][idx] = array

    exponents = sorted(collection)
    coefficients = numpy.array([collection[key] for key in exponents])
    coefficients = coefficients.reshape(-1, *shape)

    return numpoly.ndpoly.from_attributes(
        exponents=exponents,
        coefficients=list(coefficients),
        names=names,
        allocation=allocation,
    )
Exemplo n.º 6
0
def compose_polynomial_array(
    arrays,
    dtype=None,
):
    """
    Compose polynomial from array of arrays of polynomials.

    Backend for `numpoly.polynomial` when input is undetermined.

    Args:
        arrays (Any):
            Input to be converted to a `numpoly.ndpoly` polynomial type.
        dtype (Optional[numpy.dtype]):
            Data type used for the polynomial coefficients.

    Return:
        (numpoly.ndpoly):
            Polynomial based on input `arrays`.
    """
    arrays_ = numpy.array(arrays, dtype=object)
    shape = arrays_.shape
    if not arrays_.size:
        return numpoly.ndpoly(shape=shape, dtype=dtype)
    if len(arrays_.shape) > 1:
        return numpoly.concatenate([
            numpoly.aspolynomial(array, dtype)[numpy.newaxis]
            for array in arrays
        ],
                                   axis=0)

    arrays = arrays_.flatten()

    indices = numpy.array(
        [isinstance(array, numpoly.ndpoly) for array in arrays])
    arrays[indices] = numpoly.align_indeterminants(*arrays[indices])
    names = arrays[indices][0] if numpy.any(indices) else None
    arrays = arrays.tolist()

    dtypes = []
    keys = {(0, )}
    for array in arrays:
        if isinstance(array, numpoly.ndpoly):
            dtypes.append(array.dtype)
            keys = keys.union([tuple(key) for key in array.exponents.tolist()])
        elif isinstance(array, (numpy.generic, numpy.ndarray)):
            dtypes.append(array.dtype)
        else:
            dtypes.append(type(array))

    if dtype is None:
        dtype = numpy.find_common_type(dtypes, [])
    length = max([len(key) for key in keys])

    collection = {}
    for idx, array in enumerate(arrays):
        if isinstance(array, numpoly.ndpoly):
            for key, value in zip(array.exponents, array.coefficients):
                key = tuple(key) + (0, ) * (length - len(key))
                if key not in collection:
                    collection[key] = numpy.zeros(len(arrays), dtype=dtype)
                collection[key][idx] = value
        else:
            key = (0, ) * length
            if key not in collection:
                collection[key] = numpy.zeros(len(arrays), dtype=dtype)
            collection[key][idx] = array

    exponents = sorted(collection)
    coefficients = numpy.array([collection[key] for key in exponents])
    coefficients = coefficients.reshape(-1, *shape)

    exponents, coefficients, names = postprocess_attributes(
        exponents, coefficients, names)
    return numpoly.ndpoly.from_attributes(
        exponents=exponents,
        coefficients=coefficients,
        names=names,
    )
Exemplo n.º 7
0
def power(x1, x2, **kwargs):
    """
    First array elements raised to powers from second array, element-wise.

    Raise each base in `x1` to the positionally-corresponding power in
    `x2`.  `x1` and `x2` must be broadcastable to the same shape. Note that an
    integer type raised to a negative integer power will raise a ValueError.

    Args:
        x1 (numpoly.ndpoly):
            The bases.
        x2 (numpoly.ndpoly):
            The exponents. If ``x1.shape != x2.shape``, they must be
            broadcastable to a common shape (which becomes the shape of the
            output).
        out (Optional[numpy.ndarray]):
            A location into which the result is stored. If provided, it must
            have a shape that the inputs broadcast to. If not provided or
            `None`, a freshly-allocated array is returned. A tuple (possible
            only as a keyword argument) must have length equal to the number of
            outputs.
        where (Optional[numpy.ndarray]):
            This condition is broadcast over the input. At locations where the
            condition is True, the `out` array will be set to the ufunc result.
            Elsewhere, the `out` array will retain its original value. Note
            that if an uninitialized `out` array is created via the default
            ``out=None``, locations within it where the condition is False will
            remain uninitialized.
        kwargs:
            Keyword args passed to numpy.ufunc.

    Returns:
        (numpoly.ndpoly):
            The bases in `x1` raised to the exponents in `x2`. This is a scalar
            if both `x1` and `x2` are scalars.

    Examples:
        >>> x = numpoly.symbols("x")
        >>> (x+1)**3
        polynomial(1+3*x+3*x**2+x**3)
        >>> poly = numpoly.symbols("x y")
        >>> (poly+1)**[1, 2]
        polynomial([1+x, 1+2*y+y**2])

    """
    x1 = numpoly.aspolynomial(x1)
    x2 = numpoly.aspolynomial(x2).tonumpy().astype(int)

    if not x2.shape:
        out = numpoly.ndpoly.from_attributes(
            [(0, )], [numpy.ones(x1.shape, dtype=x1._dtype)], x1.names[:1])
        for _ in range(x2.item()):
            out = numpoly.multiply(out, x1, **kwargs)

    elif x1.shape:
        if x2.shape[-1] == 1:
            if x1.shape[-1] == 1:
                out = numpoly.power(x1.T[0].T, x2.T[0].T).T[numpy.newaxis].T
            else:
                out = numpoly.concatenate(
                    [power(x, x2.T[0])[numpy.newaxis] for x in x1.T], axis=0).T
        elif x1.shape[-1] == 1:
            out = numpoly.concatenate(
                [power(x1.T[0].T, x.T).T[numpy.newaxis] for x in x2.T],
                axis=0).T
        else:
            out = numpoly.concatenate([
                power(x1_, x2_).T[numpy.newaxis]
                for x1_, x2_ in zip(x1.T, x2.T)
            ],
                                      axis=0).T
    else:
        out = numpoly.concatenate(
            [power(x1, x.T).T[numpy.newaxis] for x in x2.T], axis=0).T
    return out