Example #1
0
    def __init__(self, grid, alpha, params, nk=None):
        """
        Constructor
        @param grid: Grid
        @param alpha: surplus vector
        @param params: parameter set
        @param E: expectation value of grid, alpha
        @param V: variance of grid, alpha
        @param nk: maximum length of interactions
        """
        self.__grid = grid
        self.__alpha = alpha
        self.__params = params

        self.__ap = self.__params.activeParams()
        self.__U = self.__ap.getIndependentJointDistribution()
        self.__T = self.__ap.getJointTransformation()
        self.__xlim = self.__U.getBounds()
        self.__dim = len(self.__ap)

        if self.__dim < 2:
            raise AttributeError('dimensionality has to be > 1')

        # check if highest order term is required
        self.__has_highest_order_term = not nk or nk > self.__dim - 1

        if self.__has_highest_order_term:
            self.__nk = self.__dim - 1
        else:
            self.__nk = nk

        self.__expectation_funcs = None
        self.__anova_components = None
        self.__variance_components = None

        self._verbose = True
        self.__marginalization = MarginalAnalyticEstimationStrategy()
        self.__estimation = AnalyticEstimationStrategy()
Example #2
0
    def testMarginalEstimationStrategy(self):
        xlim = np.array([[-1, 1], [-1, 1]])
        trans = JointTransformation()
        dists = []
        for idim in range(xlim.shape[0]):
            trans.add(LinearTransformation(xlim[idim, 0], xlim[idim, 1]))
            dists.append(Uniform(xlim[idim, 0], xlim[idim, 1]))
        dist = J(dists)

        def f(x):
            return np.prod([(1 + xi) * (1 - xi) for xi in x])

        def F(x):
            return 1. - x**3 / 3.

        grid, alpha_vec = interpolate(f,
                                      1,
                                      2,
                                      gridType=GridType_Poly,
                                      deg=2,
                                      trans=trans)
        alpha = alpha_vec.array()

        q = (F(1) - F(-1))**2
        q1 = doQuadrature(grid, alpha)
        q2 = AnalyticEstimationStrategy().mean(grid, alpha, dist,
                                               trans)["value"]

        self.assertTrue(abs(q - q1) < 1e-10)
        self.assertTrue(abs(q - q2) < 1e-10)

        ngrid, nalpha, _ = MarginalAnalyticEstimationStrategy().mean(
            grid, alpha, dist, trans, [[0]])

        self.assertTrue(abs(nalpha[0] - 2. / 3.) < 1e-10)

        plotSG3d(grid, alpha)
        plt.figure()
        plotSG1d(ngrid, nalpha)
        plt.show()
