Пример #1
0
def test_align_polynomials():
    poly1 = 5 + 3 * Y + 3 * X
    poly2 = 4.
    poly1_, poly2_ = numpoly.align_polynomials(poly1, poly2)
    assert poly1 == poly1_
    assert poly2 == poly2_
    assert numpy.all(poly1_.exponents == poly2_.exponents)
    assert poly1_.exponents.shape[-1] == 2
    assert poly1_.shape == poly2_.shape

    X_, Y_ = numpoly.align_polynomials(X, Y)
    assert not X_.shape
    assert not Y_.shape
    assert X_ == X
    assert Y_ == Y
Пример #2
0
def divmod(
    x1: PolyLike,
    x2: PolyLike,
    out: Union[None, ndpoly, Tuple[ndpoly, ...]] = None,
    where: Optional[numpy.ndarray] = numpy.array(True),
    **kwargs: Any,
) -> Tuple[ndpoly, ndpoly]:
    """
    Return element-wise quotient and remainder simultaneously.

    ``numpoly.divmod(x, y)`` is equivalent to ``(x // y, x % y)``, but faster
    because it avoids redundant work. It is used to implement the Python
    built-in function ``divmod`` on arrays.

    Args:
        x1:
            Dividend array.
        x2:
            Divisor array. 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:
        Element-wise quotient and remainder resulting from floor division.

    Raises:
        numpoly.baseclass.FeatureNotSupported:
            If either `x1` or `x2` contains indeterminants, numerical division
            is no longer possible and an error is raised instead. For
            polynomial division-remainder see ``numpoly.poly_divmod``.

    Examples:
        >>> numpoly.divmod([1, 22, 444], 4)
        (polynomial([0, 5, 111]), polynomial([1, 2, 0]))

    """
    del out
    x1, x2 = numpoly.align_polynomials(x1, x2)
    if not x1.isconstant() or not x2.isconstant():
        raise numpoly.FeatureNotSupported(DIVMOD_ERROR_MSG)
    quotient, remainder = numpy.divmod(x1.tonumpy(),
                                       x2.tonumpy(),
                                       where=where,
                                       **kwargs)
    return numpoly.polynomial(quotient), numpoly.polynomial(remainder)
Пример #3
0
def equal(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[numpy.ndarray] = None,
    where: numpy.typing.ArrayLike = True,
    **kwargs: Any,
) -> numpy.ndarray:
    """
    Return (x1 == 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:
        Output array, element-wise comparison of `x1` and `x2`. Typically of
        type bool, unless ``dtype=object`` is passed. This is a scalar if both
        `x1` and `x2` are scalars.

    Examples:
        >>> q0, q1, q2 = q0q1q2 = numpoly.variable(3)
        >>> numpoly.equal(q0q1q2, q0)
        array([ True, False, False])
        >>> numpoly.equal(q0q1q2, [q1, q1, q2])
        array([False,  True,  True])
        >>> numpoly.equal(q0, q1)
        False

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    if out is None:
        out = numpy.ones(x1.shape, dtype=bool)
    if not out.shape:
        return equal(x1.ravel(), x2.ravel(), out=out.ravel()).item()
    for coeff1, coeff2 in zip(x1.coefficients, x2.coefficients):
        out &= numpy.equal(coeff1,
                           coeff2,
                           where=numpy.asarray(where),
                           **kwargs)
    return out
Пример #4
0
def remainder(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[ndpoly] = None,
    where: numpy.typing.ArrayLike = True,
    **kwargs: Any,
) -> ndpoly:
    """
    Return element-wise remainder of numerical division.

    Args:
        x1:
            Dividend array.
        x2:
            Divisor array. 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:
        The element-wise remainder of the quotient ``floor_divide(x1, x2)``.
        This is a scalar if both `x1` and `x2` are scalars.

    Examples:
        >>> numpoly.remainder([14, 7], 5)
        polynomial([4, 2])
        >>> numpoly.remainder(numpoly.variable(), 2)  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
            ...
        numpoly.baseclass.FeatureNotSupported: Polynomial division ...
        Use ``numpoly.poly_remainder`` to get polynomial remainder.

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    if not x1.isconstant() or not x2.isconstant():
        raise numpoly.FeatureNotSupported(REMAINDER_ERROR_MSG)
    where = None if where is None else numpy.asarray(where)
    return numpoly.polynomial(
        numpy.remainder(x1.tonumpy(),
                        x2.tonumpy(),
                        out=out,
                        where=where,
                        **kwargs))
