Exemplo n.º 1
0
def dsplit(ary, indices_or_sections):
    """
    Split array into multiple sub-arrays along the 3rd axis (depth).

    Please refer to the `split` documentation.  `dsplit` is equivalent
    to `split` with ``axis=2``, the array is always split along the third
    axis provided the array dimension is greater than or equal to 3.

    Examples:
        >>> poly = numpoly.monomial(8).reshape(2, 2, 2)
        >>> poly
        polynomial([[[1, q],
                     [q**2, q**3]],
        <BLANKLINE>
                    [[q**4, q**5],
                     [q**6, q**7]]])
        >>> part1, part2 = numpoly.dsplit(poly, 2)
        >>> part1
        polynomial([[[1],
                     [q**2]],
        <BLANKLINE>
                    [[q**4],
                     [q**6]]])
        >>> part2
        polynomial([[[q],
                     [q**3]],
        <BLANKLINE>
                    [[q**5],
                     [q**7]]])

    """
    ary = numpoly.aspolynomial(ary)
    results = numpy.dsplit(ary.values, indices_or_sections=indices_or_sections)
    return [numpoly.aspolynomial(result, names=ary.indeterminants)
            for result in results]
Exemplo n.º 2
0
def atleast_3d(*arys: PolyLike) -> Union[ndpoly, List[ndpoly]]:
    """
    View inputs as arrays with at least three dimensions.

    Args:
        arys:
            One or more array-like sequences. Non-array inputs are converted
            to arrays. Arrays that already have three or more dimensions are
            preserved.

    Returns:
        An array, or list of arrays, each with ``a.ndim >= 3``.  Copies are
        avoided where possible, and views with three or more dimensions are
        returned.  For example, a 1-D array of shape ``(N,)`` becomes a view of
        shape ``(1, N, 1)``, and a 2-D array of shape ``(M, N)`` becomes a view
        of shape ``(M, N, 1)``.

    Examples:
        >>> numpoly.atleast_3d(numpoly.variable())
        polynomial([[[q0]]])
        >>> a, b = numpoly.atleast_3d(1, [2, 3])
        >>> a
        polynomial([[[1]]])
        >>> b
        polynomial([[[2],
                     [3]]])

    """
    if len(arys) == 1:
        poly = numpoly.aspolynomial(arys[0])
        array = numpy.atleast_3d(poly.values)
        return numpoly.aspolynomial(array, names=poly.indeterminants)
    return [atleast_3d(ary) for ary in arys]
Exemplo n.º 3
0
def atleast_1d(*arys: PolyLike) -> Union[ndpoly, List[ndpoly]]:
    """
    Convert inputs to arrays with at least one dimension.

    Scalar inputs are converted to 1-dimensional arrays, whilst
    higher-dimensional inputs are preserved.

    Args:
        arys:
            One or more input arrays.

    Returns:
        An array, or list of arrays, each with ``a.ndim >= 1``.
        Copies are made only if necessary.

    Examples:
        >>> numpoly.atleast_1d(numpoly.variable())
        polynomial([q0])
        >>> numpoly.atleast_1d(1, [2, 3])
        [polynomial([1]), polynomial([2, 3])]

    """
    if len(arys) == 1:
        poly = numpoly.aspolynomial(arys[0])
        array = numpy.atleast_1d(poly.values)
        return numpoly.aspolynomial(array, names=poly.indeterminants)
    return [atleast_1d(ary) for ary in arys]
Exemplo n.º 4
0
def atleast_2d(*arys: PolyLike) -> Union[ndpoly, List[ndpoly]]:
    """
    View inputs as arrays with at least two dimensions.

    Args:
        arys:
            One or more array-like sequences. Non-array inputs are converted
            to arrays. Arrays that already have two or more dimensions are
            preserved.

    Returns:
        An array, or list of arrays, each with ``a.ndim >= 2``. Copies are
        avoided where possible, and views with two or more dimensions are
        returned.

    Examples:
        >>> numpoly.atleast_2d(numpoly.variable())
        polynomial([[q0]])
        >>> numpoly.atleast_2d(1, [2], [[3]])
        [polynomial([[1]]), polynomial([[2]]), polynomial([[3]])]

    """
    if len(arys) == 1:
        poly = numpoly.aspolynomial(arys[0])
        array = numpy.atleast_2d(poly.values)
        return numpoly.aspolynomial(array, names=poly.indeterminants)
    return [atleast_2d(ary) for ary in arys]