Example #3
0
class HDMRAnalytic(object):
    """
    The HDMR class
    """
    def __init__(self, grid, alpha, params, nk=None):
        """
        Constructor
        @param grid: Grid
        @param alpha: surplus vector
        @param params: parameter set
        @param E: expectation value of grid, alpha
        @param V: variance of grid, alpha
        @param nk: maximum length of interactions
        """
        self.__grid = grid
        self.__alpha = alpha
        self.__params = params

        self.__ap = self.__params.activeParams()
        self.__U = self.__ap.getIndependentJointDistribution()
        self.__T = self.__ap.getJointTransformation()
        self.__xlim = self.__U.getBounds()
        self.__dim = len(self.__ap)

        if self.__dim < 2:
            raise AttributeError('dimensionality has to be > 1')

        # check if highest order term is required
        self.__has_highest_order_term = not nk or nk > self.__dim - 1

        if self.__has_highest_order_term:
            self.__nk = self.__dim - 1
        else:
            self.__nk = nk

        self.__expectation_funcs = None
        self.__anova_components = None
        self.__variance_components = None

        self._verbose = True
        self.__marginalization = MarginalAnalyticEstimationStrategy()
        self.__estimation = AnalyticEstimationStrategy()

    def __computeMean(self):
        print "estimate mean:",
        self.__E, _ = self.__estimation.mean(self.__grid, self.__alpha,
                                             self.__U, self.__T)
        print "done"

    def __computeVariance(self):
        print "estimate variance:",
        self.__V, _ = self.__estimation.var(self.__grid, self.__alpha,
                                            self.__U, self.__T, self.__E)
        print "done"

    def getSortedPermutations(self, keys):
        """
        Sort keys with respect (1) to their length and (2) their lexical order
        @param keys:
        """
        ans = [tuple()] * len(keys)
        ix = 0
        for x in sorted(np.unique(map(len, keys))):
            for ck in sorted(filter(lambda k: len(k) == x, keys)):
                ans[ix] = ck
                ix += 1

        return ans

    def __expectation_functions(self):
        """
        Compute the marginalized expectation functions for the ANOVA
        decomposition.
        """
        if self.__nk < 1 or self.__nk > self.__dim - 1:
            raise AttributeError('The truncated order has to be in \
                                  {1, ..., %i}' % (self.__dim - 1, ))

        # init
        expec = {}

        if self._verbose:
            print "-" * 60

        # add higher order terms
        for k in xrange(self.__nk):
            perms = it.combinations(self.__U.getTupleIndices(), r=k + 1)
            for perm in perms:
                # select dimensions to be integrated
                dd = [d for d in self.__U.getTupleIndices() if d not in perm]

                if self._verbose:
                    print "Explore %s, Integrate: %s" % (perm, dd),

                # -----------------------------------------------
                # Make sure that perm and dd are disjoint sets
                # covering the whole set
                # assert sorted(list(perm) + dd) == range(self.__dim)
                assert len(dd) == self.__dim - len(perm)
                assert len(dd) > 0
                # -----------------------------------------------
                # compute first moment
                grid, alpha, err = self.__marginalization.mean(
                    self.__grid, self.__alpha, self.__U, self.__T, dd)
                expec[tuple([d for di in perm for d in di])] = grid, alpha

                if self._verbose:
                    print "L2 err = %g" % err

                # plot result
#                 if len(perm) == 1:
#                     plotSG1d(grid, alpha)
#                     plt.show()

