Exemplo n.º 1
0
 def _mom(self, kloc, dist, scale, shift, parameters):
     del parameters
     poly = numpoly.variable(len(self))
     poly = numpoly.sum(scale*poly, axis=-1)+shift
     poly = numpoly.set_dimensions(numpoly.prod(poly**kloc), len(self))
     out = sum(dist._get_mom(key)*coeff
               for key, coeff in zip(poly.exponents, poly.coefficients))
     return out
Exemplo n.º 2
0
    def _mom(self, kloc, mean, sigma, cache):
        poly = numpoly.variable(len(self))
        cholesky = numpy.linalg.cholesky(self._covariance)
        poly = numpoly.sum(cholesky * poly, axis=-1) + mean

        poly = numpoly.set_dimensions(numpoly.prod(poly**kloc), len(self))
        out = sum(
            self._dist.mom(key) * coeff
            for key, coeff in zip(poly.exponents, poly.coefficients))
        return out
def orth_ttr(order,
             dist,
             normed=False,
             graded=True,
             reverse=True,
             retall=False,
             cross_truncation=1.,
             sort=None,
             **kws):
    """
    Create orthogonal polynomial expansion from three terms recurrence formula.

    Args:
        order (int):
            Order of polynomial expansion.
        dist (Distribution):
            Distribution space where polynomials are orthogonal If dist.ttr
            exists, it will be used. Must be stochastically independent.
        normed (bool):
            If True orthonormal polynomials will be used.
        graded (bool):
            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**2*q1*q2``,
            ``q0*q1**2*q2`` and ``q0*q1*q2**2``, which all have exponent sum of
            5.
        reverse (bool):
            Reverse lexicographical sorting meaning that ``q0*q1**3`` is
            considered bigger than ``q0**3*q1``, instead of the opposite.
        retall (bool):
            If true return numerical stabilized norms as well. Roughly the same
            as ``cp.E(orth**2, dist)``.
        cross_truncation (float):
            Use hyperbolic cross truncation scheme to reduce the number of
            terms in expansion. only include terms where the exponents ``K``
            satisfied the equation
            ``order >= sum(K**(1/cross_truncation))**cross_truncation``.

    Returns:
        (numpoly.ndpoly, numpy.ndarray):
            Orthogonal polynomial expansion. Norms of the orthogonal
            expansion on the form ``E(orth**2, dist)``. Calculated using
            recurrence coefficients for stability.

    Examples:
        >>> distribution = chaospy.J(chaospy.Normal(), chaospy.Normal())
        >>> polynomials, norms = chaospy.orth_ttr(2, distribution, retall=True)
        >>> polynomials.round(10)
        polynomial([1.0, q1, q0, q1**2-1.0, q0*q1, q0**2-1.0])
        >>> norms.round(10)
        array([1., 1., 1., 2., 1., 2.])
        >>> polynomials = chaospy.orth_ttr(2, distribution, normed=True)
        >>> polynomials.round(3)
        polynomial([1.0, q1, q0, 0.707*q1**2-0.707, q0*q1, 0.707*q0**2-0.707])

    """
    logger = logging.getLogger(__name__)
    if sort is not None:
        logger.warning("deprecation warning: 'sort' argument is deprecated; "
                       "use 'graded' and/or 'reverse' instead")
        graded = "G" in sort.upper()
        reverse = "R" not in sort.upper()

    try:
        _, polynomials, norms, = chaospy.quadrature.recurrence.analytical_stieljes(
            numpy.max(order), dist, normed=normed)
    except NotImplementedError:
        abscissas, weights = chaospy.quadrature.generate_quadrature(
            int(10000**(1 / len(dist))), dist, rule="fejer")
        _, polynomials, norms, = chaospy.quadrature.recurrence.discretized_stieltjes(
            numpy.max(order), abscissas, weights, normed=normed)

    polynomials = polynomials.reshape((len(dist), numpy.max(order) + 1))

    order = numpy.array(order)
    indices = numpoly.glexindex(start=0,
                                stop=order + 1,
                                dimensions=len(dist),
                                graded=graded,
                                reverse=reverse,
                                cross_truncation=cross_truncation)
    if len(dist) > 1:
        polynomials = numpoly.prod(
            chaospy.polynomial(
                [poly[idx] for poly, idx in zip(polynomials, indices.T)]), 0)
        norms = numpy.prod(
            [norms_[idx] for norms_, idx in zip(norms, indices.T)], 0)
    else:
        polynomials = polynomials.flatten()
        norms = norms.flatten()

    if retall:
        return polynomials, norms
    return polynomials
Exemplo n.º 4
0
def orth_ttr(order,
             dist,
             normed=False,
             graded=True,
             reverse=True,
             retall=False,
             cross_truncation=1.):
    """
    Create orthogonal polynomial expansion from three terms recurrence formula.

    Args:
        order (int):
            Order of polynomial expansion.
        dist (Distribution):
            Distribution space where polynomials are orthogonal If dist.ttr
            exists, it will be used. Must be stochastically independent.
        normed (bool):
            If True orthonormal polynomials will be used.
        graded (bool):
            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**2*q1*q2``,
            ``q0*q1**2*q2`` and ``q0*q1*q2**2``, which all have exponent sum of
            5.
        reverse (bool):
            Reverse lexicographical sorting meaning that ``q0*q1**3`` is
            considered bigger than ``q0**3*q1``, instead of the opposite.
        retall (bool):
            If true return numerical stabilized norms as well. Roughly the same
            as ``cp.E(orth**2, dist)``.
        cross_truncation (float):
            Use hyperbolic cross truncation scheme to reduce the number of
            terms in expansion. only include terms where the exponents ``K``
            satisfied the equation
            ``order >= sum(K**(1/cross_truncation))**cross_truncation``.

    Returns:
        (numpoly.ndpoly, numpy.ndarray):
            Orthogonal polynomial expansion. Norms of the orthogonal
            expansion on the form ``E(orth**2, dist)``. Calculated using
            recurrence coefficients for stability.

    Examples:
        >>> distribution = chaospy.J(chaospy.Normal(), chaospy.Normal())
        >>> polynomials, norms = chaospy.orth_ttr(2, distribution, retall=True)
        >>> polynomials.round(10)
        polynomial([1.0, q1, q0, q1**2-1.0, q0*q1, q0**2-1.0])
        >>> norms.round(10)
        array([1., 1., 1., 2., 1., 2.])
        >>> polynomials = chaospy.orth_ttr(2, distribution, normed=True)
        >>> polynomials.round(3)
        polynomial([1.0, q1, q0, 0.707*q1**2-0.707, q0*q1, 0.707*q0**2-0.707])

    """
    _, polynomials, norms, = chaospy.stieltjes(numpy.max(order), dist)
    if normed:
        polynomials = numpoly.true_divide(polynomials, numpy.sqrt(norms))
        norms[:] = 1.

    polynomials = polynomials.reshape((len(dist), numpy.max(order) + 1))

    order = numpy.array(order)
    indices = numpoly.glexindex(start=0,
                                stop=order + 1,
                                dimensions=len(dist),
                                graded=graded,
                                reverse=reverse,
                                cross_truncation=cross_truncation)
    if len(dist) > 1:
        polynomials = numpoly.prod(
            chaospy.polynomial(
                [poly[idx] for poly, idx in zip(polynomials, indices.T)]), 0)
        norms = numpy.prod(
            [norms_[idx] for norms_, idx in zip(norms, indices.T)], 0)
    else:
        polynomials = polynomials.flatten()
        norms = norms.flatten()

    if retall:
        return polynomials, norms
    return polynomials
Exemplo n.º 5
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_