Exemplo n.º 5
0
def logical_and(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[numpy.ndarray] = None,
    where: Union[bool, Sequence[bool]] = True,
    **kwargs: Any,
) -> numpy.ndarray:
    """
    Compute the truth value of x1 AND x2 element-wise.

    Args:
        x1, x2
            Input arrays. If ``x1.shape != x2.shape``, they must be
            broadcastable to a common shape (which becomes the shape of the
            output).
        out:
            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:
            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:
        Boolean result of the logical OR operation applied to the elements of
        `x1` and `x2`; the shape is determined by broadcasting. This is a
        scalar if both `x1` and `x2` are scalars.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> numpoly.logical_and(q0, 0)
        False
        >>> numpoly.logical_and([q0, False], [q0, q1])
        array([ True, False])
        >>> const = numpy.arange(5)
        >>> numpoly.logical_and(const > 1, const < 4)
        array([False, False,  True,  True, False])

    """
    x1 = numpoly.aspolynomial(x1)
    x2 = numpoly.aspolynomial(x2)
    coefficients1 = numpy.any(numpy.asarray(x1.coefficients), 0)
    coefficients2 = numpy.any(numpy.asarray(x2.coefficients), 0)
    where_ = numpy.asarray(where)
    return numpy.logical_and(coefficients1,
                             coefficients2,
                             out=out,
                             where=where_,
                             **kwargs)
Exemplo n.º 6
0
def derivative(poly: PolyLike, *diffvars: Union[ndpoly, str, int]) -> ndpoly:
    """
    Polynomial differential operator.

    Args:
        poly:
            Polynomial to differentiate.
        diffvars:
            Singleton variables to take derivative off.

    Returns:
        Same as ``poly`` but differentiated with respect to ``diffvars``.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> poly = numpoly.polynomial([1, q0, q0*q1**2+1])
        >>> poly
        polynomial([1, q0, q0*q1**2+1])
        >>> numpoly.derivative(poly, "q0")
        polynomial([0, 1, q1**2])
        >>> numpoly.derivative(poly, 0, 1)
        polynomial([0, 0, 2*q1])
        >>> numpoly.derivative(poly, q0, q0, q0)
        polynomial([0, 0, 0])

    """
    poly = poly_ref = numpoly.aspolynomial(poly)

    for diffvar in diffvars:
        if isinstance(diffvar, str):
            idx = poly.names.index(diffvar)
        elif isinstance(diffvar, int):
            idx = diffvar
        else:
            diffvar = numpoly.aspolynomial(diffvar)
            exponents, names = numpoly.remove_redundant_names(
                diffvar.exponents, diffvar.names)
            assert names is not None and len(names) == 1, "one at the time"
            assert numpy.all(
                exponents == 1), ("derivative variable assumes singletons")
            idx = poly.names.index(names[0])

        exponents = poly.exponents
        coefficients = [
            (exponent[idx] * coefficient.T).T
            for exponent, coefficient in zip(exponents, poly.coefficients)
        ]
        exponents[:, idx] -= 1
        assert not numpy.any(exponents < 0)

        poly = numpoly.ndpoly.from_attributes(
            exponents=exponents,
            coefficients=coefficients,
            names=poly_ref.names,
        )
        poly, poly_ref = numpoly.align_polynomials(poly, poly_ref)
    return poly
Exemplo n.º 7
0
def ediff1d(
    ary: PolyLike,
    to_end: Optional[PolyLike] = None,
    to_begin: Optional[PolyLike] = None,
) -> ndpoly:
    """
    Difference between consecutive elements of an array.

    Args:
        ary:
            If necessary, will be flattened before the differences are taken.
        to_end:
            Polynomial(s) to append at the end of the returned differences.
        to_begin:
            Polynomial(s) to prepend at the beginning of the returned
            differences.

    Returns:
        The differences. Loosely, this is ``ary.flat[1:] - ary.flat[:-1]``.

    Examples:
        >>> poly = numpoly.monomial(4)
        >>> poly
        polynomial([1, q0, q0**2, q0**3])
        >>> numpoly.ediff1d(poly)
        polynomial([q0-1, q0**2-q0, q0**3-q0**2])
        >>> q0, q1 = numpoly.variable(2)
        >>> numpoly.ediff1d(poly, to_begin=q0, to_end=[1, q1])
        polynomial([q0, q0-1, q0**2-q0, q0**3-q0**2, 1, q1])

    """
    ary = numpoly.aspolynomial(ary).ravel()
    arys_ = [ary[1:] - ary[:-1]]
    if to_end is not None:
        arys_.append(numpoly.aspolynomial(to_end).ravel())
    if to_begin is not None:
        arys_.insert(0, numpoly.aspolynomial(to_begin).ravel())
    arys = tuple(numpoly.aspolynomial(ary) for ary in arys_)
    if len(arys) > 1:
        arys = numpoly.align_exponents(*arys)

    out = numpoly.ndpoly(
        exponents=arys[0].exponents,
        shape=(sum([ary.size for ary in arys]), ),
        names=arys[0].names,
        dtype=ary[0].dtype,
    )

    idx = 0
    for ary in arys:
        for key in ary.keys:
            out.values[key][idx:idx + ary.size] = ary.values[key]
        idx += ary.size

    return out
