add_coupling in SpinModel

How do I use this algorithm? What does that parameter do?
Post Reply
bart
Posts: 26
Joined: 23 Jan 2019, 09:35

add_coupling in SpinModel

Post by bart »

I am not sure how the add_couplings in ``models/spins.py`` are constructed (for the Jx and Jy terms).

When I use the substitutions \(S^\pm=S^x \pm \mathrm{i} S^y\), I get:

\(J_x S^x_i S^x_j + J_y S^y_i S^y_j = \left( \frac{J_x + J_y}{4} \right)(S^+_i S^-_j + S^-_i S^+_j) + \left( \frac{J_x - J_y}{4} \right)(S^+_i S^+_j + S^-_i S^-_j) \)

Writing this with Hermitian conjugates, I get:

\(J_x S^x_i S^x_j + J_y S^y_i S^y_j = \left( \frac{J_x + J_y}{4} \right)(S^+_i S^-_j + (S^+_j S^-_i)^\dagger) + \left( \frac{J_x - J_y}{4} \right)(S^+_i S^+_j + (S^+_j S^+_i)^\dagger) \)

I do not see how this corresponds to the couplings:

Code: Select all

# Sp = Sx + i Sy, Sm = Sx - i Sy,  Sx = (Sp+Sm)/2, Sy = (Sp-Sm)/2i
# Sx.Sx = 0.25 ( Sp.Sm + Sm.Sp + Sp.Sp + Sm.Sm )
# Sy.Sy = 0.25 ( Sp.Sm + Sm.Sp - Sp.Sp - Sm.Sm )
for u1, u2, dx in self.lat.nearest_neighbors:
    self.add_coupling((Jx + Jy) / 4., u1, 'Sp', u2, 'Sm', dx)
    self.add_coupling(np.conj((Jx + Jy) / 4.), u2, 'Sp', u1, 'Sm', -dx)  # h.c.
    self.add_coupling((Jx - Jy) / 4., u1, 'Sp', u2, 'Sp', dx)
    self.add_coupling(np.conj((Jx - Jy) / 4.), u2, 'Sm', u1, 'Sm', -dx)  # h.c.
Specifically, I don't see how the two h.c. couplings are compatible with each other. Presuming the first h.c. coupling is correct, shouldn't the second one read:

Code: Select all

self.add_coupling(np.conj((Jx - Jy) / 4.), u2, 'Sp', u1, 'Sp', -dx)  # h.c.
?

Any clarification as to how to properly construct the h.c. coupling would be much appreciated :-) Also for the cases where one has compound operators on both sides, such as:

Code: Select all

self.add_coupling(J, u1, 'Sp1 Sm1', u2, 'Sp2 Sm2', -dx)
...where 1 and 2 are labels e.g. for a GroupedSite.
User avatar
Johannes
Site Admin
Posts: 413
Joined: 21 Jul 2018, 12:52
Location: TU Munich

Re: add_coupling in SpinModel

Post by Johannes »

bart wrote: 06 May 2019, 13:02 Writing this with Hermitian conjugates, I get:

\(J_x S^x_i S^x_j + J_y S^y_i S^y_j = \left( \frac{J_x + J_y}{4} \right)(S^+_i S^-_j + (S^+_j S^-_i)^\dagger) + \left( \frac{J_x - J_y}{4} \right)(S^+_i S^+_j + (S^+_j S^+_i)^\dagger) \)
Sorry, but I disagree. Using h.c. it reads:
\(J_x S^x_i S^x_j + J_y S^y_i S^y_j = \left( \frac{J_x + J_y}{4} \right)(S^+_i S^-_j + (S^+_i S^-_j)^\dagger) + \left( \frac{J_x - J_y}{4} \right)(S^+_i S^+_j + (S^+_i S^+_j)^\dagger) \\
= \left( \frac{J_x + J_y}{4} \right)(S^+_i S^-_j + h.c.) + \left( \frac{J_x - J_y}{4} \right)(S^+_i S^+_j + h.c.) \)

The second term is always the h.c. of the first term (otherwise H would not be hermitian in total for \(J_x \neq J_y\)).
A general example with unique operator names would be

Code: Select all

self.add_coupling(strength, u1, 'A', u2, 'B', dx)
self.add_coupling(np.conj(strength), u2, 'Bdagger', u1, 'Adagger', -dx)  # h.c.
(The strenght argument can be a site-dependend numpy array, but even in this case it should work.)

