{ "cells": [ { "cell_type": "markdown", "id": "54dd40bd-9ded-476e-8960-b23b44ea3a83", "metadata": {}, "source": [ "# Converting a Circuit to an MPO\n", "\n", "This example shows how to convert a quantum circuit (that is sufficiently shallow) into a matrix product operator (MPO).\n", "\n", "\n", "```{warning}\n", "This simple approach only works when the circuit is shallow enough that the bond dimension is explicitly manageable exactly, and also the gates are local.\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "id": "a7e988e7-1174-4bb8-8018-5cc30303f91d", "metadata": {}, "outputs": [], "source": [ "%config InlineBackend.figure_formats = ['svg']\n", "import quimb.tensor as qtn" ] }, { "cell_type": "markdown", "id": "0b269b50-355a-46e1-8b8b-67007fd93b00", "metadata": {}, "source": [ "First we generate some random 1D gates:" ] }, { "cell_type": "code", "execution_count": 2, "id": "a9043b3e-54fb-4187-b386-f640eaf1a5d4", "metadata": {}, "outputs": [], "source": [ "gates = qtn.circuit_gen.gates_1D_rand(10, depth=8, seed=42)" ] }, { "cell_type": "markdown", "id": "0305b1c2-9fab-4187-ac56-934b9ae08beb", "metadata": {}, "source": [ "Then we construct the [`Circuit`](#Circuit):" ] }, { "cell_type": "code", "execution_count": 3, "id": "6fb9dd46-d562-431d-af68-235c88db8521", "metadata": {}, "outputs": [], "source": [ "circ = qtn.Circuit.from_gates(\n", " gates,\n", " # this ensure each tensor belongs to one site only\n", " gate_contract=\"split-gate\",\n", " # just for cleaner tags\n", " tag_gate_numbers=False,\n", ")" ] }, { "cell_type": "markdown", "id": "e515545c-90d1-4603-922e-80d80f730d2b", "metadata": {}, "source": [ "Next we extract just the unitary part of the tensor network:" ] }, { "cell_type": "code", "execution_count": 4, "id": "b1cb8fcf-6507-4798-9e02-118899ff8cdf", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "tn_uni = circ.get_uni()\n", "tn_uni.draw(tn_uni.site_tags, show_tags=False)" ] }, { "cell_type": "markdown", "id": "a4e13ea9-4b67-4fe7-9eb9-4d077ef66ff2", "metadata": {}, "source": [ "## By direct contraction:\n", "\n", "Then we contract each group of tensor associate with each site (color above):" ] }, { "cell_type": "code", "execution_count": 5, "id": "aeea7aea-2098-44f2-b895-f81b01e22c53", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "for site in tn_uni.site_tags:\n", " tn_uni ^= site\n", "\n", "tn_uni.draw(tn_uni.site_tags, show_tags=False)" ] }, { "cell_type": "code", "execution_count": 6, "id": "cf259f17-2032-46cd-be97-d29a0a2f73e7", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "tn_uni.fuse_multibonds_()\n", "tn_uni.draw(tn_uni.site_tags, show_tags=False)" ] }, { "cell_type": "markdown", "id": "b37b3d70-0291-4b23-bc7a-19edb0620989", "metadata": {}, "source": [ "Now it has the form of an MPO, we can cast it the actual [`MatrixProductOperator`](#MatrixProductOperator) class:" ] }, { "cell_type": "code", "execution_count": 7, "id": "2b807f83-4fb0-48d0-8cd9-0f088fbab22b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
MatrixProductOperator(tensors=10, indices=29, L=10, max_bond=256)
Tensor(shape=(2, 256, 2), inds=[b0, _595a34AAAAf, k0], tags={U3, I0, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b1, _595a34AAAAf, _595a34AAAAp, k1], tags={U3, I1, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b2, _595a34AAAAQ, _595a34AAAAp, k2], tags={U3, I2, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b3, _595a34AAAAQ, _595a34AAAAV, k3], tags={U3, I3, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b4, _595a34AAAAV, _595a34AAAAu, k4], tags={U3, I4, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b5, _595a34AAAAa, _595a34AAAAu, k5], tags={U3, I5, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b6, b, _595a34AAAAa, k6], tags={U3, I6, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b7, b, _595a34AAABi, k7], tags={U3, I7, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 256, 2), inds=[b8, _595a34AAABi, _595a34AAABs, k8], tags={U3, I8, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(2, 256, 2), inds=[b9, _595a34AAABs, k9], tags={U3, I9, CZ}),backend=numpy, dtype=complex128, data=...
" ], "text/plain": [ "MatrixProductOperator(tensors=10, indices=29, L=10, max_bond=256)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tn_uni.view_as_(\n", " qtn.MatrixProductOperator,\n", " cyclic=False,\n", " L=circ.N,\n", ")" ] }, { "cell_type": "markdown", "id": "0ce26b33-a08f-435d-b25d-2ee9f50cdc64", "metadata": {}, "source": [ "```{hint}\n", "You may want or need to call the [`ensure_bonds_exist`](#TensorNetwork1DFlat.ensure_bonds_exist) method at this point if there were not bonds connecting all adjacent tensors in the circuit.\n", "```\n", "\n", "This allows us to call MPO specific methods." ] }, { "cell_type": "code", "execution_count": 8, "id": "2b6b7eec-f044-419b-9d35-9792335876a6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "│4│16│64│128│125│128│64│16│4│\n", "●─<──<──<━━━<━━━<━━━<──<──<─<\n", "│ │ │ │ │ │ │ │ │ │\n" ] } ], "source": [ "tn_uni.compress(cutoff=1e-6, cutoff_mode=\"rel\")\n", "tn_uni.show()" ] }, { "cell_type": "markdown", "id": "04086020-88f6-4624-9ae2-056e9265e85f", "metadata": {}, "source": [ "## By fitting\n", "\n", "An alternative approach that will scale better, especially if a fixed `max_bond` is known ahead of time is to directly fit a low-rank 1D TN to the unitary:" ] }, { "cell_type": "code", "execution_count": 9, "id": "1682edfd-f334-4d30-9a50-662aebe6c3cb", "metadata": {}, "outputs": [], "source": [ "# get a fresh (uncontracted) TN representation of the circuit\n", "tn_uni = circ.get_uni()" ] }, { "cell_type": "code", "execution_count": 10, "id": "0322b9ec-c8a1-4495-b686-2b92b2ec9232", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "max_tdiff=8.62e-07: 8%|8 | 8/100 [00:01<00:14, 6.56it/s]\n" ] } ], "source": [ "# compress via fitting:\n", "tnc = qtn.tensor_network_1d_compress(\n", " tn_uni,\n", " max_bond=32,\n", " cutoff=0.0,\n", " method=\"fit\",\n", " bsz=2, # bsz=1 is cheaper per sweep, but possibly slower to converge\n", " max_iterations=100,\n", " tol=1e-6,\n", " progbar=True,\n", ")" ] }, { "cell_type": "markdown", "id": "1a7a702f-2b2e-4c20-9182-0fdf19ede77f", "metadata": {}, "source": [ "Compute relative frobenius norm error:" ] }, { "cell_type": "code", "execution_count": 11, "id": "d1be1c46-6ae9-4429-a9f5-60c1990cb0e6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "np.float64(0.09292853617632899)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tnc.distance_normalized(tn_uni)" ] }, { "cell_type": "code", "execution_count": 12, "id": "55835bc5-735e-4469-9016-e6df88ffe78d", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
MatrixProductOperator(tensors=10, indices=29, L=10, max_bond=32)
Tensor(shape=(32, 32, 2, 2), inds=[_595a34AAAHg, _595a34AAAHh, b6, k6], tags={U3, I6, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(32, 16, 2, 2), inds=[_595a34AAAHg, _595a34AAAHi, b7, k7], tags={U3, I7, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(32, 16, 2, 2), inds=[_595a34AAAHj, _595a34AAAHk, b2, k2], tags={U3, I2, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(32, 32, 2, 2), inds=[_595a34AAAHj, _595a34AAAHl, b3, k3], tags={U3, I3, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(32, 32, 2, 2), inds=[_595a34AAAHl, _595a34AAAHm, b4, k4], tags={U3, I4, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(32, 32, 2, 2), inds=[_595a34AAAHh, _595a34AAAHm, b5, k5], tags={U3, I5, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(4, 2, 2), inds=[_595a34AAAHn, b0, k0], tags={U3, I0, CZ}),backend=numpy, dtype=complex128, data=array([[[-0.61604372+2.40819678e-17j, 0.25919934+2.30325559e-01j],\n", " [-0.05734167-3.41258809e-01j, 0.32784968-5.22517871e-01j]],\n", "\n", " [[-0.65808868-2.40819678e-17j, 0.1087671 -2.34730203e-01j],\n", " [-0.24610535+7.93029015e-02j, -0.07633141+6.53687583e-01j]],\n", "\n", " [[-0.10613633-2.75222489e-17j, -0.079237 -6.94514262e-01j],\n", " [ 0.59143999-3.73011592e-01j, -0.06566129-8.28022244e-02j]],\n", "\n", " [[ 0.41969573-3.59768069e-17j, 0.53097181-2.05615319e-01j],\n", " [-0.32049612-4.70893724e-01j, 0.34493524+2.37081819e-01j]]])
Tensor(shape=(4, 16, 2, 2), inds=[_595a34AAAHn, _595a34AAAHk, b1, k1], tags={U3, I1, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(16, 4, 2, 2), inds=[_595a34AAAHi, _595a34AAAHo, b8, k8], tags={U3, I8, CZ}),backend=numpy, dtype=complex128, data=...
Tensor(shape=(4, 2, 2), inds=[_595a34AAAHo, b9, k9], tags={U3, I9, CZ}),backend=numpy, dtype=complex128, data=array([[[ 10.46656957-0.j , -8.28078722+3.04946084j],\n", " [ -7.62832633-4.40215621j, -10.30453618-1.75636178j]],\n", "\n", " [[ -8.43641373-0.j , 3.89935365-8.36740555j],\n", " [ -7.84146634-4.86507481j, -7.0820341 +4.61468449j]],\n", "\n", " [[ -5.17145175-0.j , -6.68877199+4.18585282j],\n", " [ 5.20979118-5.94800211j, -0.82457769+5.10399981j]],\n", "\n", " [[ 7.02674189-0.j , 3.03830461-4.03398835j],\n", " [ 3.26177468-3.84660945j, 1.56292165+6.85004125j]]])
" ], "text/plain": [ "MatrixProductOperator(tensors=10, indices=29, L=10, max_bond=32)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# againt cast as MPO if we want more methods\n", "tnc.view_as_(\n", " qtn.MatrixProductOperator,\n", " cyclic=False,\n", " L=circ.N,\n", ")" ] }, { "cell_type": "code", "execution_count": 13, "id": "4a142d78-2d14-4ae7-b39e-5f703a85c260", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "│4│16│32│32│32│32│32│16│4│\n", ">─>──>──>──>──>──>──>──>─●\n", "│ │ │ │ │ │ │ │ │ │\n" ] } ], "source": [ "tnc.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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" } }, "nbformat": 4, "nbformat_minor": 2 }