Example #1
0
 def compute_sobol_indices(self, fval, cardinality=-1):
     """
     Compute Sobol indices based on Tang (2009), GLOBAL SENSITIVITY ANALYSIS 
     FOR STOCHASTIC COLLOCATION EXPANSION.  Approximates main-effect indices.
     Main effect indices (non-normalized) are returned in a dictionary D,
     with keys tuples of dimension indices.  E.g. D[(0,3,4)] is the
     main-effect index (cardinality 3) of the variables x_0, x_3, x_4.
     """
     cmax  = self.dim if cardinality==-1 else cardinality
     mu    = self.integrate(fval)    # Compute mean, variance
     fval2 = dict([(i, val**2) for i, val in fval.items()])
     var     = self.integrate(fval2) - mu**2
     D       = {(): mu**2}
     full    = range(self.dim)
     for c in range(1, cmax + 1):
                                     # Loop over all combinations of c indices
                                     # I.e. y = (0,), (1,), (dim-1,) then
                                     # y = (0,1), (0,2), (1,2), etc
         for y in itertools.combinations(full, c):
             z = mylib.complement(y, self.dim)
                                     # Integrate over dimensions z
             sp_r, fval_r = self.integrate_partial(fval, z)
                                     # Square result
             fval_r2 = dict([(i, val**2) for i, val in fval_r.items()])
                                     # Integrate over remaining dimensions
             D[y] = sp_r.integrate(fval_r2)
             for t in mylib.all_subsets(y, strict=True, null=True):
                 D[y] -= D[t]
     return D, mu, var
Example #2
0
 def compute_sobol_indices(self, fval, cardinality=-1):
     """
     Compute Sobol indices based on Tang (2009), GLOBAL SENSITIVITY ANALYSIS 
     FOR STOCHASTIC COLLOCATION EXPANSION.  Approximates main-effect indices.
     Main effect indices (non-normalized) are returned in a dictionary D,
     with keys tuples of dimension indices.  E.g. D[(0,3,4)] is the
     main-effect index (cardinality 3) of the variables x_0, x_3, x_4.
     """
     cmax = self.dim if cardinality == -1 else cardinality
     mu = self.integrate(fval)  # Compute mean, variance
     fval2 = dict([(i, val**2) for i, val in fval.items()])
     var = self.integrate(fval2) - mu**2
     D = {(): mu**2}
     full = range(self.dim)
     for c in range(1, cmax + 1):
         # Loop over all combinations of c indices
         # I.e. y = (0,), (1,), (dim-1,) then
         # y = (0,1), (0,2), (1,2), etc
         for y in itertools.combinations(full, c):
             z = mylib.complement(y, self.dim)
             # Integrate over dimensions z
             sp_r, fval_r = self.integrate_partial(fval, z)
             # Square result
             fval_r2 = dict([(i, val**2) for i, val in fval_r.items()])
             # Integrate over remaining dimensions
             D[y] = sp_r.integrate(fval_r2)
             for t in mylib.all_subsets(y, strict=True, null=True):
                 D[y] -= D[t]
     return D, mu, var
Example #3
0
 def _sobol_variances(self, fval, cardinality):
     """
     Performs the integrals defined in Tang (2009), GLOBAL SENSITIVITY ANALYSIS
     FOR STOCHASTIC COLLOCATION EXPANSION, on the current sparse grid.  Only 
     for use by compute_sobol_variances(), do not call directly.
     """
     cmax = self.dim if cardinality == -1 else cardinality
     mu = self.integrate(fval)  # Compute mean, variance
     fval2 = dict([(i, val**2) for i, val in fval.items()])
     var = self.integrate(fval2) - mu**2
     D = {(): mu**2}  # Temporary, to simplify following code
     full = range(self.dim)
     for c in range(1, cmax + 1):
         # Loop over all combinations of c indices
         # I.e. y = (0,), (1,), (dim-1,) then
         # y = (0,1), (0,2), (1,2), etc
         for y in itertools.combinations(full, c):
             z = mylib.complement(y, self.dim)
             # Integrate over dimensions z
             sp_r, fval_r = self.integrate_partial(fval, z)
             # Square result
             fval_r2 = dict([(i, val**2) for i, val in fval_r.items()])
             # Integrate over remaining dimensions
             D[y] = sp_r.integrate(fval_r2)
             for t in mylib.all_subsets(y, strict=True, null=True):
                 D[y] -= D[t]
     D[()] = var
     return D, mu, var
Example #4
0
 def reduce_axes(self, axes):
     """
     Create new IndexSet by reducing this one along specified dimensions.
     Corresponds to equivalent, lower- dimensional sparse-grid rule.  This
     IndexSet remains untouched.
       axes - dimensions to remove from the indexset
     Return:
       New IndexSet object
     """
     # Axes to *keep*
     axes_r = mylib.complement(axes, self.dim)
     I_r = set([])  # New, reduced I
     for mi in self.I:
         I_r |= {tuple(np.array(mi, dtype=np.int8)[axes_r])}
     return IndexSet(I=I_r)
