Commit 351601bf authored by Bruno Buijtendorp's avatar Bruno Buijtendorp
Browse files

add landau levels core functionality to continuum

parent be364e7c
Pipeline #5100 passed with stages
in 16 minutes and 36 seconds
''' Core functionality of Landau Level project
We have set hbar and the elementary charge e to 1, this is the natural system
of atomic units called Hartree units
'''
import numpy as np
import sympy as sp
from scipy.sparse import coo_matrix, kron
import operator
import inspect
import functools
def combine(operator, functions, args_names=None):
"""Combine an arbitrary number of ``functions`` with given ``operator``.
Parameters
----------
operator: function
Operator that should be used to combine ``functions``.
For example ``operator.add``.
functions: sequence of functions
Sequence of functions to be combined.
args_names
Name of positional arguments.
Returns
-------
function, parameters are union of initial function
parameters, keyword only unless listed in ``args_names``.
"""
KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY
POSITIONAL_OR_KEYWORD = inspect.Parameter.POSITIONAL_OR_KEYWORD
if args_names is None:
args_names = []
signatures = [inspect.signature(f) for f in functions]
parameters = [set(sig.parameters) for sig in signatures]
parameters = sorted(set.union(*parameters))
kwargs_names = [name for name in parameters if name not in args_names]
parameters = [inspect.Parameter(name, kind=POSITIONAL_OR_KEYWORD)
for name in args_names]
parameters += [inspect.Parameter(name, kind=KEYWORD_ONLY)
for name in kwargs_names]
signature = inspect.Signature(parameters=parameters)
def applied_filtered(function, signature, kwargs):
names = list(signature.parameters.keys())
kwargs_names = [(name, value) for name, value in kwargs.items()
if name in names]
return function(**dict(kwargs_names))
def pre_wrapped(**kwargs):
"""Calculate combination of function for given ``kwargs``."""
f_vals = [applied_filtered(f, sig, kwargs)
for (f, sig) in zip(functions, signatures)]
return functools.reduce(operator, f_vals)
def final_wrapper(*args, **kwargs):
bind = signature.bind(*args, **kwargs)
kwargs = bind.kwargs
for name, arg in zip(args_names, bind.args):
kwargs[name] = arg
return(pre_wrapped(**kwargs))
final_wrapper.__signature__ = signature
return final_wrapper
def get_ll_matrix(kprod, N):
"""Substitute a product of momentum operators with ladder operators.
Parameters
----------
kprod : Sympy Expression
Arbitrary product of powers of momentum operators.
N : Integer
Number of Landau levels after which to truncate the expansion.
Returns
-------
sparse matrix truncated to N Landau levels.
"""
kx, ky = sp.symbols('kx ky', commutative=False)
ll_matrix_factors = []
for k_exp in kprod.as_ordered_factors():
k, power = k_exp.as_base_exp()
ll_matrix_factors += [k] * power
kprod_power = len(ll_matrix_factors)
intermediate_size = N + kprod_power // 2
# Define <n|a^dagger|n'> and <n|a|n'> arrays.
i, j = np.indices((intermediate_size, intermediate_size))
ad = np.sqrt(i)
ad[i != j+1] = 0
a = np.sqrt(j)
a[i != j-1] = 0
# Define <n|kx|n'> and <n|ky|n'> arrays.
nkx = ad + a
nky = 1j*(a-ad)
num_ll_matrix_factors = [nkx if k == kx else nky for k in ll_matrix_factors]
ll_matrix = np.linalg.multi_dot(num_ll_matrix_factors)[:N, :N]
return coo_matrix(ll_matrix), kprod_power
def to_ll_basis(kprod, N):
"""Expand a product of momentum operators in the Landau level basis.
This function first replaces each momentum operator with ladder operator,
and then multiply it by ``sqrt(B/2)`` in correct power.
Parameters
----------
kprod : Sympy Expression
Arbitrary product of powers of momentum operators.
N : Integer
Number of Landau levels after which to truncate the expansion.
Returns
-------
Function taking a single parameter (magnetic field) and returning a scipy
sparse matrix representation of 'operator'.
"""
LL_nm, kprod_power = get_ll_matrix(kprod, N)
return lambda B: np.sqrt(B / 2)**kprod_power * LL_nm
def do_ll_conversion(hamiltonian, N):
"""Convert a continuum Hamiltonian into a Landau level basis.
Parameters
----------
hamiltonian : dict
Map from Sympy expressions (products of powers of momentum operators)
to dense matrices (containing the Hamiltonian substructure, e.g. spin)
or a callable returning them.
N : Integer
Number of Landau levels after which to truncate the expansion.
Returns
-------
Function taking union of (B, parameters of callables) and returning a scipy
sparse matrix representation of the Hamiltonian.
"""
result = []
for momenta, H_nm in hamiltonian.items():
if not callable(H_nm):
ham_nm = H_nm.copy()
H_nm = lambda: coo_matrix(ham_nm)
X_nm = to_ll_basis(momenta, N)
result.append((X_nm, H_nm))
# combine multiplication
result = [combine(kron, (X_nm, H_nm)) for X_nm, H_nm in result]
# combine summands
result = combine(operator.add, result)
return result
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment