def test_set_dimensions(): """Tests for numpoly.set_dimensions.""" assert numpoly.set_dimensions(POLY1).names == ("q0", "q1", "q2") assert numpoly.set_dimensions(POLY1, 1).names == ("q0", ) assert numpoly.set_dimensions(POLY1, 2).names == ("q0", "q1") assert numpoly.set_dimensions(POLY1, 3).names == ("q0", "q1", "q2") assert numpoly.set_dimensions(POLY1, 4).names == ("q0", "q1", "q2", "q3")
def Sens_m2(poly, dist, **kws): """ Variance-based decomposition/Sobol' indices. Second order sensitivity indices. Args: poly (numpoly.ndpoly): Polynomial to find second order Sobol indices on. dist (Dist): The distributions of the input used in ``poly``. Returns: (numpy.ndarray): First order sensitivity indices for each parameters in ``poly``, with shape ``(len(dist), len(dist)) + poly.shape``. Examples: >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0*q1, q0**3*q1, q0*q1**3]) >>> dist = chaospy.Iid(chaospy.Uniform(0, 1), 2) >>> chaospy.Sens_m2(poly, dist).round(4) array([[[0. , 0. , 0. , 0. ], [0. , 0.1429, 0.2093, 0.2093]], <BLANKLINE> [[0. , 0.1429, 0.2093, 0.2093], [0. , 0. , 0. , 0. ]]]) """ dim = len(dist) poly = numpoly.set_dimensions(poly, len(dist)) out = numpy.zeros((dim, dim) + poly.shape) variance = Var(poly, dist) valids = variance != 0 if not numpy.all(valids): out[:, :, valids] = Sens_m2(poly[valids], dist, **kws) return out conditional_v = numpy.zeros((dim, ) + poly.shape) for idx, unit_vec in enumerate(numpy.eye(dim, dtype=int)): conditional_e = E_cond(poly, unit_vec, dist, **kws) conditional_v[idx] = Var(conditional_e, dist, **kws) for idx, unit_vec1 in enumerate(numpy.eye(dim, dtype=int)): for idy, unit_vec2 in enumerate( numpy.eye(dim, dtype=int)[idx + 1:], idx + 1): conditional_e = E_cond(poly, unit_vec1 + unit_vec2, dist, **kws) out[idx, idy] = Var(conditional_e, dist, **kws) out[idx, idy] -= conditional_v[idx] out[idx, idy] -= conditional_v[idy] out[idx, idy] /= variance # copy upper matrix triangle down to lower triangle indices = numpy.tril_indices(dim, -1) out[indices] = numpy.swapaxes(out, 0, 1)[indices] return out
def Var(poly, dist=None, **kws): """ Element by element 2nd order statistics. Args: poly (numpoly.ndpoly, Distribution): Input to take variance on. dist (Distribution): Defines the space the variance is taken on. It is ignored if ``poly`` is a distribution. Returns: (numpy.ndarray): Element for element variance along ``poly``, where ``variation.shape == poly.shape``. Examples: >>> dist = chaospy.J(chaospy.Gamma(1, 1), chaospy.Normal(0, 2)) >>> chaospy.Var(dist) array([1., 4.]) >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1]) >>> chaospy.Var(poly, dist) array([ 0., 1., 4., 800.]) """ if dist is None: dist, poly = poly, numpoly.variable(len(poly)) poly = numpoly.set_dimensions(poly, len(dist)) if not poly.isconstant: return poly.tonumpy()**2 poly = poly-E(poly, dist, **kws) poly = numpoly.square(poly) return E(poly, dist, **kws)
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 Kurt(poly, dist=None, fisher=True, **kws): """ The forth order statistical moment Kurtosis. Element by element 4rd order statistics of a distribution or polynomial. Args: poly (numpoly.ndpoly, Distribution): Input to take kurtosis on. dist (Distribution): Defines the space the skewness is taken on. It is ignored if ``poly`` is a distribution. fisher (bool): If True, Fisher's definition is used (Normal -> 0.0). If False, Pearson's definition is used (normal -> 3.0) Returns: (numpy.ndarray): Element for element variance along ``poly``, where ``skewness.shape==poly.shape``. Examples: >>> dist = chaospy.J(chaospy.Gamma(1, 1), chaospy.Normal(0, 2)) >>> chaospy.Kurt(dist).round(4) array([6., 0.]) >>> chaospy.Kurt(dist, fisher=False).round(4) array([9., 3.]) >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1-1]) >>> chaospy.Kurt(poly, dist).round(4) array([nan, 6., 0., 15.]) >>> chaospy.Kurt(4., dist) array(nan) """ adjust = 3 if fisher else 0 if dist is None: dist, poly = poly, numpoly.variable(len(poly)) poly = numpoly.set_dimensions(poly, len(dist)) if poly.isconstant(): return numpy.full(poly.shape, numpy.nan) poly = poly - E(poly, dist, **kws) poly = numpoly.true_divide(poly, Std(poly, dist, **kws)) return E(poly**4, dist, **kws) - adjust
def E(poly, dist=None, **kws): """ The expected value of a distribution or polynomial. 1st order statistics of a probability distribution or polynomial on a given probability space. Args: poly (numpoly.ndpoly, Distribution): Input to take expected value on. dist (Distribution): Defines the space the expected value is taken on. It is ignored if ``poly`` is a distribution. Returns: (numpy.ndarray): The expected value of the polynomial or distribution, where ``expected.shape == poly.shape``. Examples: >>> dist = chaospy.J(chaospy.Gamma(1, 1), chaospy.Normal(0, 2)) >>> chaospy.E(dist) array([1., 0.]) >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1-1]) >>> chaospy.E(poly, dist) array([ 1., 1., 0., -1.]) """ if dist is None: dist, poly = poly, numpoly.variable(len(poly)) poly = numpoly.set_dimensions(poly, len(dist)) if poly.isconstant(): return poly.tonumpy() moments = dist.mom(poly.exponents.T, **kws) if len(dist) == 1: moments = moments[0] out = numpy.zeros(poly.shape) for idx, key in enumerate(poly.keys): out += poly[key] * moments[idx] return out
def Sens_t(poly, dist, **kws): """ Variance-based decomposition AKA Sobol' indices Total effect sensitivity index Args: poly (numpoly.ndpoly): Polynomial to find first order Sobol indices on. dist (Dist): The distributions of the input used in ``poly``. Returns: (numpy.ndarray) : First order sensitivity indices for each parameters in ``poly``, with shape ``(len(dist),) + poly.shape``. Examples: >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1-1]) >>> dist = chaospy.Iid(chaospy.Uniform(0, 1), 2) >>> chaospy.Sens_t(poly, dist) array([[0. , 1. , 0. , 0.57142857], [0. , 0. , 1. , 0.57142857]]) """ dim = len(dist) poly = numpoly.set_dimensions(poly, dim) out = numpy.zeros((dim, ) + poly.shape, dtype=float) variance = Var(poly, dist, **kws) valids = variance != 0 if not numpy.all(valids): out[:, valids] = Sens_t(poly[valids], dist, **kws) return out out[:] = variance for idx, unit_vec in enumerate(numpy.eye(dim, dtype=int)): conditional = E_cond(poly, 1 - unit_vec, dist, **kws) out[idx] -= Var(conditional, dist, **kws) out[idx] /= variance return out
def Cov(poly, dist=None, **kws): """ Variance/Covariance matrix of a distribution or polynomial array. Args: poly (numpoly.ndpoly, Distribution) : Input to take covariance on. Must have `len(poly)>=2`. dist (Distribution) : Defines the space the covariance is taken on. It is ignored if `poly` is a distribution. Returns: (numpy.ndarray): Covariance matrix with shape ``poly.shape+poly.shape``. Examples: >>> dist = chaospy.MvNormal([0, 0], [[2, .5], [.5, 1]]) >>> chaospy.Cov(dist) array([[2. , 0.5], [0.5, 1. ]]) >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1-1]) >>> chaospy.Cov(poly, dist) array([[ 0. , 0. , 0. , 0. ], [ 0. , 2. , 0.5, 0. ], [ 0. , 0.5, 1. , 0. ], [ 0. , 0. , 0. , 225. ]]) >>> chaospy.Cov([1, 2, 3], dist) array([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]) """ if dist is None: dist, poly = poly, numpoly.variable(len(poly)) poly = numpoly.set_dimensions(poly, len(dist)) if poly.isconstant(): return numpy.zeros((len(poly), len(poly))) poly = poly-E(poly, dist) poly = numpoly.outer(poly, poly) return E(poly, dist)
def Skew(poly, dist=None, **kws): """ The third order statistical moment Kurtosis. Element by element 3rd order statistics of a distribution or polynomial. Args: poly (numpoly.ndpoly, Distribution): Input to take skewness on. dist (Distribution): Defines the space the skewness is taken on. It is ignored if ``poly`` is a distribution. Returns: (numpy.ndarray): Element for element variance along ``poly``, where ``skewness.shape == poly.shape``. Examples: >>> dist = chaospy.J(chaospy.Gamma(1, 1), chaospy.Normal(0, 2)) >>> chaospy.Skew(dist) array([2., 0.]) >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1-1]) >>> chaospy.Skew(poly, dist) array([nan, 2., 0., 0.]) >>> chaospy.Skew(2., dist) array(nan) """ if dist is None: dist, poly = poly, numpoly.variable(len(poly)) poly = numpoly.set_dimensions(poly, len(dist)) if poly.isconstant(): return numpy.full(poly.shape, numpy.nan) poly = poly - E(poly, dist, **kws) poly = numpoly.true_divide(poly, Std(poly, dist, **kws)) return E(poly**3, dist, **kws)
def Sens_m(poly, dist, **kws): """ Variance-based decomposition/Sobol' indices. First order sensitivity indices. Args: poly (numpoly.ndpoly): Polynomial to find first order Sobol indices on. dist (Dist): The distributions of the input used in ``poly``. Returns: (numpy.ndarray): First order sensitivity indices for each parameters in ``poly``, with shape ``(len(dist),) + poly.shape``. Examples: >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1-1]) >>> distribution = chaospy.Iid(chaospy.Uniform(0, 1), 2) >>> chaospy.Sens_m(poly, distribution) array([[0. , 1. , 0. , 0.42857143], [0. , 0. , 1. , 0.42857143]]) """ dim = len(dist) poly = numpoly.set_dimensions(poly, dim) out = numpy.zeros((dim, ) + poly.shape) variance = Var(poly, dist, **kws) valids = variance != 0 for idx, unit_vec in enumerate(numpy.eye(dim, dtype=int)): conditional = E_cond(poly[valids], unit_vec, dist, **kws) out[idx, valids] = Var(conditional, dist, **kws) out[idx, valids] /= variance[valids] return out
def E_cond(poly, freeze, dist, **kws): """ Conditional expected value of a distribution or polynomial. 1st order statistics of a polynomial on a given probability space conditioned on some of the variables. Args: poly (numpoly.ndpoly): Polynomial to find conditional expected value on. freeze (numpy.ndpoly): Boolean values defining the conditional variables. True values implies that the value is conditioned on, e.g. frozen during the expected value calculation. dist (Distribution) : The distributions of the input used in ``poly``. Returns: (numpoly.ndpoly) : Same as ``poly``, but with the variables not tagged in ``frozen`` integrated away. Examples: >>> q0, q1 = chaospy.variable(2) >>> poly = chaospy.polynomial([1, q0, q1, 10*q0*q1-1]) >>> poly polynomial([1, q0, q1, 10*q0*q1-1]) >>> dist = chaospy.J(chaospy.Gamma(1, 1), chaospy.Normal(0, 2)) >>> chaospy.E_cond(poly, q0, dist) polynomial([1.0, q0, 0.0, -1.0]) >>> chaospy.E_cond(poly, q1, dist) polynomial([1.0, 1.0, q1, 10.0*q1-1.0]) >>> chaospy.E_cond(poly, [q0, q1], dist) polynomial([1, q0, q1, 10*q0*q1-1]) >>> chaospy.E_cond(poly, [], dist) polynomial([1.0, 1.0, 0.0, -1.0]) >>> chaospy.E_cond(4, [], dist) array(4) """ poly = numpoly.set_dimensions(poly, len(dist)) if poly.isconstant(): return poly.tonumpy() assert not dist.stochastic_dependent, dist freeze = numpoly.aspolynomial(freeze) if not freeze.size: return numpoly.polynomial(chaospy.E(poly, dist)) if not freeze.isconstant(): freeze = [ name in freeze.names for name in sorted(poly.names, key=lambda x: int(x[1:])) ] else: freeze = freeze.tonumpy() freeze = numpy.asarray(freeze, dtype=bool) # decompose into frozen and unfrozen part poly = numpoly.decompose(poly) unfrozen = poly(**{("q%d" % idx): 1 for idx, keep in enumerate(freeze) if keep}) frozen = poly(**{("q%d" % idx): 1 for idx, keep in enumerate(freeze) if not keep}) # if no unfrozen, poly will return numpy.ndarray instead of numpoly.ndpoly if not isinstance(unfrozen, numpoly.ndpoly): return numpoly.sum(frozen, 0) # Remove frozen coefficients, such that poly == sum(frozen*unfrozen) holds for key in unfrozen.keys: unfrozen.values[key] = unfrozen.values[key] != 0 return numpoly.sum(frozen * expected.E(unfrozen, dist), 0)