def _build_mu(self, D, order): r"""Build the list containing the lists :math:`\mu_i` where each :math:`\mu_i` contains the :math:`D`-tuples in reverse lexicographical order. :param D: The dimension :math:`D` of the wavepacket. :param order: The maximal :math:`l_1` norm of any basis index :math:`\underline{k}`. """ return [list(lattice_points_norm(D, i)) for i in range(order + 1)]
def overlap(self, D, Pi, eps): r"""Compute the overlap matrix: .. math:: \mathbf{K}_{r,c} := \langle \psi_{\underline{e_r}}[\Pi] | \phi_{\underline{e_c}}[\Pi] \rangle :param D: The dimension :math:`D`. :param Pi: The parameter set :math:`\Pi`. :param eps: The semiclassical scaling parameter :math:`\varepsilon`. """ ED = list(lattice_points_norm(D, 1)) BS = SimplexShape(D, 1) WPo = HagedornWavepacket(D, 1, eps) WPo.set_parameters(Pi) WPo.set_basis_shapes([BS]) WPn = HagedornWavepacketPsi(D, 1, eps) WPn.set_parameters(Pi) WPn.set_basis_shapes([BS]) TPG = TensorProductQR(D * [GaussHermiteQR(2)]) DHQ = DirectHomogeneousQuadrature(TPG) G = DHQ.transform_nodes(Pi, eps) W = TPG.get_weights() phi = WPo.evaluate_basis_at(G, component=0) psi = WPn.evaluate_basis_at(G, component=0) K = zeros((D, D), dtype=complexfloating) for r, er in enumerate(ED): for c, ec in enumerate(ED): K[r, c] = eps**D * sum( conjugate(psi[BS[er], :]) * phi[BS[ec], :] * W) return K
def overlap(self, D, Pi, eps): r"""Compute the overlap matrix: .. math:: \mathbf{K}_{r,c} := \langle \psi_{\underline{e_r}}[\Pi] | \phi_{\underline{e_c}}[\Pi] \rangle :param D: The dimension :math:`D`. :param Pi: The parameter set :math:`\Pi`. :param eps: The semiclassical scaling parameter :math:`\varepsilon`. """ ED = list(lattice_points_norm(D, 1)) BS = SimplexShape(D, 1) WPo = HagedornWavepacket(D, 1, eps) WPo.set_parameters(Pi) WPo.set_basis_shapes([BS]) WPn = HagedornWavepacketPsi(D, 1, eps) WPn.set_parameters(Pi) WPn.set_basis_shapes([BS]) TPG = TensorProductQR(D * [GaussHermiteQR(2)]) DHQ = DirectHomogeneousQuadrature(TPG) G = DHQ.transform_nodes(Pi, eps) W = TPG.get_weights() phi = WPo.evaluate_basis_at(G, component=0) psi = WPn.evaluate_basis_at(G, component=0) K = zeros((D, D), dtype=complexfloating) for r, er in enumerate(ED): for c, ec in enumerate(ED): K[r, c] = eps**D * sum(conjugate(psi[BS[er], :]) * phi[BS[ec], :] * W) return K
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]