Hamiltonian not hermician for an infinite wire with random complex hopping
Hello (again), Everything is in the title. I want to implement random (and complex) next nearest neighbors hopping in a Haldane infinite wire. Without the random part, 'kwant.plotter.bands()' correctly plot the band structure of my system. However, when I add a random contribution on the modulus of the NNN hopping term, I get an error from 'kwant.plotter.bands()' : 'The cell Hamiltonian is not Hermitian' Which is strange because I red everywhere that the hermicity constraint is always fullfilled using Kwant. The function for random NNN hopping works perfectly fine for a finite system. So, is this comming from the inter-cell hopping terms ? If so, how to correct it ? Kwant does not consider the hopping terms of both ends of the cell as being equal ? It should be because u_k(r) = u_k(r+R) is like periodic boundary conditions for u_k. I add my script at the end so you can see for yourself (the NNN hopping randomness parameter is 'rand_nnn'). Best regards, Alexandre BERNARD ----------------- my script ---------------------- from types import SimpleNamespace import matplotlib import math from matplotlib import pyplot from mpl_toolkits import mplot3d import numpy as np import random import kwant def random_uni(param): return param*(random.random() - 0.5)*2 # returns a random number between +param and -param def onsite(site, p): # Here we affect a potential whose sign depends on which sublattice the atom lives in (breaking sublattice symmetry) if site.family == A: # sublattice A return p.m + random_uni(p.rand_os) else: # sublattice B return -p.m + random_uni(p.rand_os) def nn_hopping(site1, site2, params): return params.t_1 + random_uni(params.rand_nn) def nnn_hopping(site1, site2, params): return (math.cos(params.phi) + 1j*math.sin(params.phi)) * (params.t_2 + random_uni(params.rand_nnn)) def ribbon_shape_armchair(pos): return (-1 <= pos[0] < w) def hopping_color(site1, site2): if site1.family == A and site2.family == A: return 'b' elif site1.family == B and site2.family == B: return 'r' else: return '0.5' def site_color(site): if site.family == A: return 'b' else: return 'r' np.random.seed(271828) # Fixing the RNG seed for reproducibility (or not, because of how Kwant works) # Graphene lattice "pointing up", with two sublattices graphene = kwant.lattice.general([[1, 0], [1/2, np.sqrt(3)/2]], # Here are the vectors of the Bravais lattice [[0, 0], [0, 1/np.sqrt(3)]]) # Here are the positions of the atoms in the unit cell A, B = graphene.sublattices w = 29 # width of the ribbon p = SimpleNamespace(t_1=1.0, t_2=0.1, m=0.0, phi=np.pi/2, rand_os=0., rand_nn=0., rand_nnn=0.1) # Creation of the list of (oriented) bonds that will have the complex hopping term nnn_hoppings_A = (((-1, 0), A, A), ((0, 1), A, A), ((1, -1), A, A)) # Bonds within the A sublattice nnn_hoppings_B = (((1, 0), B, B), ((0, -1), B, B), ((-1, 1), B, B)) # Bonds within the B sublattice nnn_hoppings = nnn_hoppings_A + nnn_hoppings_B haldane_armchair = kwant.Builder(kwant.TranslationalSymmetry((0, 1*np.sqrt(3)))) haldane_armchair[graphene.shape(ribbon_shape_armchair, (0, 0))] = onsite haldane_armchair[graphene.neighbors(1)] = nn_hopping haldane_armchair[[kwant.builder.HoppingKind(*hopping) for hopping in nnn_hoppings]] = nnn_hopping kwant.plot(haldane_armchair, site_color=site_color, hop_color=hopping_color, fig_size=(6, 9)); kwant.plotter.bands(haldane_armchair.finalized(), args=[p], fig_size=(12, 8));
Dear Alexandre, In the documentation, it is mentioned that the function defining the potential in the lead should have the same symmetry as the lead which is obviously not fulfilled with your random function. Another thing, you need to be careful when you define your unit cell in the lead (or in your system with the translational symmetry). If you define a larger unit cell, the translational symmetry will make the sites doubled. The last thing I would like to comment is that when you have a system with random sites, you can not pretend to have a continuous spectrum (or disjoint bands). In fact, from random matrix theory, we know that usually the eigenvalues are repelling each other and the probability to get two eigenvalues close to each other tends to zero. So, I suspect that, more likely you will have a spectrum composed by disjoint points rather than bands. I hope this helps. Adel On Fri, May 18, 2018 at 4:21 PM, <alexandre.bernard1@u-psud.fr> wrote:
Hello (again),
Everything is in the title.
I want to implement random (and complex) next nearest neighbors hopping in a Haldane infinite wire.
Without the random part, 'kwant.plotter.bands()' correctly plot the band structure of my system. However, when I add a random contribution on the modulus of the NNN hopping term, I get an error from 'kwant.plotter.bands()' :
'The cell Hamiltonian is not Hermitian'
Which is strange because I red everywhere that the hermicity constraint is always fullfilled using Kwant. The function for random NNN hopping works perfectly fine for a finite system.
So, is this comming from the inter-cell hopping terms ? If so, how to correct it ? Kwant does not consider the hopping terms of both ends of the cell as being equal ? It should be because u_k(r) = u_k(r+R) is like periodic boundary conditions for u_k.
I add my script at the end so you can see for yourself (the NNN hopping randomness parameter is 'rand_nnn').
Best regards,
Alexandre BERNARD
----------------- my script ----------------------
from types import SimpleNamespace
import matplotlib import math from matplotlib import pyplot from mpl_toolkits import mplot3d import numpy as np import random import kwant
def random_uni(param): return param*(random.random() - 0.5)*2 # returns a random number between +param and -param
def onsite(site, p): # Here we affect a potential whose sign depends on which sublattice the atom lives in (breaking sublattice symmetry) if site.family == A: # sublattice A return p.m + random_uni(p.rand_os) else: # sublattice B return -p.m + random_uni(p.rand_os)
def nn_hopping(site1, site2, params): return params.t_1 + random_uni(params.rand_nn)
def nnn_hopping(site1, site2, params): return (math.cos(params.phi) + 1j*math.sin(params.phi)) * (params.t_2 + random_uni(params.rand_nnn))
def ribbon_shape_armchair(pos): return (-1 <= pos[0] < w)
def hopping_color(site1, site2): if site1.family == A and site2.family == A: return 'b' elif site1.family == B and site2.family == B: return 'r' else: return '0.5'
def site_color(site): if site.family == A: return 'b' else: return 'r'
np.random.seed(271828) # Fixing the RNG seed for reproducibility (or not, because of how Kwant works)
# Graphene lattice "pointing up", with two sublattices graphene = kwant.lattice.general([[1, 0], [1/2, np.sqrt(3)/2]], # Here are the vectors of the Bravais lattice [[0, 0], [0, 1/np.sqrt(3)]]) # Here are the positions of the atoms in the unit cell A, B = graphene.sublattices
w = 29 # width of the ribbon p = SimpleNamespace(t_1=1.0, t_2=0.1, m=0.0, phi=np.pi/2, rand_os=0., rand_nn=0., rand_nnn=0.1)
# Creation of the list of (oriented) bonds that will have the complex hopping term nnn_hoppings_A = (((-1, 0), A, A), ((0, 1), A, A), ((1, -1), A, A)) # Bonds within the A sublattice nnn_hoppings_B = (((1, 0), B, B), ((0, -1), B, B), ((-1, 1), B, B)) # Bonds within the B sublattice nnn_hoppings = nnn_hoppings_A + nnn_hoppings_B
haldane_armchair = kwant.Builder(kwant.TranslationalSymmetry((0, 1*np.sqrt(3))))
haldane_armchair[graphene.shape(ribbon_shape_armchair, (0, 0))] = onsite haldane_armchair[graphene.neighbors(1)] = nn_hopping haldane_armchair[[kwant.builder.HoppingKind(*hopping) for hopping in nnn_hoppings]] = nnn_hopping
kwant.plot(haldane_armchair, site_color=site_color, hop_color=hopping_color, fig_size=(6, 9));
kwant.plotter.bands(haldane_armchair.finalized(), args=[p], fig_size=(12, 8));
-- Abbout Adel
Hi, I don't quite understand what 'having the same symmetry' means in this context. For example, everything works fine for on-site random potential, which doesn't have the 1D translationnal symmetry in the unit cell, but Kwant makes the hamiltonian such that the symmetry with respect to the cells separated by a symmetry vector is valid. So, this does work for on-site random term but not for the hoppings ? (it also doesn't work for random real nearest neighbors hopping terms) I will try to fix it by hand, by specifying the hopping terms between the cells, and see if it works. Best regards, Alexandre ----- Mail original ----- De: "Abbout Adel" <abbout.adel@gmail.com> À: "alexandre bernard1" <alexandre.bernard1@u-psud.fr> Cc: "kwant-discuss" <kwant-discuss@kwant-project.org> Envoyé: Samedi 19 Mai 2018 23:21:02 Objet: Re: [Kwant] Hamiltonian not hermician for an infinite wire with random complex hopping Dear Alexandre, In the documentation, it is mentioned that the function defining the potential in the lead should have the same symmetry as the lead which is obviously not fulfilled with your random function. Another thing, you need to be careful when you define your unit cell in the lead (or in your system with the translational symmetry). If you define a larger unit cell, the translational symmetry will make the sites doubled. The last thing I would like to comment is that when you have a system with random sites, you can not pretend to have a continuous spectrum (or disjoint bands). In fact, from random matrix theory, we know that usually the eigenvalues are repelling each other and the probability to get two eigenvalues close to each other tends to zero. So, I suspect that, more likely you will have a spectrum composed by disjoint points rather than bands. I hope this helps. Adel On Fri, May 18, 2018 at 4:21 PM, < alexandre.bernard1@u-psud.fr > wrote: Hello (again), Everything is in the title. I want to implement random (and complex) next nearest neighbors hopping in a Haldane infinite wire. Without the random part, 'kwant.plotter.bands()' correctly plot the band structure of my system. However, when I add a random contribution on the modulus of the NNN hopping term, I get an error from 'kwant.plotter.bands()' : 'The cell Hamiltonian is not Hermitian' Which is strange because I red everywhere that the hermicity constraint is always fullfilled using Kwant. The function for random NNN hopping works perfectly fine for a finite system. So, is this comming from the inter-cell hopping terms ? If so, how to correct it ? Kwant does not consider the hopping terms of both ends of the cell as being equal ? It should be because u_k(r) = u_k(r+R) is like periodic boundary conditions for u_k. I add my script at the end so you can see for yourself (the NNN hopping randomness parameter is 'rand_nnn'). Best regards, Alexandre BERNARD ----------------- my script ---------------------- from types import SimpleNamespace import matplotlib import math from matplotlib import pyplot from mpl_toolkits import mplot3d import numpy as np import random import kwant def random_uni(param): return param*(random.random() - 0.5)*2 # returns a random number between +param and -param def onsite(site, p): # Here we affect a potential whose sign depends on which sublattice the atom lives in (breaking sublattice symmetry) if site.family == A: # sublattice A return p.m + random_uni(p.rand_os) else: # sublattice B return -p.m + random_uni(p.rand_os) def nn_hopping(site1, site2, params): return params.t_1 + random_uni(params.rand_nn) def nnn_hopping(site1, site2, params): return (math.cos(params.phi) + 1j*math.sin(params.phi)) * (params.t_2 + random_uni(params.rand_nnn)) def ribbon_shape_armchair(pos): return (-1 <= pos[0] < w) def hopping_color(site1, site2): if site1.family == A and site2.family == A: return 'b' elif site1.family == B and site2.family == B: return 'r' else: return '0.5' def site_color(site): if site.family == A: return 'b' else: return 'r' np.random.seed(271828) # Fixing the RNG seed for reproducibility (or not, because of how Kwant works) # Graphene lattice "pointing up", with two sublattices graphene = kwant.lattice.general([[1, 0], [1/2, np.sqrt(3)/2]], # Here are the vectors of the Bravais lattice [[0, 0], [0, 1/np.sqrt(3)]]) # Here are the positions of the atoms in the unit cell A, B = graphene.sublattices w = 29 # width of the ribbon p = SimpleNamespace(t_1=1.0, t_2=0.1, m=0.0, phi=np.pi/2, rand_os=0., rand_nn=0., rand_nnn=0.1) # Creation of the list of (oriented) bonds that will have the complex hopping term nnn_hoppings_A = (((-1, 0), A, A), ((0, 1), A, A), ((1, -1), A, A)) # Bonds within the A sublattice nnn_hoppings_B = (((1, 0), B, B), ((0, -1), B, B), ((-1, 1), B, B)) # Bonds within the B sublattice nnn_hoppings = nnn_hoppings_A + nnn_hoppings_B haldane_armchair = kwant.Builder(kwant.TranslationalSymmetry((0, 1*np.sqrt(3)))) haldane_armchair[graphene.shape(ribbon_shape_armchair, (0, 0))] = onsite haldane_armchair[graphene.neighbors(1)] = nn_hopping haldane_armchair[[kwant.builder.HoppingKind(*hopping) for hopping in nnn_hoppings]] = nnn_hopping kwant.plot(haldane_armchair, site_color=site_color, hop_color=hopping_color, fig_size=(6, 9)); kwant.plotter.bands(haldane_armchair.finalized(), args=[p], fig_size=(12, 8)); -- Abbout Adel
Dear Alexandre, When you define your site potential you call your function once. For hopping, it is deferent: when you define it for (site1, site2) kwant tries to ensure that the hamiltonian is Hermitian so he calls again the function and takes its Hermitian conjugate to set the hopping for (site2,site1). Your function being random gives a different value when you call it the second time. check the function test_hermitian_conjugation() taken from the file test_builder.py (some modifications are done to the following function) import kwant import tinyarray as ta import random def test_hermitian_conjugation(): def f(i, j, arg): i, j = i.tag, j.tag if j[0] == i[0] + 1: return arg * (1+1j)*(random.random() - 0.5)*2 *ta.array([[1, 2j], [3 + 1j, 4j]]) else: raise ValueError syst = kwant.builder.Builder() fam = kwant.builder.SimpleSiteFamily() syst[fam(0)] = syst[fam(1)] = ta.identity(2) syst[fam(0), fam(1)] = f assert syst[fam(0), fam(1)] is f assert isinstance(syst[fam(1), fam(0)], kwant.builder.HermConjOfFunc) assert (syst[fam(1), fam(0)](fam(1), fam(0), 2) == syst[fam(0), fam(1)](fam(0), fam(1), 2).conjugate().transpose()) test_hermitian_conjugation() I hope this helps. Adel On Tue, May 22, 2018 at 11:01 AM, <alexandre.bernard1@u-psud.fr> wrote:
Hi,
I don't quite understand what 'having the same symmetry' means in this context. For example, everything works fine for on-site random potential, which doesn't have the 1D translationnal symmetry in the unit cell, but Kwant makes the hamiltonian such that the symmetry with respect to the cells separated by a symmetry vector is valid.
So, this does work for on-site random term but not for the hoppings ? (it also doesn't work for random real nearest neighbors hopping terms)
I will try to fix it by hand, by specifying the hopping terms between the cells, and see if it works.
Best regards, Alexandre
------------------------------ *De: *"Abbout Adel" <abbout.adel@gmail.com> *À: *"alexandre bernard1" <alexandre.bernard1@u-psud.fr> *Cc: *"kwant-discuss" <kwant-discuss@kwant-project.org> *Envoyé: *Samedi 19 Mai 2018 23:21:02 *Objet: *Re: [Kwant] Hamiltonian not hermician for an infinite wire with random complex hopping
Dear Alexandre,
In the documentation, it is mentioned that the function defining the potential in the lead should have the same symmetry as the lead which is obviously not fulfilled with your random function.
Another thing, you need to be careful when you define your unit cell in the lead (or in your system with the translational symmetry). If you define a larger unit cell, the translational symmetry will make the sites doubled.
The last thing I would like to comment is that when you have a system with random sites, you can not pretend to have a continuous spectrum (or disjoint bands). In fact, from random matrix theory, we know that usually the eigenvalues are repelling each other and the probability to get two eigenvalues close to each other tends to zero. So, I suspect that, more likely you will have a spectrum composed by disjoint points rather than bands.
I hope this helps. Adel
On Fri, May 18, 2018 at 4:21 PM, <alexandre.bernard1@u-psud.fr> wrote:
Hello (again),
Everything is in the title.
I want to implement random (and complex) next nearest neighbors hopping in a Haldane infinite wire.
Without the random part, 'kwant.plotter.bands()' correctly plot the band structure of my system. However, when I add a random contribution on the modulus of the NNN hopping term, I get an error from 'kwant.plotter.bands()' :
'The cell Hamiltonian is not Hermitian'
Which is strange because I red everywhere that the hermicity constraint is always fullfilled using Kwant. The function for random NNN hopping works perfectly fine for a finite system.
So, is this comming from the inter-cell hopping terms ? If so, how to correct it ? Kwant does not consider the hopping terms of both ends of the cell as being equal ? It should be because u_k(r) = u_k(r+R) is like periodic boundary conditions for u_k.
I add my script at the end so you can see for yourself (the NNN hopping randomness parameter is 'rand_nnn').
Best regards,
Alexandre BERNARD
----------------- my script ----------------------
from types import SimpleNamespace
import matplotlib import math from matplotlib import pyplot from mpl_toolkits import mplot3d import numpy as np import random import kwant
def random_uni(param): return param*(random.random() - 0.5)*2 # returns a random number between +param and -param
def onsite(site, p): # Here we affect a potential whose sign depends on which sublattice the atom lives in (breaking sublattice symmetry) if site.family == A: # sublattice A return p.m + random_uni(p.rand_os) else: # sublattice B return -p.m + random_uni(p.rand_os)
def nn_hopping(site1, site2, params): return params.t_1 + random_uni(params.rand_nn)
def nnn_hopping(site1, site2, params): return (math.cos(params.phi) + 1j*math.sin(params.phi)) * (params.t_2 + random_uni(params.rand_nnn))
def ribbon_shape_armchair(pos): return (-1 <= pos[0] < w)
def hopping_color(site1, site2): if site1.family == A and site2.family == A: return 'b' elif site1.family == B and site2.family == B: return 'r' else: return '0.5'
def site_color(site): if site.family == A: return 'b' else: return 'r'
np.random.seed(271828) # Fixing the RNG seed for reproducibility (or not, because of how Kwant works)
# Graphene lattice "pointing up", with two sublattices graphene = kwant.lattice.general([[1, 0], [1/2, np.sqrt(3)/2]], # Here are the vectors of the Bravais lattice [[0, 0], [0, 1/np.sqrt(3)]]) # Here are the positions of the atoms in the unit cell A, B = graphene.sublattices
w = 29 # width of the ribbon p = SimpleNamespace(t_1=1.0, t_2=0.1, m=0.0, phi=np.pi/2, rand_os=0., rand_nn=0., rand_nnn=0.1)
# Creation of the list of (oriented) bonds that will have the complex hopping term nnn_hoppings_A = (((-1, 0), A, A), ((0, 1), A, A), ((1, -1), A, A)) # Bonds within the A sublattice nnn_hoppings_B = (((1, 0), B, B), ((0, -1), B, B), ((-1, 1), B, B)) # Bonds within the B sublattice nnn_hoppings = nnn_hoppings_A + nnn_hoppings_B
haldane_armchair = kwant.Builder(kwant.TranslationalSymmetry((0, 1*np.sqrt(3))))
haldane_armchair[graphene.shape(ribbon_shape_armchair, (0, 0))] = onsite haldane_armchair[graphene.neighbors(1)] = nn_hopping haldane_armchair[[kwant.builder.HoppingKind(*hopping) for hopping in nnn_hoppings]] = nnn_hopping
kwant.plot(haldane_armchair, site_color=site_color, hop_color=hopping_color, fig_size=(6, 9));
kwant.plotter.bands(haldane_armchair.finalized(), args=[p], fig_size=(12, 8));
-- Abbout Adel
-- Abbout Adel
Hi again, Sorry if I am spamming you a bit, but I have new informations about my issue : - my cell hamiltonian is not hermician, but my full hamiltonian is hermician (tested with 'np.allclose(ham, ham.conjugate().transpose())' for both hamiltonians) - if I put a random magnitude on my second nearest neighbors hopping terms, not a single of these hopping terms remains 'hermician' in my cell hamiltonian, even in the core of the cell (checked by plotting the cell hamiltonian) Using real random hopping terms leads to the same result. I still don't understand why this is happening and how to fix it. I guess it has something to do with how Kwant construct the hamiltonian depending on the symmetries of the system. Best regards, Alexandre
Hi,
Hi again,
Sorry if I am spamming you a bit, but I have new informations about my issue : - my cell hamiltonian is not hermician, but my full hamiltonian is hermician (tested with 'np.allclose(ham, ham.conjugate().transpose())' for both hamiltonians) - if I put a random magnitude on my second nearest neighbors hopping terms, not a single of these hopping terms remains 'hermician' in my cell hamiltonian, even in the core of the cell (checked by plotting the cell hamiltonian) Using real random hopping terms leads to the same result.
I still don't understand why this is happening and how to fix it. I guess it has something to do with how Kwant construct the hamiltonian depending on the symmetries of the system.
This does indeed seem quite mysterious; Kwant should ensure that the cell Hamiltonian is indeed Hermitian. I have observed that if you use 'kwant.digest.uniform' (a hash function), rather than using an RNG then the Hamiltonian is properly Hermitian. You can replace 'random_uni' with 'hash_uniform': def hash_uniform(site1, site2=None, amplitude=0): # Just some unique array per site/hopping arr = site1.tag if site2 is None else np.vstack((site1.tag, site2.tag)) return 2 * amplitude * (kwant.digest.uniform(arr) - 0.5) The fact that this produces a Hermitian cell Hamiltonian strongly suggests that the behaviour you observe has something to do with the use of the RNG. The use of the hashing function still has the property that it assigns completely independent (i.e. not conjugate) values to hoppings (i, j) and (j, i), so the behaviour you observe cannot be due to this. The use of hashes, however, ensures that the same onsite/hopping is always assigned the *same* value (You can control this using the 'salt' parameter to 'kwant.digest.uniform', if required). It will require more investigation to figure out exactly why using an RNG in this case causes unexpected results. Happy Kwanting, Joe
Then, thanks to both of you, I think it is safe to say that the case is solved : the hermicity of the hamiltonian is 'ensured' by Kwant by recalling the same function (and taking the complex conjugate) for i--->j and for j--->i, but in the case of a RNG in the function, this yields to different values. But using a table of random numbers generated with a hash function 'kwant.digest.uniform()' works fine ! Thank you very much for your help ! Alexandre
On 05/22/2018 03:06 PM, alexandre.bernard1@u-psud.fr wrote:
Then, thanks to both of you, I think it is safe to say that the case is solved :
the hermicity of the hamiltonian is 'ensured' by Kwant by _recalling the same function_ (and taking the complex conjugate) for i--->j and for j--->i, but in the case of a RNG in the function, this yields to different values. But using a table of random numbers generated with a hash function 'kwant.digest.uniform()' works fine !
Thank you very much for your help !
Alexandre
Ah yes, I understand now. I had read Adel's answer but did not believe it at first. He was indeed correct. Happy Kwanting, Joe
participants (3)
-
Abbout Adel
-
alexandre.bernard1@u-psud.fr
-
Joseph Weston