Skip to content
This repository was archived by the owner on Nov 7, 2024. It is now read-only.

Commit d12fffb

Browse files
authored
add 2d free fermion mpo (#920)
* add test * add 2d free fermions and ising * import mpos * remove 2d TFising * linting * more linting * fix init * move function definition * remove .copy(), fix typo
1 parent a08618d commit d12fffb

3 files changed

Lines changed: 150 additions & 5 deletions

File tree

tensornetwork/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
from tensornetwork.matrixproductstates.finite_mps import FiniteMPS
3939
from tensornetwork.matrixproductstates.dmrg import FiniteDMRG
4040
from tensornetwork.matrixproductstates.mpo import (FiniteMPO, FiniteTFI,
41-
FiniteXXZ)
41+
FiniteXXZ,
42+
FiniteFreeFermion2D)
4243
from tensornetwork.backend_contextmanager import DefaultBackend
4344
from tensornetwork.backend_contextmanager import set_default_backend
4445
from tensornetwork import block_sparse

tensornetwork/matrixproductstates/mpo.py

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def __init__(self,
4848
self.tensors = [self.backend.convert_to_tensor(t) for t in tensors]
4949
if len(self.tensors) > 0:
5050
if not all(
51-
[self.tensors[0].dtype == tensor.dtype for tensor in self.tensors]):
51+
self.tensors[0].dtype == tensor.dtype for tensor in self.tensors):
5252
raise TypeError('not all dtypes in BaseMPO.tensors are the same')
5353

5454
self.name = name
@@ -62,7 +62,7 @@ def __len__(self) -> int:
6262
@property
6363
def dtype(self) -> Type[np.number]:
6464
if not all(
65-
[self.tensors[0].dtype == tensor.dtype for tensor in self.tensors]):
65+
self.tensors[0].dtype == tensor.dtype for tensor in self.tensors):
6666
raise TypeError('not all dtypes in BaseMPO.tensors are the same')
6767
return self.tensors[0].dtype
6868

