{ "cells": [ { "cell_type": "markdown", "id": "26d84d10", "metadata": {}, "source": [ "# Conversion example from Eka\n", "\n", "```{note}\n", "The widgets in this notebook are interactive!\n", "```\n", "\n", "We start by defining an `Eka` object that encodes a simple memory experiment on a distance 3 repetition code, that consists of a reset, a logical X and a measurement, with some syndromes extraction." ] }, { "cell_type": "code", "execution_count": null, "id": "d9877ab0", "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from loom.eka.block import Block\n", "from loom.eka.eka import Eka\n", "from loom.eka.lattice import Lattice\n", "from loom.eka.operations.code_operation import (\n", " LogicalX,\n", " MeasureBlockSyndromes,\n", " MeasureLogicalZ,\n", " ResetAllDataQubits,\n", ")\n", "from loom.eka.pauli_operator import PauliOperator\n", "from loom.eka.stabilizer import Stabilizer\n", "import loom.visualizer as vis\n", "from loom.interpreter.interpreter import interpret_eka\n", "import plotly.io as pio\n", "\n", "pio.renderers.default = \"notebook\"\n", "\n", "# Set up a bit-flip repetition code with a distance of 3\n", "distance = 3\n", "lattice = Lattice.linear((distance + 1,))\n", "\n", "base_position = (1,)\n", "initial_rep_block = Block(\n", " unique_label=\"q1\",\n", " stabilizers=tuple(\n", " Stabilizer(\n", " pauli=\"ZZ\",\n", " data_qubits=(\n", " (base_position[0] + i, 0),\n", " (base_position[0] + i + 1, 0),\n", " ),\n", " ancilla_qubits=((base_position[0] + i, 1),),\n", " )\n", " for i in range(distance - 1)\n", " ),\n", " logical_x_operators=(\n", " PauliOperator(\"XXX\", tuple((base_position[0] + i, 0) for i in range(distance))),\n", " ),\n", " logical_z_operators=(PauliOperator(\"Z\", ((base_position[0], 0),)),),\n", ")\n", "\n", "\n", "meas_block_and_meas_log = [\n", " ResetAllDataQubits(initial_rep_block.unique_label, state=\"0\"),\n", " MeasureBlockSyndromes(initial_rep_block.unique_label, n_cycles=1),\n", " LogicalX(initial_rep_block.unique_label),\n", " MeasureBlockSyndromes(initial_rep_block.unique_label, n_cycles=1),\n", " MeasureLogicalZ(initial_rep_block.unique_label),\n", "]\n", "\n", "eka = Eka(lattice, blocks=[initial_rep_block], operations=meas_block_and_meas_log)\n", "\n", "interpreted_eka = interpret_eka(eka)\n", "\n", "stab_plot = vis.StabilizerPlot(\n", " lattice,\n", " title=f\"Repetition Code\",\n", ")\n", "stab_plot.add_dqubit_traces()\n", "stab_plot.plot_blocks(initial_rep_block)\n", "# Sphinx formatting\n", "stab_plot._fig.update_layout(margin=dict(t=60, l=30, b=30), width=680, height=400)\n", "stab_plot.show()" ] }, { "cell_type": "markdown", "id": "e88144dd", "metadata": {}, "source": [ "## Conversion to QASM" ] }, { "cell_type": "code", "execution_count": 2, "id": "e6701797", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Simulation results: \n", "Each shot gives a bitstring of the form: \"ss ss mmm\", where each ss is a syndrome and mmm is the measurement result.\n", "{'00 00 111': 10}\n" ] } ], "source": [ "from loom.executor.eka_circuit_to_qasm_converter import convert_circuit_to_qasm\n", "from qiskit import transpile, qasm3\n", "from qiskit_aer import Aer\n", "\n", "# Convert the Eka circuit to QASM string representation\n", "QASM_string = convert_circuit_to_qasm(\n", " interpreted_eka.final_circuit,\n", " interpreted_eka.syndromes,\n", " interpreted_eka.detectors,\n", " interpreted_eka.logical_observables,\n", ")\n", "\n", "# Execute the QASM circuit using Qiskit Aer simulator\n", "backend = Aer.get_backend(\"aer_simulator\")\n", "qc = qasm3.loads(QASM_string[\"qasm_circuit\"]) # load QASM‑3\n", "qc = transpile(qc, backend) # prepare for backend\n", "shots = 10\n", "result = backend.run(qc, shots=shots).result() # run (no “execute”)\n", "\n", "print(\"Simulation results: \")\n", "print(\n", " 'Each shot gives a bitstring of the form: \"ss ss mmm\", where each ss is a syndrome '\n", " \"and mmm is the measurement result.\"\n", ")\n", "print(result.get_counts())" ] }, { "cell_type": "markdown", "id": "884b5114", "metadata": {}, "source": [ "## Conversion to Stim" ] }, { "cell_type": "code", "execution_count": 3, "id": "fb8c76ce", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Results:\n", "Shot 0: 00 00 111\n", "Shot 1: 00 00 111\n", "Shot 2: 00 00 111\n" ] } ], "source": [ "from loom.executor.eka_circuit_to_stim_converter import EkaCircuitToStimConverter\n", "\n", "\n", "converter = EkaCircuitToStimConverter()\n", "\n", "stim_circuit = converter.convert(interpreted_eka)\n", "\n", "# Sample results\n", "sampler = stim_circuit.compile_sampler()\n", "num_samples = 3\n", "results = sampler.sample(shots=num_samples)\n", "\n", "# Format and print simulation results\n", "print(\"Results:\")\n", "bitstrings = tuple(\n", " [\"\".join(\"1\" if b else \"0\" for b in shot) for shot in results][i]\n", " for i in range(num_samples)\n", ")\n", "\n", "for i in range(num_samples):\n", " print(f\"Shot {i}: {bitstrings[i][:2]} {bitstrings[i][2:4]} {bitstrings[i][4:]}\")" ] }, { "cell_type": "markdown", "id": "b4b47eaa", "metadata": {}, "source": [ "As expected, since there is no noise in the simulations used, the 2 rounds of syndromes extractions yield the same outputs. The measured outcome of the data qubits is always 1, which is what is expected after applying reset and X on the logical qubit." ] } ], "metadata": { "kernelspec": { "language": "python" }, "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.12.9" } }, "nbformat": 4, "nbformat_minor": 5 }