To add the h.c. you need to hermitian-conjugate the operators individually (i.e. know the h.c. operator name), and switch the order (including the u1/u2). This is important for Fermions, not so important for spins. Switching the order requires to use -dx instead of dx, otherwise you get different couplings for more complicated lattices (e.g. Honeycomb).
For spins, you could also do

Code: Select all

self.add_coupling(np.conj(strength), u1, 'Adagger', u2, 'Bdagger', dx) # h.c. if A and B on different sites commute (and dx != 0)
In both cases, if you have compound operators, e.g. 'A' -> 'A1 A2 A3', you would follow the usual math rules to get 'Adagger' -> 'A3dagger A2dagger A1dagger'.
For example for 'Sp1 Sm1', you would get '(Sp1 Sm1)dagger' = 'Sp1 Sm1'.
Or, if you have 'Sp1 Sm2', you would get '(Sp1 Sm2)dagger' = 'Sp2 Sm1'.
(assuming that Sp and Sm are the spin S+/S- operators.)
bart
Posts: 26
Joined: 23 Jan 2019, 09:35

Re: add_coupling in SpinModel

Post by bart »

Thank you for quick reply and explanation - this makes sense and is surely correct. I was trying to implement a more complicated Hamiltonian, which then made me generally confused... :oops:

I am looking at a Hamiltonian of the form:

\(
H = J \sum_{<i,j>}\sum_{a,b=1}^3 T^{ab}_i T^{ab}_j
\)

where \(\sigma^a\) and \(\tau^a\) are Pauli operators in spin and valley spaces, and \(T^{ab}=\sigma^a \otimes \tau^b \).

In other words, this is two spin sites grouped together, such that:

Code: Select all

ss = SpinSite(conserve='Sz')
gs = GroupedSite([ss, ss], labels=['spin', 'valley'], charges='same')
Expanding out this Hamiltonian yields:

\(
\begin{align}
\frac{H}{J}=\sum_{<i,j>}( &(\sigma^x_i \otimes \tau^x_i)(\sigma^x_j \otimes \tau^x_j)+(\sigma^x_i \otimes \tau^y_i)(\sigma^x_j \otimes \tau^y_j)+(\sigma^x_i \otimes \tau^z_i)(\sigma^x_j \otimes \tau^z_j) \\
+& (\sigma^y_i \otimes \tau^x_i)(\sigma^y_j \otimes \tau^x_j)+(\sigma^y_i \otimes \tau^y_i)(\sigma^y_j \otimes \tau^y_j)+(\sigma^y_i \otimes \tau^z_i)(\sigma^y_j \otimes \tau^z_j) \\
+& (\sigma^z_i \otimes \tau^x_i)(\sigma^z_j \otimes \tau^x_j)+(\sigma^z_i \otimes \tau^y_i)(\sigma^z_j \otimes \tau^y_j)+(\sigma^z_i \otimes \tau^z_i)(\sigma^z_j \otimes \tau^z_j))
\end{align}
\)

Focusing on the first summand, I can write:

\(\sigma^x_i \otimes \tau^x_i = \left( \frac{\sigma^+_i + \sigma^-_i}{2} \right)\left( \frac{\tau^+_i + \tau^-_i}{2} \right) = \frac{1}{4} (\sigma^+_i \tau ^+_i + \sigma^+_i \tau^-_i + \sigma^-_i \tau^+_i + \tau^-_i \sigma^-_i)\).

These operators do not commute here because they are acting on the same site. Expanding the Hamiltonian in this way yields:

\(
\frac{H}{J}=\sum_{<i,j>}\left( \frac{\sigma^+_i \tau^-_i \sigma^-_j \tau^+_j}{4}+\frac{\sigma^-_i \tau^+_i \sigma^+_j \tau^-_j}{4}+\frac{\sigma^-_i \tau^-_i \sigma^+_j \tau^+_j}{4} + \frac{\sigma^+_i \tau^+_i \sigma^-_j \tau^-_j}{4} + \frac{\sigma^+_i \tau^z_i \sigma^-_j \tau^z_j}{2}+\frac{\sigma^-_i \tau^z_i \sigma^+_j \tau^z_j}{2}+\frac{\sigma^z_i \tau^+_i \sigma^z_j \tau^-_j}{2} + \frac{\sigma^z_i \tau^-_i \sigma^z_j \tau^+_j}{2}\right)+\sigma^z_i \tau^z_i \sigma^z_j \tau^z_j
\)

