Hello,

is there a way to have a finite periodic chain (so a ring) for the BoseHubbard model?

As far as I understand setting bc_MPS to "finite" gives a finite chain with open boundary conditions and "infinite" is basically performing iDMRG - or am I already getting this part wrong?

Thanks in advance!

Best regards,

Korbinian

## finite open, finite periodic and infinite periodic chains

### Re: finite open, finite periodic and infinite periodic chains

Kind of. We do

**not**support finite MPS with periodic boundaries for the MPS itself i.e. writing

\[ | \Psi\rangle = \sum Tr(A^{\sigma_1} \cdots A^{\sigma_L}) | \sigma_1 \cdots \sigma_L\rangle \]

This is a form which is usefull analytically (e.g. if you write the ground state of the AKLT model on a finite ring), but not numerically, because it doesn't allow to define a canonical form.

However, you

**can**define a

`bc_MPS="finite"`

and still have periodic couplings in your Hamiltonian. The price you pay for this is that the coupling over the "boundary" of the MPS is long range afterwards. Hence you can't use TEBD, and if you use DMRG, you should definitely use the mixer.To do that, take a look at the parameters documented in init_lattice, i.e. use

`bc_MPS=True, bc_x="periodic"`

.Ian McCulloch once suggested that one can also use a different "enumeration" or "

**order**" of the MPS compared to the physical sites in such a case to avoid having the terribly long range:

Instead of using

\[ | \Psi\rangle = \sum A^{\sigma_1} A^{\sigma_2} A^{\sigma_3} \cdots A^{\sigma_L}) | \sigma_1 \cdots \sigma_L\rangle \]

one could use

\[ | \Psi\rangle = \sum A^{\sigma_L} A^{\sigma_1} A^{\sigma_{L-1}} A^{\sigma_2} A^{\sigma_{L-2}} A^{\sigma_3} \cdots A^{\sigma_{L/2}} | \sigma_1 \cdots \sigma_L\rangle \]

In that way, a nearest neighbor coupling on the ring becomes a next-nearest neighbour coupling for the MPO.

I've never tried that out myself with TeNPy, but it is implemented already with the help of the order. I added a few lines in a git commit a few minutes ago such that you can now use

`order='folded'`

as model parameter for the tenpy.models.lattice.Chain.Be aware the functions like the expectation_value, which return an array with the expectation value of a local operator on each site of an MPS will also be affected by that order. You can use the lattice method mps2lat_values to permute the values in the array such that it corresponds to the original/default order.

### Re: finite open, finite periodic and infinite periodic chains

First of all thanks for providing this feature!Johannes wrote: ↑15 Oct 2019, 15:15(..)

In that way, a nearest neighbor coupling on the ring becomes a next-nearest neighbour coupling for the MPO.

I've never tried that out myself with TeNPy, but it is implemented already with the help of the order. I added a few lines in a git commit a few minutes ago such that you can now use`order='folded'`

as model parameter for the tenpy.models.lattice.Chain.

Be aware the functions like the expectation_value, which return an array with the expectation value of a local operator on each site of an MPS will also be affected by that order. You can use the lattice method mps2lat_values to permute the values in the array such that it corresponds to the original/default order.

I am trying now to use this folding method. What @Johannes wrote here sounds like I can just give a Chain with order="folded" as the lattice in model_params, but is this really the case? Don't i need to have 2 single n-n coupling at initial and last bond and n-n-n-coupling in the bulk, in order to get the periodic circle?

I am talking about n-n models that are inititated like

Code: Select all

```
def init_terms(self, model_params):
# 0) Read and set parameters.
t = get_parameter(model_params, 't', 1., self.name, True)
U = get_parameter(model_params, 'U', 0., self.name, True)
for u in range(len(self.lat.unit_cell)):
self.add_onsite(U / 2., u, 'NN')
for u1, u2, dx in self.lat.pairs['nearest_neighbors']:
self.add_coupling(-t, u1, 'Bd', u2, 'B', dx, plus_hc=True)
```

edit: I guess I am asking how I would implement it in the end. I am bit puzzled by the add_coupling routine and the fact that u1, and u2 are both 0 in the n-n case (general confusion, no specific to this post/model).

Maybe something like this could work:

Code: Select all