Пример #5
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
Пример #6
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
Пример #7
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_)
Пример #8
0
def simple_dispatch(
        numpy_func,
        inputs,
        out=None,
        **kwargs
):
    """
    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 (Callable):
            The numpy function to evaluate `inputs` on.
        inputs (Iterable[numpoly.ndpoly]):
            One or more input arrays.
        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.
        kwargs:
            Keyword args passed to `numpy_func`.

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

    """
    inputs = numpoly.align_polynomials(*inputs)
    no_output = out is None
    for key in inputs[0].keys:

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

    if no_output:
        out = numpoly.clean_attributes(out)
    return out
Пример #9
0
def where(condition: numpy.typing.ArrayLike, *args: PolyLike) -> ndpoly:
    """
    Return elements chosen from `x` or `y` depending on `condition`.

    .. note::
        When only `condition` is provided, this function is a shorthand for
        ``np.asarray(condition).nonzero()``. Using `nonzero` directly should be
        preferred, as it behaves correctly for subclasses. The rest of this
        documentation covers only the case where all three arguments a re
        provided.

    Args:
        condition:
            Where True, yield `x`, otherwise yield `y`.
        x:
            Values from which to choose. `x`, `y` and `condition` need to be
            broadcastable to some shape.

    Returns:
        An array with elements from `x` where `condition` is True,
        and elements from `y` elsewhere.

    Examples:
        >>> poly = numpoly.variable()*numpy.arange(4)
        >>> poly
        polynomial([0, q0, 2*q0, 3*q0])
        >>> numpoly.where([1, 0, 1, 0], 7, 2*poly)
        polynomial([7, 2*q0, 7, 6*q0])
        >>> numpoly.where(poly, 2*poly, 4)
        polynomial([4, 2*q0, 4*q0, 6*q0])
        >>> numpoly.where(poly)
        (array([1, 2, 3]),)

    """
    if isinstance(condition, numpoly.ndpoly):
        condition = numpy.any(numpy.asarray(condition.coefficients),
                              0).astype(bool)
    if not args:
        return numpy.where(condition)

    poly1, poly2 = numpoly.align_polynomials(*args)
    coefficients = [
        numpy.where(condition, x1, x2)
        for x1, x2 in zip(poly1.coefficients, poly2.coefficients)
    ]
    dtype = numpy.result_type(poly1.dtype, poly2.dtype)
    return numpoly.polynomial_from_attributes(
        exponents=poly1.exponents,
        coefficients=coefficients,
        names=poly1.names,
        dtype=dtype,
    )