@@ -222,7 +222,7 @@ def __init__(self,
222222

223223
class FiniteTFI(FiniteMPO):
224224
"""
225-
The famous transverse field Ising Hamiltonian.
225+
The famous transverse field Ising Hamiltonian.
226226
The ground state energy of the infinite system at criticality is -4/pi.
227227
228228
Convention: sigma_z=diag([-1,1])
@@ -286,3 +286,102 @@ def __init__(self,
286286
temp[2, 0, :, :] = self.Bz[-1] * sigma_z
287287
mpo.append(temp)
288288
super().__init__(tensors=mpo, backend=backend, name=name)
289+
290+
291+
class FiniteFreeFermion2D(FiniteMPO):
292+
"""
293+
Free fermions on a 2d grid
294+
"""
295+
296+
def __init__(self,
297+
t1: float,
298+
t2: float,
299+
v: float,
300+
N1: int,
301+
N2: int,
302+
dtype: Type[np.number],
303+
backend: Optional[Union[AbstractBackend, Text]] = None,
304+
name: Text = '2DTFI_MPO'):
305+
"""
306+
Returns the MPO of the free fermions on
307+
an N1 by N2 grid. The MPO is snaked
308+
along the vertical direction.
309+
310+
Args:
311+
t1: The hopping amplitude along vertical direction.
312+
t2: The hopping amplitude along horizontal direction.
313+
v: local potential strength.
314+
N1: The vertical size of the lattice.
315+
N2: The horizontal size of the lattice.
316+
dtype: The dtype of the MPO.
317+
backend: An optional backend.
318+
name: A name for the MPO.
319+
320+
Returns:
321+
FiniteFreeFermion2D: The mpo of the TFI model on an N1 x N2 grid.
322+
"""
323+
324+
self.t1 = t1
325+
self.t2 = t2
326+
self.N1 = N1
327+
self.N2 = N2
328+
self.v = v
329+
330+
eye = np.eye(2).astype(dtype)
331+
c = np.array([[0, 1], [0, 0]]).astype(dtype)
332+
particle_number = np.diag([0, 1]).astype(dtype)
333+
sigma_z = np.diag([1, -1]).astype(dtype)
334+
cdag = c.T.conj()
335+
336+
mpo_dim = 2 * N1 + 2
337+
mpo_matrix = np.zeros((1, mpo_dim, 2, 2), dtype=dtype)
338+
mpo_matrix[0, 0, :, :] = v * particle_number
339+
340+
mpo_matrix[0, 1, :, :] = t1 * cdag
341+
mpo_matrix[0, N1, :, :] = t2 * cdag
342+
mpo_matrix[0, N1 + 1, :, :] = t1 * c # c @ sigma_z == -c
343+
mpo_matrix[0, 2 * N1, :, :] = t2 * c # c @ sigma_z == -c
344+
345+
mpo_matrix[0, 2 * N1 + 1, :, :] = eye
346+
mpo = [mpo_matrix]
347+
348+
n2 = 0
349+
for n in range(1, N1 * N2 - 1):
350+
if (n + 1) % N1 == 0:
351+
_t1 = 0
352+
else:
353+
_t1 = t1
354+
355+
if n < N1 * (N2 - 1):
356+
_t2 = t2
357+
else:
358+
_t2 = 0
359+
if n % N1 == 0:
360+
n2 += 1
361+
mpo_matrix = np.zeros((mpo_dim, mpo_dim, 2, 2), dtype=dtype)
362+
mpo_matrix[0, 0, :, :] = eye
363+
mpo_matrix[1, 0, :, :] = c
364+
for n1 in range(2, N1 + 1):
365+
mpo_matrix[n1, n1 - 1, :, :] = sigma_z
366+
367+
mpo_matrix[N1 + 1, 0, :, :] = cdag
368+
for n1 in range(N1 + 2, 2 * N1 + 1):
369+
mpo_matrix[n1, n1 - 1, :, :] = sigma_z
370+
371+
mpo_matrix[2 * N1 + 1, 0, :, :] = v * particle_number
372+
373+
mpo_matrix[2 * N1 + 1, 1, :, :] = _t1 * cdag # cdag @ sigma_z == cdag
374+
mpo_matrix[2 * N1 + 1, N1, :, :] = _t2 * cdag
375+
mpo_matrix[2 * N1 + 1, N1+1, :, :] = _t1 * c # c @ sigma_z == -c
376+
mpo_matrix[2 * N1 + 1, 2*N1, :, :] = _t2 * c # c @ sigma_z == -c
377+
378+
mpo_matrix[2 * N1 + 1, 2 * N1 + 1, :, :] = eye
379+
mpo.append(mpo_matrix)
380+
381+
mpo_matrix = np.zeros((mpo_dim, 1, 2, 2), dtype=dtype)
382+
mpo_matrix[0, 0, :, :] = eye
383+
mpo_matrix[1, 0, :, :] = c
384+
mpo_matrix[N1 + 1, 0, :, :] = cdag
385+
mpo_matrix[2 * N1 + 1, 0, :, :] = v * particle_number
386+
mpo.append(mpo_matrix)
387+
super().__init__(tensors=mpo, backend=backend, name=name)

tensornetwork/matrixproductstates/mpo_test.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
import torch
66
from tensornetwork.backends import backend_factory
77
#pylint: disable=line-too-long
8-
from tensornetwork.matrixproductstates.mpo import FiniteMPO, BaseMPO, InfiniteMPO
8+
from tensornetwork.matrixproductstates.mpo import (FiniteMPO,
9+
BaseMPO,
10+
InfiniteMPO,
11+
FiniteFreeFermion2D)
12+
from tensornetwork.matrixproductstates.finite_mps import FiniteMPS
13+
from tensornetwork.matrixproductstates.dmrg import FiniteDMRG
14+
15+
916

1017

1118
@pytest.fixture(
@@ -81,3 +88,41 @@ def test_len(backend):
8188
]
8289
mpo = BaseMPO(tensors=tensors, backend=backend)
8390
assert len(mpo) == 3
91+
92+
93+
@pytest.mark.parametrize("N1, N2, D", [(2, 2, 4), (2, 4, 16), (4, 4, 128)])
94+
def test_finiteFreeFermions2d(N1, N2, D):
95+
def adjacency(N1, N2):
96+
neighbors = {}
97+
mat = np.arange(N1 * N2).reshape(N1, N2)
98+
for n in range(N1 * N2):
99+
x, y = np.divmod(n, N2)
100+
if n not in neighbors:
101+
neighbors[n] = []
102+
if y < N2 - 1:
103+
neighbors[n].append(mat[x, y + 1])
104+
if x > 0:
105+
neighbors[n].append(mat[x - 1, y])
106+
return neighbors
107+
108+
adj = adjacency(N1, N2)
109+
tij = np.zeros((N1 * N2, N1 * N2))
110+
t = -1
111+
v = -1
112+
for n, d in adj.items():
113+
for ind in d:
114+
tij[n, ind] += t
115+
tij[ind, n] += t
116+
tij += np.diag(np.ones(N1 * N2) * v)
117+
118+
eta, _ = np.linalg.eigh(tij)
119+
expected = min(np.cumsum(eta))
120+
121+
t1 = t
122+
t2 = t
123+
dtype = np.float64
124+
mpo = FiniteFreeFermion2D(t1, t2, v, N1, N2, dtype)
125+
mps = FiniteMPS.random([2] * N1 * N2, [D] * (N1 * N2 - 1), dtype=np.float64)
126+
dmrg = FiniteDMRG(mps, mpo)
127+
actual = dmrg.run_one_site()
128+
np.testing.assert_allclose(actual, expected)

0 commit comments

Comments
 (0)