Example #5
0
 def reduce_axes(self, axes):
     """
     Create new LevelSet by reducing this one along specified dimensions.
     Corresponds to equivalent, lower- dimensional sparse-grid rule.  This
     LevelSet remains untouched.
       axes - dimensions to remove from the levelset
     Return:
       ls_r - LevelSet of reduced dimension
     """
     axes_r = mylib.complement(axes, self.dim)
     dim_r = len(axes_r)
     ls_r = LevelSet(dim_r, 0, fill='none')
                                     # Delete unwanted dimensions and remove
                                     # duplicate multi-indices (lose order)
     ls_r.I = np.array(self.I)[:,axes_r]
     ls_r.I = np.array(list(set([tuple(i) for i in ls_r.I])))
                                     # Reinitialize active and old points
                                     # TODO: finish this... currently all
                                     # active.  Only needed for adaptivity
     ls_r.A, ls_r.O = set(range(len(ls_r.I))), set()
     return ls_r
Example #6
0
 def reduce_axes(self, axes):
     """
     Create new LevelSet by reducing this one along specified dimensions.
     Corresponds to equivalent, lower- dimensional sparse-grid rule.  This
     LevelSet remains untouched.
       axes - dimensions to remove from the levelset
     Return:
       ls_r - LevelSet of reduced dimension
     """
     axes_r = mylib.complement(axes, self.dim)
     dim_r = len(axes_r)
     ls_r = LevelSet(dim_r, 0, fill='none')
     # Delete unwanted dimensions and remove
     # duplicate multi-indices (lose order)
     ls_r.I = np.array(self.I)[:, axes_r]
     ls_r.I = np.array(list(set([tuple(i) for i in ls_r.I])))
     # Reinitialize active and old points
     # TODO: finish this... currently all
     # active.  Only needed for adaptivity
     ls_r.A, ls_r.O = set(range(len(ls_r.I))), set()
     return ls_r
Example #7
0
 def integrate_partial(self, fval, axes):
     """
     Integrate over a subset of the dimensions of the rule.  If axes lists all
     the axes this is equivalent to integrate().
       fval   - data evaluated at all support points of the component rule.  
                If f is vector-valued the last dimension is the vector
       axes   - list of axes over which to integrate
     Return:
       sc_r   - SparseComponentRule object of reduced dimension
       fval_r - reduced rank version of fval, dictionary indexed by new
                reduced-dim multi-indices
       axes_r - list of remaining axes in f_r (those not integrated yet)
     """
     # Full-rank representation of f
     f = self.dimensionate(self.extract_fvec(fval))
     if len(axes) == 0:
         return f, range(self.dim)
     # Creative use of einsum()
     assert f.ndim < 26, ValueError('Implementation limit dim < 26')
     ijk = np.array(list('abcdefghijklmnopqrstuvwxyz'))
     # Eg. cmd = 'abcde,b,c' for dim=3,
     # axis=[1,2], and matrix-valued f.
     # We avoid the ellipsis '...' because
     # of non-mature implementation.
     cmd = ''.join(ijk[:f.ndim]) + ',' + ','.join(ijk[list(axes)])
     w = self.quad.dw if self.delta else self.quad.w
     warg = [w[self.levelidx[ai] - 1] for ai in axes]
     f_r = np.einsum(cmd, f, *warg)  # Partial integral of f
     # Complement of axes (remaining axes)
     axes_r = mylib.complement(axes, self.dim)
     # Remaining level indices, new comp rule
     levelidx_r = list(np.array(self.levelidx)[axes_r])
     sc_r = SparseComponentRule(self.quad, levelidx_r, delta=self.delta)
     # CHECK TODO: correct ordering?
     fvec_r = sc_r.undimensionate(f_r)
     fval_r = dict(zip([tuple(midx) for midx in sc_r.i], fvec_r))
     return sc_r, fval_r, axes_r
Example #8
0
 def integrate_partial(self, fval, axes):
     """
     Integrate over a subset of the dimensions of the rule.  If axes lists all
     the axes this is equivalent to integrate().
       fval   - data evaluated at all support points of the component rule.  
                If f is vector-valued the last dimension is the vector
       axes   - list of axes over which to integrate
     Return:
       sc_r   - SparseComponentRule object of reduced dimension
       fval_r - reduced rank version of fval, dictionary indexed by new
                reduced-dim multi-indices
       axes_r - list of remaining axes in f_r (those not integrated yet)
     """
                                     # Full-rank representation of f
     f = self.dimensionate( self.extract_fvec(fval) )
     if len(axes) == 0: return f, range(self.dim)
                                     # Creative use of einsum()
     assert f.ndim < 26, ValueError('Implementation limit dim < 26')
     ijk  = np.array(list('abcdefghijklmnopqrstuvwxyz'))
                                     # Eg. cmd = 'abcde,b,c' for dim=3,
                                     # axis=[1,2], and matrix-valued f.
                                     # We avoid the ellipsis '...' because
                                     # of non-mature implementation.
     cmd  = ''.join(ijk[:f.ndim]) + ',' + ','.join(ijk[list(axes)])
     w    = self.quad.dw if self.delta else self.quad.w
     warg = [w[self.levelidx[ai]-1] for ai in axes]
     f_r = np.einsum(cmd, f, *warg)  # Partial integral of f
                                     # Complement of axes (remaining axes)
     axes_r = mylib.complement(axes, self.dim)
                                     # Remaining level indices, new comp rule
     levelidx_r = list(np.array(self.levelidx)[axes_r])
     sc_r = SparseComponentRule(self.quad, levelidx_r, delta=self.delta)
                                     # CHECK TODO: correct ordering?
     fvec_r = sc_r.undimensionate(f_r)
     fval_r = dict(zip([tuple(midx) for midx in sc_r.i], fvec_r))
     return sc_r, fval_r, axes_r