Пример #10
0
def equal(x1, x2, out=None, where=True, **kwargs):
    """
    Return (x1 == x2) element-wise.

    Args:
        x1, x2 (numpoly.ndpoly):
            Input arrays. 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:
        (Union[numpy.ndarray, numpy.generic]):
            Output array, element-wise comparison of `x1` and `x2`. Typically
            of type bool, unless ``dtype=object`` is passed. This is a scalar
            if both `x1` and `x2` are scalars.

    Examples:
        >>> x, y, z = xyz = numpoly.symbols("x y z")
        >>> numpoly.equal(xyz, x)
        array([ True, False, False])
        >>> numpoly.equal(xyz, [y, y, z])
        array([False,  True,  True])
        >>> numpoly.equal(x, y)
        array(False)

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    if out is None:
        out = numpy.ones(x1.shape, dtype=bool)
    for coeff1, coeff2 in zip(x1.coefficients, x2.coefficients):
        out &= numpy.equal(coeff1, coeff2, where=where, **kwargs)
    return out
Пример #11
0
def divide(x1, x2, out=None, where=True, **kwargs):
    """
    Return a true division of the inputs, element-wise.

    Instead of the Python traditional 'floor division', this returns a true
    division.  True division adjusts the output type to present the best
    answer, regardless of input types.

    Args:
        x1 (numpoly.ndpoly):
            Dividend array.
        x2 (numpoly.ndpoly):
            Divisor array. If ``x1.shape != x2.shape``, they must be
            broadcastable to a commo n 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):
            This is a scalar if both `x1` and `x2` are scalars.

    Examples:
        >>> xyz = numpoly.symbols("x y z")
        >>> numpoly.divide(xyz, 4)
        polynomial([0.25*x, 0.25*y, 0.25*z])
        >>> numpoly.divide(xyz, [1, 2, 4])
        polynomial([x, 0.5*y, 0.25*z])
        >>> numpoly.divide([1, 2, 4], xyz)
        Traceback (most recent call last):
            ...
        ValueError: only constant polynomials can be converted to array.

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    x2 = x2.tonumpy()
    no_output = out is None
    if no_output:
        out = numpoly.ndpoly(
            exponents=x1.exponents,
            shape=x1.shape,
            names=x1.indeterminants,
            dtype=numpy.common_type(x1, numpy.array(1.)),
        )
    elif not isinstance(out, numpy.ndarray):
        assert len(out) == 1, "only one output"
        out = out[0]
    for key in x1.keys:
        out[key] = 0
        numpy.true_divide(x1[key], x2, out=out[key], where=where, **kwargs)
    if no_output:
        out = numpoly.clean_attributes(out)
    return out
Пример #12
0
def greater(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[numpy.ndarray] = None,
    **kwargs: Any,
) -> numpy.ndarray:
    """
    Return the truth value of (x1 > 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:
        Output array, element-wise comparison of `x1` and `x2`. Typically of
        type bool, unless ``dtype=object`` is passed. This is a scalar if both
        `x1` and `x2` are scalars.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> numpoly.greater(3, 4)
        False
        >>> numpoly.greater(4*q0, 3*q0)
        True
        >>> numpoly.greater(q0, q1)
        False
        >>> numpoly.greater(q0**2, q0)
        True
        >>> numpoly.greater([1, q0, q0**2, q0**3], q1)
        array([False, False,  True,  True])
        >>> numpoly.greater(q0+1, q0-1)
        True
        >>> numpoly.greater(q0, q0)
        False

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    coefficients1 = x1.coefficients
    coefficients2 = x2.coefficients
    if out is None:
        out = numpy.greater(coefficients1[0], coefficients2[0], **kwargs)
    if not out.shape:
        return greater(x1.ravel(), x2.ravel(), out=out.ravel()).item()

    options = numpoly.get_options()
    for idx in numpoly.glexsort(x1.exponents.T,
                                graded=options["sort_graded"],
                                reverse=options["sort_reverse"]):

        indices = (coefficients1[idx] != 0) | (coefficients2[idx] != 0)
        indices &= coefficients1[idx] != coefficients2[idx]
        out[indices] = numpy.greater(coefficients1[idx], coefficients2[idx],
                                     **kwargs)[indices]
    return out
Пример #13
0
def floor_divide(x1, x2, out=None, where=True, **kwargs):
    """
    Return the largest integer smaller or equal to the division of the inputs.

    It is equivalent to the Python ``//`` operator and pairs with the
    Python ``%`` (`remainder`), function so that ``a = a % b + b * (a // b)``
    up to roundoff.

    Args:
        x1 (numpoly.ndpoly):
            Numerator.
        x2 (numpoly.ndpoly):
            Denominator. 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):
            This is a scalar if both `x1` and `x2` are scalars.

    Examples:
        >>> xyz = [1, 2, 4]*numpoly.symbols("x y z")
        >>> numpoly.floor_divide(xyz, 2.)
        polynomial([0.0, y, 2.0*z])
        >>> numpoly.floor_divide(xyz, [1, 2, 4])
        polynomial([x, y, z])
        >>> numpoly.floor_divide([1, 2, 4], xyz)
        Traceback (most recent call last):
            ...
        ValueError: only constant polynomials can be converted to array.

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    x2 = x2.tonumpy()
    no_output = out is None
    if no_output:
        out = numpoly.ndpoly(
            exponents=x1.exponents,
            shape=x1.shape,
            names=x1.indeterminants,
            dtype=numpy.common_type(x1, numpy.array(1.)),
        )
    for key in x1.keys:
        numpy.floor_divide(x1[key], x2, out=out[key], where=where, **kwargs)
    if no_output:
        out = numpoly.clean_attributes(out)
    return out