...which I think can be written as...

\(
\frac{H}{J}=\sum_{<i,j>}\left( \frac{\sigma^+_i \tau^-_i \sigma^-_j \tau^+_j}{4}+\frac{\sigma^-_i \tau^-_i \sigma^+_j \tau^+_j}{4} + \frac{\sigma^+_i \tau^z_i \sigma^-_j \tau^z_j}{2}+\frac{\sigma^z_i \tau^+_i \sigma^z_j \tau^-_j}{2} +\text{H.c.}\right)+\sigma^z_i \tau^z_i \sigma^z_j \tau^z_j
\)

My attempt to implement this in TeNPy is then:

Code: Select all

for u1, u2, dx in self.lat.nearest_neighbors:
    self.add_coupling(1 / 4 * J, u1, 'Spspin Smvalley', u2, 'Smspin Spvalley', dx)
    self.add_coupling(np.conj(1 / 4 * J), u2, 'Spspin Smvalley', u1, 'Smspin Spvalley', -dx)  # H.c.
    self.add_coupling(1 / 4 * J, u1, 'Smspin Smvalley', u2, 'Spspin Spvalley', dx)
    self.add_coupling(np.conj(1 / 4 * J), u2, 'Smspin Smvalley', u1, 'Spspin Spvalley', -dx)  # H.c.
    self.add_coupling(1 / 2 * J, u1, 'Spspin Szvalley', u2, 'Smspin Szvalley', dx)
    self.add_coupling(np.conj(1 / 2 * J), u2, 'Spspin Szvalley', u1, 'Smspin Szvalley', -dx)  # H.c.
    self.add_coupling(1 / 2 * J, u1, 'Szspin Spvalley', u2, 'Szspin Smvalley', dx)
    self.add_coupling(np.conj(1 / 2 * J), u2, 'Szspin Spvalley', u1, 'Szspin Smvalley', -dx)  # H.c.
    self.add_coupling(J, u1, 'Szspin Szvalley', u2, 'Szspin Szvalley', dx)
The code runs at least... Does this implementation look correct to you?
User avatar
Johannes
Site Admin
Posts: 413
Joined: 21 Jul 2018, 12:52
Location: TU Munich

Re: add_coupling in SpinModel

Post by Johannes »

bart wrote: 07 May 2019, 11:02 These operators do not commute here because they are acting on the same site.
\(\sigma_i\) and \(\tau_i\) certianly do commute, which is obvious if you don't think in the grouped-site picture.

In other terms, your hamiltonian is
\(
\begin{align}
H &= J \sum_{<i,j>}
(\sigma^x_i \sigma^x_j + \sigma^y_i \sigma^y_j + \sigma^z_i \sigma^z_j)
(\tau^x_i \tau^x_j + \tau^y_i \tau^y_j + \tau^z_i \tau^z_j) \\
&= J \sum_{<i,j>}
(\frac{1}{2}(\sigma^+_i \sigma^-_j + \sigma^-_i \sigma^+_j) + \sigma^z_i \sigma^z_j)
(\frac{1}{2}(\tau^+_i \tau^-_j + \tau^-_i \tau^+_j) + \tau^z_i \tau^z_j)
\end{align}
\)
which gives the 8 terms (or 4 + h.c. terms) you have obtained.
The implementation looks also fine. :)

And a final remark: if these are the only hopping terms in your hamiltonian, your system does actually preserves the total Sz of just the valley spins and just the "spin" spins independently. :!:
On one hand, you should be aware of this when choosing the initial state (e.g. don't just use Neel pattern (up, down, up, down, ...), but make the neel pattern accross different sites (up, up, down, down, up, up, down, down, ....) or even (up, down, down, up, ...).
On the other hand, you can also exploit it for further speedup (at least for large bond dimensions) with

Code: Select all

gs = GroupedSite([ss, ss], labels=['spin', 'valley'], charges='independent')
bart
Posts: 26
Joined: 23 Jan 2019, 09:35

Re: add_coupling in SpinModel

Post by bart »

Thank you for the clarification, and tips for further speedup! It's helpful to know that I am roughly on the right lines with this now. Thanks again :D
Post Reply