Beispiel #1
0
    def __getitem__(self, index: Any) -> "ndpoly":
        """
        Get array item or slice.

        Args:
            index:
                The index to extract.

        Returns:
            Polynomial array element.

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

        """
        return numpoly.polynomial_from_attributes(
            exponents=self.exponents,
            coefficients=[coeff[index] for coeff in self.coefficients],
            names=self.names,
        )
Beispiel #2
0
 def __iter__(self) -> Iterator["ndpoly"]:
     """Iterate polynomial array."""
     coefficients = numpy.array(list(self.coefficients))
     return iter(numpoly.polynomial_from_attributes(
         exponents=self.exponents,
         coefficients=coefficients[:, idx],
         names=self.names,
     ) for idx in range(len(self)))
Beispiel #3
0
def stack(
    arrays: Sequence[PolyLike],
    axis: int = 0,
    out: Optional[ndpoly] = None,
) -> ndpoly:
    """
    Join a sequence of arrays along a new axis.

    The ``axis`` parameter specifies the index of the new axis in the
    dimensions of the result. For example, if ``axis=0`` it will be the first
    dimension and if ``axis=-1`` it will be the last dimension.

    Args:
        arrays:
            Each array must have the same shape.
        axis:
            The axis in the result array along which the input arrays are
            stacked.
        out:
            If provided, the destination to place the result. The shape must be
            correct, matching that of what stack would have returned if no out
            argument were specified.

    Returns:
        The stacked array has one more dimension than the input arrays.

    Examples:
        >>> poly = numpoly.variable(3)
        >>> const = numpoly.polynomial([1, 2, 3])
        >>> numpoly.stack([poly, const])
        polynomial([[q0, q1, q2],
                    [1, 2, 3]])
        >>> numpoly.stack([poly, const], axis=-1)
        polynomial([[q0, 1],
                    [q1, 2],
                    [q2, 3]])

    """
    arrays = numpoly.align_exponents(*arrays)
    if out is None:
        coefficients = [numpy.stack(
            [array.values[key] for array in arrays], axis=axis)
                        for key in arrays[0].keys]
        out = numpoly.polynomial_from_attributes(
            exponents=arrays[0].exponents,
            coefficients=coefficients,
            names=arrays[0].names,
            dtype=coefficients[0].dtype,
        )
    else:
        for key in out.keys:
            if key in arrays[0].keys:
                numpy.stack([array.values[key] for array in arrays],
                            out=out.values[key], axis=axis)
    return out
Beispiel #4
0
 def astype(self, dtype: Any, **kwargs: Any) -> "ndpoly":  # type: ignore
     """Wrap ndarray.astype."""
     coefficients = [coefficient.astype(dtype, **kwargs)
                     for coefficient in self.coefficients]
     return numpoly.polynomial_from_attributes(
         exponents=self.exponents,
         coefficients=coefficients,
         names=self.names,
         allocation=self.allocation,
         dtype=dtype,
     )
Beispiel #5
0
def concatenate(
    arrays: Sequence[PolyLike],
    axis: int = 0,
    out: Optional[ndpoly] = None,
) -> ndpoly:
    """
    Join a sequence of arrays along an existing axis.

    Args:
        arrays:
            The arrays must have the same shape, except in the dimension
            corresponding to `axis` (the first, by default).
        axis:
            The axis along which the arrays will be joined.  If axis is None,
            arrays are flattened before use.  Default is 0.
        out:
            If provided, the destination to place the result. The shape must be
            correct, matching that of what concatenate would have returned if
            no out argument were specified.

    Returns:
        The concatenated array.

    Examples:
        >>> const = numpy.array([[1, 2], [3, 4]])
        >>> poly = numpoly.variable(2).reshape(1, 2)
        >>> numpoly.concatenate((const, poly), axis=0)
        polynomial([[1, 2],
                    [3, 4],
                    [q0, q1]])
        >>> numpoly.concatenate((const, poly.T), axis=1)
        polynomial([[1, 2, q0],
                    [3, 4, q1]])
        >>> numpoly.concatenate((const, poly), axis=None)
        polynomial([1, 2, 3, 4, q0, q1])

    """
    arrays = numpoly.align_exponents(*arrays)
    if out is None:
        coefficients = [numpy.concatenate(
            [array.values[key] for array in arrays], axis=axis)
                        for key in arrays[0].keys]
        out = numpoly.polynomial_from_attributes(
            exponents=arrays[0].exponents,
            coefficients=coefficients,
            names=arrays[0].names,
            dtype=coefficients[0].dtype,
        )
    else:
        for key in out.keys:
            if key in arrays[0].keys:
                numpy.concatenate([array.values[key] for array in arrays],
                                  out=out.values[key], axis=axis)
    return out
