Source code for WaveBlocksND.SparsityOraclePSHAWP

"""The WaveBlocks Project

This file contains the code for a sparsity oracle looking
at the phase space distance between both packets.

@author: R. Bourquin
@copyright: Copyright (C) 2013, 2014 R. Bourquin
@license: Modified BSD License
"""

from numpy import array, ones, abs, sqrt, dot, atleast_1d
from numpy.linalg import norm

from WaveBlocksND.SparsityOracle import SparsityOracle

__all__ = ["SparsityOraclePSHAWP"]


[docs]class SparsityOraclePSHAWP(SparsityOracle): r"""This class implements an oracle by looking at a phase space distance. """
[docs] def __init__(self, factor=1.5): r"""Initialize an oracle for estimating if a specific overlap integral :math:`\langle \Psi_k | \Psi_l \rangle` is approximately zero. The oracle works by computing first and second moments :math:`\mu` and :math:`\sigma` of the highest order function :math:`\phi_i` of both wavepackts :math:`\Psi_k` and :math:`\Psi_l` for both, position and momentum. Then we compute the estimators: .. math:: \|q_k - q_l\| \leq \alpha ( \|\sigma^q_k\| + \|\sigma^q_l\| ) and .. math:: \|p_k - p_l\| \leq \alpha ( \|\sigma^p_k\| + \|\sigma^p_l\| ) :param factor: The factor :math:`\alpha` in the phase space distance. The default value of 1.5 should be reasonable in most cases. """ self._factor = factor self._bias_bra = False self._bias_ket = False
[docs] def is_not_zero(self, pacbra, packet, component=None): r"""Try to estimate if the overlap integral :math:`\langle \Psi_k | \Psi_l \rangle` is zero or at least negligible. :param pacbra: The packet :math:`\Psi_k` that is used for the 'bra' part. :param packet: The packet :math:`\Psi_l` that is used for the 'ket' part. :param component: The component of the packet that is considered. :return: ``True`` or ``False`` whether the inner product is negligible. """ eps = packet.get_eps() qbra, Qbra, pbra, Pbra = pacbra.get_parameters(key=("q", "Q", "p", "P")) qket, Qket, pket, Pket = packet.get_parameters(key=("q", "Q", "p", "P")) # First strategy # TODO: Can there be a 'wrong' largest index in case there are more than one? #kbra = array(pacbra.get_basis_shapes(component=component).find_largest_index()) #kket = array(packet.get_basis_shapes(component=component).find_largest_index()) # Second strategy #Kbra = pacbra.get_basis_shapes(component=component) #indices = array([ node for node in Kbra.get_node_iterator() ]) #kbra = indices.max(axis=0) #Kket = packet.get_basis_shapes(component=component) #indices = array([ node for node in Kket.get_node_iterator() ]) #kket = indices.max(axis=0) # Third strategy if component is not None: kbra = array(pacbra.get_basis_shapes(component=component).find_largest_index()) kket = array(packet.get_basis_shapes(component=component).find_largest_index()) else: kbra = array(max([K.find_largest_index() for K in pacbra.get_basis_shapes()])) kket = array(max([K.find_largest_index() for K in packet.get_basis_shapes()])) # Bias for small k if self._bias_bra: if norm(kbra) < self._bra_min_k_norm: kbra = self._bra_min_k if self._bias_ket: if norm(kket) < self._ket_min_k_norm: kket = self._ket_min_k D = pacbra.get_dimension() kbra = norm(kbra) / sqrt(D) * ones(D) kket = norm(kket) / sqrt(D) * ones(D) # Compute second moments sigqbra = eps / sqrt(2.0) * sqrt(dot(abs(Qbra)**2, 2 * kbra + 1)) sigqket = eps / sqrt(2.0) * sqrt(dot(abs(Qket)**2, 2 * kket + 1)) sigpbra = eps / sqrt(2.0) * sqrt(dot(abs(Pbra)**2, 2 * kbra + 1)) sigpket = eps / sqrt(2.0) * sqrt(dot(abs(Pket)**2, 2 * kket + 1)) return (norm(qbra - qket) <= self._factor * (norm(sigqbra) + norm(sigqket)) and norm(pbra - pket) <= self._factor * (norm(sigpbra) + norm(sigpket)))
[docs] def bias(self, bramink=None, ketmink=None): r"""Bias the sparsity oracle. The oracle tends to underestimate the wavepacket spread for small basis shapes :math:`\mathfrak{K}` and therefore small maximal indices :math:`k \in \mathfrak{K}`. This method allows to set a minimal :math:`k` for both the bra and ket independently. :param bramink: Minimal :math:`k` for :math:`\langle \Psi |` :param ketmink: Minimal :math:`k` for :math:`| \Psi \rangle` """ if bramink is not None: self._bra_min_k = bramink self._bra_min_k_norm = norm(atleast_1d(bramink)) self._bias_bra = True if ketmink is not None: self._ket_min_k = ketmink self._ket_min_k_norm = norm(atleast_1d(ketmink)) self._bias_ket = True