{ "cells": [ { "cell_type": "markdown", "id": "3dee6016", "metadata": {}, "source": [ "# Configuring Storage and Executors, Submitting to Quantinuum, Using Predefined Workers\n", "In this example we're covering a finer grained control over the workflow run.\n", "These are the internals that are set inside the `run_workflow` function.\n", "For this we're going to construct a graph thad runs a `pytket` circuit on a simulator using the `quantinuum_worker`\n", "The worker can be installed using `pip install tkr-quantinuum-worker`\n", "\n", "## Opaque Types\n", "Tierkreis can use any type that is serializable as in and outputs.\n", "To use such types for type hinting you can use the `OpaqueType`." ] }, { "cell_type": "code", "execution_count": null, "id": "f554cd69", "metadata": {}, "outputs": [], "source": [ "%pip install tierkreis pytket qnexus" ] }, { "cell_type": "code", "execution_count": null, "id": "4baf1b60", "metadata": {}, "outputs": [], "source": [ "from tierkreis.controller.data.models import OpaqueType\n", "\n", "Circuit = OpaqueType[\"pytket._tket.circuit.Circuit\"]\n", "BackendResult = OpaqueType[\"pytket.backends.backendresult.BackendResult\"]" ] }, { "cell_type": "markdown", "id": "ed257edc", "metadata": {}, "source": [ "Now we can construct a graph using the `quantinuum_worker`.\n", "The api definitions for workers build by the tierkreis teams are already included in tierkreis.\n", "Still it is necessary to install the worker manually.\n", "We define a graph `Circuit -> BackendResult` using hardcoded information for which emulator backend to use." ] }, { "cell_type": "code", "execution_count": null, "id": "d3bafb06", "metadata": {}, "outputs": [], "source": [ "from tierkreis.builder import GraphBuilder\n", "from tierkreis.controller.data.models import TKR\n", "from tierkreis.quantinuum_worker import (\n", " compile_using_info,\n", " get_backend_info,\n", " run_circuit,\n", ")\n", "\n", "g = GraphBuilder(TKR[Circuit], TKR[BackendResult])\n", "info = g.task(get_backend_info(device_name=g.const(\"H2-1\")))\n", "compiled_circuit = g.task(compile_using_info(g.inputs, info))\n", "results = g.task(\n", " run_circuit(\n", " circuit=compiled_circuit,\n", " n_shots=g.const(10),\n", " device_name=g.const(\"H2-1SC\"),\n", " ),\n", ")\n", "g.outputs(results)" ] }, { "cell_type": "markdown", "id": "7493c5cd", "metadata": {}, "source": [ "Now we will define our own storage and executor.\n", "Storage is responsible for setting up the checkpointing; it stores the state of the computation.\n", "We have to provide a uuid, and optionally a name, as before." ] }, { "cell_type": "code", "execution_count": null, "id": "c119b226", "metadata": {}, "outputs": [], "source": [ "from uuid import UUID\n", "\n", "from tierkreis.storage import FileStorage\n", "\n", "storage = FileStorage(UUID(int=209), do_cleanup=True, name=\"quantinuum_submission\")" ] }, { "cell_type": "markdown", "id": "1a08a288", "metadata": {}, "source": [ "Since the `quantinuum_worker` is a python worker we will use `uv` to run it.\n", "An executor lives in context, where it can access workers to run their `main` entrypoints.\n", "We define this by providing a path to the directory our workers live in, in this case in the `tierkreis_workers` directory.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "72fcc865", "metadata": {}, "outputs": [], "source": [ "from tierkreis.consts import PACKAGE_PATH\n", "from tierkreis.executor import UvExecutor\n", "\n", "executor = UvExecutor(PACKAGE_PATH.parent / \"tierkreis_workers\", storage.logs_path)" ] }, { "cell_type": "markdown", "id": "69f11464", "metadata": {}, "source": [ "Since this graph is using the `qnexus` api internally you also need to run the following once: " ] }, { "cell_type": "code", "execution_count": null, "id": "901c2287", "metadata": { "tags": [ "skip-execution" ] }, "outputs": [], "source": [ "from qnexus.client.auth import login\n", "\n", "login()" ] }, { "cell_type": "markdown", "id": "cc099589", "metadata": {}, "source": [ "Once we provide the graph inputs we can now run it by providing a storage and an executor." ] }, { "cell_type": "code", "execution_count": null, "id": "e3a28ef6", "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "\n", "from pytket.qasm.qasm import circuit_from_qasm\n", "\n", "from tierkreis import run_graph\n", "\n", "circuit = circuit_from_qasm(Path().parent / \"data\" / \"ghz_state_n23.qasm\")\n", "run_graph(storage, executor, g, circuit)" ] }, { "cell_type": "markdown", "id": "80d0cd4e", "metadata": {}, "source": [ "And finally we can print the outputs" ] }, { "cell_type": "code", "execution_count": null, "id": "eb173135", "metadata": {}, "outputs": [], "source": [ "from tierkreis.storage import read_outputs\n", "\n", "outputs = read_outputs(g, storage)" ] } ], "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.13.11" } }, "nbformat": 4, "nbformat_minor": 5 }