diff --git a/ionq/noise_profiling_across_batch_of_ionq_circuits.ipynb b/ionq/noise_profiling_across_batch_of_ionq_circuits.ipynb new file mode 100644 index 0000000..724dd26 --- /dev/null +++ b/ionq/noise_profiling_across_batch_of_ionq_circuits.ipynb @@ -0,0 +1,422 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from braket.circuits import Circuit\n", + "import itertools as it\n", + "import random\n", + "\n", + "def cnot_sequence(circuit_length, input_bits='00'):\n", + " c = Circuit()\n", + " \n", + " # encode the input\n", + " if input_bits[0] == '1': c.x(0)\n", + " if input_bits[1] == '1': c.x(1)\n", + " \n", + " # create the CNOT sequence\n", + " for idx in range(circuit_length):\n", + " if idx % 2 == 0: c.cnot(0, 1)\n", + " if idx % 2 == 1: c.cnot(1, 0)\n", + " \n", + " return c\n", + "\n", + "possible_input_bits = ('00', '01', '10', '11')\n", + "possible_circuit_lengths = (1, 2, 3, 4, 5, 6)\n", + "possible_keys = list(it.product(possible_input_bits, possible_circuit_lengths))\n", + "\n", + "circuit_pool = {}\n", + "for input_bits in possible_input_bits:\n", + " for circuit_length in possible_circuit_lengths:\n", + " circuit = cnot_sequence(circuit_length, input_bits=input_bits)\n", + " circuit_pool[(input_bits, circuit_length)] = circuit\n", + "\n", + "def generate_circuit_batch(size):\n", + " random_keys = random.choices(possible_keys, k=size)\n", + " return [(key, circuit_pool[key]) for key in random_keys]\n", + "\n", + "print(\"EXAMPLE CIRCUIT BATCH\")\n", + "print(\"_\" * 24)\n", + "for key, circuit in generate_circuit_batch(5):\n", + " print()\n", + " print(\"input_bits={}, length={}\".format(*key))\n", + " print(\"-\" * 24)\n", + " print(circuit)\n", + " print(\"_\" * 24)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The following is just a convenient little timer for things that take a while in the code below.\n", + "# I snipped it from https://medium.com/@DahlitzF/how-to-create-your-own-timing-context-manager-in-python-a0e944b48cf8\n", + "\n", + "from time import time\n", + "\n", + "class Timer:\n", + " def __init__(self, description):\n", + " self.description = description\n", + " def __enter__(self):\n", + " self.start = time()\n", + " def __exit__(self, type, value, traceback):\n", + " self.end = time()\n", + " print(f\"complete: {self.end - self.start:.3f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# On with the actual code...\n", + " \n", + "from braket.aws import AwsDevice\n", + "\n", + "aws_simulator = AwsDevice(\"arn:aws:braket:::device/quantum-simulator/amazon/sv1\")\n", + "ionq = AwsDevice(\"arn:aws:braket:::device/qpu/ionq/ionQdevice\")\n", + "s3_folder = (\"amazon-braket-project-840eb696707f\", \"ionq_mwe_preliminary\")\n", + "\n", + "reference_table = {}\n", + "\n", + "for input_bits in possible_input_bits:\n", + " for circuit_length in possible_circuit_lengths:\n", + " \n", + " circuit_to_simulate = circuit_pool[(input_bits, circuit_length)]\n", + " print(f\"Starting job: input_bits={input_bits}, circuit_length={circuit_length}...\", end=\" \")\n", + " \n", + " with Timer(\"AWS simulator\"):\n", + " # First create the task for Amazon's circuit simulator.\n", + " # Note that the number of shots is irrelevant here;\n", + " # I want the simulated measurement probabilities only.\n", + " task = aws_simulator.run(circuit_to_simulate, s3_folder, shots=1)\n", + " \n", + " # Now I can extract the measurement probabilities.\n", + " # This is a dictionary of the form {correct_output: 1}.\n", + " # The useful information is therefore the key, not the value.\n", + " result = task.result().measurement_probabilities\n", + " correct_output = list(result.keys())[0]\n", + " \n", + " # I now store the correct output in the reference table.\n", + " reference_table[(input_bits, circuit_length)] = correct_output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for input_bits in possible_input_bits:\n", + " reference = [input_bits] + [reference_table[(input_bits, l)] for l in possible_circuit_lengths]\n", + " print(\"{} | {} {} {} {} {} {}\".format(*reference))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "test_batch = generate_circuit_batch(1000)\n", + "tasks = [ionq.run(circuit, s3_folder, shots=1000) for key, circuit in test_batch]\n", + "task_id = [t.id for t in tasks]\n", + "print(task_id)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "state_list = []\n", + "\n", + "with Timer(\"Fetching the state takes super long...\"):\n", + " for k in range(len(tasks)):\n", + " state = tasks[k].state()\n", + " state_list += [state]\n", + " print(f\"Task {k:>3}: {state:<10}\", end=\"\\r\")\n", + " print(\"State fetch\", end=\" \")\n", + "\n", + "number_of_tasks_still_queued = sum(1 if state_list[k] == 'QUEUED' else 0\n", + " for k in range(len(state_list)))\n", + "\n", + "if number_of_tasks_still_queued == 0:\n", + " print(\"All tasks complete!\")\n", + "else:\n", + " print(f\"Still waiting on {number_of_tasks_still_queued} tasks.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "data = []\n", + "\n", + "for idx in range(len(tasks)):\n", + " the_task = tasks[idx]\n", + " task_id = the_task.id\n", + " the_result = the_task.result()\n", + " \n", + " start_time = pd.to_datetime(the_result.task_metadata.createdAt)\n", + " end_time = pd.to_datetime(the_result.task_metadata.endedAt)\n", + " elapsed_time = end_time - start_time\n", + " \n", + " batch_member = test_batch[idx]\n", + " circuit_key = batch_member[0]\n", + " input_bits = circuit_key[0]\n", + " circuit_length = circuit_key[1]\n", + " \n", + " measurement_probabilities = the_result.measurement_probabilities\n", + " correct_output = reference_table[circuit_key]\n", + " success_probability = measurement_probabilities[correct_output]\n", + " \n", + " data.append((task_id,\n", + " input_bits,\n", + " circuit_length,\n", + " start_time,\n", + " end_time,\n", + " elapsed_time,\n", + " success_probability))\n", + "\n", + "data = pd.DataFrame(data, columns=['id_string',\n", + " 'input_bits',\n", + " 'circuit_length',\n", + " 'start_time',\n", + " 'end_time',\n", + " 'elapsed_time',\n", + " 'success_probability'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data['elapsed_time'].astype('timedelta64[h]').hist()\n", + "plt.xlabel(\"Number of hours\")\n", + "plt.ylabel(\"Number of tasks\")\n", + "plt.title(\"Amount of time waited to obtain data from IonQ\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data['success_probability'].hist()\n", + "plt.xlabel(\"Probability of success\")\n", + "plt.ylabel(\"Number of circuits\")\n", + "plt.title(\"A simple histogram of the circuit success probabilities\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.hist([df[\"success_probability\"] for input_bits, df in data.groupby(\"input_bits\")],\n", + " bins=50, range=(0.7, 1.0), stacked=True)\n", + "\n", + "plt.xlabel(\"Probability of success\")\n", + "plt.ylabel(\"Number of circuits\")\n", + "plt.title(\"Circuit success probabilities grouped by input\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.hist([df[\"success_probability\"] for input_bits, df in data.groupby(\"circuit_length\")],\n", + " bins=50, range=(0.7, 1.0), stacked=True)\n", + "\n", + "plt.xlabel(\"Probability of success\")\n", + "plt.ylabel(\"Number of circuits\")\n", + "plt.title(\"Circuit success probabilities grouped by circuit length\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data.plot.scatter(x=\"end_time\", y=\"success_probability\")\n", + "plt.xlabel(\"Circuit execution timestamp\")\n", + "plt.ylabel(\"Success probability\")\n", + "plt.title(\"Variable quality of execution windows\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data.plot.scatter(x=\"end_time\", y=\"success_probability\", c='circuit_length', marker='.')\n", + "plt.xlabel(\"Circuit execution timestamp\")\n", + "plt.ylabel(\"Success probability\")\n", + "plt.title(\"Execution window data grouped by circuit length\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import seaborn as sns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sns.violinplot(data=data, x='circuit_length', y='success_probability')\n", + "plt.xlabel(\"Circuit Length\")\n", + "plt.ylabel(\"Success Probability\")\n", + "plt.title(\"Performance for random CNOT test\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data['good?'] = data['success_probability'] > (90 + (7 - data['circuit_length']))/100\n", + "sns.violinplot(data=data, x='circuit_length', y='success_probability', hue='good?')\n", + "plt.xlabel(\"Circuit Length\")\n", + "plt.ylabel(\"Success Probability\")\n", + "plt.title(\"Performance for random CNOT test\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sns.kdeplot(data=data, x='end_time', hue='good?', multiple='fill')\n", + "plt.xlabel(\"Circuit Execution Timestamp\")\n", + "plt.xticks(rotation=-90)\n", + "plt.title(\"Simple Execution Window Classification\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data['execution_window'] = 'discarded'\n", + "\n", + "end_A = pd.Timestamp(year=2023, month=1, day=29, hour=22, tz='UTC')\n", + "start_B = pd.Timestamp(year=2023, month=1, day=30, hour=2, tz='UTC')\n", + "end_B = pd.Timestamp(year=2023, month=1, day=30, hour=4, tz='UTC')\n", + "\n", + "data.loc[data['end_time'] < end_A, 'execution_window'] = 'A'\n", + "data.loc[(data['end_time'] >= start_B) & (data['end_time'] < end_B), 'execution_window'] = 'B'\n", + "\n", + "sns.lmplot(data=data, x='circuit_length', y='success_probability', hue='execution_window')\n", + "plt.xlabel(\"Circuit Length\")\n", + "plt.ylabel(\"Success Probability\")\n", + "plt.title(\"Performance classified by execution window\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "g = sns.kdeplot(data=data.groupby('circuit_length').get_group(6),\n", + " x='success_probability', hue='execution_window', multiple='fill')\n", + "sns.move_legend(g, 'upper left', title='Execution Window')\n", + "plt.xlabel('Success Probability')\n", + "plt.xlim(0.7, 1.0)\n", + "plt.title(\"Execution window quality check\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sns.histplot(data=data, x='end_time', bins=100)\n", + "plt.xticks(rotation=-90)\n", + "plt.xlabel(\"Execution timestamp\")\n", + "plt.title(\"Distribution of execution times for a set of 1000 circuits\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for id_str in task_id:\n", + " print(id_str)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for key, circuit in test_batch:\n", + " print(key)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "len(tasks)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +}