{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Single QPU VQE experiment\n", "\n", "This notebook goes through the running of a VQE algorithm using interlin-q. For simplicity, we only try out using one QPU." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 1: Import libraries.\n", "\n", "First we import all the necessary libraries. Interlin-q is build using the python framework [QuNetSim](https://arxiv.org/abs/2003.06397) which is a python software framework that can be used to simulate quantum networks up to the network layer. We also need PennyLane's chemistry library for decomposing the Hamiltonian. We would also use PennyLane for the optimiser component" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Basic Libraries\n", "import sys\n", "from pennylane import numpy as np\n", "sys.path.append(\"../../\")\n", "\n", "# QuNetSim Components\n", "from qunetsim.components import Network\n", "from qunetsim.objects import Logger\n", "from qunetsim.backends.qutip_backend import QuTipBackend\n", "\n", "# Interlin-q Components\n", "from interlinq import (ControllerHost, Constants, Clock,\n", "Circuit, Layer, ComputingHost, Operation)\n", "\n", "# Extra needed components\n", "from pennylane import GradientDescentOptimizer\n", "from hamiltonian_decomposition import decompose\n", "\n", "Logger.DISABLED = False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 2: Decompose the Hamiltonian." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "geometry = 'h2.xyz'\n", "charge = 0\n", "multiplicity = 1\n", "basis_set = 'sto-3g'\n", "name = 'h2'" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(-0.04207897647782276, [('Identity', 0)]),\n", " (0.17771287465139946, [('PauliZ', 0)]),\n", " (0.1777128746513994, [('PauliZ', 1)]),\n", " (-0.24274280513140462, [('PauliZ', 2)]),\n", " (-0.24274280513140462, [('PauliZ', 3)]),\n", " (0.17059738328801052, [('PauliZ', 0), ('PauliZ', 1)]),\n", " (0.04475014401535161,\n", " [('PauliY', 0), ('PauliX', 1), ('PauliX', 2), ('PauliY', 3)]),\n", " (-0.04475014401535161,\n", " [('PauliY', 0), ('PauliY', 1), ('PauliX', 2), ('PauliX', 3)]),\n", " (-0.04475014401535161,\n", " [('PauliX', 0), ('PauliX', 1), ('PauliY', 2), ('PauliY', 3)]),\n", " (0.04475014401535161,\n", " [('PauliX', 0), ('PauliY', 1), ('PauliY', 2), ('PauliX', 3)]),\n", " (0.12293305056183798, [('PauliZ', 0), ('PauliZ', 2)]),\n", " (0.1676831945771896, [('PauliZ', 0), ('PauliZ', 3)]),\n", " (0.1676831945771896, [('PauliZ', 1), ('PauliZ', 2)]),\n", " (0.12293305056183798, [('PauliZ', 1), ('PauliZ', 3)]),\n", " (0.17627640804319591, [('PauliZ', 2), ('PauliZ', 3)])]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "coefficients, observables, qubit_num = decompose(name, geometry, charge, multiplicity, basis_set)\n", "terms = list(zip(coefficients, observables))\n", "\n", "terms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 3: Prepare Circuit for Given Parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The circuit can be prepared using two different ways: either as one circuit, or several circuits run sequentially. The former approach is simpler and generally better for the optimisation function. The latter is better for debugging and for dynamic components of a quantum circuit (i.e. circuits that have a lot of changing operations)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Main Blocks" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def rotational_gate(params):\n", " phi, theta, omega = params\n", " cos = np.cos(theta / 2)\n", " sin = np.sin(theta / 2)\n", " \n", " res = np.array([[np.exp(-1j * (phi + omega) / 2) * cos, -np.exp(1j * (phi - omega) / 2) * sin], \n", " [np.exp(-1j * (phi - omega) / 2) * sin, np.exp(1j * (phi + omega) / 2) * cos]])\n", " \n", " return res.unwrap()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def initialisation_operations(q_map):\n", " ops = []\n", " host_id = list(q_map.keys())[0]\n", " \n", " op = Operation(\n", " name=Constants.PREPARE_QUBITS,\n", " qids=q_map[host_id],\n", " computing_host_ids=[host_id])\n", " ops.append(op)\n", " \n", " # Prepare the qubits on the computing host\n", " op = Operation(\n", " name=Constants.SINGLE,\n", " qids=[q_map[host_id][0]],\n", " gate=Operation.X,\n", " computing_host_ids=[host_id])\n", " ops.append(op)\n", " \n", " op = Operation(\n", " name=Constants.SINGLE,\n", " qids=[q_map[host_id][1]],\n", " gate=Operation.X,\n", " computing_host_ids=[host_id])\n", " ops.append(op)\n", " \n", " return Layer(ops)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def ansatz_operations(q_map, parameters):\n", " layers = []\n", " host_id = list(q_map.keys())[0]\n", " \n", " ops = []\n", " \n", " for i in range(len(q_map[host_id])):\n", " op = Operation(\n", " name=Constants.SINGLE,\n", " qids=[q_map[host_id][i]],\n", " gate=Operation.CUSTOM,\n", " gate_param=rotational_gate(parameters[i]),\n", " computing_host_ids=[host_id])\n", " \n", " ops.append(op)\n", " \n", " layers.append(Layer(ops))\n", " \n", " op = Operation(\n", " name=Constants.TWO_QUBIT,\n", " qids=[q_map[host_id][2], q_map[host_id][3]],\n", " gate=Operation.CNOT,\n", " computing_host_ids=[host_id])\n", " \n", " layers.append(Layer([op]))\n", " \n", " op = Operation(\n", " name=Constants.TWO_QUBIT,\n", " qids=[q_map[host_id][2], q_map[host_id][0]],\n", " gate=Operation.CNOT,\n", " computing_host_ids=[host_id])\n", " \n", " layers.append(Layer([op]))\n", " \n", " op = Operation(\n", " name=Constants.TWO_QUBIT,\n", " qids=[q_map[host_id][3], q_map[host_id][1]],\n", " gate=Operation.CNOT,\n", " computing_host_ids=[host_id])\n", " \n", " layers.append(Layer([op]))\n", " \n", " return layers" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def measurement_operations(q_map):\n", " ops = []\n", " # Measuring only the first qubit\n", " op = Operation(\n", " name=Constants.MEASURE,\n", " qids=['q_0_0'],\n", " cids=['q_0_0'],\n", " computing_host_ids=[host_id])\n", " ops.append(op)\n", " layers.append(Layer(ops))\n", " \n", " # Measuring all qubits\n", " q_ids = q_map[host_id].copy()\n", " ops = []\n", " for q_id in q_ids:\n", " op = Operation(\n", " name=Constants.MEASURE,\n", " qids=[q_id],\n", " cids=[q_id],\n", " computing_host_ids=[computing_host_ids[0]])\n", " ops.append(op)\n", " \n", " return Layer(ops)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Single-step approach" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "def initialise_and_create_ansatz(q_map, parameters):\n", " layers = []\n", " host_id = list(q_map.keys())[0]\n", " \n", " # Initialise the qubits on the computing host\n", " layers.append(initialisation_operations(q_map))\n", " \n", " # Apply the ansatz\n", " layers = layers + ansatz_operations(q_map, parameters)\n", " \n", " circuit = Circuit(q_map, layers)\n", " return circuit" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def controller_host_protocol(host, q_map, params):\n", " \"\"\"\n", " Protocol for the controller host\n", " \"\"\"\n", " \n", " monolithic_circuit = initialise_and_create_ansatz(q_map, params)\n", "\n", " host.generate_and_send_schedules(monolithic_circuit)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def computing_host_protocol(host):\n", " host.receive_schedule()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Split-steps approach" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def prepare_qubits(q_map): \n", " circuit = Circuit(q_map, [initialisation_operations(q_map)])\n", " return circuit" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "def apply_ansatz(q_map, parameters):\n", " circuit = Circuit(q_map, ansatz_operations(q_map, parameters))\n", " return circuit" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "def controller_host_protocol_preparation(host, q_map, params):\n", " \"\"\"\n", " Protocol for the controller host\n", " \"\"\"\n", " host.generate_and_send_schedules(prepare_qubits(q_map))" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "def controller_host_protocol_ansatz(host, q_map, params):\n", " \"\"\"\n", " Protocol for the controller host\n", " \"\"\"\n", " host.generate_and_send_schedules(apply_ansatz(q_map, params))" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# Used for the last one\n", "def computing_host_protocol(host):\n", " host.receive_schedule()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 4: Run the circuit and get the Expectation Value" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def init_network():\n", " network = Network.get_instance()\n", " network.delay = 0\n", " network.start()\n", "\n", " clock = Clock()\n", "\n", " qutip = QuTipBackend()\n", "\n", " controller_host = ControllerHost(\n", " host_id=\"host_1\",\n", " clock=clock, \n", " backend=qutip\n", " )\n", "\n", " computing_hosts, q_map = controller_host.create_distributed_network(\n", " num_computing_hosts=1,\n", " num_qubits_per_host=4)\n", " controller_host.start()\n", "\n", " network.add_hosts([\n", " computing_hosts[0],\n", " controller_host])\n", " \n", " return clock, controller_host, computing_hosts, q_map" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "params = np.random.rand(4, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Running for the single-step approach" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:qu_net_sim:Host QPU_0 started processing\n", "INFO:qu_net_sim:Host host_1 started processing\n", "INFO:qu_net_sim:host_1 sends BROADCAST message\n", "INFO:qu_net_sim:sending ACK:1 from QPU_0 to host_1\n", "INFO:qu_net_sim:QPU_0 received {\"QPU_0\": [{\"name\": \"PREPARE_QUBITS\", \"qids\": [\"q_0_0\", \"q_0_1\", \"q_0_2\", \"q_0_3\"], \"cids\": null, \"gate\": null, \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_0\"], \"cids\": null, \"gate\": \"X\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_1\"], \"cids\": null, \"gate\": \"X\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_0\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.935132620818695, -0.34995168750809186], [-0.0549545845743462, 0.006386824348507643]], [[0.0549545845743462, 0.006386824348507643], [0.935132620818695, 0.34995168750809186]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_1\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.879507800560643, -0.16263760408224082], [-0.4471232796357334, 0.00978832463470065]], [[0.4471232796357334, 0.00978832463470065], [0.879507800560643, 0.16263760408224082]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_2\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.8415306556123834, -0.3629895117941569], [-0.40006883103057383, 0.0031145513098929673]], [[0.40006883103057383, 0.0031145513098929673], [0.8415306556123834, 0.3629895117941569]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_3\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.9274354442890774, -0.16893973773183632], [-0.3326177226041721, -0.026235706604433237]], [[0.3326177226041721, -0.026235706604433237], [0.9274354442890774, 0.16893973773183632]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_2\", \"q_0_3\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 2}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_2\", \"q_0_0\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 3}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_3\", \"q_0_1\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 4}]} with sequence number 0\n", "INFO:qu_net_sim:QPU_0 sends CLASSICAL to host_1 with sequence 0\n", "INFO:qu_net_sim:host_1 received ACK from QPU_0 with sequence number 0\n", "INFO:qu_net_sim:QPU_0 awaits classical ACK from host_1 with sequence 0\n", "INFO:qu_net_sim:sending ACK:1 from host_1 to QPU_0\n", "INFO:qu_net_sim:host_1 received ACK with sequence number 0\n", "INFO:qu_net_sim:QPU_0 received ACK from host_1 with sequence number 0\n" ] } ], "source": [ "clock, controller_host, computing_hosts, q_map = init_network()\n", "\n", "t1 = controller_host.run_protocol(\n", " controller_host_protocol,\n", " (q_map, params))\n", "t2 = computing_hosts[0].run_protocol(computing_host_protocol)\n", "\n", "t1.join()\n", "t2.join()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# This should be 7 after the first invocation. \n", "# For any further invocations, it would increase by 6: 13,19, 25, etc. So is that expected behaviour?\n", "clock.ticks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Running for the multi-step approach" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:qu_net_sim:Host QPU_0 started processing\n", "INFO:qu_net_sim:Host host_1 started processing\n", "INFO:qu_net_sim:host_1 sends BROADCAST message\n", "INFO:qu_net_sim:sending ACK:1 from QPU_0 to host_1\n", "INFO:qu_net_sim:QPU_0 received {\"QPU_0\": [{\"name\": \"PREPARE_QUBITS\", \"qids\": [\"q_0_0\", \"q_0_1\", \"q_0_2\", \"q_0_3\"], \"cids\": null, \"gate\": null, \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_0\"], \"cids\": null, \"gate\": \"X\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_1\"], \"cids\": null, \"gate\": \"X\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}]} with sequence number 0\n", "INFO:qu_net_sim:QPU_0 sends CLASSICAL to host_1 with sequence 0\n", "INFO:qu_net_sim:host_1 received ACK from QPU_0 with sequence number 0\n", "INFO:qu_net_sim:QPU_0 awaits classical ACK from host_1 with sequence 0\n", "INFO:qu_net_sim:sending ACK:1 from host_1 to QPU_0\n", "INFO:qu_net_sim:host_1 received ACK with sequence number 0\n", "INFO:qu_net_sim:QPU_0 received ACK from host_1 with sequence number 0\n" ] } ], "source": [ "clock, controller_host, computing_hosts, q_map = init_network()\n", "\n", "t1 = controller_host.run_protocol(\n", " controller_host_protocol_preparation,\n", " (q_map, params))\n", "t2 = computing_hosts[0].run_protocol(computing_host_protocol)\n", "\n", "t1.join()\n", "t2.join()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "clock.ticks" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:qu_net_sim:host_1 sends BROADCAST message\n", "INFO:qu_net_sim:sending ACK:2 from QPU_0 to host_1\n", "INFO:qu_net_sim:QPU_0 received {\"QPU_0\": [{\"name\": \"SINGLE\", \"qids\": [\"q_0_0\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.935132620818695, -0.34995168750809186], [-0.0549545845743462, 0.006386824348507643]], [[0.0549545845743462, 0.006386824348507643], [0.935132620818695, 0.34995168750809186]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 2}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_1\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.879507800560643, -0.16263760408224082], [-0.4471232796357334, 0.00978832463470065]], [[0.4471232796357334, 0.00978832463470065], [0.879507800560643, 0.16263760408224082]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 2}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_2\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.8415306556123834, -0.3629895117941569], [-0.40006883103057383, 0.0031145513098929673]], [[0.40006883103057383, 0.0031145513098929673], [0.8415306556123834, 0.3629895117941569]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 2}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_3\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.9274354442890774, -0.16893973773183632], [-0.3326177226041721, -0.026235706604433237]], [[0.3326177226041721, -0.026235706604433237], [0.9274354442890774, 0.16893973773183632]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 2}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_2\", \"q_0_3\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 3}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_2\", \"q_0_0\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 4}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_3\", \"q_0_1\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 5}]} with sequence number 1\n", "INFO:qu_net_sim:QPU_0 sends CLASSICAL to host_1 with sequence 1\n", "INFO:qu_net_sim:QPU_0 awaits classical ACK from host_1 with sequence 1\n", "INFO:qu_net_sim:host_1 received ACK from QPU_0 with sequence number 1\n", "INFO:qu_net_sim:sending ACK:2 from host_1 to QPU_0\n", "INFO:qu_net_sim:host_1 received ACK with sequence number 1\n", "INFO:qu_net_sim:QPU_0 received ACK from host_1 with sequence number 1\n" ] } ], "source": [ "t1 = controller_host.run_protocol(\n", " controller_host_protocol_ansatz,\n", " (q_map, params))\n", "t2 = computing_hosts[0].run_protocol(computing_host_protocol)\n", "\n", "t1.join()\n", "t2.join()" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "clock.ticks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using qutip to get the expectation value" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "from qutip import identity, sigmax, sigmay, sigmaz\n", "from qutip import expect\n", "\n", "def string_to_qutip_pauli(string):\n", " if string == 'Identity':\n", " return identity(2)\n", " if string == 'PauliX':\n", " return sigmax()\n", " if string == 'PauliY':\n", " return sigmay()\n", " if string == 'PauliZ':\n", " return sigmaz()\n", "\n", "def expectation_value(terms, matrices):\n", " total = 0\n", " \n", " for term in terms:\n", " coefficient, observables = term\n", " \n", " needed_matrices = []\n", " needed_paulis = []\n", " \n", " for obs in observables:\n", " pauli, index = obs\n", " \n", " needed_matrices.append(matrices[index])\n", " needed_paulis.append(string_to_qutip_pauli(pauli))\n", " \n", " expectation = expect(needed_paulis, needed_matrices)\n", " \n", " total += coefficient * expectation[0][0]\n", " \n", " return total" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True\n", " Qobj data =\n", " [[ 0.16214572+0.j -0.04915474+0.01713544j]\n", " [-0.04915474-0.01713544j 0.83785428+0.j ]],\n", " Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True\n", " Qobj data =\n", " [[ 0.34145788+0.j -0.39165646+0.04298185j]\n", " [-0.39165646-0.04298185j 0.65854212+0.j ]],\n", " Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True\n", " Qobj data =\n", " [[ 0.83993523+0.j -0.020644 +0.00909593j]\n", " [-0.020644 -0.00909593j 0.16006477+0.j ]],\n", " Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True\n", " Qobj data =\n", " [[ 0.7642501 +0.j -0.24510936+0.01696731j]\n", " [-0.24510936-0.01696731j 0.2357499 +0.j ]]]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "density_matrices = []\n", "\n", "for qubit_id in computing_hosts[0].qubit_ids:\n", " qubit = computing_hosts[0].get_qubit_by_id(qubit_id)\n", " density_matrices.append(computing_hosts[0].backend.density_operator(qubit))\n", " \n", "density_matrices" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-0.7957850305933003" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "expectation_value(terms, density_matrices)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Optimise" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "from qutip import identity, sigmax, sigmay, sigmaz\n", "from qutip import expect\n", "\n", "def string_to_qutip_pauli(string):\n", " if string == 'Identity':\n", " return identity(2)\n", " if string == 'PauliX':\n", " return sigmax()\n", " if string == 'PauliY':\n", " return sigmay()\n", " if string == 'PauliZ':\n", " return sigmaz()\n", "\n", "def expectation_value(terms, matrices):\n", " total = 0\n", " \n", " for term in terms:\n", " coefficient, observables = term\n", " \n", " needed_matrices = []\n", " needed_paulis = []\n", " \n", " for obs in observables:\n", " pauli, index = obs\n", " \n", " needed_matrices.append(matrices[index])\n", " needed_paulis.append(string_to_qutip_pauli(pauli))\n", " \n", " expectation = expect(needed_paulis, needed_matrices)\n", " \n", " total += coefficient * expectation[0][0]\n", " \n", " return total" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "def cost_fn(params):\n", " network = Network.get_instance()\n", " network.delay = 0\n", " network.start()\n", "\n", " clock = Clock()\n", "\n", " qutip = QuTipBackend()\n", "\n", " controller_host = ControllerHost(\n", " host_id=\"host_1\",\n", " clock=clock, \n", " backend=qutip\n", " )\n", "\n", " computing_hosts, q_map = controller_host.create_distributed_network(\n", " num_computing_hosts=1,\n", " num_qubits_per_host=4)\n", " controller_host.start()\n", "\n", " network.add_hosts([\n", " computing_hosts[0],\n", " controller_host])\n", " \n", " t1 = controller_host.run_protocol(\n", " controller_host_protocol,\n", " (q_map, params))\n", " t2 = computing_hosts[0].run_protocol(computing_host_protocol)\n", "\n", " t1.join()\n", " t2.join()\n", " \n", " density_matrices = []\n", "\n", " for qubit_id in computing_hosts[0].qubit_ids:\n", " qubit = computing_hosts[0].get_qubit_by_id(qubit_id)\n", " density_matrices.append(computing_hosts[0].backend.density_operator(qubit))\n", " \n", " \n", " network.remove_host(computing_hosts[0])\n", " network.remove_host(controller_host)\n", " \n", " return expectation_value(terms, density_matrices)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tensor([[ 1.11797316, -3.86530105, 1.84447336],\n", " [-2.49246701, 4.95869687, -2.97578573],\n", " [-0.56524129, 1.42750818, 1.3953073 ],\n", " [-1.11492183, -1.9811752 , 0.79328341]], requires_grad=True)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "opt = opt = GradientDescentOptimizer(stepsize=0.4)\n", "params = np.random.normal(0, np.pi, (4, 3))\n", "\n", "params" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:qu_net_sim:Host QPU_0 started processing\n", "INFO:qu_net_sim:Host host_1 started processing\n", "INFO:qu_net_sim:host_1 sends BROADCAST message\n", "INFO:qu_net_sim:sending ACK:1 from QPU_0 to host_1\n", "INFO:qu_net_sim:QPU_0 received {\"QPU_0\": [{\"name\": \"PREPARE_QUBITS\", \"qids\": [\"q_0_0\", \"q_0_1\", \"q_0_2\", \"q_0_3\"], \"cids\": null, \"gate\": null, \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_0\"], \"cids\": null, \"gate\": \"X\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_1\"], \"cids\": null, \"gate\": \"X\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 0}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_0\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[-0.03166728279602556, 0.3525897498727833], [0.8742146405529816, -0.3323047001289419]], [[-0.8742146405529816, -0.3323047001289419], [-0.03166728279602556, -0.3525897498727833]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_1\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.7240487217891628, -0.3125154764682361], [-0.5970209248675964, -0.14715142103816284]], [[0.5970209248675964, -0.14715142103816284], [0.7240487217891628, 0.3125154764682361]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_2\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.6917350553796867, -0.3047979267544777], [-0.36452021651009525, 0.5438068119842441]], [[0.36452021651009525, 0.5438068119842441], [0.6917350553796867, 0.3047979267544777]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"SINGLE\", \"qids\": [\"q_0_3\"], \"cids\": null, \"gate\": \"custom_gate\", \"gate_param\": [[[0.5411248043502964, 0.08778132718020476], [0.4836945380987444, -0.6822887794246493]], [[-0.4836945380987444, -0.6822887794246493], [0.5411248043502964, -0.08778132718020476]]], \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 1}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_2\", \"q_0_3\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 2}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_2\", \"q_0_0\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 3}, {\"name\": \"TWO_QUBIT\", \"qids\": [\"q_0_3\", \"q_0_1\"], \"cids\": null, \"gate\": \"cnot\", \"gate_param\": null, \"computing_host_ids\": [\"QPU_0\"], \"pre_allocated_qubits\": false, \"layer_end\": 4}]} with sequence number 0\n", "INFO:qu_net_sim:QPU_0 sends CLASSICAL to host_1 with sequence 0\n", "INFO:qu_net_sim:host_1 received ACK from QPU_0 with sequence number 0\n", "INFO:qu_net_sim:QPU_0 awaits classical ACK from host_1 with sequence 0\n", "INFO:qu_net_sim:sending ACK:1 from host_1 to QPU_0\n", "INFO:qu_net_sim:host_1 received ACK with sequence number 0\n", "INFO:qu_net_sim:QPU_0 received ACK from host_1 with sequence number 0\n" ] }, { "data": { "text/plain": [ "0.03713374738267447" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cost_fn(params)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "Logger.DISABLED = True" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "def rotational_gate(params):\n", " phi, theta, omega = params\n", " cos = np.cos(theta / 2)\n", " sin = np.sin(theta / 2)\n", " \n", " res = np.array([[np.exp(-1j * (phi + omega) / 2) * cos, -np.exp(1j * (phi - omega) / 2) * sin], \n", " [np.exp(-1j * (phi - omega) / 2) * sin, np.exp(1j * (phi + omega) / 2) * cos]])\n", " \n", " if isinstance(res, np.tensor):\n", " return res.unwrap()\n", " else:\n", " return res._value" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "ERROR:root:No traceback has been produced, nothing to debug.\n", "/home/shiro-raven/.local/lib/python3.8/site-packages/autograd/tracer.py:14: UserWarning: Output seems independent of input.\n", " warnings.warn(\"Output seems independent of input.\")\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Iteration = 0, Energy = 0.03713375 Ha\n" ] } ], "source": [ "%debug\n", "max_iterations = 200\n", "conv_tol = 1e-06\n", "\n", "for n in range(max_iterations):\n", " params, prev_energy = opt.step_and_cost(cost_fn, params)\n", " energy = cost_fn(params)\n", " conv = np.abs(energy - prev_energy)\n", "\n", " if n % 20 == 0:\n", " print('Iteration = {:}, Energy = {:.8f} Ha'.format(n, energy))\n", "\n", " if conv <= conv_tol:\n", " break" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.8.5" } }, "nbformat": 4, "nbformat_minor": 2 }