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
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
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
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_