{ "cells": [ { "cell_type": "markdown", "id": "be565231", "metadata": {}, "source": [ "# Circuit Basics" ] }, { "cell_type": "markdown", "id": "fcdfed33", "metadata": {}, "source": [ "## Overview\n", "\n", "In this note, we will learn about basic operations of the core object in TensorCircuit - ``tc.Circuit`` which supports both noiseless simulation and noisy simulation with the Monte Carlo trajectory-based method. More importantly, near all the operations on the Circuit object is differentiable and jittable, which is the key for successful and efficient variational quantum algorithm simulations.\n", "\n", "[WIP note]" ] }, { "cell_type": "markdown", "id": "c51c024b", "metadata": {}, "source": [ "## Setup" ] }, { "cell_type": "code", "execution_count": 1, "id": "98f21e9b", "metadata": {}, "outputs": [], "source": [ "from functools import partial\n", "import inspect\n", "import sys\n", "import numpy as np\n", "import tensorflow as tf\n", "\n", "import tensorcircuit as tc" ] }, { "cell_type": "markdown", "id": "558cdc17", "metadata": {}, "source": [ "## Hello world example" ] }, { "cell_type": "code", "execution_count": 2, "id": "b83f24f4", "metadata": {}, "outputs": [], "source": [ "def get_circuit(n):\n", " c = tc.Circuit(n) # initialize a circuit object with n qubits\n", " for i in range(n):\n", " c.H(i) # apply Hadamard gate on each qubit\n", " c.cnot(0, 1) # apply cnot with control qubit on 0-th qubit\n", " c.CNOT(n - 1, n - 2) # capitalized API also works\n", " return c" ] }, { "cell_type": "code", "execution_count": 3, "id": "601a072c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['i', 'x', 'y', 'z', 'h', 't', 's', 'td', 'sd', 'wroot', 'cnot', 'cz', 'swap', 'cy', 'iswap', 'ox', 'oy', 'oz', 'toffoli', 'fredkin']\n" ] } ], "source": [ "# print possible gates without parameters\n", "print(tc.Circuit.sgates)" ] }, { "cell_type": "code", "execution_count": 4, "id": "c191ea53", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i\n", "[[1.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j]]\n", "x\n", "[[0.+0.j 1.+0.j]\n", " [1.+0.j 0.+0.j]]\n", "y\n", "[[0.+0.j 0.-1.j]\n", " [0.+1.j 0.+0.j]]\n", "z\n", "[[ 1.+0.j 0.+0.j]\n", " [ 0.+0.j -1.+0.j]]\n", "h\n", "[[ 0.70710677+0.j 0.70710677+0.j]\n", " [ 0.70710677+0.j -0.70710677+0.j]]\n", "t\n", "[[1. +0.j 0. +0.j ]\n", " [0. +0.j 0.70710677+0.70710677j]]\n", "s\n", "[[1.+0.j 0.+0.j]\n", " [0.+0.j 0.+1.j]]\n", "td\n", "[[1. +0.j 0. +0.j ]\n", " [0. +0.j 0.70710677-0.70710677j]]\n", "sd\n", "[[1.+0.j 0.+0.j]\n", " [0.+0.j 0.-1.j]]\n", "wroot\n", "[[ 0.70710677+0.j -0.5 -0.5j]\n", " [ 0.5 -0.5j 0.70710677+0.j ]]\n", "cnot\n", "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]\n", " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]]\n", "cz\n", "[[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n", " [ 0.+0.j 0.+0.j 0.+0.j -1.+0.j]]\n", "swap\n", "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n", "cy\n", "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.-1.j]\n", " [0.+0.j 0.+0.j 0.+1.j 0.+0.j]]\n", "iswap\n", "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+1.j 0.+0.j]\n", " [0.+0.j 0.+1.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n", "ox\n", "[[0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n", "oy\n", "[[0.+0.j 0.-1.j 0.+0.j 0.+0.j]\n", " [0.+1.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n", "oz\n", "[[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [ 0.+0.j -1.+0.j 0.+0.j 0.+0.j]\n", " [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n", " [ 0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n", "toffoli\n", "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j]]\n", "fredkin\n", "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n" ] } ], "source": [ "# the corresponding matrix for these gates definition\n", "for g in tc.Circuit.sgates:\n", " gf = getattr(tc.gates, g)\n", " print(g)\n", " print(tc.gates.matrix_for_gate(gf()))" ] }, { "cell_type": "code", "execution_count": 5, "id": "96c15225", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'gatef': h,\n", " 'gate': Gate(\n", " name: 'h',\n", " tensor:\n", " array([[ 0.70710677+0.j, 0.70710677+0.j],\n", " [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n", " edges: [\n", " Edge('cnot'[2] -> 'h'[0] ),\n", " Edge('h'[1] -> 'qb-1'[0] )\n", " ]),\n", " 'index': (0,),\n", " 'name': 'h',\n", " 'split': None,\n", " 'mpo': False},\n", " {'gatef': h,\n", " 'gate': Gate(\n", " name: 'h',\n", " tensor:\n", " array([[ 0.70710677+0.j, 0.70710677+0.j],\n", " [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n", " edges: [\n", " Edge('cnot'[3] -> 'h'[0] ),\n", " Edge('h'[1] -> 'qb-2'[0] )\n", " ]),\n", " 'index': (1,),\n", " 'name': 'h',\n", " 'split': None,\n", " 'mpo': False},\n", " {'gatef': h,\n", " 'gate': Gate(\n", " name: 'h',\n", " tensor:\n", " array([[ 0.70710677+0.j, 0.70710677+0.j],\n", " [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n", " edges: [\n", " Edge('cnot'[2] -> 'h'[0] ),\n", " Edge('h'[1] -> 'qb-3'[0] )\n", " ]),\n", " 'index': (2,),\n", " 'name': 'h',\n", " 'split': None,\n", " 'mpo': False},\n", " {'gatef': cnot,\n", " 'gate': Gate(\n", " name: 'cnot',\n", " tensor:\n", " array([[[[1.+0.j, 0.+0.j],\n", " [0.+0.j, 0.+0.j]],\n", " \n", " [[0.+0.j, 1.+0.j],\n", " [0.+0.j, 0.+0.j]]],\n", " \n", " \n", " [[[0.+0.j, 0.+0.j],\n", " [0.+0.j, 1.+0.j]],\n", " \n", " [[0.+0.j, 0.+0.j],\n", " [1.+0.j, 0.+0.j]]]], dtype=complex64),\n", " edges: [\n", " Edge(Dangling Edge)[0],\n", " Edge('cnot'[3] -> 'cnot'[1] ),\n", " Edge('cnot'[2] -> 'h'[0] ),\n", " Edge('cnot'[3] -> 'h'[0] )\n", " ]),\n", " 'index': (0, 1),\n", " 'name': 'cnot',\n", " 'split': None,\n", " 'mpo': False},\n", " {'gatef': cnot,\n", " 'gate': Gate(\n", " name: 'cnot',\n", " tensor:\n", " array([[[[1.+0.j, 0.+0.j],\n", " [0.+0.j, 0.+0.j]],\n", " \n", " [[0.+0.j, 1.+0.j],\n", " [0.+0.j, 0.+0.j]]],\n", " \n", " \n", " [[[0.+0.j, 0.+0.j],\n", " [0.+0.j, 1.+0.j]],\n", " \n", " [[0.+0.j, 0.+0.j],\n", " [1.+0.j, 0.+0.j]]]], dtype=complex64),\n", " edges: [\n", " Edge(Dangling Edge)[0],\n", " Edge(Dangling Edge)[1],\n", " Edge('cnot'[2] -> 'h'[0] ),\n", " Edge('cnot'[3] -> 'cnot'[1] )\n", " ]),\n", " 'index': (2, 1),\n", " 'name': 'cnot',\n", " 'split': None,\n", " 'mpo': False}]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = get_circuit(3)\n", "ir = c.to_qir() # intermediate representation of the circuit\n", "ir" ] }, { "cell_type": "code", "execution_count": 6, "id": "9ab7fd6e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(array([[ 0.70710677+0.j, 0.70710677+0.j],\n", " [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n", " array([[[[1.+0.j, 0.+0.j],\n", " [0.+0.j, 0.+0.j]],\n", " \n", " [[0.+0.j, 1.+0.j],\n", " [0.+0.j, 0.+0.j]]],\n", " \n", " \n", " [[[0.+0.j, 0.+0.j],\n", " [0.+0.j, 1.+0.j]],\n", " \n", " [[0.+0.j, 0.+0.j],\n", " [1.+0.j, 0.+0.j]]]], dtype=complex64))" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ir[0][\"gatef\"]().tensor, ir[-1][\"gate\"].tensor # the actually unitary for each gate" ] }, { "cell_type": "code", "execution_count": 7, "id": "ecdc0f1a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j,\n", " 0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j],\n", " dtype=complex64)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# compute the final output quantum state from the circuit\n", "c.state()" ] }, { "cell_type": "code", "execution_count": 8, "id": "64fa321b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0.9999998+0j) 0j\n" ] } ], "source": [ "# compute some expectation values, say \n", "x1 = c.expectation([tc.gates.x(), [1]])\n", "\n", "# or \n", "z1z2 = c.expectation([tc.gates.z(), [1]], [tc.gates.z(), [2]])\n", "\n", "print(x1, z1z2)" ] }, { "cell_type": "code", "execution_count": 9, "id": "c8292569", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(array([0., 0., 0.], dtype=float32), 0.12499997764825821)\n", "(array([1., 1., 0.], dtype=float32), 0.1249999776482098)\n", "(array([1., 1., 0.], dtype=float32), 0.1249999776482098)\n", "(array([0., 1., 0.], dtype=float32), 0.12499997764825821)\n", "(array([1., 0., 0.], dtype=float32), 0.12499997019766829)\n", "(array([0., 0., 1.], dtype=float32), 0.12499997764825821)\n", "(array([1., 1., 1.], dtype=float32), 0.1250001713634208)\n", "(array([1., 0., 0.], dtype=float32), 0.12499997019766829)\n", "(array([0., 1., 1.], dtype=float32), 0.12499997764825821)\n", "(array([1., 0., 1.], dtype=float32), 0.12499997019766829)\n" ] } ], "source": [ "# make some random samples\n", "for _ in range(10):\n", " print(c.perfect_sampling())" ] }, { "cell_type": "code", "execution_count": 10, "id": "c2c0bb84", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j\n", " 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j], shape=(8,), dtype=complex64)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "[0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j\n", " 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j]\n", "tensor([0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j,\n", " 0.3536+0.j])\n" ] } ], "source": [ "# we can easily switch simulation backends away from NumPy!\n", "\n", "with tc.runtime_backend(\"tensorflow\") as K:\n", " c = get_circuit(3)\n", " print(c.state())\n", "\n", "with tc.runtime_backend(\"jax\") as K:\n", " c = get_circuit(3)\n", " print(c.state())\n", "\n", "with tc.runtime_backend(\"pytorch\") as K:\n", " # best performance and full functionality are not guaranteed on pytorch backend\n", " c = get_circuit(3)\n", " print(c.state())" ] }, { "cell_type": "markdown", "id": "0cbe17e7", "metadata": {}, "source": [ "## Parameterized Quantum Circuit (PQC)" ] }, { "cell_type": "code", "execution_count": 11, "id": "66192a2d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['r', 'cr', 'rx', 'ry', 'rz', 'crx', 'cry', 'crz', 'orx', 'ory', 'orz', 'any', 'exp', 'exp1']\n" ] } ], "source": [ "# circuit gates that accept parameters\n", "\n", "print(tc.Circuit.vgates)" ] }, { "cell_type": "code", "execution_count": 12, "id": "bae96276", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "r (theta: float = 0, alpha: float = 0, phi: float = 0) -> tensorcircuit.gates.Gate\n", "cr (theta: float = 0, alpha: float = 0, phi: float = 0) -> tensorcircuit.gates.Gate\n", "rx (theta: float = 0) -> tensorcircuit.gates.Gate\n", "ry (theta: float = 0) -> tensorcircuit.gates.Gate\n", "rz (theta: float = 0) -> tensorcircuit.gates.Gate\n", "crx (*args: Any, **kws: Any) -> Any\n", "cry (*args: Any, **kws: Any) -> Any\n", "crz (*args: Any, **kws: Any) -> Any\n", "orx (*args: Any, **kws: Any) -> Any\n", "ory (*args: Any, **kws: Any) -> Any\n", "orz (*args: Any, **kws: Any) -> Any\n", "any (unitary: Any, name: str = 'any') -> tensorcircuit.gates.Gate\n", "exp (unitary: Any, theta: float, name: str = 'none') -> tensorcircuit.gates.Gate\n", "exp1 (unitary: Any, theta: float, name: str = 'none') -> tensorcircuit.gates.Gate\n" ] } ], "source": [ "# see the keyword parameters (with type float) for each type of variable gate\n", "for g in tc.Circuit.vgates:\n", " print(g, inspect.signature(getattr(tc.gates, g).f))" ] }, { "cell_type": "code", "execution_count": 13, "id": "55df5ffa", "metadata": {}, "outputs": [], "source": [ "def get_circuit(n, params):\n", " c = tc.Circuit(n) # initialize a circuit object with n qubits\n", " for i in range(n):\n", " c.rx(i, theta=params[i]) # apply rx gate\n", " c.cnot(0, 1)\n", " return c" ] }, { "cell_type": "code", "execution_count": 14, "id": "84392f01", "metadata": {}, "outputs": [], "source": [ "K = tc.set_backend(\"tensorflow\")" ] }, { "cell_type": "code", "execution_count": 15, "id": "24ba6d64", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[ 0.6758712 +0.j 0. -0.36923012j 0. -0.36923015j\n", " -0.20171136-0.j -0.20171136+0.j 0. +0.11019541j\n", " 0. -0.36923015j -0.20171136-0.j ], shape=(8,), dtype=complex64)\n" ] } ], "source": [ "n = 3\n", "params = K.ones([n])\n", "c = get_circuit(n, params)\n", "print(c.state())" ] }, { "cell_type": "code", "execution_count": 16, "id": "c85cb07f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'gatef': rx,\n", " 'index': (0,),\n", " 'name': 'rx',\n", " 'split': None,\n", " 'mpo': False,\n", " 'parameters': {'theta': },\n", " 'gate': Gate(\n", " name: '__unnamed_node__',\n", " tensor:\n", " ,\n", " edges: [\n", " Edge('cnot'[2] -> '__unnamed_node__'[0] ),\n", " Edge('__unnamed_node__'[1] -> 'qb-1'[0] )\n", " ])},\n", " {'gatef': rx,\n", " 'index': (1,),\n", " 'name': 'rx',\n", " 'split': None,\n", " 'mpo': False,\n", " 'parameters': {'theta': },\n", " 'gate': Gate(\n", " name: '__unnamed_node__',\n", " tensor:\n", " ,\n", " edges: [\n", " Edge('cnot'[3] -> '__unnamed_node__'[0] ),\n", " Edge('__unnamed_node__'[1] -> 'qb-2'[0] )\n", " ])},\n", " {'gatef': rx,\n", " 'index': (2,),\n", " 'name': 'rx',\n", " 'split': None,\n", " 'mpo': False,\n", " 'parameters': {'theta': },\n", " 'gate': Gate(\n", " name: '__unnamed_node__',\n", " tensor:\n", " ,\n", " edges: [\n", " Edge(Dangling Edge)[0],\n", " Edge('__unnamed_node__'[1] -> 'qb-3'[0] )\n", " ])},\n", " {'gatef': cnot,\n", " 'gate': Gate(\n", " name: 'cnot',\n", " tensor:\n", " ,\n", " edges: [\n", " Edge(Dangling Edge)[0],\n", " Edge(Dangling Edge)[1],\n", " Edge('cnot'[2] -> '__unnamed_node__'[0] ),\n", " Edge('cnot'[3] -> '__unnamed_node__'[0] )\n", " ]),\n", " 'index': (0, 1),\n", " 'name': 'cnot',\n", " 'split': None,\n", " 'mpo': False}]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ir = c.to_qir()\n", "ir" ] }, { "cell_type": "code", "execution_count": 17, "id": "71ca41e2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# see the gate unitary\n", "ir[0][\"gatef\"](**ir[0][\"parameters\"]).tensor" ] }, { "cell_type": "code", "execution_count": 18, "id": "eb13a4ef", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(, )\n" ] } ], "source": [ "# let us compose a differentiable quantum function\n", "\n", "\n", "def energy(params):\n", " c = get_circuit(n, params)\n", " return K.real(c.expectation([tc.gates.z(), [1]]))\n", "\n", "\n", "energy_vag = K.value_and_grad(energy)\n", "\n", "print(energy_vag(params))\n", "\n", "# once we have the gradient, we can run gradient-based descent for variational optimization" ] }, { "cell_type": "code", "execution_count": 19, "id": "1a82a3a1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(, )\n" ] } ], "source": [ "# and jit it for acceleration!\n", "\n", "energy_vag_jit = K.jit(K.value_and_grad(energy))\n", "\n", "print(energy_vag_jit(params))\n", "# the first time to run a jitted function will be slow, but the following evaluation will be super fast" ] }, { "cell_type": "markdown", "id": "36c710ef", "metadata": {}, "source": [ "## Advances for Circuit" ] }, { "cell_type": "markdown", "id": "d4e55e05", "metadata": {}, "source": [ "### Input State\n", "\n", "We can replace the input state from the default |0^n>" ] }, { "cell_type": "code", "execution_count": 20, "id": "49865f13", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "input_state = K.ones([2**n])\n", "input_state /= K.norm(input_state)\n", "\n", "c = tc.Circuit(n, inputs=input_state)\n", "c.H(0)\n", "c.state()" ] }, { "cell_type": "markdown", "id": "47f2a348", "metadata": {}, "source": [ "### Monte Carlo Noise Simulation\n", "\n", "``tc.Circuit`` supports noisy simulation using the Monte Carlo method, and it is also jittable! Besides, ``tc.DMCircuit`` supports noisy simulation using the full density matrix method." ] }, { "cell_type": "code", "execution_count": 21, "id": "e17b0b8b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(0j, shape=(), dtype=complex64)\n" ] } ], "source": [ "c = tc.Circuit(n)\n", "for i in range(n):\n", " c.H(i)\n", "for i in range(n - 1):\n", " c.cnot(i, i + 1)\n", " c.depolarizing(i, px=0.1, py=0.1, pz=0.1)\n", " c.apply_general_kraus(tc.channels.phasedampingchannel(gamma=0.2), i + 1)\n", "print(c.expectation([tc.gates.y(), [1]]))" ] }, { "cell_type": "markdown", "id": "ae498792", "metadata": {}, "source": [ "### Apply Arbitrary Gate\n", "\n", "Just directly using ``any`` API by feeding the corresponding unitary" ] }, { "cell_type": "code", "execution_count": 22, "id": "1fed32f3", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = tc.Circuit(n)\n", "c.any(0, 1, unitary=K.ones([4, 4]) / K.norm(K.ones([4, 4])))\n", "c.state()" ] }, { "cell_type": "markdown", "id": "1d64546c", "metadata": {}, "source": [ "### Exponential Gate\n", "\n", "If we want to simulate gate as $e^{i\\theta G}$ where $G^2=1$ is a matrix, we have a fast and efficient implementation for such gates as\n", "`exp1`" ] }, { "cell_type": "code", "execution_count": 23, "id": "32f50d3a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = tc.Circuit(n)\n", "for i in range(n):\n", " c.H(i)\n", "for i in range(n - 1):\n", " c.exp1(i, i + 1, theta=K.ones([]), unitary=tc.gates._zz_matrix)\n", "c.state()" ] }, { "cell_type": "markdown", "id": "934c3885", "metadata": {}, "source": [ "In the above example $G=Z\\otimes Z$" ] }, { "cell_type": "code", "execution_count": 24, "id": "409ed76b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1. 0. 0. 0.]\n", " [ 0. -1. 0. -0.]\n", " [ 0. 0. -1. -0.]\n", " [ 0. -0. -0. 1.]]\n" ] } ], "source": [ "print(tc.gates._zz_matrix)" ] }, { "cell_type": "markdown", "id": "ce35316b", "metadata": {}, "source": [ "Common matrices in gates modules are listed below" ] }, { "cell_type": "code", "execution_count": 25, "id": "f8c647b0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "_cnot_matrix :\n", " [[1. 0. 0. 0.]\n", " [0. 1. 0. 0.]\n", " [0. 0. 0. 1.]\n", " [0. 0. 1. 0.]]\n", "_cy_matrix :\n", " [[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", " [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n", " [ 0.+0.j 0.+0.j 0.+0.j -0.-1.j]\n", " [ 0.+0.j 0.+0.j 0.+1.j 0.+0.j]]\n", "_cz_matrix :\n", " [[ 1. 0. 0. 0.]\n", " [ 0. 1. 0. 0.]\n", " [ 0. 0. 1. 0.]\n", " [ 0. 0. 0. -1.]]\n", "_fredkin_matrix :\n", " [[1. 0. 0. 0. 0. 0. 0. 0.]\n", " [0. 1. 0. 0. 0. 0. 0. 0.]\n", " [0. 0. 1. 0. 0. 0. 0. 0.]\n", " [0. 0. 0. 1. 0. 0. 0. 0.]\n", " [0. 0. 0. 0. 1. 0. 0. 0.]\n", " [0. 0. 0. 0. 0. 0. 1. 0.]\n", " [0. 0. 0. 0. 0. 1. 0. 0.]\n", " [0. 0. 0. 0. 0. 0. 0. 1.]]\n", "_h_matrix :\n", " [[ 0.70710678 0.70710678]\n", " [ 0.70710678 -0.70710678]]\n", "_i_matrix :\n", " [[1. 0.]\n", " [0. 1.]]\n", "_ii_matrix :\n", " [[1. 0. 0. 0.]\n", " [0. 1. 0. 0.]\n", " [0. 0. 1. 0.]\n", " [0. 0. 0. 1.]]\n", "_s_matrix :\n", " [[1.+0.j 0.+0.j]\n", " [0.+0.j 0.+1.j]]\n", "_swap_matrix :\n", " [[1. 0. 0. 0.]\n", " [0. 0. 1. 0.]\n", " [0. 1. 0. 0.]\n", " [0. 0. 0. 1.]]\n", "_t_matrix :\n", " [[1. +0.j 0. +0.j ]\n", " [0. +0.j 0.70710678+0.70710678j]]\n", "_toffoli_matrix :\n", " [[1. 0. 0. 0. 0. 0. 0. 0.]\n", " [0. 1. 0. 0. 0. 0. 0. 0.]\n", " [0. 0. 1. 0. 0. 0. 0. 0.]\n", " [0. 0. 0. 1. 0. 0. 0. 0.]\n", " [0. 0. 0. 0. 1. 0. 0. 0.]\n", " [0. 0. 0. 0. 0. 1. 0. 0.]\n", " [0. 0. 0. 0. 0. 0. 0. 1.]\n", " [0. 0. 0. 0. 0. 0. 1. 0.]]\n", "_wroot_matrix :\n", " [[ 0.70710678+0.j -0.5 -0.5j]\n", " [ 0.5 -0.5j 0.70710678+0.j ]]\n", "_x_matrix :\n", " [[0. 1.]\n", " [1. 0.]]\n", "_xx_matrix :\n", " [[0. 0. 0. 1.]\n", " [0. 0. 1. 0.]\n", " [0. 1. 0. 0.]\n", " [1. 0. 0. 0.]]\n", "_y_matrix :\n", " [[ 0.+0.j -0.-1.j]\n", " [ 0.+1.j 0.+0.j]]\n", "_yy_matrix :\n", " [[ 0.+0.j 0.-0.j 0.-0.j -1.+0.j]\n", " [ 0.+0.j 0.+0.j 1.-0.j 0.-0.j]\n", " [ 0.+0.j 1.-0.j 0.+0.j 0.-0.j]\n", " [-1.+0.j 0.+0.j 0.+0.j 0.+0.j]]\n", "_z_matrix :\n", " [[ 1. 0.]\n", " [ 0. -1.]]\n", "_zz_matrix :\n", " [[ 1. 0. 0. 0.]\n", " [ 0. -1. 0. -0.]\n", " [ 0. 0. -1. -0.]\n", " [ 0. -0. -0. 1.]]\n" ] } ], "source": [ "for name in dir(tc.gates):\n", " if name.endswith(\"_matrix\"):\n", " print(name, \":\\n\", getattr(tc.gates, name))" ] }, { "cell_type": "markdown", "id": "7851cdcd", "metadata": {}, "source": [ "### Non-unitary Gate\n", "\n", "``tc.Circuit`` automatically support non-unitary circuit simulation due to its TensorNetwork engine nature" ] }, { "cell_type": "code", "execution_count": 26, "id": "e1805a84", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = tc.Circuit(n)\n", "c.exp1(1, unitary=tc.gates._x_matrix, theta=K.ones([]) + 1.0j * K.ones([]))\n", "c.state()" ] }, { "cell_type": "markdown", "id": "28222612", "metadata": {}, "source": [ "Note in this case the final state is not normalized anymore" ] }, { "cell_type": "code", "execution_count": 27, "id": "1581cf4f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Not equal to tolerance rtol=1e-07, atol=0\n", "\n", "Mismatched elements: 1 / 1 (100%)\n", "Max absolute difference: 0.93963802\n", "Max relative difference: 0.93963802\n", " x: array(1.939638+0.j, dtype=complex64)\n", " y: array(1.)\n" ] } ], "source": [ "try:\n", " np.testing.assert_allclose(K.norm(c.state()), 1.0)\n", "except AssertionError as e:\n", " print(e)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.8.0" } }, "nbformat": 4, "nbformat_minor": 5 }