Exemplo n.º 8
0
def diff(poly, *diffvars):
    """
    Polynomial differential operator.

    Args:
        poly (numpoly.ndpoly):
            Polynomial to differentiate.
        diffvars (numpoly.ndpoly, str):
            Singleton variables to take derivative off.

    Returns:
        Same as ``poly`` but differentiated with respect to ``diffvars``.

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

    """
    poly = poly_ref = numpoly.aspolynomial(poly)

    for diffvar in diffvars:
        if isinstance(diffvar, string_types):
            idx = poly.names.index(diffvar)
        elif isinstance(diffvar, int):
            idx = diffvar
        else:
            diffvar = numpoly.aspolynomial(diffvar)
            assert len(diffvar.names) == 1, "only one at the time"
            assert numpy.all(diffvar.exponents == 1), (
                "derivative variable assumes singletons")
            idx = poly.names.index(diffvar.names[0])

        exponents = poly.exponents
        coefficients = [
            (exponent[idx] * coefficient.T).T
            for exponent, coefficient in zip(exponents, poly.coefficients)
        ]
        exponents[:, idx] -= 1
        assert not numpy.any(exponents < 0)

        poly = numpoly.ndpoly.from_attributes(
            exponents=exponents,
            coefficients=coefficients,
            names=poly_ref.names,
        )
        poly, poly_ref = numpoly.align_polynomials(poly, poly_ref)
    return poly
Exemplo n.º 9
0
def matmul(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[ndpoly] = None,
    **kwargs: Any,
) -> ndpoly:
    """
    Matrix product of two arrays.

    Args:
        x1, x2:
            Input arrays, scalars not allowed.
        out:
            A location into which the result is stored. If provided, it must
            have a shape that matches the signature `(n,k),(k,m)->(n,m)`.
            If not provided or `None`, a freshly-allocated array is returned.

    Returns:
        The matrix product of the inputs. This is a scalar only when both
        x1, x2 are 1-d vectors.

    Raises:
        ValueError:
            If the last dimension of `x1` is not the same size as
            the second-to-last dimension of `x2`.

    Examples:
        >>> poly = numpoly.variable(4).reshape(2, 2)
        >>> poly
        polynomial([[q0, q1],
                    [q2, q3]])
        >>> numpoly.matmul(poly, [[0, 1], [2, 3]])
        polynomial([[2*q1, 3*q1+q0],
                    [2*q3, 3*q3+q2]])
        >>> numpoly.matmul(poly, [4, 5])
        polynomial([[4*q1+4*q0, 5*q1+5*q0],
                    [4*q3+4*q2, 5*q3+5*q2]])
        >>> numpoly.matmul(*poly)
        polynomial([q1*q2+q0*q2, q1*q3+q0*q3])

    """
    x1 = numpoly.aspolynomial(x1)
    x2 = numpoly.aspolynomial(x2)
    if not x1.shape:
        raise ValueError(ERROR_MESSAGE % 0)
    if not x2.shape:
        raise ValueError(ERROR_MESSAGE % 1)
    x1 = numpoly.reshape(x1, x1.shape+(1,))
    x2 = numpoly.reshape(x2, x2.shape[:-2]+(1,)+x2.shape[-2:])
    x1, x2 = numpoly.broadcast_arrays(x1, x2)
    out_ = numpoly.multiply(x1, x2, out=out, **kwargs)
    return numpoly.sum(out_, axis=-2)
Exemplo n.º 10
0
def simple_dispatch(numpy_func: Callable,
                    inputs: Sequence[Any],
                    out: Optional[Tuple[ndpoly, ...]] = None,
                    **kwargs: Any) -> ndpoly:
    """
    Dispatch function between numpy and numpoly.

    Assumes that evaluation can be performed on the coefficients alone and that
    there are no change to the polynomials.

    Args:
        numpy_func:
            The numpy function to evaluate `inputs` on.
        inputs:
            One or more input arrays.
        out:
            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.
        kwargs:
            Keyword args passed to `numpy_func`.

    Returns:
        Polynomial, where the coefficients from `input` are passed to
        `numpy_func` to create the output coefficients.

    """
    inputs = numpoly.align_polynomials(*inputs)
    keys = (inputs[0] if out is None else numpoly.aspolynomial(out[0])).keys

    tmp = numpy_func(*[poly.values[keys[0]] for poly in inputs], **kwargs)
    if out is None:
        out_ = numpoly.ndpoly(
            exponents=inputs[0].exponents,
            shape=tmp.shape,
            names=inputs[0].indeterminants,
            dtype=tmp.dtype,
        )
    else:
        assert len(out) == 1
        out_ = out[0]
    out_.values[keys[0]] = tmp

    for key in keys[1:]:
        out_.values[key] = numpy_func(*[poly.values[key] for poly in inputs],
                                      **kwargs)

    if out is None:
        out_ = numpoly.clean_attributes(out_)
    return numpoly.aspolynomial(out_)