Пример #14
0
def allclose(a, b, rtol=1e-5, atol=1e-8, equal_nan=False):
    """
    Return True if two arrays are element-wise equal within a tolerance.

    The tolerance values are positive, typically very small numbers.  The
    relative difference (`rtol` * abs(`b`)) and the absolute difference
    `atol` are added together to compare against the absolute difference
    between `a` and `b`.

    If either array contains one or more NaNs, False is returned.
    Infs are treated as equal if they are in the same place and of the same
    sign in both arrays.

    Args:
        a, b (numpoly.ndpoly):
            Input arrays to compare.
        rtol (float):
            The relative tolerance parameter (see Notes).
        atol : float
            The absolute tolerance parameter (see Notes).
        equal_nan : bool
            Whether to compare NaN's as equal.  If True, NaN's in `a` will be
            considered equal to NaN's in `b` in the output array.

    Returns:
        (bool):
            Returns True if the two arrays are equal within the given
            tolerance; False otherwise.

    Notes:
        If the following equation is element-wise True, then allclose returns
        True.

        absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))

        The above equation is not symmetric in `a` and `b`, so that
        ``allclose(a, b)`` might be different from ``allclose(b, a)`` in some
        rare cases.

        The comparison of `a` and `b` uses standard broadcasting, which means
        that `a` and `b` need not have the same shape in order for
        ``allclose(a, b)`` to evaluate to True.  The same is true for `equal`
        but not `array_equal`.

    Examples:
        >>> x, y = numpoly.symbols("x y")
        >>> numpoly.allclose([1e10*x, 1e-7], [1.00001e10*x, 1e-8])
        False
        >>> numpoly.allclose([1e10*x, 1e-8], [1.00001e10*x, 1e-9])
        True
        >>> numpoly.allclose([1e10*x, 1e-8], [1.00001e10*y, 1e-9])
        False
        >>> numpoly.allclose([x, numpy.nan],
        ...                  [x, numpy.nan], equal_nan=True)
        True

    """
    a, b = numpoly.align_polynomials(a, b)
    for coeff1, coeff2 in zip(a.coefficients, b.coefficients):
        if not numpy.allclose(
                coeff1, coeff2, atol=atol, rtol=rtol, equal_nan=equal_nan):
            return False
    return True