Beispiel #6
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,
    )
Beispiel #7
0
def dstack(tup: Sequence[PolyLike]) -> ndpoly:
    """
    Stack arrays in sequence depth wise (along third axis).

    This is equivalent to concatenation along the third axis after 2-D arrays
    of shape `(M,N)` have been reshaped to `(M,N,1)` and 1-D arrays of shape
    `(N,)` have been reshaped to `(1,N,1)`. Rebuilds arrays divided by
    `dsplit`.

    This function makes most sense for arrays with up to 3 dimensions. For
    instance, for pixel-data with a height (first axis), width (second axis),
    and r/g/b channels (third axis). The functions `concatenate`, `stack` and
    `block` provide more general stacking and concatenation operations.

    Args:
        tup:
            The arrays must have the same shape along all but the third axis.
            1-D or 2-D arrays must have the same shape.

    Returns:
        The array formed by stacking the given arrays, will be at least 3-D.

    Examples:
        >>> poly1 = numpoly.variable(3)
        >>> const1 = numpoly.polynomial([1, 2, 3])
        >>> numpoly.dstack([poly1, const1])
        polynomial([[[q0, 1],
                     [q1, 2],
                     [q2, 3]]])
        >>> const2 = numpoly.polynomial([[1], [2], [3]])
        >>> poly2 = poly1.reshape(3, 1)
        >>> numpoly.dstack([const2, poly2])
        polynomial([[[1, q0]],
        <BLANKLINE>
                    [[2, q1]],
        <BLANKLINE>
                    [[3, q2]]])

    """
    arrays = numpoly.align_exponents(*tup)
    coefficients = [numpy.dstack([array.values[key] for array in arrays])
                    for key in arrays[0].keys]
    return numpoly.polynomial_from_attributes(
        exponents=arrays[0].exponents,
        coefficients=coefficients,
        names=arrays[0].names,
        dtype=coefficients[0].dtype,
    )
Beispiel #8
0
def hstack(tup: Sequence[PolyLike]) -> ndpoly:
    """
    Stack arrays in sequence horizontally (column wise).

    This is equivalent to concatenation along the second axis, except for 1-D
    arrays where it concatenates along the first axis. Rebuilds arrays divided
    by `hsplit`.

    This function makes most sense for arrays with up to 3 dimensions. For
    instance, for pixel-data with a height (first axis), width (second axis),
    and r/g/b channels (third axis). The functions `concatenate`, `stack` and
    `block` provide more general stacking and concatenation operations.

    Args:
        tup:
            The arrays must have the same shape along all but the second axis,
            except 1-D arrays which can be any length.

    Returns:
        The array formed by stacking the given arrays.

    Examples:
        >>> poly1 = numpoly.variable(3)
        >>> const1 = numpoly.polynomial([1, 2, 3])
        >>> numpoly.hstack([poly1, const1])
        polynomial([q0, q1, q2, 1, 2, 3])
        >>> const2 = numpoly.polynomial([[1], [2], [3]])
        >>> poly2 = poly1.reshape(3, 1)
        >>> numpoly.hstack([const2, poly2])
        polynomial([[1, q0],
                    [2, q1],
                    [3, q2]])

    """
    arrays = numpoly.align_exponents(*tup)
    coefficients = [
        numpy.hstack([array.values[key] for array in arrays])
        for key in arrays[0].keys
    ]
    return numpoly.polynomial_from_attributes(
        exponents=arrays[0].exponents,
        coefficients=coefficients,
        names=arrays[0].names,
        dtype=coefficients[0].dtype,
    )
Beispiel #9
0
    def indeterminants(self) -> "ndpoly":
        """
        Polynomial indeterminants.

        Secondary polynomial only consisting of an array of simple independent
        variables found in the polynomial array.

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

        """
        return numpoly.polynomial_from_attributes(
            exponents=numpy.eye(len(self.names), dtype=int),
            coefficients=numpy.eye(len(self.names), dtype=int),
            names=self.names,
        )