Exemplo n.º 11
0
def logical_or(x1, x2, out=None, where=True, **kwargs):
    """
    Compute the truth value of x1 OR x2 element-wise.

    Args:
        x1, x2 (numpoly.ndpoly):
            Logical OR is applied to the elements of `x1` and `x2`. 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:
        y (numpy.ndarray):
            Boolean result of the logical OR operation applied to the elements
            of `x1` and `x2`; the shape is determined by broadcasting.
            This is a scalar if both `x1` and `x2` are scalars.

    Examples:
        >>> numpoly.logical_or(True, False)
        True
        >>> numpoly.logical_or([True, False], [False, False])
        array([ True, False])
        >>> x = numpy.arange(5)
        >>> numpoly.logical_or(x < 1, x > 3)
        array([ True, False, False, False,  True])

    """
    x1 = numpoly.aspolynomial(x1)
    x2 = numpoly.aspolynomial(x2)
    coefficients1 = numpy.any(x1.coefficients, 0)
    coefficients2 = numpy.any(x2.coefficients, 0)
    return numpy.logical_or(coefficients1,
                            coefficients2,
                            out=out,
                            where=where,
                            **kwargs)
Exemplo n.º 12
0
def nonzero(x: PolyLike, **kwargs: Any) -> Tuple[numpy.ndarray, ...]:
    """
    Return the indices of the elements that are non-zero.

    Args:
        x:
            Input array.

    Returns:
        Indices of elements that are non-zero.

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

    """
    x = numpoly.aspolynomial(x)
    return numpy.nonzero(numpy.any(numpy.asarray(x.coefficients), axis=0))
Exemplo n.º 13
0
def tonumpy(poly: PolyLike) -> numpy.ndarray:
    """
    Cast polynomial to numpy.ndarray, if possible.

    Args:
        poly:
            polynomial to cast.

    Returns:
        Numpy array.

    Raises:
        numpoly.baseclass.FeatureNotSupported:
            Only constant polynomials can be cast to numpy.ndarray.

    Examples:
        >>> numpoly.tonumpy(numpoly.polynomial([1, 2]))
        array([1, 2])

    """
    poly = numpoly.aspolynomial(poly)
    if not poly.isconstant():
        raise numpoly.FeatureNotSupported(
            "only constant polynomials can be converted to array.")
    idx = numpy.argwhere(numpy.all(poly.exponents == 0, -1)).item()
    if poly.size:
        return numpy.array(poly.coefficients[idx])
    return numpy.array([])
Exemplo n.º 14
0
def common_type(*arrays):
    """
    Return a scalar type which is common to the input arrays.

    The return type will always be an inexact (i.e. floating point) scalar
    type, even if all the arrays are integer arrays. If one of the inputs is an
    integer array, the minimum precision type that is returned is a 64-bit
    floating point dtype.

    All input arrays except int64 and uint64 can be safely cast to the
    returned dtype without loss of information.

    Args:
        arrays (numpoly.ndpoly):
            Input arrays.

    Return:
        out (numpy.generic):
            Data type code.

    Examples:
        >>> numpoly.common_type(
        ...     numpy.array(2, dtype=numpy.float32)).__name__
        'float32'
        >>> numpoly.common_type(
        ...     numpoly.symbols("x")).__name__
        'float64'
        >>> numpoly.common_type(
        ...     numpy.arange(3), 1j*numpoly.symbols("x"), 45).__name__
        'complex128'

    """
    arrays = [numpoly.aspolynomial(array) for array in arrays]
    arrays = [array[array.keys[0]] for array in arrays]
    return numpy.common_type(*arrays)