Пример #15
0
def floor_divide(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[ndpoly] = None,
    where: Optional[numpy.ndarray] = numpy.array(True),
    **kwargs: Any,
) -> ndpoly:
    """
    Return the largest integer smaller or equal to the division of the inputs.

    It is equivalent to the Python ``//`` operator and pairs with the
    Python ``%`` (`remainder`), function so that ``a = a % b + b * (a // b)``
    up to roundoff.

    Args:
        x1:
            Dividend.
        x2:
            Divisor. 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:
        This is a scalar if both `x1` and `x2` are scalars.

    Raises:
        ValueError:
            If `x2` contains indeterminants, numerical division is no longer
            possible and an error is raised instead. For polynomial
            division see ``numpoly.poly_divide``.

    Examples:
        >>> numpoly.floor_divide([1, 3, 5], 2)
        polynomial([0, 1, 2])
        >>> poly = [1, 2, 4]*numpoly.variable(3)
        >>> poly
        polynomial([q0, 2*q1, 4*q2])
        >>> numpoly.floor_divide(poly, 2.)
        polynomial([0.0, q1, 2.0*q2])
        >>> numpoly.floor_divide(poly, [1, 2, 4])
        polynomial([q0, q1, q2])

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    if not x2.isconstant():
        raise numpoly.FeatureNotSupported(DIVIDE_ERROR_MSG)
    x2 = x2.tonumpy()
    dtype = numpy.common_type(x1, x2)
    if x1.dtype == x2.dtype == "int64":
        dtype = "int64"
    no_output = out is None
    if out is None:
        out = numpoly.ndpoly(
            exponents=x1.exponents,
            shape=x1.shape,
            names=x1.indeterminants,
            dtype=dtype,
        )
    assert isinstance(out, numpoly.ndpoly)
    for key in x1.keys:
        out.values[key] = 0
        numpy.floor_divide(x1.values[key],
                           x2,
                           out=out.values[key],
                           where=where,
                           **kwargs)
    if no_output:
        out = numpoly.clean_attributes(out)
    return out
Пример #16
0
def poly_divmod(
    dividend: PolyLike,
    divisor: PolyLike,
    out: Tuple[Optional[ndpoly], Optional[ndpoly]] = (None, None),
    where: numpy.typing.ArrayLike = True,
    **kwargs: Any,
) -> Tuple[ndpoly, ndpoly]:
    """
    Return element-wise quotient and remainder simultaneously.

    ``numpoly.divmod(x, y)`` is equivalent to ``(x / y, x % y)``, but faster
    because it avoids redundant work. It is used to implement the Python
    built-in function ``divmod`` on Numpoly arrays.

    Notes:
        Unlike numbers, this returns the polynomial division and polynomial
        remainder. This means that this function is _not_ backwards compatible
        with ``numpy.divmod`` for constants. For example:
        ``numpy.divmod(11, 2) == (5, 1)`` while
        ``numpoly.divmod(11, 2) == (5.5, 0)``.

    Args:
        dividend:
            The array being divided.
        divisor:
            Array that that will divide the dividend.
        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:
        Element-wise quotient and remainder resulting from floor division. This
        is a scalar if both `x1` and `x2` are scalars.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> denominator = [q0*q1**2+2*q0**3*q1**2, -2+q0*q1**2]
        >>> numerator = -2+q0*q1**2
        >>> floor, remainder = numpoly.poly_divmod(
        ...     denominator, numerator)
        >>> floor
        polynomial([2.0*q0**2+1.0, 1.0])
        >>> remainder
        polynomial([4.0*q0**2+2.0, 0.0])
        >>> floor*numerator+remainder
        polynomial([2.0*q0**3*q1**2+q0*q1**2, q0*q1**2-2.0])

    """
    assert where is True, "changing 'where' is not supported."
    dividend_, divisor = numpoly.align_polynomials(dividend, divisor)

    if not dividend_.shape:
        floor, remainder = poly_divmod(
            dividend_.ravel(),
            divisor.ravel(),
            out=out,
            where=where,
            **kwargs,
        )
        return floor[0], remainder[0]

    quotient = numpoly.zeros(dividend_.shape)
    while True:

        candidates = get_division_candidate(dividend_, divisor)
        if candidates is None:
            break
        idx1, idx2, include, candidate = candidates

        exponent_diff = dividend_.exponents[idx1] - divisor.exponents[idx2]
        candidate = candidate * numpoly.prod(
            divisor.indeterminants**exponent_diff, 0)
        key = dividend_.keys[idx1]

        quotient = numpoly.add(quotient, numpoly.where(include, candidate, 0),
                               **kwargs)
        dividend_ = numpoly.subtract(
            dividend_, numpoly.where(include, divisor * candidate, 0),
            **kwargs)

        # ensure the candidate values are actual zero
        if key in dividend_.keys:
            dividend_.values[key][include] = 0

        dividend_, divisor = numpoly.align_polynomials(dividend_, divisor)

    return quotient, dividend_
Пример #17
0
def true_divide(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[ndpoly] = None,
    where: numpy.typing.ArrayLike = True,
    **kwargs: Any,
) -> ndpoly:
    """
    Return true division of the inputs, element-wise.

    Instead of the Python traditional 'floor division', this returns a true
    division.  True division adjusts the output type to present the best
    answer, regardless of input types.

    Args:
        x1:
            Dividend array.
        x2:
            Divisor array. 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:
        This is a scalar if both `x1` and `x2` are scalars.

    Raises:
        numpoly.baseclass.FeatureNotSupported:
            If `x2` contains indeterminants, numerical division is no longer
            possible and an error is raised instead. For polynomial
            division see ``numpoly.poly_divide``.

    Examples:
        >>> q0q1q2 = numpoly.variable(3)
        >>> numpoly.true_divide(q0q1q2, 4)
        polynomial([0.25*q0, 0.25*q1, 0.25*q2])
        >>> numpoly.true_divide(q0q1q2, [1, 2, 4])
        polynomial([q0, 0.5*q1, 0.25*q2])

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    if not x2.isconstant():
        raise numpoly.FeatureNotSupported(DIVIDE_ERROR_MSG)
    x2 = x2.tonumpy()
    if out is None:
        out_ = numpoly.ndpoly(
            exponents=x1.exponents,
            shape=x1.shape,
            names=x1.indeterminants,
            dtype=numpy.common_type(x1, numpy.array(1.)),
        )
    else:
        assert len(out) == 1
        out_ = out[0]
    assert isinstance(out_, numpoly.ndpoly)
    for key in x1.keys:
        out_[key] = 0
        numpy.true_divide(x1.values[key],
                          x2,
                          out=out_.values[key],
                          where=numpy.asarray(where),
                          **kwargs)
    if out is None:
        out_ = numpoly.clean_attributes(out_)
    return out_
