def mean(self, grid, alpha, U, T):
        r"""
        Extraction of the expectation the given sparse grid function
        interpolating the product of function value and pdf.

        \int\limits_{[0, 1]^d} f_N(x) * pdf(x) dx
        """
        # extract correct pdf for moment estimation
        vol, W = self._extractPDFforMomentEstimation(U, T)
        D = T.getTransformations()
        # compute the integral of the product
        gs = grid.getStorage()
        acc = DataVector(gs.size())
        acc.setAll(1.)
        tmp = DataVector(gs.size())
        err = 0
        # run over all dimensions
        for i, dims in enumerate(W.getTupleIndices()):
            dist = W[i]
            trans = D[i]

            # get the objects needed for integration the current dimensions
            gpsi, basisi = project(grid, dims)

            if isinstance(dist, SGDEdist):
                # if the distribution is given as a sparse grid function we
                # need to compute the bilinear form of the grids
                # accumulate objects needed for computing the bilinear form
                gpsj, basisj = project(dist.grid, range(len(dims)))

                # compute the bilinear form
                bf = BilinearGaussQuadratureStrategy()
                A, erri = bf.computeBilinearFormByList(gpsi, basisi,
                                                       gpsj, basisj)
                # weight it with the coefficient of the density function
                self.mult(A, dist.alpha, tmp)
            else:
                # the distribution is given analytically, handle them
                # analytically in the integration of the basis functions
                if isinstance(dist, Dist) and len(dims) > 1:
                    raise AttributeError('analytic quadrature not supported for multivariate distributions')
                if isinstance(dist, Dist):
                    dist = [dist]
                    trans = [trans]

                lf = LinearGaussQuadratureStrategy(dist, trans)
                tmp, erri = lf.computeLinearFormByList(gpsi, basisi)

            # print error stats
            # print "%s: %g -> %g" % (str(dims), err, err + D[i].vol() * erri)
            # import ipdb; ipdb.set_trace()

            # accumulate the error
            err += D[i].vol() * erri

            # accumulate the result
            acc.componentwise_mult(tmp)

        moment = alpha.dotProduct(acc)
        return vol * moment, err
Example #2
0
 def initQuadratureStrategy(self, grid):
     if self.linearForm is None:
         self.linearForm = LinearGaussQuadratureStrategy(grid.getType())
     if self.bilinearForm is None:
         self.bilinearForm = BilinearGaussQuadratureStrategy(grid.getType())
     if self.trilinearForm is None:
         self.trilinearForm = TrilinearGaussQuadratureStrategy(grid.getType())
