def construct_rule(self):
        r"""Compute the tensor product of the given quadrature rules.

        .. note:: This is an internal method and there should be no reason
                  to explicitely call it manually.

        :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|)`.
        """
        self._number_nodes = reduce(multiply, [rule.get_number_nodes() for rule in self._rules])
        # The quadrature nodes \gamma.
        nodes = meshgrid_nd([rule.get_nodes() for rule in self._rules])
        self._nodes = vstack([node.reshape(1, -1) for node in nodes])
        # The quadrature weights \omega.
        weights = meshgrid_nd([rule.get_weights() for rule in self._rules])
        weights = reduce(multiply, weights)
        self._weights = weights.reshape(1, -1)
Beispiel #2
0
    def construct_rule(self):
        r"""Compute the tensor product of the given quadrature rules.

        .. note:: This is an internal method and there should be no reason
                  to explicitely call it manually.

        :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|)`.
        """
        self._number_nodes = reduce(
            multiply, [rule.get_number_nodes() for rule in self._rules])
        # The quadrature nodes \gamma.
        nodes = meshgrid_nd([rule.get_nodes() for rule in self._rules])
        self._nodes = vstack([node.reshape(1, -1) for node in nodes])
        # The quadrature weights \omega.
        weights = meshgrid_nd([rule.get_weights() for rule in self._rules])
        weights = reduce(multiply, weights)
        self._weights = weights.reshape(1, -1)
Beispiel #3
0
    def construct_rule(self, K, tolerance=1e-15):
        r"""Compute the quadrature nodes :math:`\{\gamma_i\}_i` and quadrature
        weights :math:`\{\omega_i\}_i`.

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

        .. note:: This is an internal method and there should be no reason
                  to explicitely call it manually.

        .. 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.
        """
        # Check for valid level parameter
        if not K >= 1:
            raise ValueError("Smolyak level has to be 1 at least.")
        if K > max(self._rules.keys()):
            raise ValueError("Not enough quadrature rules to build Smolyak grid of level %d" % K)

        self._level = K
        D = self._dimension

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

        # Index Set
        for q in range(max(0, K - D), K):
            S = lattice_points_norm(D, 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.reshape(-1) 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(multiply, weights)
                allnodes.append(nodes)
                allweights.append(weights.reshape(-1))
                factors.append((-1)**(K - 1 - q) * binom(D - 1, K - 1 - q))

        # Sort
        allnodes = hstack(allnodes).reshape(D, -1)
        allweights = hstack([f * w for f, w 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 range(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 range(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]