Пример #18
0
def isclose(a, b, rtol=1e-5, atol=1e-8, equal_nan=False):
    """
    Return true where two arrays are element-wise equal within a tolerance.

    The tolerance values are positive, typically very small numbers. The
    relative difference (`rtol` * abs(`b`)) and the absolute difference `atol`
    are added together to compare against the absolute difference between `a`
    and `b`.

    .. warning:: The default `atol` is not appropriate for comparing numbers
                that are much smaller than one (see Notes).

    Args:
        a, b (numpoly.ndpoly):
            Input arrays to compare.
        rtol (float):
            The relative tolerance parameter (see Notes).
        atol (float):
            The absolute tolerance parameter (see Notes).
        equal_nan (bool):
            Whether to compare NaN's as equal.  If True, NaN's in `a` will be
            considered equal to NaN's in `b` in the output array.

    Returns:
        (numpy.ndarray):
            Returns a boolean array of where `a` and `b` are equal within the
            given tolerance. If both `a` and `b` are scalars, returns a single
            boolean value.

    Notes:
        For finite values, isclose uses the following equation to test whether
        two floating point values are equivalent.

        absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))

        Unlike the built-in `math.isclose`, the above equation is not symmetric
        in `a` and `b` -- it assumes `b` is the reference value -- so that
        `isclose(a, b)` might be different from `isclose(b, a)`. Furthermore,
        the default value of atol is not zero, and is used to determine what
        small values should be considered close to zero. The default value is
        appropriate for expected values of order unity: if the expected values
        are significantly smaller than one, it can result in false positives.
        `atol` should be carefully selected for the use case at hand. A zero
        value for `atol` will result in `False` if either `a` or `b` is zero.

    Examples:
        >>> x, y = numpoly.symbols("x y")
        >>> numpoly.isclose([1e10*x, 1e-7], [1.00001e10*x, 1e-8])
        array([ True, False])
        >>> numpoly.isclose([1e10*x, 1e-8], [1.00001e10*x, 1e-9])
        array([ True,  True])
        >>> numpoly.isclose([1e10*x, 1e-8], [1.00001e10*y, 1e-9])
        array([False,  True])
        >>> numpoly.isclose([x, numpy.nan],
        ...                 [x, numpy.nan], equal_nan=True)
        array([ True,  True])

    """
    a, b = numpoly.align_polynomials(a, b)
    out = numpy.ones(a.shape, dtype=bool)
    for key in a.keys:
        out &= numpy.isclose(a[key],
                             b[key],
                             atol=atol,
                             rtol=rtol,
                             equal_nan=equal_nan)
    return out