Exemplo n.º 15
0
def transpose(a, axes=None):
    """
    Permute the dimensions of an array.

    Args:
        a (numpoly.ndpoly):
            Input array.
        axes (int, Sequence[int]):
            By default, reverse the dimensions, otherwise permute the axes
            according to the values given.

    Returns:
        (numpoly.ndpoly):
            `a` with its axes permuted.  A view is returned whenever possible.

    Examples:
        >>> poly = numpoly.monomial(3, names=("x", "y")).reshape(2, 3)
        >>> poly
        polynomial([[1, y, x],
                    [y**2, x*y, x**2]])
        >>> numpoly.transpose(poly)
        polynomial([[1, y**2],
                    [y, x*y],
                    [x, x**2]])

    """
    a = numpoly.aspolynomial(a)
    out = numpy.transpose(a.values, axes=axes)
    out = numpoly.polynomial(out, names=a.indeterminants)
    return out
Exemplo n.º 16
0
def isconstant(poly: PolyLike) -> bool:
    """
    Check if a polynomial is constant or not.

    Args:
        poly:
            polynomial to check if is constant or not.

    Returns:
        True if polynomial has no indeterminants.

    Examples:
        >>> q0 = numpoly.variable()
        >>> numpoly.isconstant(numpoly.polynomial([q0]))
        False
        >>> numpoly.isconstant(numpoly.polynomial([1]))
        True

    """
    poly = numpoly.aspolynomial(poly)
    for exponent, coefficient in zip(poly.exponents, poly.coefficients):
        if not numpy.any(exponent):
            continue
        if numpy.any(coefficient):
            return False
    return True
Exemplo n.º 17
0
def transpose(
    a: PolyLike,
    axes: Union[None, Sequence[int], numpy.ndarray] = None,
) -> ndpoly:
    """
    Permute the dimensions of an array.

    Args:
        a:
            Input array.
        axes:
            By default, reverse the dimensions, otherwise permute the axes
            according to the values given.

    Returns:
        `a` with its axes permuted. A view is returned whenever possible.

    Examples:
        >>> poly = numpoly.monomial([3, 3]).reshape(2, 3)
        >>> poly
        polynomial([[1, q0, q0**2],
                    [q1, q0*q1, q1**2]])
        >>> numpoly.transpose(poly)
        polynomial([[1, q1],
                    [q0, q0*q1],
                    [q0**2, q1**2]])

    """
    a = numpoly.aspolynomial(a)
    out = numpy.transpose(a.values, axes=axes)
    out = numpoly.polynomial(out, names=a.indeterminants)
    return out
Exemplo n.º 18
0
def amin(
    a: PolyLike,
    axis: Union[None, int, Sequence[int]] = None,
    out: Optional[ndpoly] = None,
    **kwargs: Any,
) -> ndpoly:
    """
    Return the minimum of an array or minimum along an axis.

    Args:
        a:
            Input data.
        axis:
            Axis or axes along which to operate.  By default, flattened input
            is used. If this is a tuple of ints, the minimum is selected over
            multiple axes, instead of a single axis or all the axes as before.
        out:
            Alternative output array in which to place the result. Must be of
            the same shape and buffer length as the expected output.
        keepdims:
            If this is set to True, the axes which are reduced are left in the
            result as dimensions with size one. With this option, the result
            will broadcast correctly against the input array.

            If the default value is passed, then `keepdims` will not be passed
            through to the `amax` method of sub-classes of `ndarray`, however
            any non-default value will be.  If the sub-class' method does not
            implement `keepdims` any exceptions will be raised.
        initial:
            The minimum value of an output element. Must be present to allow
            computation on empty slice.
        where:
            Elements to compare for the maximum.

    Returns:
        Minimum of `a`. If `axis` is None, the result is a scalar value.
        If `axis` is given, the result is an array of dimension ``a.ndim-1``.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> numpoly.amin([13, 7])
        polynomial(7)
        >>> numpoly.amin([1, q0, q0**2, q1])
        polynomial(1)
        >>> numpoly.amin([q0, q1, q0**2])
        polynomial(q0)
        >>> numpoly.amin([[3*q0**2, q0**2],
        ...               [2*q0**2, 4*q0**2]], axis=1)
        polynomial([q0**2, 2*q0**2])

    """
    del out
    poly = numpoly.aspolynomial(a)
    options = numpoly.get_options()
    proxy = numpoly.sortable_proxy(
        poly, graded=options["sort_graded"], reverse=options["sort_reverse"])
    indices = numpy.amin(proxy, axis=axis, **kwargs)
    out = poly[numpy.isin(proxy, indices)]
    out = out[numpy.argsort(indices.ravel())]
    return numpoly.reshape(out, indices.shape)