Example #3
0
    def test_variance_opt(self):
        # parameters
        level = 4

        gridConfig = RegularGridConfiguration()
        gridConfig.type_ = GridType_Linear
        gridConfig.maxDegree_ = 2  # max(2, level + 1)
        gridConfig.boundaryLevel_ = 0
        gridConfig.dim_ = 2

        # mu = np.ones(gridConfig.dim_) * 0.5
        # cov = np.diag(np.ones(gridConfig.dim_) * 0.1 / 10.)
        # dist = MultivariateNormal(mu, cov, 0, 1)  # problems in 3d/l2
        # f = lambda x: dist.pdf(x)
        def f(x):
            return np.prod(4 * x * (1 - x))

        def f(x):
            return np.arctan(
                50 *
                (x[0] - .35)) + np.pi / 2 + 4 * x[1]**3 + np.exp(x[0] * x[1] -
                                                                 1)

        # --------------------------------------------------------------------------
        # define parameters
        paramsBuilder = ParameterBuilder()
        up = paramsBuilder.defineUncertainParameters()
        for idim in range(gridConfig.dim_):
            up.new().isCalled("x_%i" % idim).withBetaDistribution(3, 3, 0, 1)
        params = paramsBuilder.andGetResult()
        U = params.getIndependentJointDistribution()
        T = params.getJointTransformation()
        # --------------------------------------------------------------------------

        grid = pysgpp.Grid.createGrid(gridConfig)
        gs = grid.getStorage()
        grid.getGenerator().regular(level)
        nodalValues = np.ndarray(gs.getSize())

        p = DataVector(gs.getDimension())
        for i in range(gs.getSize()):
            gp = gs.getCoordinates(gs.getPoint(i), p)
            nodalValues[i] = f(p.array())

        # --------------------------------------------------------------------------
        alpha_vec = pysgpp.DataVector(nodalValues)
        pysgpp.createOperationHierarchisation(grid).doHierarchisation(
            alpha_vec)
        alpha = alpha_vec.array()
        checkInterpolation(grid, alpha, nodalValues, epsilon=1e-13)
        # --------------------------------------------------------------------------

        quad = AnalyticEstimationStrategy()
        mean = quad.mean(grid, alpha, U, T)["value"]
        var = quad.var(grid, alpha, U, T, mean)["value"]

        if self.verbose:
            print("mean: %g" % mean)
            print("var : %g" % var)
            print("-" * 80)

        # drop arbitrary grid points and compute the mean and the variance
        # -> just use leaf nodes for simplicity
        bilinearForm = BilinearGaussQuadratureStrategy(grid.getType())
        bilinearForm.setDistributionAndTransformation(U.getDistributions(),
                                                      T.getTransformations())
        linearForm = LinearGaussQuadratureStrategy(grid.getType())
        linearForm.setDistributionAndTransformation(U.getDistributions(),
                                                    T.getTransformations())

        i = np.random.randint(0, gs.getSize())
        gpi = gs.getPoint(i)
        # --------------------------------------------------------------------------
        # check refinement criterion
        ranking = ExpectationValueOptRanking()
        mean_rank = ranking.rank(grid, gpi, alpha, params)
        if self.verbose:
            print("rank mean: %g" % (mean_rank, ))
        # --------------------------------------------------------------------------
        # check refinement criterion
        ranking = VarianceOptRanking()
        var_rank = ranking.rank(grid, gpi, alpha, params)
        if self.verbose:
            print("rank var:  %g" % (var_rank, ))
        # --------------------------------------------------------------------------
        # remove one grid point and update coefficients
        toBeRemoved = IndexList()
        toBeRemoved.push_back(i)
        ixs = gs.deletePoints(toBeRemoved)
        gpsj = []
        new_alpha = np.ndarray(gs.getSize())
        for j in range(gs.getSize()):
            new_alpha[j] = alpha[ixs[j]]
            gpsj.append(gs.getPoint(j))
        # --------------------------------------------------------------------------
        # compute the mean and the variance of the new grid
        mean_trunc = quad.mean(grid, new_alpha, U, T)["value"]
        var_trunc = quad.var(grid, new_alpha, U, T, mean_trunc)["value"]
        basis = getBasis(grid)

        # compute the covariance
        A, _ = bilinearForm.computeBilinearFormByList(gs, [gpi], basis, gpsj,
                                                      basis)
        b, _ = linearForm.computeLinearFormByList(gs, gpsj, basis)

        mean_uwi_phii = np.dot(new_alpha, A[0, :])
        mean_phii, _ = linearForm.getLinearFormEntry(gs, gpi, basis)
        mean_uwi = np.dot(new_alpha, b)
        cov_uwi_phii = mean_uwi_phii - mean_phii * mean_uwi

        # compute the variance of phi_i
        firstMoment, _ = linearForm.getLinearFormEntry(gs, gpi, basis)
        secondMoment, _ = bilinearForm.getBilinearFormEntry(
            gs, gpi, basis, gpi, basis)
        var_phii = secondMoment - firstMoment**2

        # update the ranking
        var_estimated = var_trunc + alpha[i]**2 * var_phii + 2 * alpha[
            i] * cov_uwi_phii

        mean_diff = np.abs(mean_trunc - mean)
        var_diff = np.abs(var_trunc - var)

        if self.verbose:
            print("-" * 80)
            print("diff: |var - var_estimated| = %g" %
                  (np.abs(var - var_estimated), ))
            print("diff: |var - var_trunc|     = %g = %g = var opt ranking" %
                  (var_diff, var_rank))
            print("diff: |mean - mean_trunc|   = %g = %g = mean opt ranking" %
                  (mean_diff, mean_rank))

        self.assertTrue(np.abs(var - var_estimated) < 1e-14)
        self.assertTrue(np.abs(mean_diff - mean_rank) < 1e-14)
        self.assertTrue(np.abs(var_diff - var_rank) < 1e-14)