Пример #19
0
def multiply(x1, x2, out=None, where=True, **kwargs):
    """
    Multiply arguments element-wise.

    Args:
        x1, x2 (numpoly.ndpoly):
            Input arrays to be multiplied. 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 product of `x1` and `x2`, element-wise. This is a scalar if
            both `x1` and `x2` are scalars.

    Examples:
        >>> x1 = numpy.arange(9.0).reshape((3, 3))
        >>> xyz = numpoly.symbols("x y z")
        >>> numpoly.multiply(x1, xyz)
        polynomial([[0.0, y, 2.0*z],
                    [3.0*x, 4.0*y, 5.0*z],
                    [6.0*x, 7.0*y, 8.0*z]])

    """
    x1, x2 = numpoly.align_polynomials(x1, x2)
    no_output = out is None
    if no_output:
        exponents = (numpy.tile(x1.exponents, (len(x2.exponents), 1)) +
                     numpy.repeat(x2.exponents, len(x1.exponents), 0))
        out = numpoly.ndpoly(
            exponents=numpy.unique(exponents, axis=0),
            shape=x1.shape,
            names=x1.indeterminants,
            dtype=x1.dtype,
        )

    seen = set()
    for expon1, coeff1 in zip(x1.exponents, x1.coefficients):
        for expon2, coeff2 in zip(x2.exponents, x2.coefficients):
            key = (expon1 + expon2 + x1.KEY_OFFSET).flatten()
            key = key.view("U%d" % len(expon1)).item()
            if key in seen:
                out[key] += numpy.multiply(coeff1,
                                           coeff2,
                                           where=where,
                                           **kwargs)
            else:
                numpy.multiply(coeff1,
                               coeff2,
                               out=out[key],
                               where=where,
                               **kwargs)
            seen.add(key)
    if no_output:
        out = numpoly.clean_attributes(out)
    return out
Пример #20
0
def minimum(
    x1: PolyLike,
    x2: PolyLike,
    out: Optional[ndpoly] = None,
    **kwargs: Any,
) -> ndpoly:
    """
    Element-wise minimum of array elements.

    Compare two arrays and returns a new array containing the element-wise
    minima. If one of the elements being compared is a NaN, then that
    element is returned. If both elements are NaNs then the first is
    returned. The latter distinction is important for complex NaNs, which
    are defined as at least one of the real or imaginary parts being a NaN.
    The net effect is that NaNs are propagated.

    Args:
        x1, x2 :
            The arrays holding the elements to be compared. 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:
        The minimum of `x1` and `x2`, element-wise. This is a scalar if
        both `x1` and `x2` are scalars.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> numpoly.minimum(3, 4)
        polynomial(3)
        >>> numpoly.minimum(4*q0, 3*q0)
        polynomial(3*q0)
        >>> numpoly.minimum(q0, q1)
        polynomial(q0)
        >>> numpoly.minimum(q0**2, q0)
        polynomial(q0)
        >>> numpoly.minimum([1, q0, q0**2, q0**3], q1)
        polynomial([1, q0, q1, q1])
        >>> numpoly.minimum(q0+1, q0-1)
        polynomial(q0-1)

    """
    del out
    x1, x2 = numpoly.align_polynomials(x1, x2)
    coefficients1 = x1.coefficients
    coefficients2 = x2.coefficients
    out_ = numpy.zeros(x1.shape, dtype=bool)

    options = numpoly.get_options()
    for idx in numpoly.glexsort(x1.exponents.T,
                                graded=options["sort_graded"],
                                reverse=options["sort_reverse"]):

        indices = (coefficients1[idx] != 0) | (coefficients2[idx] != 0)
        indices = coefficients1[idx] != coefficients2[idx]
        out_[indices] = (coefficients1[idx] < coefficients2[idx])[indices]
    return numpoly.where(out_, x1, x2)