# add highest order term
        if self.__has_highest_order_term:
            perm = tuple(range(self.__dim))
            expec[perm] = self.__grid, self.__alpha

        if self._verbose:
            print "-" * 60

        return expec

    def __combine_terms(self, perm):
        """
        Combine the terms in order to get the ANOVA component specified in perm
        @param perm: tuple identifies the ANOVA component
        """
        # init, constant term + own term
        fi = {'const': ((-1)**len(perm), self.__E), 'var': [(1, perm)]}

        # add all lower order terms with alternating coefficient
        for k in xrange(len(perm) - 1):
            pperms = it.combinations(list(perm), r=k + 1)
            for pperm in pperms:
                fi['var'] += [((-1)**(len(perm) - len(pperm)), pperm)]

        return fi

    def __decompose(self):
        """
        Computes the ANOVA components for the given function
        when the marginalized parts are available
        """
        fis = {}

        # add higher order terms
        for perm in self.__expectation_funcs.keys():
            fis[perm] = self.__combine_terms(perm)

        return fis

    def doDecomposition(self):
        """
        Computes the ANOVA decomposition for the given sparse grid function
        and the corresponding marginal distributions
        """
        if not self.__anova_components:
            # compute mean and variance
            self.__computeMean()
            self.__computeVariance()
            # marginalize
            self.__expectation_funcs = self.__expectation_functions()
            # combine marginalized terms
            self.__anova_components = self.__decompose()

    def __evalHigherOrderComponent(self, fi, x):
        """
        Evaluate the higher order components
        @param fi: linear combination of marginalized functions
        @param x: DataVector coordinate to be evaluated
        """
        # constant term
        sign, f0 = fi['const']
        s = sign * f0

        # higher order terms terms
        for sign, pperm in fi['var']:
            grid, alpha = self.__expectation_funcs[pperm]
            p = DataVector([x[ix] for ix in pperm])
            val = evalSGFunction(grid, alpha, p)
            s += sign * val

        return s

    def eval(self, x):
        """
        Evaluate the ANOVA decomposition at the given position
        @param x: coordinates to be evaluated
        """
        if not self.__anova_components:
            raise Exception('Do the decomposition first')

        # type check
        if isNumerical(x):
            x = np.array(x, dtype='float')

        # evaluation function

        # add constant term
        s = self.__E

        # add higher order terms
        for components in self.__anova_components.values():
            s += self.__evalHigherOrderComponent(components, x)

        return s

    def evalComponent(self, perm, x):
        """
        Evaluate a single ANOVA component
        @param perm: identifier
        @param x: coordinates
        """
        if len(perm) == 0:
            return self.__E
        elif perm in self.__anova_components:
            fi = self.__anova_components[perm]
            return self.__evalHigherOrderComponent(fi, x)
        else:
            raise AttributeError('The component %s does not exist' % (perm, ))

    def getVarianceDecomposition(self):
        """
        Compute the variance of each ANOVA component
        """
        # check if this taks has alread been done
        if self.__variance_components:
            return self.__variance_components

        # do the anova decompisition first
        self.doDecomposition()

        # initialization
        vis = {}
        self.__variance_components = {}

        if self._verbose:
            print "-" * 60

        # run over all available permutations and compute the variance
        keys = self.__ap.keys()
        for perm in self.getSortedPermutations(self.__anova_components.keys()):
            # get the sparse grid function
            grid, alpha = self.__expectation_funcs[perm]

            # prepare parameter set
            dd = [keys[d] for d in perm]
            params = self.__ap.getSubset(dd)

            # transformation, pdf and volume
            T = params.getJointTransformation()
            U = params.getIndependentJointDistribution()

            # estimate variance
            mean, _ = self.__estimation.mean(grid, alpha, U, T)
            vi, err = self.__estimation.var(grid, alpha, U, T, mean)
            # store the variance
            vis[perm] = vi

            if self._verbose:
                print "Estimated V[%s]: %g, L2 err = %g" % (perm, vi, err)

            # add lower order components
            fi = self.__anova_components[perm]
            for sign, pperm in fi['var']:
                if len(pperm) < len(perm):
                    vi += sign * vis[pperm]

            self.__variance_components[perm] = vi

        if self._verbose:
            print "-" * 60

        return self.__variance_components

    def getSobolIndices(self):
        """
        Computes the relative influence of one single parameter combination
        to the whole variance.
        """
        # make sure that there exists a variance
        if self.__V > 0:
            vis = self.getVarianceDecomposition()
            ans = dict([(perm, vi / self.__V) for perm, vi in vis.items()])
        else:
            ans = {}
            for k in xrange(self.__nk):
                perms = it.combinations(range(self.__dim), r=k + 1)
                for perm in perms:
                    ans[perm] = 0.0
            if self.__has_highest_order_term:
                ans[tuple(range(self.__dim))] = 0.0

        return ans

    def getMainEffects(self):
        """
        Just compute the sobol indices without interactions
        """
        sobol = self.getSobolIndices()
        me = {}
        for perm in sobol.keys():
            if len(perm) == 1:
                me[perm] = sobol[perm]
        return me

    def getTotalEffects(self):
        """
        Compute the sum of all sobol indices where one single parameter
        is part of the interaction
        """
        sobol = self.getSobolIndices()
        te = {}
        for perm in sobol.keys():
            if len(perm) == 1:
                s = [
                    sobol[pperm] for pperm in sobol.keys() if perm[0] in pperm
                ]
                te[perm] = sum(s)

        return te
Example #4
0
 def withAnalyticEstimationStrategy(self, *args, **kws):
     self.__estimationStrategy = AnalyticEstimationStrategy()
     return self