Exemplo n.º 19
0
def expand_dims(a: PolyLike, axis: int) -> ndpoly:
    """
    Expand the shape of an array.

    Insert a new axis that will appear at the `axis` position in the expanded
    array shape.

    Args:
        a:
            Input array.
        axis:
            Position in the expanded axes where the new axis is placed.

    Returns:
        View of `a` with the number of dimensions increased by one.

    Examples:
        >>> poly = numpoly.variable(2)
        >>> numpoly.expand_dims(poly, axis=0)
        polynomial([[q0, q1]])
        >>> numpoly.expand_dims(poly, axis=1)
        polynomial([[q0],
                    [q1]])

    """
    a = numpoly.aspolynomial(a)
    out = numpy.expand_dims(a.values, axis=axis)
    return numpoly.polynomial(out, names=a.indeterminants)
Exemplo n.º 20
0
def apply_over_axes(
    func: Callable,
    a: PolyLike,
    axes: numpy.typing.ArrayLike,
) -> ndpoly:
    """
    Apply a function repeatedly over multiple axes.

    `func` is called as `res = func(a, axis)`, where `axis` is the first
    element of `axes`.  The result `res` of the function call must have either
    the same dimensions as `a` or one less dimension.  If `res` has one less
    dimension than `a`, a dimension is inserted before `axis`.  The call to
    `func` is then repeated for each axis in `axes`, with `res` as the first
    argument.

    Args:
        func:
            This function must take two arguments, `func(a, axis)`.
        a:
            Input array.
        axes:
            Axes over which `func` is applied; the elements must be integers.

    Returns:
        The output array.  The number of dimensions is the same as `a`, but
        the shape can be different.  This depends on whether `func` changes
        the shape of its output with respect to its input.

    Examples:
        >>> polynomial = numpy.arange(24).reshape(2, 4, 3)
        >>> polynomial = polynomial*numpoly.variable(3)
        >>> numpoly.apply_over_axes(
        ...     func=numpoly.sum, a=polynomial, axes=1)
        polynomial([[[18*q0, 22*q1, 26*q2]],
        <BLANKLINE>
                    [[66*q0, 70*q1, 74*q2]]])
        >>> numpoly.apply_over_axes(
        ...     func=numpoly.sum, a=polynomial, axes=[0, 2])
        polynomial([[[16*q2+14*q1+12*q0],
                     [22*q2+20*q1+18*q0],
                     [28*q2+26*q1+24*q0],
                     [34*q2+32*q1+30*q0]]])

    """
    @wraps(func)
    def wrapper_func(array, axis):
        """Wrap func function."""
        # Align indeterminants in case slicing changed them
        array = numpoly.polynomial(array, names=a.indeterminants)
        array, _ = numpoly.align.align_indeterminants(array, a.indeterminants)
        # Evaluate function
        out = func(array, axis=axis)
        # Restore indeterminants in case func changed them.
        out, _ = numpoly.align.align_indeterminants(out, a.indeterminants)
        return out

    # Initiate wrapper
    a = numpoly.aspolynomial(a)
    out = numpy.apply_over_axes(wrapper_func, a=a.values, axes=axes)
    return out
Exemplo n.º 21
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.º 22
0
def align_dtype(*polys):
    """
    Align polynomial by shape.

    Args:
        polys (numpoly.ndpoly):
            Polynomial to make adjustment to.

    Returns:
        (Tuple[numpoly.ndpoly, ...]):
            Same as ``polys``, but internal adjustments made to make them
            compatible for further operations.

    Examples:
        >>> x = numpoly.symbols("x")
        >>> x.dtype.name
        'int64'
        >>> poly, _ = numpoly.align_dtype(x, 4.5)
        >>> poly.dtype.name
        'float64'

    """
    polys = [numpoly.aspolynomial(poly) for poly in polys]
    dtype = numpy.sum([numpy.array(True, dtype=poly.dtype)
                       for poly in polys]).dtype
    polys = [
        numpoly.ndpoly.from_attributes(
            exponents=poly.exponents,
            coefficients=poly.coefficients,
            names=poly.indeterminants,
            dtype=dtype,
            clean=False,
        ) for poly in polys
    ]
    return tuple(polys)
Exemplo n.º 23
0
def common_type(*arrays: PolyLike) -> numpy.dtype:
    """
    Return a scalar type which is common to the input arrays.

    The return type will always be an inexact (i.e. floating point) scalar
    type, even if all the arrays are integer arrays. If one of the inputs is an
    integer array, the minimum precision type that is returned is a 64-bit
    floating point dtype.

    All input arrays except int64 and uint64 can be safely cast to the
    returned dtype without loss of information.

    Args:
        arrays:
            Input arrays.

    Return:
        Data type code.

    Examples:
        >>> scalar = numpy.array(2, dtype=numpy.float32)
        >>> numpoly.common_type(scalar) is numpy.float32
        True
        >>> q0 = numpoly.variable()
        >>> numpoly.common_type(q0) is numpy.float64
        True
        >>> numpoly.common_type(q0, 1j) is numpy.complex128
        True

    """
    arrays_ = [numpoly.aspolynomial(array) for array in arrays]
    arrays_ = [array.values[array.keys[0]] for array in arrays_]
    return numpy.common_type(*arrays_)
