{ "cells": [ { "cell_type": "markdown", "source": [ "# MERA" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Overview\n", "\n", "In this tutorial, we'll show you how to implement MERA (multi-scale entangled renormalization ansatz) with TensorCircuit, but not in physics perspective." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Background\n", "\n", "MERA is a kind of VQE starts from only one qubit in the $\\ket{0}$ state, and progressively enlarges the Hilbert space by tensoring on new qubits.\n", "In the MERA we are going to train (denoted by $U(\\theta)$), we use parameterized quantum gates $e^{i\\theta XX}$, $e^{i\\theta ZZ}$ as two-qubit gates and $e^{i\\theta X}$, $e^{i\\theta Z}$ as single-qubit gates.\n", "The Hamiltonian we choose as the example is from TFIM as $\\hat{H}_{Ising}=J\\sum_{i}{Z_{i}Z_{i+1}}-B_{x}\\sum_{i}{X_{i}}$. \n", "And the loss function to be minimized in this task is $\\mathcal{L}_{MERA}(\\rm{\\theta})=\\langle 0^n\\vert U(\\theta)^\\dagger \\hat{H} U(\\theta)\\vert 0^n\\rangle$. " ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Setup" ], "metadata": {} }, { "cell_type": "code", "execution_count": 1, "source": [ "import numpy as np\n", "import tensorflow as tf\n", "import tensorcircuit as tc\n", "\n", "tc.set_backend(\"tensorflow\")\n", "tc.set_dtype(\"complex128\")" ], "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "('complex128', 'float64')" ] }, "metadata": {}, "execution_count": 1 } ], "metadata": { "scrolled": false } }, { "cell_type": "markdown", "source": [ "## Energy\n", "We first design the Hamiltonian energy expectation function as loss.\n", "$$ \\hat{H}_{Ising}=J\\sum_{i}{Z_{i}Z_{i+1}}-B_{x}\\sum_{i}{X_{i}} $$" ], "metadata": {} }, { "cell_type": "code", "execution_count": 2, "source": [ "def energy(c: tc.Circuit, j: float = 1.0, hx: float = 1.0):\n", " e = 0.0\n", " n = c._nqubits\n", " # \n", " for i in range(n - 1):\n", " e += j * c.expectation((tc.gates.z(), [i]), (tc.gates.z(), [i + 1]))\n", " # \n", " for i in range(n):\n", " e -= hx * c.expectation((tc.gates.x(), [i]))\n", " return tc.backend.real(e)" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "## MERA circuit\n", "\n", "Now we design the circuit. We use $\\theta$ as input." ], "metadata": {} }, { "cell_type": "code", "execution_count": 5, "source": [ "def MERA(params, n):\n", " params = tc.backend.cast(params, \"complex128\")\n", " c = tc.Circuit(n)\n", "\n", " idx = 0 # index of params\n", "\n", " for i in range(n):\n", " c.rx(i, theta=params[2 * i])\n", " c.rz(i, theta=params[2 * i + 1])\n", " idx += 2 * n\n", "\n", " for n_layer in range(1, int(np.log2(n)) + 1):\n", " n_qubit = 2**n_layer # number of qubits involving\n", " step = int(n / n_qubit)\n", "\n", " # even\n", " for i in range(step, n - step, 2 * step):\n", " c.exp1(i, i + step, theta=params[idx], unitary=tc.gates._xx_matrix)\n", " c.exp1(i, i + step, theta=params[idx + 1], unitary=tc.gates._zz_matrix)\n", " idx += 2\n", "\n", " # odd\n", " for i in range(0, n, 2 * step):\n", " c.exp1(i, i + step, theta=params[idx], unitary=tc.gates._xx_matrix)\n", " c.exp1(i, i + step, theta=params[idx + 1], unitary=tc.gates._zz_matrix)\n", " idx += 2\n", "\n", " # single qubit\n", " for i in range(0, n, step):\n", " c.rx(i, theta=params[idx])\n", " c.rz(i, theta=params[idx + 1])\n", " idx += 2\n", "\n", " # measure\n", " e = energy(c)\n", " return e\n", " # return c, idx" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "We can visualize the MERA circuit. \n", "\n", "Hint: Please change return to `return c, idx`, which will only be used here. After visulization, don't forget to restore the return and run the code block above again." ], "metadata": {} }, { "cell_type": "code", "execution_count": 4, "source": [ "n = 8\n", "cirq, idx = MERA(np.zeros(1000), n)\n", "print(\"The number of parameters is\", idx)\n", "cirq.draw()" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "The number of parameters is 66\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ "
" ], "image/svg+xml": "\n\n\n \n \n \n \n 2022-12-05T21:29:46.404387\n image/svg+xml\n \n \n Matplotlib v3.5.3, https://matplotlib.org/\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" }, "metadata": {}, "execution_count": 4 } ], "metadata": { "scrolled": true } }, { "cell_type": "markdown", "source": [ "## Train\n", "\n", "Now we can train the MERA circuit with tensorflow." ], "metadata": {} }, { "cell_type": "code", "execution_count": 6, "source": [ "MERA_tfim_vvag = tc.backend.jit(tc.backend.vectorized_value_and_grad(MERA))\n", "\n", "\n", "def batched_train(n, batch=10, maxiter=10000, lr=0.005):\n", " params = tf.Variable(\n", " initial_value=tf.random.normal(\n", " shape=[batch, idx], stddev=1, dtype=getattr(tf, tc.rdtypestr)\n", " )\n", " )\n", " opt = tf.keras.optimizers.Adam(lr)\n", " lowest_energy = 1e5\n", " for i in range(maxiter):\n", " e, grad = MERA_tfim_vvag(params, n)\n", " opt.apply_gradients([(grad, params)])\n", " if tf.reduce_min(e) < lowest_energy:\n", " lowest_energy = tf.reduce_min(e)\n", " if i % 200 == 0:\n", " print(e)\n", " return lowest_energy\n", "\n", "\n", "n = 8\n", "lowest_energy = batched_train(n, batch=5, maxiter=2000, lr=0.007)" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "tf.Tensor([-0.6449017 0.14083987 0.17227418 1.42731099 0.93767164], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.57952648 -9.15354269 -9.53415983 -9.55291257 -9.46880555], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.63166728 -9.60922826 -9.59883555 -9.66639936 -9.60174669], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.65441326 -9.61830383 -9.6219077 -9.68289435 -9.61427165], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.66991104 -9.6307931 -9.64993901 -9.71396225 -9.63848947], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.67960751 -9.64303661 -9.67696885 -9.76317346 -9.6507455 ], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.68303361 -9.6575349 -9.70118521 -9.7740601 -9.65751254], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.68481667 -9.67473162 -9.71392119 -9.78200161 -9.66880068], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.6864865 -9.67835678 -9.73033137 -9.79128949 -9.68317883], shape=(5,), dtype=float64)\n", "tf.Tensor([-9.68762425 -9.67928153 -9.77502182 -9.79465957 -9.69252806], shape=(5,), dtype=float64)\n" ] } ], "metadata": { "scrolled": false } }, { "cell_type": "markdown", "source": [ "## Compare\n", "\n", "We can compare the ground energy we get by MERA with DMRG." ], "metadata": {} }, { "cell_type": "code", "execution_count": 7, "source": [ "# DMRG\n", "import quimb\n", "\n", "h = quimb.tensor.tensor_gen.MPO_ham_ising(n, j=4.0, bx=2.0, S=0.5, cyclic=False)\n", "dmrg = quimb.tensor.tensor_dmrg.DMRG(\n", " h, bond_dims=[10, 20, 100, 100, 200], cutoffs=1e-13\n", ")\n", "dmrg.solve(tol=1e-9, verbosity=0)\n", "energy_DMRG = dmrg.energy\n", "\n", "# Compare\n", "print(\"DMRG solution: \", energy_DMRG)\n", "print(\"MERA solution: \", lowest_energy.numpy())" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "DMRG solution: -9.837951447459426\n", "MERA solution: -9.795198473308487\n" ] } ], "metadata": {} } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.12 64-bit", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" }, "vscode": { "interpreter": { "hash": "18d2a9923f839b0d86cf68fd09770e726264cf9d62311eaf57b1fff0ca4bed8e" } } }, "nbformat": 4, "nbformat_minor": 5 }