Ejemplo n.º 1
0
    def calculate_local_quadratic(self, diagonal_component=None):
        r"""
        Calculate the local quadratic approximation :math:`U` of the potential's eigenvalue :math:`\lambda`.

        :param diagonal_component: Dummy parameter that has no effect here.

        .. note:: This function is idempotent.
        """
        # Calculation already done at some earlier time?
        if self.taylor_eigen_s is not None:
            return

        self.calculate_eigenvalues()
        self.calculate_jacobian()
        self.calculate_hessian()

        self.taylor_eigen_s = [ (0, self.eigenvalues_s), (1, self.jacobian_s), (2, self.hessian_s) ]

        # Construct function to evaluate the approximation at point q at the given nodes
        assert(self.taylor_eigen_n is None)

        self.taylor_eigen_n = [
            (order, sympy.vectorize(0)(sympy.lambdify([self.x], f, "numpy")))
            for order, f in self.taylor_eigen_s
            ]
Ejemplo n.º 2
0
    def __init__(self, expression, variables):
        r"""
        Create a new ``MatrixPotential1S`` instance for a given potential matrix :math:`V\left(x\right)`.

        :param expression: An expression representing the potential.
        """
        #: The variable :math:`x` that represents position space.
        self.x = variables[0]
        #: The matrix of the potential :math:`V\left(x\right)`.
        self.potential = expression
        # Unpack single matrix entry
        self.potential = self.potential[0,0]
        self.exponential = None

        self.number_components = 1

        # prepare the function in every potential matrix cell for numerical evaluation
        self.potential_n = sympy.vectorize(0)(sympy.lambdify(self.x, self.potential, "numpy"))

        # Symbolic and numerical eigenvalues and eigenvectors
        self.eigenvalues_s = None
        self.eigenvalues_n = None
        self.eigenvectors_s = None
        self.eigenvectors_n = None

        self.taylor_eigen_s = None
        self.taylor_eigen_n = None

        self.remainder_eigen_s = None
        self.remainder_eigen_n = None
Ejemplo n.º 3
0
 def calculate_hessian(self):
     r"""
     Calculate the hessian matrix for component :math:`V_{0,0}` of the potential.
     For potentials which depend only one variable :math:`x`, this equals the second derivative.
     """
     self.hessian_s = sympy.diff(self.potential, self.x, 2)
     self.hessian_n = sympy.vectorize(0)(sympy.lambdify(self.x, self.hessian_s, "numpy"))
Ejemplo n.º 4
0
 def calculate_hessian(self):
     r"""
     Calculate the hessian matrix for each component :math:`V_{i,j}` of the potential.
     For potentials which depend only one variable :math:`x`, this equals the second derivative.
     """
     self.hessian_s = tuple([ sympy.diff(item, self.x, 2) for item in self.potential ])
     self.hessian_n = tuple([ sympy.vectorize(0)(sympy.lambdify(self.x, item, "numpy")) for item in self.hessian_s ])
Ejemplo n.º 5
0
    def __init__(self, expression, variables):
        r"""
        Create a new :py:class:`MatrixPotentialMS` instance for a given potential matrix :math:`V\left(x\right)`.

        :param expression: An expression representing the potential.
        """
        #: The variable :math:`x` that represents position space.
        self.x = variables[0]
        #: The matrix of the potential :math:`V\left(x\right)`.
        self.potential = expression

        self.number_components = self.potential.shape[0]

        # prepare the function in every potential matrix cell for numerical evaluation
        self.potential_n = tuple([ sympy.vectorize(0)(sympy.lambdify(self.x, item, "numpy")) for item in self.potential ])

        # {}[chi] -> [(order, function),...]
        self.taylor_eigen_n = {}

        # {}[chi] -> [remainder]
        self.remainder_eigen_s = {}
        self.remainder_eigen_n = {}

        # [] -> [remainder]
        self.remainder_eigen_ih_s = None
        self.remainder_eigen_ih_n = None
Ejemplo n.º 6
0
    def calculate_eigenvalues(self):
        r"""
        Calculate the eigenvalue :math:`\lambda_0\left(x\right)` of the potential :math:`V\left(x\right)`.
        In the scalar case this is just the matrix entry :math:`V_{0,0}`.

        .. note:: This function is idempotent and the eigenvalues are memoized for later reuse.
        """
        if self.eigenvalues_s is None:
            self.eigenvalues_s = self.potential
            self.eigenvalues_n = sympy.vectorize(0)(sympy.lambdify(self.x, self.potential, "numpy"))
Ejemplo n.º 7
0
    def calculate_eigenvectors(self):
        r"""
        Calculate the eigenvector :math:`nu_0\left(x\right)` of the potential :math:`V\left(x\right)`.
        In the scalar case this is just the value :math:`1`.

        .. note:: This function is idempotent and the eigenvectors are memoized for later reuse.
        """
        if self.eigenvectors_s is None:
            self.eigenvectors_s = sympy.Matrix([[1]])
            self.eigenvectors_n = sympy.vectorize(0)(sympy.lambdify(self.x, 1, "numpy"))
Ejemplo n.º 8
0
    def evaluate_exponential_at(self, nodes):
        r"""
        Evaluate the exponential of the potential matrix :math:`V` at some grid nodes :math:`\gamma`.

        :param nodes: The grid nodes :math:`\gamma` we want to evaluate the exponential at.
        :return: The numerical approximation of the matrix exponential at the given grid nodes.
        """
        # Hack for older sympy versions, see recent issue:
        # http://www.mail-archive.com/[email protected]/msg05137.html
        lookup = {"I" : 1j}

        # prepare the function of every potential matrix exponential cell for numerical evaluation
        self.expfunctions = sympy.vectorize(0)(sympy.lambdify(self.x, self.exponential, (lookup, "numpy")))

        return tuple([ numpy.array(self.expfunctions(nodes)) ])
Ejemplo n.º 9
0
    def calculate_local_remainder(self, diagonal_component=None):
        r"""
        Calculate the non-quadratic remainder :math:`W` of the quadratic
        approximation :math:`U` of the potential's eigenvalue :math:`\lambda`.
        This function is used for the homogeneous case and takes into account
        the leading component :math:`\chi`.

        :param diagonal_component: Dummy parameter that has no effect here.

        .. note:: This function is idempotent.
        """
        # Calculation already done at some earlier time?
        if self.remainder_eigen_s is not None:
            return

        self.calculate_eigenvalues()

        f = self.eigenvalues_s

        # point where the taylor series is computed
        q = sympy.Symbol("q")

        p = f.subs(self.x, q)
        j = sympy.diff(f, self.x)
        j = j.subs(self.x, q)
        h = sympy.diff(f, self.x, 2)
        h = h.subs(self.x, q)

        quadratic =  p + j*(self.x-q) + sympy.Rational(1,2)*h*(self.x-q)**2

        # Symbolic expression for the taylor expansion remainder term
        self.remainder_eigen_s = self.potential - quadratic

        # Construct functions to evaluate the approximation at point q at the given nodes
        assert(self.remainder_eigen_n is None)

        self.remainder_eigen_n = sympy.vectorize(1)(sympy.lambdify([q, self.x], self.remainder_eigen_s, "numpy"))