Example #4
0
class AnalyticEstimationStrategy(SparseGridEstimationStrategy):
    def __init__(self):
        super(self.__class__, self).__init__()
        # system matrices for mean and mean^2
        self.A_mean = {}
        self.A_var = {}
        self.linearForm = None
        self.bilinearForm = None
        self.trilinearForm = None

    def initQuadratureStrategy(self, grid):
        if self.linearForm is None:
            self.linearForm = LinearGaussQuadratureStrategy(grid.getType())
        if self.bilinearForm is None:
            self.bilinearForm = BilinearGaussQuadratureStrategy(grid.getType())
        if self.trilinearForm is None:
            self.trilinearForm = TrilinearGaussQuadratureStrategy(
                grid.getType())

    def getSystemMatrixForMean(self, grid, W, D):
        self.initQuadratureStrategy(grid)
        hash_value = (grid.hash_hexdigest(), hash(tuple(W)), hash(tuple(D)))
        if hash_value not in self.A_var:
            self.A_mean[hash_value] = self.computeSystemMatrixForMean(
                grid, W, D)

        return self.A_mean[hash_value]

    def computeSystemMatrixForMeanProjected(self, gs, gpsi, basisi, dist,
                                            trans, dims):
        if isinstance(dist, SGDEdist):
            # if the distribution is given as a sparse grid function we
            # need to compute the bilinear form of the grids
            # accumulate objects needed for computing the bilinear form
            assert len(dims) == dist.grid.getStorage().getDimension()
            gpsj, basisj = project(dist.grid, list(range(len(dims))))

            # compute the bilinear form
            # -> the measure needs to be uniform, since it is already
            #    encoded in the sparse grid density
            self.bilinearForm.setDistributionAndTransformation(
                [Uniform(0, 1)] * gs.getDimension(), None)
            A, erri = self.bilinearForm.computeBilinearFormByList(
                gs, gpsi, basisi, gpsj, basisj)
            # weight it with the coefficient of the density function
            tmp = A.dot(dist.alpha)
        else:
            # the distribution is given analytically, handle them
            # analytically in the integration of the basis functions
            if isinstance(dist, Dist) and len(dims) > 1:
                #                 print "WARNINING: results are just approximated -> not independent random variables"
                # marginalize the densities and continue
                marg_dists = [None] * len(dims)
                for i, idim in enumerate(dims):
                    marg_dists[i] = dist.marginalizeToDimX(idim)
                dist = marg_dists
                trans = trans.getTransformations()

            if isinstance(dist, Dist):
                dist = [dist]
                trans = [trans]

            self.linearForm.setDistributionAndTransformation(dist, trans)
            tmp, erri = self.linearForm.computeLinearFormByList(
                gs, gpsi, basisi)

        return tmp, erri

    def computeSystemMatrixForMeanList(self, gs, gps, basis, W, D):
        # compute the integral of the product
        A_mean = np.ones(len(gps))
        err = 0
        # run over all dimensions
        for i, dims in enumerate(W.getTupleIndices()):
            dist = W[i]
            trans = D[i]

            # get the objects needed for integration the current dimensions
            gps_projected = projectList(gps, dims)
            A_idim, erri = self.computeSystemMatrixForMeanProjected(
                gs, gps_projected, basis, dist, trans, dims)

            # print error stats
            # print "%s: %g -> %g" % (str(dims), err, err + D[i].vol() * erri)
            # import ipdb; ipdb.set_trace()

            # accumulate the error
            err += erri

            # accumulate the result
            A_mean *= A_idim

        return A_mean, err

    def computeSystemMatrixForMean(self, grid, W, D):
        # compute the integral of the product
        gs = grid.getStorage()
        gps = [None] * gs.getSize()
        for i in range(gs.getSize()):
            gps[i] = gs.getPoint(i)
        basis = getBasis(grid)

        return self.computeSystemMatrixForMeanList(gs, gps, basis, W, D)

    def getSystemMatrixForVariance(self, grid, W, D):
        self.initQuadratureStrategy(grid)
        hash_value = (grid.hash_hexdigest(), hash(tuple(W)), hash(tuple(D)))
        if hash_value not in self.A_var:
            self.A_var[hash_value] = self.computeSystemMatrixForVariance(
                grid, W, D)

        return self.A_var[hash_value]

    def computeSystemMatrixForVarianceProjected(self, gs, gpsi, basisi, gpsj,
                                                basisj, dist, trans, dims):
        if isinstance(dist, SGDEdist):
            # project distribution on desired dimensions
            # get the objects needed for integrating
            # the current dimensions
            gpsk, basisk = project(dist.grid, list(range(len(dims))))
            # compute the bilinear form
            # -> the measure needs to be uniform, since it is already
            #    encoded in the sparse grid density
            self.trilinearForm.setDistributionAndTransformation(
                [Uniform(0, 1)] * gs.getDimension(), None)
            A_idim, erri = self.trilinearForm.computeTrilinearFormByList(
                gs, gpsk, basisk, dist.alpha, gpsi, basisi, gpsj, basisj)
        else:
            # the distribution is given analytically, handle them
            # analytically in the integration of the basis functions
            if isinstance(dist, Dist) and len(dims) > 1:
                #                 print "WARNINING: results are just approximated -> not independent random variables"
                # marginalize the densities and continue
                marg_dists = [None] * len(dims)
                for i, idim in enumerate(dims):
                    marg_dists[i] = dist.marginalizeToDimX(idim)
                dist = marg_dists
                trans = trans.getTransformations()

            if isinstance(dist, Dist):
                dist = [dist]
                trans = [trans]

            self.bilinearForm.setDistributionAndTransformation(dist, trans)
            A_idim, erri = self.bilinearForm.computeBilinearFormByList(
                gs, gpsi, basisi, gpsj, basisj)
        return A_idim, erri

    def computeSystemMatrixForVarianceList(self, gs, gpsi, basisi, gpsj,
                                           basisj, W, D):
        # compute the integral of the product times the pdf
        A_var = np.ones((len(gpsi), len(gpsj)))
        err = 0
        for i, dims in enumerate(W.getTupleIndices()):
            dist = W[i]
            trans = D[i]

            # get the objects needed for integrating
            # the current dimensions
            gpsi_projected = projectList(gpsi, dims)
            gpsj_projected = projectList(gpsj, dims)
            A_idim, erri = self.computeSystemMatrixForVarianceProjected(
                gs, gpsi_projected, basisi, gpsj_projected, basisj, dist,
                trans, dims)

            # accumulate the results
            A_var *= A_idim

            # accumulate the error
            err += np.mean(A_var) * erri

        return A_var, err

    def computeSystemMatrixForVariance(self, grid, W, D):
        # compute the integral of the product
        gs = grid.getStorage()
        gps = [None] * gs.getSize()
        for i in range(gs.getSize()):
            gps[i] = gs.getPoint(i)
        basis = getBasis(grid)
        return self.computeSystemMatrixForVarianceList(gs, gps, basis, gps,
                                                       basis, W, D)

    def mean(self, grid, alpha, U, T):
        r"""
        Extraction of the expectation the given sparse grid function
        interpolating the product of function value and pdf.

        \int\limits_{[0, 1]^d} f_N(x) * pdf(x) dx
        """
        # extract correct pdf for moment estimation
        vol, W, D = self._extractPDFforMomentEstimation(U, T)
        A_mean, err = self.getSystemMatrixForMean(grid, W, D)

        moment = vol * np.dot(alpha, A_mean)

        return {
            "value": moment,
            "err": err,
            "confidence_interval": (moment, moment)
        }

    def secondMoment(self, grid, alpha, U, T):
        r"""
        Extraction of the second moment of the given sparse grid function
        interpolating the product of function value and pdf.

        \int\limits_{[0, 1]^d} f(x)^2 * pdf(x) dx
        """
        # extract correct pdf for moment estimation
        vol, W, D = self._extractPDFforMomentEstimation(U, T)
        A_var, err = self.getSystemMatrixForVariance(grid, W, D)

        moment = vol * np.dot(alpha, np.dot(A_var, alpha))

        return {
            "value": moment,
            "err": err,
            "confidence_interval": (moment, moment)
        }

    def var(self, grid, alpha, U, T, mean):
        r"""
        Extraction of variance of the given sparse grid function
        interpolating the product of function value and pdf.

        \int\limits_{[0, 1]^d} (f(x) - E(f))^2 * pdf(x) dx
        """
        moment = self.secondMoment(grid, alpha, U, T)
        var = moment["value"] - mean**2

        return {
            "value": var,
            "err": moment["err"],
            "confidence_interval": (var, var)
        }
    def mean(self, grid, alpha, U, T):
        r"""
        Extraction of the expectation the given sparse grid function
        interpolating the product of function value and pdf.

        \int\limits_{[0, 1]^d} f_N(x) * pdf(x) dx
        """
        # extract correct pdf for moment estimation
        vol, W = self._extractPDFforMomentEstimation(U, T)
        D = T.getTransformations()
        # compute the integral of the product
        gs = grid.getStorage()
        acc = DataVector(gs.size())
        acc.setAll(1.)
        tmp = DataVector(gs.size())
        err = 0
        # run over all dimensions
        for i, dims in enumerate(W.getTupleIndices()):
            dist = W[i]
            trans = D[i]

            # get the objects needed for integration the current dimensions
            gpsi, basisi = project(grid, dims)

            if isinstance(dist, SGDEdist):
                # if the distribution is given as a sparse grid function we
                # need to compute the bilinear form of the grids
                # accumulate objects needed for computing the bilinear form
                gpsj, basisj = project(dist.grid, range(len(dims)))

                # compute the bilinear form
                bf = BilinearGaussQuadratureStrategy()
                A, erri = bf.computeBilinearFormByList(gpsi, basisi, gpsj,
                                                       basisj)
                # weight it with the coefficient of the density function
                self.mult(A, dist.alpha, tmp)
            else:
                # the distribution is given analytically, handle them
                # analytically in the integration of the basis functions
                if isinstance(dist, Dist) and len(dims) > 1:
                    raise AttributeError(
                        'analytic quadrature not supported for multivariate distributions'
                    )
                if isinstance(dist, Dist):
                    dist = [dist]
                    trans = [trans]

                lf = LinearGaussQuadratureStrategy(dist, trans)
                tmp, erri = lf.computeLinearFormByList(gpsi, basisi)

            # print error stats
            # print "%s: %g -> %g" % (str(dims), err, err + D[i].vol() * erri)
            # import ipdb; ipdb.set_trace()

            # accumulate the error
            err += D[i].vol() * erri

            # accumulate the result
            acc.componentwise_mult(tmp)

        moment = alpha.dotProduct(acc)
        return vol * moment, err