Beispiel #10
0
    def from_attributes(
            exponents: numpy.typing.ArrayLike,
            coefficients: Sequence[numpy.typing.ArrayLike],
            names: Union[None, str, Tuple[str, ...], "ndpoly"] = None,
            dtype: Optional[numpy.typing.DTypeLike] = None,
            allocation: Optional[int] = None,
            retain_coefficients: Optional[bool] = None,
            retain_names: Optional[bool] = None,
    ) -> "ndpoly":
        """
        Construct polynomial from polynomial attributes.

        Args:
            exponents:
                The exponents in an integer array with shape ``(N, D)``, where
                ``N`` is the number of terms in the polynomial sum and ``D`` is
                the number of dimensions.
            coefficients:
                The polynomial coefficients. Must correspond to `exponents` by
                having the same length ``N``.
            names:
                The indeterminants names, either as string names or as
                simple polynomials. Must correspond to the exponents by having
                length 1 or ``D``. If omitted, use
                ``numpoly.get_options()["default_varname"]``.
            dtype:
                The data type of the polynomial. If omitted, extract from
                `coefficients`.
            allocation:
                The maximum number of polynomial exponents. If omitted, use
                length of exponents for allocation.
            retain_coefficients:
                Do not remove redundant coefficients. If omitted use global
                defaults.
            retain_names:
                Do not remove redundant names. If omitted use global defaults.

        Returns:
            Polynomials with attributes defined by input.

        Examples:
            >>> numpoly.ndpoly.from_attributes(
            ...     exponents=[[0]], coefficients=[4])
            polynomial(4)
            >>> numpoly.ndpoly.from_attributes(
            ...     exponents=[[1]], coefficients=[[1, 2, 3]])
            polynomial([q0, 2*q0, 3*q0])
            >>> numpoly.ndpoly.from_attributes(
            ...     exponents=[[0], [1]], coefficients=[[0, 1], [1, 1]])
            polynomial([q0, q0+1])
            >>> numpoly.ndpoly.from_attributes(
            ...     exponents=[[0, 1], [1, 1]], coefficients=[[0, 1], [1, 1]])
            polynomial([q0*q1, q0*q1+q1])

        """
        return numpoly.polynomial_from_attributes(
            exponents=exponents,
            coefficients=coefficients,
            names=names,
            dtype=dtype,
            allocation=allocation,
            retain_coefficients=retain_coefficients,
            retain_names=retain_names,
        )
Beispiel #11
0
def set_dimensions(poly: PolyLike, dimensions: Optional[int] = None) -> ndpoly:
    """
    Adjust the dimensions of a polynomial.

    Args:
        poly:
            Input polynomial
        dimensions:
            The dimensions of the output polynomial. If omitted, increase
            polynomial with one dimension.

    Returns:
        Polynomials with no internal dimensions. Unless the new dim is smaller
        then `poly`'s dimensions, the polynomial should have the same content.

    Examples:
        >>> q0, q1 = numpoly.variable(2)
        >>> poly = q0*q1-q0**2
        >>> numpoly.set_dimensions(poly, 1)
        polynomial(-q0**2)
        >>> numpoly.set_dimensions(poly, 3)
        polynomial(q0*q1-q0**2)
        >>> numpoly.set_dimensions(poly).names
        ('q0', 'q1', 'q2')

    """
    poly = numpoly.aspolynomial(poly)
    if dimensions is None:
        dimensions = len(poly.names)+1
    diff = dimensions-len(poly.names)
    if diff > 0:
        padding = numpy.zeros((len(poly.exponents), diff), dtype="uint32")
        exponents = numpy.hstack([poly.exponents, padding])
        coefficients = poly.coefficients
        varname = numpoly.get_options()["default_varname"]
        names_ = list(poly.names)
        idx = 0
        while len(names_) < dimensions:
            if f"{varname}{idx}" not in names_:
                names_.append(f"{varname}{idx}")
            idx += 1

        indices = numpy.lexsort([names_])
        exponents = exponents[:, indices]
        names = tuple(names_[idx] for idx in indices)

    elif diff < 0:
        indices = True ^ numpy.any(poly.exponents[:, dimensions:], -1)
        exponents = poly.exponents[:, :dimensions]
        exponents = exponents[indices]
        coefficients = [
            coeff for coeff, idx in zip(poly.coefficients, indices) if idx]
        names = poly.names[:dimensions]

    else:
        return poly

    return numpoly.polynomial_from_attributes(
        exponents=exponents,
        coefficients=coefficients,
        names=names,
        dtype=poly.dtype,
        allocation=poly.allocation,
        retain_names=True,
    )