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)
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)
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]