MERA#

概述#

在本教程中,我们将不涉及物理层面的探讨,而将演示如何使用TensorCircuit实现MERA (多尺度纠缠重整化假设,multi-scale entangled renormalization ansatz)。

背景#

MERA是VQE的其中一种。它由一个量子比特的 \(\ket{0}\) 态开始,逐层添加新的量子比特以扩张希尔伯特空间。 在将要训练的MERA(记作 \(U(\theta)\) )中,我们使用可变参量子门 \(e^{i\theta XX}\)\(e^{i\theta ZZ}\) 作为双比特门,以及 \(e^{i\theta X}\)\(e^{i\theta Z}\) 作为单比特门。 在本教程中,我们使用的哈密顿量是横场伊辛模型的哈密顿量 \(\hat{H}_{Ising}=J\sum_{i}{Z_{i}Z_{i+1}}-B_{x}\sum_{i}{X_{i}}\)。 我们要减小的损失函数是 \(\mathcal{L}_{MERA}(\rm{\theta})=\langle 0^n\vert U(\theta)^\dagger \hat{H} U(\theta)\vert 0^n\rangle\)

设置#

[1]:
import numpy as np
import tensorflow as tf
import tensorcircuit as tc

tc.set_backend("tensorflow")
tc.set_dtype("complex128")
[1]:
('complex128', 'float64')

能量#

我们先设计哈密顿量的能量期望函数作为损失函数。

\[\hat{H}_{Ising}=J\sum_{i}{Z_{i}Z_{i+1}}-B_{x}\sum_{i}{X_{i}}\]
[2]:
def energy(c: tc.Circuit, j: float = 1.0, hx: float = 1.0):
    e = 0.0
    n = c._nqubits
    # <Z_i Z_{i+1}>
    for i in range(n - 1):
        e += j * c.expectation((tc.gates.z(), [i]), (tc.gates.z(), [i + 1]))
    # <X_i>
    for i in range(n):
        e -= hx * c.expectation((tc.gates.x(), [i]))
    return tc.backend.real(e)

MERA 电路#

现在,我们设计电路。我们用 \(\theta\) 作为输入。

[5]:
def MERA(params, n):
    params = tc.backend.cast(params, "complex128")
    c = tc.Circuit(n)

    idx = 0  # index of params

    for i in range(n):
        c.rx(i, theta=params[2 * i])
        c.rz(i, theta=params[2 * i + 1])
    idx += 2 * n

    for n_layer in range(1, int(np.log2(n)) + 1):
        n_qubit = 2**n_layer  # number of qubits involving
        step = int(n / n_qubit)

        # 偶数层
        for i in range(step, n - step, 2 * step):
            c.exp1(i, i + step, theta=params[idx], unitary=tc.gates._xx_matrix)
            c.exp1(i, i + step, theta=params[idx + 1], unitary=tc.gates._zz_matrix)
            idx += 2

        # 奇数层
        for i in range(0, n, 2 * step):
            c.exp1(i, i + step, theta=params[idx], unitary=tc.gates._xx_matrix)
            c.exp1(i, i + step, theta=params[idx + 1], unitary=tc.gates._zz_matrix)
            idx += 2

        # 单比特门
        for i in range(0, n, step):
            c.rx(i, theta=params[idx])
            c.rz(i, theta=params[idx + 1])
            idx += 2

    # 测量
    e = energy(c)
    return e
    # return c, idx

我们可以将MERA电路可视化。

注意:请把return改为return c, idx。这个return只有在这儿会被用到。可视化完成后,请别忘了将return还原并重新运行上方代码块。

[4]:
n = 8
cirq, idx = MERA(np.zeros(1000), n)
print("The number of parameters is", idx)
cirq.draw()
The number of parameters is 66
[4]:
../_images/tutorials_mera_cn_10_1.svg

训练#

现在,我们使用tensorflow训练MERA电路。

[6]:
MERA_tfim_vvag = tc.backend.jit(tc.backend.vectorized_value_and_grad(MERA))


def batched_train(n, batch=10, maxiter=10000, lr=0.005):
    params = tf.Variable(
        initial_value=tf.random.normal(
            shape=[batch, idx], stddev=1, dtype=getattr(tf, tc.rdtypestr)
        )
    )
    opt = tf.keras.optimizers.Adam(lr)
    lowest_energy = 1e5
    for i in range(maxiter):
        e, grad = MERA_tfim_vvag(params, n)
        opt.apply_gradients([(grad, params)])
        if tf.reduce_min(e) < lowest_energy:
            lowest_energy = tf.reduce_min(e)
        if i % 200 == 0:
            print(e)
    return lowest_energy


n = 8
lowest_energy = batched_train(n, batch=5, maxiter=2000, lr=0.007)
tf.Tensor([-0.6449017   0.14083987  0.17227418  1.42731099  0.93767164], shape=(5,), dtype=float64)
tf.Tensor([-9.57952648 -9.15354269 -9.53415983 -9.55291257 -9.46880555], shape=(5,), dtype=float64)
tf.Tensor([-9.63166728 -9.60922826 -9.59883555 -9.66639936 -9.60174669], shape=(5,), dtype=float64)
tf.Tensor([-9.65441326 -9.61830383 -9.6219077  -9.68289435 -9.61427165], shape=(5,), dtype=float64)
tf.Tensor([-9.66991104 -9.6307931  -9.64993901 -9.71396225 -9.63848947], shape=(5,), dtype=float64)
tf.Tensor([-9.67960751 -9.64303661 -9.67696885 -9.76317346 -9.6507455 ], shape=(5,), dtype=float64)
tf.Tensor([-9.68303361 -9.6575349  -9.70118521 -9.7740601  -9.65751254], shape=(5,), dtype=float64)
tf.Tensor([-9.68481667 -9.67473162 -9.71392119 -9.78200161 -9.66880068], shape=(5,), dtype=float64)
tf.Tensor([-9.6864865  -9.67835678 -9.73033137 -9.79128949 -9.68317883], shape=(5,), dtype=float64)
tf.Tensor([-9.68762425 -9.67928153 -9.77502182 -9.79465957 -9.69252806], shape=(5,), dtype=float64)

对比#

我们可以把我们用MERA得到的基态能量和DMRG进行对比。

[7]:
# DMRG
import quimb

h = quimb.tensor.tensor_gen.MPO_ham_ising(n, j=4.0, bx=2.0, S=0.5, cyclic=False)
dmrg = quimb.tensor.tensor_dmrg.DMRG(
    h, bond_dims=[10, 20, 100, 100, 200], cutoffs=1e-13
)
dmrg.solve(tol=1e-9, verbosity=0)
energy_DMRG = dmrg.energy

# Compare
print("DMRG solution: ", energy_DMRG)
print("MERA solution: ", lowest_energy.numpy())
DMRG solution:  -9.837951447459426
MERA solution:  -9.795198473308487