Exemplo n.º 24
0
def diag(y: PolyLike, k: int = 0) -> ndpoly:
    """
    Extract a diagonal or construct a diagonal array.

    Args:
        v:
            If `v` is a 2-D array, return a copy of its `k`-th diagonal.
            If `v` is a 1-D array, return a 2-D array with `v` on the `k`-th
            diagonal.
        k:
            Diagonal in question. Use `k > 0` for diagonals above the main
            diagonal, and `k < 0` for diagonals below the main diagonal.

    Returns:
        The extracted diagonal or constructed diagonal array.

    Examples:
        >>> poly = numpoly.monomial(9).reshape(3, 3)
        >>> poly
        polynomial([[1, q0, q0**2],
                    [q0**3, q0**4, q0**5],
                    [q0**6, q0**7, q0**8]])
        >>> numpoly.diag(poly)
        polynomial([1, q0**4, q0**8])
        >>> numpoly.diag(poly, k=1)
        polynomial([q0, q0**5])
        >>> numpoly.diag(poly, k=-1)
        polynomial([q0**3, q0**7])

    """
    y = numpoly.aspolynomial(y)
    out = numpy.diag(y.values, k=k)
    return numpoly.polynomial(out, names=y.names)
Exemplo n.º 25
0
def to_sympy(poly: PolyLike) -> Any:
    """
    Convert numpoly object to sympy object, or array of sympy objects.

    Args:
        poly:
            Polynomial object to convert to sympy.

    Returns:
        If scalar, a sympy expression object, or if array, numpy.array with
        expression object values.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> poly = numpoly.polynomial([[1, q0**3], [q1-1, -3*q0]])
        >>> sympy_poly = to_sympy(poly)
        >>> sympy_poly
        array([[1, q0**3],
               [q1 - 1, -3*q0]], dtype=object)
        >>> type(sympy_poly.item(-1))
        <class 'sympy.core.mul.Mul'>

    """
    poly = numpoly.aspolynomial(poly)
    if poly.shape:
        return numpy.array([to_sympy(poly_) for poly_ in poly])
    from sympy import symbols  # type: ignore
    locals_ = dict(zip(poly.names, symbols(poly.names)))
    polynomial = eval(str(poly), locals_, {})  # pylint: disable=eval-used
    return polynomial
Exemplo n.º 26
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.º 27
0
def tonumpy(poly):
    """
    Cast polynomial to numpy.ndarray, if possible.

    Args:
        poly (numpoly.ndpoly):
            polynomial to cast.

    Returns:
        (numpy.ndarray):
            Numpy array.

    Raises:
        ValueError:
            Only constant polynomials can be cast to numpy.ndarray.

    Examples:
        >>> numpoly.tonumpy(numpoly.polynomial([1, 2]))
        array([1, 2])
        >>> numpoly.tonumpy(numpoly.symbols("x"))
        Traceback (most recent call last):
            ...
        ValueError: only constant polynomials can be converted to array.

    """
    poly = numpoly.aspolynomial(poly)
    if not poly.isconstant():
        raise ValueError(
            "only constant polynomials can be converted to array.")
    idx = numpy.argwhere(numpy.all(poly.exponents == 0, -1)).item()
    if poly.size:
        return numpy.array(poly.coefficients[idx])
    return numpy.array([])
Exemplo n.º 28
0
def reshape(
    a: PolyLike,
    newshape: Union[int, Sequence[int]],
    order: Order = "C",
) -> ndpoly:
    """
    Give a new shape to an array without changing its data.

    Args:
        a:
            Array to be reshaped.
        newshape:
            The new shape should be compatible with the original shape. If an
            integer, then the result will be a 1-D array of that length. One
            shape dimension can be -1. In this case, the value is inferred from
            the length of the array and remaining dimensions.
        order:
            Read the elements of `a` using this index order, and place the
            elements into the reshaped array using this index order.  'C' means
            to read / write the elements using C-like index order, with the
            last axis index changing fastest, back to the first axis index
            changing slowest. 'F' means to read / write the elements using
            Fortran-like index order, with the first index changing fastest,
            and the last index changing slowest. Note that the 'C' and 'F'
            options take no account of the memory layout of the underlying
            array, and only refer to the order of indexing. 'A' means to read
            / write the elements in Fortran-like index order if `a` is Fortran
            *contiguous* in memory, C-like order otherwise.

    Returns:
        This will be a new view object if possible; otherwise, it will be a
        copy.  Note there is no guarantee of the *memory layout* (C- or
        Fortran- contiguous) of the returned array.

    Examples:
        >>> numpoly.reshape([1, 2, 3, 4], (2, 2))
        polynomial([[1, 2],
                    [3, 4]])
        >>> numpoly.reshape(numpoly.monomial(6), (3, 2))
        polynomial([[1, q0],
                    [q0**2, q0**3],
                    [q0**4, q0**5]])

    """
    poly = numpoly.aspolynomial(a)
    array = numpy.reshape(poly.values, newshape=newshape, order=order)
    return numpoly.aspolynomial(array, names=poly.indeterminants)
