Beispiel #1
0
    def __init__(self, rules):
        r"""
        Initialize a :py:class:`TensorProductQR` instance.

        :param rules: A list of :py:class:`QuadratureRule` subclass instances. Their
                      nodes and weights will be used to compute the tensor product.
        """
        # The dimension of the quadrature rule.
        self._dimension = len(rules)

        # The individual quadrature rules.
        self._qrs = tuple(rules)

        # The order R of the tensor product quadrature.
        self._order = None
        # TODO: Compute the order from the orders of the input QRs

        # The number of nodes in this quadrature rule.
        self._number_nodes = reduce(op.mul, [ rule.get_number_nodes() for rule in rules ])

        # The quadrature nodes \gamma.
        nodes = meshgrid_nd([ rule.get_nodes() for rule in rules ])
        self._nodes = vstack([ node.flatten() for node in nodes ])

        # The quadrature weights \omega.
        weights = meshgrid_nd([ rule.get_weights() for rule in rules ])
        weights = reduce(lambda x,y: x*y, weights)
        self._weights = weights.flatten()
    def tensor_product(self, rules):
        r"""Compute the tensor product of the given quadrature rules.

        :param rules: A list of one dimensional quadrature rules.
        :return: The nodes :math:`\{\gamma_i\}_i` and weights :math:`\{\omega_i\}_i`
                 of the tensor product quadrature rule. The array of all
                 nodes has a shape of :math:`(D, |\Gamma|)` and the
                 array of weights is of shape :math:`(|\Gamma|)`.
        """
        # The quadrature nodes \gamma.
        nodes = meshgrid_nd([ rule.get_nodes() for rule in rules ])
        nodes = vstack([ node.flatten() for node in nodes ])
        # The quadrature weights \omega.
        weights = meshgrid_nd([ rule.get_weights() for rule in rules ])
        weights = reduce(lambda x,y: x*y, weights)
        return nodes, weights.flatten()
Beispiel #3
0
    def construct_rule(self, level=None, tolerance=1e-15):
        r"""Compute the quadrature nodes :math:`\{\gamma_i\}_i` and quadrature
        weights :math:`\{\omega_i\}_i`.

        :param level: The level :math:`k` of the Smolyak construction.
        :param tolerance: Tolerance for dropping identical
                          quadrature nodes.

        .. warning:: This method is very expensive and may take a long time
                     to finish. Also, the quadrature nodes may use large amounts
                     of memory depending on the dimension and level parameters.
        """
        D = self._dimension

        if level is None:
            k = self._level
        else:
            k = level

        if k > max(self._rules.keys()):
            raise ValueError("Not enough quadrature rules to build Smolyak grid of level "+str(k))

        allnodes = []
        allweights = []
        factors = []

        # Index Set
        for q in xrange(max(0, k-D), k):
            S = self.enumerate_lattice_points(q)
            for j, s in enumerate(S):
                # Only use non-negative nodes for the construction.
                # The quadrature nodes \gamma.
                rules = [ self._rules[si+1] for si in s ]
                nodes = [ rule.get_nodes() for rule in rules ]
                indices = [ where(n >= 0) for n in nodes ]
                nodes = meshgrid_nd([ n[i] for n, i in zip(nodes, indices) ])
                nodes = vstack([ node.flatten() for node in nodes ])
                # The quadrature weights \omega.
                weights = [ rule.get_weights() for rule in rules ]
                weights = meshgrid_nd([ w[i] for w, i in zip(weights, indices) ])
                weights = reduce(lambda x,y: x*y, weights)
                allnodes.append(nodes)
                allweights.append(weights.flatten())
                factors.append((-1)**(k-1-q) * binom(D-1, k-1-q))

        # Sort
        allnodes = hstack(allnodes).reshape(D,-1)
        allweights = hstack([factor*weights for factor, weights in zip(factors,allweights)]).reshape(1,-1)

        I = lexsort(map(squeeze, vsplit(allnodes, D))[::-1])

        allnodes = allnodes[:,I].reshape(D,-1)
        allweights = allweights[:,I].reshape(1,-1)

        # Remove duplicates
        last = 0
        I = [last]

        no = norm(allnodes[:,:-1] - allnodes[:,1:], axis=0)

        for col in xrange(1, allnodes.shape[1]):
            if no[col-1] <= tolerance:
                allweights[0,last] += allweights[0,col]
                allweights[0,col] = 0
            else:
                last = col
                I.append(last)

        allnodes = allnodes[:,I]
        allweights = allweights[:,I]

        # Mirror points to all other hyperoctants
        for d in xrange(D):
            indices = abs(allnodes[d,:]) >= tolerance
            mirrorn = allnodes[:,indices]
            mirrorn[d,:] *= -1.0
            mirrorw = allweights[:,indices]
            allnodes = hstack([allnodes, mirrorn]).reshape(D,-1)
            allweights = hstack([allweights, mirrorw]).reshape(1,-1)

        self._nodes = allnodes
        self._weights = allweights
        self._number_nodes = allnodes.shape[1]