```
for u1, u2, dx in self.lat.pairs['nearest_neighbors']:
self.add_coupling(t * np.array([1,0,...0,1]), u1, 'Bd', u2, 'B', dx, plus_hc=True)
for u1, u2, dx in self.lat.pairs['next_nearest_neighbors']:
self.add_coupling(t * np.array([0,1,1,....,1,1,0]), u1, 'Bd', u2, 'B', dx, plus_hc=True)
```

### Re: finite open, finite periodic and infinite periodic chains

Oops!

There was a bug in init_lattice that the 'order' parameter was read out, but not used for 1D lattices (i.e. the Chain and Ladder).

I've quickly fixed this in 9e020640e180d6fb9d09f534a9c91fa047cf6bab.

After this fix, using

Example:
The output:
The entries of order define in which order the MPS winds, and indeed you get the same order as in the bottom of your figure (apart from the fact that python starts counting with 0, so you have to subtract 1).

The second print shows that the "long range" couplings appear correctly: 0-9 now label the sites inside the MPS (left to right in your figure), so we have coupling pairs (0,1), (i, i+2) for 0 < i < 8, and (8,9), as we expect from your figure.

The product state you define for from_lat_product_state is independent of the order, i.e. as you would write it down with "default" order. (The extra brackets are for the unit cell index, for example for the ladder you need two entries each.)

Finally, the function mps2lat_values can be used to convert an array of expectation values back into the canonical form again.

There was a bug in init_lattice that the 'order' parameter was read out, but not used for 1D lattices (i.e. the Chain and Ladder).

I've quickly fixed this in 9e020640e180d6fb9d09f534a9c91fa047cf6bab.

After this fix, using

`order='folded'`

is really "enough", apart from making sure that you understand how to read expectation values etc.Example:

Code: Select all

```
import tenpy
from tenpy.models.spins import SpinModel
M = SpinModel({'L': 10,
'Jx': 0., 'Jy': 0., 'Jz': 1.,
'bc_MPS': 'finite', 'bc_x': 'periodic',
'order': 'folded'})
print("order:")
print(M.lat.order)
print("coupling terms:")
print(M.all_coupling_terms().to_TermList())
ps = [['up'], ['down']] * (M.options['L']//2) # Neel state in lattice order
psi = tenpy.networks.mps.MPS.from_lat_product_state(M.lat, ps)
Sz_mps = psi.expectation_value("Sz")
print("Sz_mps = ", Sz_mps)
Sz_lat = M.lat.mps2lat_values(Sz_mps)
print("Sz_lat = ", Sz_lat)
```

Code: Select all

```
Reading 'bc_MPS'='finite' for config SpinModel
Reading 'order'='folded' for config SpinModel
SpinModel: set conserve to Sz
Reading 'bc_x'='periodic' for config SpinModel
Reading 'L'=10 for config SpinModel
Reading 'Jx'=0.0 for config SpinModel
Reading 'Jy'=0.0 for config SpinModel
Reading 'Jz'=1.0 for config SpinModel
order:
[[0 0]
[9 0]
[1 0]
[8 0]
[2 0]
[7 0]
[3 0]
[6 0]
[4 0]
[5 0]]
coupling terms:
1.00000 * Sz_0 Sz_1 +
1.00000 * Sz_0 Sz_2 +
1.00000 * Sz_1 Sz_3 +
1.00000 * Sz_2 Sz_4 +
1.00000 * Sz_3 Sz_5 +
1.00000 * Sz_4 Sz_6 +
1.00000 * Sz_5 Sz_7 +
1.00000 * Sz_6 Sz_8 +
1.00000 * Sz_7 Sz_9 +
1.00000 * Sz_8 Sz_9
Sz_mps = [ 0.5 -0.5 -0.5 0.5 0.5 -0.5 -0.5 0.5 0.5 -0.5]
Sz_lat = [ 0.5 -0.5 0.5 -0.5 0.5 -0.5 0.5 -0.5 0.5 -0.5]
```

The second print shows that the "long range" couplings appear correctly: 0-9 now label the sites inside the MPS (left to right in your figure), so we have coupling pairs (0,1), (i, i+2) for 0 < i < 8, and (8,9), as we expect from your figure.

The product state you define for from_lat_product_state is independent of the order, i.e. as you would write it down with "default" order. (The extra brackets are for the unit cell index, for example for the ladder you need two entries each.)

Finally, the function mps2lat_values can be used to convert an array of expectation values back into the canonical form again.