Exemplo n.º 29
0
def sortable_proxy(
    poly: PolyLike,
    graded: bool = False,
    reverse: bool = False,
) -> numpy.ndarray:
    """
    Create a numerical proxy for a polynomial to allow compare.

    As polynomials are not inherently sortable, values are sorted using the
    highest `lexicographical` ordering. Between the values that have the same
    highest ordering, the elements are sorted using the coefficients. This also
    ensures that the method behaves as expected with ``numpy.ndarray``.

    Args:
        poly:
            Polynomial to convert into something sortable.
        graded:
            Graded sorting, meaning the indices are always sorted by the index
            sum. E.g. ``q0**2*q1**2*q2**2`` has an exponent sum of 6, and will
            therefore be consider larger than both ``q0**3*q1*q2``,
            ``q0*q1**3*q2`` and ``q0*q1*z**3``.
        reverse:
            Reverses lexicographical sorting meaning that ``q0*q1**3`` is
            considered bigger than ``q0**3*q1``, instead of the opposite.

    Returns:
        Integer array where ``a > b`` is retained for the giving rule of
        ``ordering``.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> poly = numpoly.polynomial(
        ...     [q0**2, 2*q0, 3*q1, 4*q0, 5])
        >>> numpoly.sortable_proxy(poly)
        array([3, 1, 4, 2, 0])
        >>> numpoly.sortable_proxy(poly, reverse=True)
        array([4, 2, 1, 3, 0])
        >>> numpoly.sortable_proxy([8, 4, 10, -100])
        array([2, 1, 3, 0])
        >>> numpoly.sortable_proxy([[8, 4], [10, -100]])
        array([[2, 1],
               [3, 0]])

    """
    poly = numpoly.aspolynomial(poly)
    coefficients = poly.coefficients
    proxy = numpy.tile(-1, poly.shape)
    largest = numpoly.lead_exponent(poly, graded=graded, reverse=reverse)

    for idx in numpoly.glexsort(
            poly.exponents.T, graded=graded, reverse=reverse):

        indices = numpy.all(largest == poly.exponents[idx], axis=-1)
        values = numpy.argsort(coefficients[idx][indices])
        proxy[indices] = numpy.argsort(values)+numpy.max(proxy)+1

    proxy = numpy.argsort(numpy.argsort(proxy.ravel())).reshape(proxy.shape)
    return proxy
Exemplo n.º 30
0
def repeat(
    a: PolyLike,
    repeats: numpy.typing.ArrayLike,
    axis: int = 0,
) -> ndpoly:
    """
    Repeat elements of an array.

    Args:
        a:
            Input array.
        repeats:
            The number of repetitions for each element. `repeats` is
            broadcasted to fit the shape of the given axis.
        axis:
            The axis along which to repeat values. By default, use the
            flattened input array, and return a flat output array.

    Returns:
        Output array which has the same shape as `a`, except along the
        given axis.

    Examples:
        >>> q0 = numpoly.variable()
        >>> numpoly.repeat(q0, 4)
        polynomial([q0, q0, q0, q0])
        >>> poly = numpoly.polynomial([[1, q0-1], [q0**2, q0]])
        >>> numpoly.repeat(poly, 2)
        polynomial([[1, q0-1],
                    [1, q0-1],
                    [q0**2, q0],
                    [q0**2, q0]])
        >>> numpoly.repeat(poly, 3, axis=1)
        polynomial([[1, 1, 1, q0-1, q0-1, q0-1],
                    [q0**2, q0**2, q0**2, q0, q0, q0]])
        >>> numpoly.repeat(poly, [1, 2], axis=0)
        polynomial([[1, q0-1],
                    [q0**2, q0],
                    [q0**2, q0]])

    """
    a = numpoly.aspolynomial(a)
    repeats = numpy.asarray(repeats)
    result = numpy.repeat(a.values, repeats=repeats, axis=axis)
    return numpoly.aspolynomial(result, names=a.indeterminants)