From 961d3e507e221ec4edd256481fafffe6f12157fa Mon Sep 17 00:00:00 2001 From: Jim Garrison Date: Fri, 8 Nov 2024 21:23:18 -0500 Subject: [PATCH 01/14] Add serverless guide w/ function template example (hamiltonian simulation) --- docs/guides/_toc.json | 4 + docs/guides/serverless-hamsim-template.ipynb | 1033 ++++++++++++++++++ 2 files changed, 1037 insertions(+) create mode 100644 docs/guides/serverless-hamsim-template.ipynb diff --git a/docs/guides/_toc.json b/docs/guides/_toc.json index 3d79793e2f0..d56f33ade67 100644 --- a/docs/guides/_toc.json +++ b/docs/guides/_toc.json @@ -508,6 +508,10 @@ { "title": "Port code to Qiskit Serverless", "url": "/guides/serverless-port-code" + }, + { + "title": "Build a Function template that performs hamiltonian simulation", + "url": "/guides/serverless-hamsim-template" } ] }, diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb new file mode 100644 index 00000000000..3f8a1dd7edb --- /dev/null +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -0,0 +1,1033 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "# Write your second Qiskit Serverless program" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "version-info" + ] + }, + "source": [ + "
\n", + "Package versions\n", + "\n", + "The code on this page was developed using the following requirements.\n", + "We recommend using these versions or newer.\n", + "\n", + "```\n", + "qiskit[all]~=1.2.4\n", + "qiskit-ibm-runtime~=0.32.0\n", + "qiskit-serverless~=0.18.0\n", + "qiskit-ibm-catalog~=0.2.0\n", + "qiskit-addon-aqc-tensor[quimb-jax]~=0.1.0\n", + "mergedeep==1.3.4\n", + "```\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "short intro describing what a function template is. this is intended to be a starting point for user to take and modify for their own needs, or that they can use as a helpful example for building out their own templates." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Example: AQC with Qiskit Serverless\n", + "\n", + "Going to make a hamiltonian simulation function that does AQC. AQC is on initial portion of circuit. FIXME.\n", + "\n", + "We will save the following code to `./source_files/hamsim_template.py`. This file is the program we'll upload to Qiskit Serverless." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# This cell is hidden from users, it just creates a new folder\n", + "from pathlib import Path\n", + "\n", + "Path(\"./source_files\").mkdir(exist_ok=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "### Access and validate program arguments" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile ./source_files/hamsim_template.py\n", + "\n", + "from qiskit import QuantumCircuit\n", + "from qiskit_serverless import get_arguments, save_result\n", + "\n", + "\n", + "# Extract parameters from arguments\n", + "#\n", + "# We do this at the top of the program so we can fail early if any required arguments are missing or invalid.\n", + "\n", + "arguments = get_arguments()\n", + "\n", + "dry_run = arguments.get(\"dry_run\", False)\n", + "backend_name = arguments[\"backend_name\"]\n", + "\n", + "aqc_evolution_time = arguments[\"aqc_evolution_time\"]\n", + "aqc_ansatz_num_trotter_steps = arguments[\"aqc_ansatz_num_trotter_steps\"]\n", + "aqc_target_num_trotter_steps = arguments[\"aqc_target_num_trotter_steps\"]\n", + "\n", + "remainder_evolution_time = arguments[\"remainder_evolution_time\"]\n", + "remainder_num_trotter_steps = arguments[\"remainder_num_trotter_steps\"]\n", + "\n", + "# Stop if this fidelity is achieved\n", + "aqc_stopping_fidelity = arguments.get(\"aqc_stopping_fidelity\", 1.0)\n", + "# Stop after this number of iterations, even if stopping fidelity is not achieved\n", + "aqc_max_iterations = arguments.get(\"aqc_max_iterations\", 500)\n", + "\n", + "hamiltonian = arguments[\"hamiltonian\"]\n", + "observable = arguments[\"observable\"]\n", + "initial_state = arguments.get(\"initial_state\", QuantumCircuit(hamiltonian.num_qubits))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "# Perform parameter validation\n", + "\n", + "if not 0.0 < aqc_stopping_fidelity <= 1.0:\n", + " raise ValueError(\n", + " f\"Invalid stopping fidelity: {aqc_stopping_fidelity} - must be positive float no greater than 1\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "import numpy as np\n", + "import json\n", + "from mergedeep import merge\n", + "\n", + "\n", + "# Configure `EstimatorOptions`, to control the parameters of our hardware experiment\n", + "#\n", + "# Set default options\n", + "estimator_default_options = {\n", + " \"resilience\": {\n", + " \"measure_mitigation\": True,\n", + " \"zne_mitigation\": True,\n", + " \"zne\": {\n", + " \"amplifier\": \"gate_folding\",\n", + " \"noise_factors\": [1, 2, 3],\n", + " \"extrapolated_noise_factors\": list(np.linspace(0, 3, 31)),\n", + " \"extrapolator\": [\"exponential\", \"linear\", \"fallback\"],\n", + " },\n", + " \"measure_noise_learning\": {\n", + " \"num_randomizations\": 512,\n", + " \"shots_per_randomization\": 512,\n", + " },\n", + " },\n", + " \"twirling\": {\n", + " \"enable_gates\": True,\n", + " \"enable_measure\": True,\n", + " \"num_randomizations\": 300,\n", + " \"shots_per_randomization\": 100,\n", + " \"strategy\": \"active\",\n", + " },\n", + "}\n", + "# Merge with user-provided options\n", + "estimator_options = merge(\n", + " arguments.get(\"estimator_options\", {}), estimator_default_options\n", + ")\n", + "print(\"estimator_options =\", json.dumps(estimator_options, indent=4))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "This `print()` call is also the first example of logging, so that there is a record of the actual Estimator options used. There are many more throughout the program below to report progress throughout the job." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "### Perform workflow with AQC\n", + "\n", + "First, we prepare a dictionary to hold all output of the Function. Keys will be added to this `dict` throughout the workflow, and it will be returned at the conclusion of the program." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "output = {}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "#### Step 1: Map\n", + "\n", + "The AQC-Tensor optimization happens in step 1 of a Qiskit pattern. First, a target state is constructed, here from a target circuit that evolves the same hamiltonian for the same time period as the AQC portion. Then, an ansatz is generated from an equivalent circuit but with fewer Trotter steps. In the main portion of the AQC algorithm, that ansatz is brought closer to the target state in an iterative process. Then, the result is combined with the remainder of the Trotter steps needed to reach the desired evolution time." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "import datetime\n", + "import quimb.tensor\n", + "from scipy.optimize import OptimizeResult, minimize\n", + "from qiskit.synthesis import SuzukiTrotter\n", + "from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit\n", + "from qiskit_addon_aqc_tensor.ansatz_generation import (\n", + " generate_ansatz_from_circuit,\n", + " AnsatzBlock,\n", + ")\n", + "from qiskit_addon_aqc_tensor.simulation import (\n", + " tensornetwork_from_circuit,\n", + " compute_overlap,\n", + ")\n", + "from qiskit_addon_aqc_tensor.simulation.quimb import QuimbSimulator\n", + "from qiskit_addon_aqc_tensor.objective import OneMinusFidelity\n", + "\n", + "print(\"Hamiltonian:\", hamiltonian)\n", + "print(\"Observable:\", observable)\n", + "simulator_settings = QuimbSimulator(quimb.tensor.CircuitMPS, autodiff_backend=\"jax\")\n", + "\n", + "# Construct the AQC target circuit\n", + "aqc_target_circuit = initial_state.copy()\n", + "if aqc_evolution_time:\n", + " aqc_target_circuit.compose(\n", + " generate_time_evolution_circuit(\n", + " hamiltonian,\n", + " synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),\n", + " time=aqc_evolution_time,\n", + " ),\n", + " inplace=True,\n", + " )\n", + "\n", + "# Construct matrix-product state representation of the AQC target state\n", + "aqc_target_mps = tensornetwork_from_circuit(aqc_target_circuit, simulator_settings)\n", + "print(\"Target MPS maximum bond dimension:\", aqc_target_mps.psi.max_bond())\n", + "output[\"target_bond_dimension\"] = aqc_target_mps.psi.max_bond()\n", + "\n", + "# Generate an ansatz and initial parameters from a Trotter circuit with fewer steps\n", + "aqc_good_circuit = initial_state.copy()\n", + "if aqc_evolution_time:\n", + " aqc_good_circuit.compose(\n", + " generate_time_evolution_circuit(\n", + " hamiltonian,\n", + " synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),\n", + " time=aqc_evolution_time,\n", + " ),\n", + " inplace=True,\n", + " )\n", + "aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(aqc_good_circuit)\n", + "print(\"Number of AQC parameters:\", len(aqc_initial_parameters))\n", + "output[\"num_aqc_parameters\"] = len(aqc_initial_parameters)\n", + "\n", + "# Calculate fidelity of ansatz circuit vs. the target state, before optimization\n", + "good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)\n", + "starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2\n", + "print(\"Starting fidelity of AQC portion:\", starting_fidelity)\n", + "output[\"aqc_starting_fidelity\"] = starting_fidelity\n", + "\n", + "# Optimize the parameters of the ansatz using MPS calculations\n", + "def callback(intermediate_result: OptimizeResult):\n", + " fidelity = 1 - intermediate_result.fun\n", + " print(f\"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}\")\n", + " if intermediate_result.fun < stopping_point:\n", + " raise StopIteration\n", + "\n", + "\n", + "objective = OneMinusFidelity(aqc_target_mps, aqc_ansatz, simulator_settings)\n", + "stopping_point = 1.0 - aqc_stopping_fidelity\n", + "\n", + "result = minimize(\n", + " objective,\n", + " aqc_initial_parameters,\n", + " method=\"L-BFGS-B\",\n", + " jac=True,\n", + " options={\"maxiter\": aqc_max_iterations},\n", + " callback=callback,\n", + ")\n", + "if result.status not in (\n", + " 0,\n", + " 1,\n", + " 99,\n", + "): # 0 => success; 1 => max iterations reached; 99 => early termination via StopIteration\n", + " raise RuntimeError(\n", + " f\"Optimization failed: {result.message} (status={result.status})\"\n", + " )\n", + "print(f\"Done after {result.nit} iterations.\")\n", + "output[\"num_iterations\"] = result.nit\n", + "aqc_final_parameters = result.x\n", + "output[\"aqc_final_parameters\"] = list(aqc_final_parameters)\n", + "\n", + "# Construct optimized circuit for initial portion of time evolution\n", + "aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)\n", + "\n", + "# Calculate fidelity after optimization\n", + "aqc_final_mps = tensornetwork_from_circuit(aqc_final_circuit, simulator_settings)\n", + "aqc_fidelity = abs(compute_overlap(aqc_final_mps, aqc_target_mps)) ** 2\n", + "print(\"Fidelity of AQC portion:\", aqc_fidelity)\n", + "output[\"aqc_fidelity\"] = aqc_fidelity\n", + "\n", + "# Construct final circuit, with remainder of time evolution\n", + "final_circuit = aqc_final_circuit.copy()\n", + "if remainder_evolution_time:\n", + " remainder_circuit = generate_time_evolution_circuit(\n", + " hamiltonian,\n", + " synthesis=SuzukiTrotter(reps=remainder_num_trotter_steps),\n", + " time=remainder_evolution_time,\n", + " )\n", + " final_circuit.compose(remainder_circuit, inplace=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "#### Step 2\n", + "\n", + "After the AQC portion of the workflow, the `final_circuit` is transpiled to hardware as usual." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "from qiskit_ibm_runtime import QiskitRuntimeService\n", + "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", + "\n", + "service = QiskitRuntimeService()\n", + "backend = service.backend(backend_name)\n", + "\n", + "# Transpile pubs (circuits and observables) to match ISA\n", + "pass_manager = generate_preset_pass_manager(backend=backend, optimization_level=3)\n", + "isa_circuit = pass_manager.run(final_circuit)\n", + "isa_observable = observable.apply_layout(isa_circuit.layout)\n", + "\n", + "isa_2qubit_depth = isa_circuit.depth(lambda x: x.operation.num_qubits == 2)\n", + "print(\"ISA circuit two-qubit depth:\", isa_2qubit_depth)\n", + "output[\"twoqubit_depth\"] = isa_2qubit_depth" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "#### Exit early if \"dry run\"" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "# Exit now if dry run; don't execute on hardware\n", + "if dry_run:\n", + " import sys\n", + "\n", + " print(\"Aborting before hardware execution since `dry_run` is True.\")\n", + " save_result(output)\n", + " sys.exit(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "#### Execute on hardware" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "# ## Step 3: Execute quantum experiments on backend\n", + "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n", + "\n", + "\n", + "estimator = Estimator(backend, options=estimator_options)\n", + "\n", + "# Submit job\n", + "job = estimator.run([(isa_circuit, isa_observable)])\n", + "print(\"Job ID:\", job.job_id())\n", + "output[\"job_id\"] = job.job_id()\n", + "\n", + "# Wait until job is complete\n", + "hw_results = job.result()\n", + "hw_results_dicts = [pub_result.data.__dict__ for pub_result in hw_results]\n", + "\n", + "# Save hardware results to serverless output dict\n", + "output[\"hw_results\"] = hw_results_dicts\n", + "\n", + "# Re-organize expectation values\n", + "hw_expvals = [pub_result_data[\"evs\"].tolist() for pub_result_data in hw_results_dicts]\n", + "\n", + "# Save expectation values to serverless\n", + "print(\"Hardware expectation values\", hw_expvals)\n", + "output[\"hw_expvals\"] = hw_expvals[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "#### Save output" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Appending to ./source_files/hamsim_template.py\n" + ] + } + ], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "save_result(output)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "This workflow grew out of a Jupyter notebook. Link to it. FIXME" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Deploy to IBM Quantum Platform\n", + "\n", + "The previous section created a program to be run remotely. The code cells in this section upload that program to Qiskit Serverless.\n", + "\n", + "Use `qiskit-ibm-catalog` to authenticate to `QiskitServerless` with your API token, which you can find in your [IBM Quantum account](https://quantum.ibm.com/account), and upload the program.\n", + "\n", + "You can use `save_account()` to save your credentials (See the \"Authenticate to the service\" step in the [Set up to use IBM Quantum Platform](./setup-channel#set-up-to-use-ibm-quantum-platform) section). Note that this writes your credentials to the same file as [`QiskitRuntimeService.save_account()`](/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#save_account)." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "from qiskit_ibm_catalog import QiskitServerless, QiskitFunction\n", + "\n", + "# Authenticate to the remote cluster and submit the pattern for remote execution\n", + "serverless = QiskitServerless()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "This program has custom `pip` dependencies, so we add them to a `dependencies` array when constructing the `QiskitFunction` instance:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "template = QiskitFunction(\n", + " title=\"hamsim_template\",\n", + " entrypoint=\"hamsim_template.py\",\n", + " working_dir=\"./source_files/\",\n", + " dependencies=[\n", + " \"qiskit-addon-utils==0.1.0\",\n", + " \"qiskit-addon-aqc-tensor[quimb-jax]==0.1.0\",\n", + " \"mergedeep\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "QiskitFunction(hamsim_template)" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "serverless.upload(template)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "To check if the program successfully uploaded, use `serverless.list()`:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[QiskitFunction(hamsim_template), QiskitFunction(aqc_tutorial_L50)]" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "serverless.list()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Perform a test run\n", + "\n", + "Here we will perform a test run using a 4-qubit hamiltonian along with a simple observable.\n", + "\n", + "First we load the template by name:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "template = serverless.load(\"hamsim_template\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Then we run it with our desired arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "from qiskit.quantum_info import SparsePauliOp\n", + "\n", + "hamiltonian = SparsePauliOp.from_sparse_list(\n", + " [(\"XX\", (i, i + 1), 1.0) for i in range(3)], num_qubits=4\n", + ") + SparsePauliOp.from_sparse_list(\n", + " [(\"YY\", (i, i + 1), 1.0) for i in range(3)], num_qubits=4\n", + ")\n", + "observable = SparsePauliOp.from_sparse_list([(\"ZZ\", (1, 2), 1.0)], num_qubits=4)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bd22fb47-ee0d-499f-8e85-2b55b526e23b\n" + ] + } + ], + "source": [ + "job = template.run(\n", + " dry_run=True,\n", + " hamiltonian=hamiltonian,\n", + " observable=observable,\n", + " backend_name=\"ibm_fez\",\n", + " estimator_options={},\n", + " aqc_evolution_time=0.2,\n", + " aqc_ansatz_num_trotter_steps=1,\n", + " aqc_target_num_trotter_steps=32,\n", + " remainder_evolution_time=0.2,\n", + " remainder_num_trotter_steps=4,\n", + " aqc_max_iterations=300,\n", + ")\n", + "print(job.job_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "job.status()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "job.logs()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Block until a result is available" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "job.result()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Next steps\n", + "\n", + "\n", + "\n", + "- FIXME Learn how to pass inputs and run your program remotely in the [Run your first Qiskit Serverless workload remotely](./serverless-run-first-workload) topic.\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# This cell is hidden from users, it just deletes the working folder we created\n", + "import shutil\n", + "\n", + "shutil.rmtree(\"./source_files/\")" + ] + } + ], + "metadata": { + "description": "How to create a parallel transpilation program and deploy it to IBM Quantum Platform to use as a reusable remote service.", + "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.11.10" + }, + "title": "Write your first Qiskit Serverless program" + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 1d8605532daa7ec32f68fff67263fe8bf5cf41af Mon Sep 17 00:00:00 2001 From: Jim Garrison Date: Tue, 12 Nov 2024 10:17:06 -0500 Subject: [PATCH 02/14] Update docs/guides/_toc.json Co-authored-by: Jen Glick <41485571+jenglick@users.noreply.github.com> --- docs/guides/_toc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/_toc.json b/docs/guides/_toc.json index d56f33ade67..845db117cae 100644 --- a/docs/guides/_toc.json +++ b/docs/guides/_toc.json @@ -511,7 +511,7 @@ }, { "title": "Build a Function template that performs hamiltonian simulation", - "url": "/guides/serverless-hamsim-template" + "url": "/guides/function-template-hamsim" } ] }, From 2847f313953330cba6f3c17bb01cf61eada2f7d1 Mon Sep 17 00:00:00 2001 From: Jim Garrison Date: Tue, 12 Nov 2024 10:17:18 -0500 Subject: [PATCH 03/14] Update docs/guides/_toc.json Co-authored-by: Jen Glick <41485571+jenglick@users.noreply.github.com> --- docs/guides/_toc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/_toc.json b/docs/guides/_toc.json index 845db117cae..7c55b9e6b1d 100644 --- a/docs/guides/_toc.json +++ b/docs/guides/_toc.json @@ -510,7 +510,7 @@ "url": "/guides/serverless-port-code" }, { - "title": "Build a Function template that performs hamiltonian simulation", + "title": "Build a Function template for Hamiltonian simulation", "url": "/guides/function-template-hamsim" } ] From 559621de5a5b18bc998ac5d17ffdf3ecfe606057 Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 10:57:27 -0600 Subject: [PATCH 04/14] Incorporate Jen's comments --- docs/guides/serverless-hamsim-template.ipynb | 145 ++++++++++++------- 1 file changed, 89 insertions(+), 56 deletions(-) diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb index 3f8a1dd7edb..1007f181bc1 100644 --- a/docs/guides/serverless-hamsim-template.ipynb +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -10,7 +10,7 @@ "tags": [] }, "source": [ - "# Write your second Qiskit Serverless program" + "# Build a function template for Hamiltonian simulation" ] }, { @@ -52,7 +52,13 @@ "tags": [] }, "source": [ - "short intro describing what a function template is. this is intended to be a starting point for user to take and modify for their own needs, or that they can use as a helpful example for building out their own templates." + "By now you've seen a basic example of how to get started writing, uploading, and running a program with Qiskit Serverless. The workloads you are building for your own use cases are likely not so simple. For example, you might need to carefully consider what domain-level inputs and outputs are relevant for your application, how to make sure your program can be reusable across a range of those inputs, and what kind of information you need returned to you during the execution of your job so that you can better evaluate the progress of your workload. You may even want to incorporate a dry run mode that lets you test the impact of a set of particular inputs before sending the resulting circuits to hardware.\n", + "\n", + "\n", + "A function template is an example of a realistic workload using a specific application domain to contextualize these aspects. It is meant to be a starting point for you to take and modify for your own needs so that you don't have to start from scratch.\n", + "\n", + "\n", + "Here, we will see a function template for addressing Hamiltonian simulation problems." ] }, { @@ -65,11 +71,11 @@ "tags": [] }, "source": [ - "## Example: AQC with Qiskit Serverless\n", + "## Write the function template\n", "\n", - "Going to make a hamiltonian simulation function that does AQC. AQC is on initial portion of circuit. FIXME.\n", + "We will write a function template for Hamiltonian simulation using the AQC-Tensor Qiskit addon to map the problem description to a reduced-depth circuit for execution on hardware.\n", "\n", - "We will save the following code to `./source_files/hamsim_template.py`. This file is the program we'll upload to Qiskit Serverless." + "We will save the following code to `./source_files/hamsim_template.py`. This file is the function template we'll upload to and run remotely with Qiskit Serverless." ] }, { @@ -102,7 +108,9 @@ "tags": [] }, "source": [ - "### Access and validate program arguments" + "### Get the domain-level inputs\n", + "\n", + "We start by getting the inputs for our template. In this case, we have domain-specific inputs relevant for Hamiltonian simulation (such as the Hamiltonian and observable) and capability-specific options (such as how much we want to compress the initial layers of our Trotter circuit using AQC-Tensor or advanced options for fine-tuning error suppression and mitigation beyond the defaults we have baked into for this example)." ] }, { @@ -157,36 +165,6 @@ "initial_state = arguments.get(\"initial_state\", QuantumCircuit(hamiltonian.num_qubits))" ] }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Appending to ./source_files/hamsim_template.py\n" - ] - } - ], - "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", - "\n", - "# Perform parameter validation\n", - "\n", - "if not 0.0 < aqc_stopping_fidelity <= 1.0:\n", - " raise ValueError(\n", - " f\"Invalid stopping fidelity: {aqc_stopping_fidelity} - must be positive float no greater than 1\"\n", - " )" - ] - }, { "cell_type": "code", "execution_count": 4, @@ -243,10 +221,50 @@ "# Merge with user-provided options\n", "estimator_options = merge(\n", " arguments.get(\"estimator_options\", {}), estimator_default_options\n", - ")\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When the function template is running, it is helpful to return information in the logs, using print statements, so that you can better evaluate the progress of your workload. Here is a simple example of printing the estimator_options so that there is a record of the actual Estimator options used. There are many more example like this throughout the program to report back progress during execution. Including the value of the objective function during the iterative component of AQC-Tensor, or the two-qubit depth of the final ISA circuit intended for execution on hardware." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "print(\"estimator_options =\", json.dumps(estimator_options, indent=4))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Validate the inputs\n", + "\n", + "An important aspect of ensuring reusability of the template across a range of inputs is to validate the inputs. Here is an example of how we check that the stopping fidelity during AQC-Tensor has been specified appropriately and, if not, return an informative error message for how to fix the error." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%writefile --append ./source_files/hamsim_template.py\n", + "\n", + "# Perform parameter validation\n", + "\n", + "if not 0.0 < aqc_stopping_fidelity <= 1.0:\n", + " raise ValueError(\n", + " f\"Invalid stopping fidelity: {aqc_stopping_fidelity} - must be positive float no greater than 1\"\n", + " )" + ] + }, { "cell_type": "markdown", "metadata": { @@ -270,9 +288,9 @@ "tags": [] }, "source": [ - "### Perform workflow with AQC\n", + "### Perform the Hamiltonian simulation workflow using AQC-Tensor\n", "\n", - "First, we prepare a dictionary to hold all output of the Function. Keys will be added to this `dict` throughout the workflow, and it will be returned at the conclusion of the program." + "First, we prepare a dictionary to hold all output of the function template. Keys will be added to this dict throughout the workflow, and it will be returned at the conclusion of the program." ] }, { @@ -312,7 +330,9 @@ "source": [ "#### Step 1: Map\n", "\n", - "The AQC-Tensor optimization happens in step 1 of a Qiskit pattern. First, a target state is constructed, here from a target circuit that evolves the same hamiltonian for the same time period as the AQC portion. Then, an ansatz is generated from an equivalent circuit but with fewer Trotter steps. In the main portion of the AQC algorithm, that ansatz is brought closer to the target state in an iterative process. Then, the result is combined with the remainder of the Trotter steps needed to reach the desired evolution time." + "The AQC-Tensor optimization happens in step 1 of a Qiskit pattern. First, a target state is constructed, here from a target circuit that evolves the same hamiltonian for the same time period as the AQC portion. Then, an ansatz is generated from an equivalent circuit but with fewer Trotter steps. In the main portion of the AQC algorithm, that ansatz is brought closer to the target state in an iterative process. Then, the result is combined with the remainder of the Trotter steps needed to reach the desired evolution time.\n", + "\n", + "Note the additional examples of logging incorporated below." ] }, { @@ -457,7 +477,7 @@ "tags": [] }, "source": [ - "#### Step 2\n", + "#### Step 2: Optimize\n", "\n", "After the AQC portion of the workflow, the `final_circuit` is transpiled to hardware as usual." ] @@ -510,7 +530,9 @@ "tags": [] }, "source": [ - "#### Exit early if \"dry run\"" + "#### Exit early if using dry run mode\n", + "\n", + "If dry run mode has been selected then the program is stopped before executing on hardware. This can be useful if, for example, you want first to inspect the two-qubit depth of the ISA circuit before deciding to execute on hardware." ] }, { @@ -554,7 +576,7 @@ "tags": [] }, "source": [ - "#### Execute on hardware" + "#### Step 3: Execute on hardware" ] }, { @@ -585,7 +607,8 @@ "\n", "estimator = Estimator(backend, options=estimator_options)\n", "\n", - "# Submit job\n", + "# Submit the underlying Estimator job. Note that this is not the\n", + "# actual function job.\n", "job = estimator.run([(isa_circuit, isa_observable)])\n", "print(\"Job ID:\", job.job_id())\n", "output[\"job_id\"] = job.job_id()\n", @@ -615,7 +638,9 @@ "tags": [] }, "source": [ - "#### Save output" + "#### Save the output\n", + "\n", + "This function template returns the relevant domain-level output for this Hamiltonian simulation workflow (expectaton values) in addition to important metadata generated along the way." ] }, { @@ -719,8 +744,8 @@ "outputs": [], "source": [ "template = QiskitFunction(\n", - " title=\"hamsim_template\",\n", - " entrypoint=\"hamsim_template.py\",\n", + " title=\"function_template_hamsim\",\n", + " entrypoint=\"function_template_hamsim.py\",\n", " working_dir=\"./source_files/\",\n", " dependencies=[\n", " \"qiskit-addon-utils==0.1.0\",\n", @@ -783,7 +808,7 @@ { "data": { "text/plain": [ - "[QiskitFunction(hamsim_template), QiskitFunction(aqc_tutorial_L50)]" + "[QiskitFunction(hamsim_template)]" ] }, "execution_count": 31, @@ -805,11 +830,9 @@ "tags": [] }, "source": [ - "## Perform a test run\n", - "\n", - "Here we will perform a test run using a 4-qubit hamiltonian along with a simple observable.\n", + "## Run the function template remotely\n", "\n", - "First we load the template by name:" + "Now that we have uploaded the function template, we can run it remotely with Qiskit Serverless. First, we load the template by name:" ] }, { @@ -837,7 +860,7 @@ "tags": [] }, "source": [ - "Then we run it with our desired arguments:" + "Then, we run the template with the domain-level inputs for Hamiltonian simulation. In this example, we specify a simple 4-qubit hamiltonian along with an observable." ] }, { @@ -907,7 +930,9 @@ }, "tags": [] }, - "source": [] + "source": [ + "We can check the status of our job:" + ] }, { "cell_type": "code", @@ -924,6 +949,13 @@ "job.status()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once the job is running, we can fetch logs created from the `print()` outputs. These can provide actionable information about the progress of our Hamiltonian simulation workflow. For example, the value of the objective function during the iterative component of AQC, or the two-qubit depth of the final ISA circuit intended for execution on hardware." + ] + }, { "cell_type": "code", "execution_count": null, @@ -949,7 +981,7 @@ "tags": [] }, "source": [ - "Block until a result is available" + "Block until a result is available. And once the job is done, we can retrieve the results. These include the domain-level output of Hamiltonian simulation (expectation value) and useful metadata." ] }, { @@ -981,7 +1013,8 @@ "\n", "\n", "\n", - "- FIXME Learn how to pass inputs and run your program remotely in the [Run your first Qiskit Serverless workload remotely](./serverless-run-first-workload) topic.\n", + "- See an [example of this function template](https://qiskit.github.io/qiskit-addon-aqc-tensor/) in action on a large-scale Hamiltonian simulation problem. \n", + "{/* - For a deeper dive into the AQC-Tensor Qiskit addon, check out the [tutorial on the Learning Platform](add-link-when-live). */}\n", "\n", "" ] From 0432abbe1fce11e6d60b65290fea5a8bb58cd8cc Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 12:16:01 -0600 Subject: [PATCH 05/14] Add it to more infra files --- qiskit_bot.yaml | 4 ++++ scripts/config/cspell/dictionaries/qiskit.txt | 1 + scripts/config/notebook-testing.toml | 1 + 3 files changed, 6 insertions(+) diff --git a/qiskit_bot.yaml b/qiskit_bot.yaml index f55d1552032..fdd75e2f56d 100644 --- a/qiskit_bot.yaml +++ b/qiskit_bot.yaml @@ -133,6 +133,10 @@ notifications: "docs/guides/monitor-job": - "@jyu00" - "@beckykd" + "docs/guides/serverless-hamsim-template": + - "@jenglick" + - "@garrison" + - "@beckykd" "docs/guides/operator-class": - "`@mtreinish`" "docs/guides/online-lab-environments": diff --git a/scripts/config/cspell/dictionaries/qiskit.txt b/scripts/config/cspell/dictionaries/qiskit.txt index 42d7efee71a..5e59b86df63 100644 --- a/scripts/config/cspell/dictionaries/qiskit.txt +++ b/scripts/config/cspell/dictionaries/qiskit.txt @@ -56,6 +56,7 @@ Qedma Qiskit Qiskit Quna +quimb RCCX SLSQP SPSA diff --git a/scripts/config/notebook-testing.toml b/scripts/config/notebook-testing.toml index d3881612138..a5a298ec675 100644 --- a/scripts/config/notebook-testing.toml +++ b/scripts/config/notebook-testing.toml @@ -46,6 +46,7 @@ notebooks_exclude = [ "docs/guides/ibm-circuit-function.ipynb", "docs/guides/qiskit-addons-sqd-get-started.ipynb", "docs/guides/fractional-gates.ipynb", + "docs/guides/serverless-hamsin-template.ipynb", ] # The following notebooks submit jobs that can be mocked with a simulator From f960ba4ad2965c01c8cda3e69464b3b06e1c89a2 Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 13:07:45 -0600 Subject: [PATCH 06/14] Add to check-patterns-index --- scripts/js/commands/checkPatternsIndex.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/js/commands/checkPatternsIndex.ts b/scripts/js/commands/checkPatternsIndex.ts index 4a19c1b02b6..c729e501ed2 100644 --- a/scripts/js/commands/checkPatternsIndex.ts +++ b/scripts/js/commands/checkPatternsIndex.ts @@ -22,6 +22,7 @@ const ALLOWLIST_MISSING_FROM_INDEX: Set = new Set([ "/guides/qiskit-code-assistant-vscode", "/guides/addons", "/guides/addons/qiskit-addons-sqd-get-started", + "/guides/function-template-hamsim", ]); // URLs that show up in the INDEX_PAGES, but are not in the left ToC under From 22837313b2eea35955547b93890421e6bb86934e Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 13:11:20 -0600 Subject: [PATCH 07/14] fix link --- docs/guides/serverless-hamsim-template.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb index 1007f181bc1..290c4ed5673 100644 --- a/docs/guides/serverless-hamsim-template.ipynb +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -1014,7 +1014,7 @@ "\n", "\n", "- See an [example of this function template](https://qiskit.github.io/qiskit-addon-aqc-tensor/) in action on a large-scale Hamiltonian simulation problem. \n", - "{/* - For a deeper dive into the AQC-Tensor Qiskit addon, check out the [tutorial on the Learning Platform](add-link-when-live). */}\n", + "{/* - For a deeper dive into the AQC-Tensor Qiskit addon, check out the tutorial on the Learning Platform (add-link-when-live). */}\n", "\n", "" ] From 6188103aa305e311b4b995a4db6dcf8fb31c1309 Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 13:21:57 -0600 Subject: [PATCH 08/14] fix name in toc --- docs/guides/_toc.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/_toc.json b/docs/guides/_toc.json index ba2e1f55411..aa37dbc0a42 100644 --- a/docs/guides/_toc.json +++ b/docs/guides/_toc.json @@ -109,7 +109,7 @@ { "title": "Multiverse Computing Singularity", "url": "/guides/multiverse-computing-singularity" - }, + }, { "title": "Q-CTRL Optimization Solver", "url": "/guides/q-ctrl-optimization-solver" @@ -515,7 +515,7 @@ }, { "title": "Build a Function template for Hamiltonian simulation", - "url": "/guides/function-template-hamsim" + "url": "/guides/serverless-hamsim-template" } ] }, From 90c53b841ed044dd4b1e18d801c4539d2e0c268b Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 13:27:21 -0600 Subject: [PATCH 09/14] fix file name --- scripts/js/commands/checkPatternsIndex.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/js/commands/checkPatternsIndex.ts b/scripts/js/commands/checkPatternsIndex.ts index c729e501ed2..1fca4ece749 100644 --- a/scripts/js/commands/checkPatternsIndex.ts +++ b/scripts/js/commands/checkPatternsIndex.ts @@ -22,7 +22,7 @@ const ALLOWLIST_MISSING_FROM_INDEX: Set = new Set([ "/guides/qiskit-code-assistant-vscode", "/guides/addons", "/guides/addons/qiskit-addons-sqd-get-started", - "/guides/function-template-hamsim", + "/guides/serverless-hamsim-template", ]); // URLs that show up in the INDEX_PAGES, but are not in the left ToC under From e820576f1a9e8804048fb50a74ea5329f3c6215e Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 14:00:02 -0600 Subject: [PATCH 10/14] rename to function_template_hamsim --- docs/guides/serverless-hamsim-template.ipynb | 44 ++++++++++---------- scripts/config/notebook-testing.toml | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb index 290c4ed5673..a0f36912cc6 100644 --- a/docs/guides/serverless-hamsim-template.ipynb +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -75,7 +75,7 @@ "\n", "We will write a function template for Hamiltonian simulation using the AQC-Tensor Qiskit addon to map the problem description to a reduced-depth circuit for execution on hardware.\n", "\n", - "We will save the following code to `./source_files/hamsim_template.py`. This file is the function template we'll upload to and run remotely with Qiskit Serverless." + "We will save the following code to `./source_files/function_template_hamsim.py`. This file is the function template we'll upload to and run remotely with Qiskit Serverless." ] }, { @@ -128,12 +128,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Overwriting ./source_files/hamsim_template.py\n" + "Overwriting ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile ./source_files/hamsim_template.py\n", + "%%writefile ./source_files/function_template_hamsim.py\n", "\n", "from qiskit import QuantumCircuit\n", "from qiskit_serverless import get_arguments, save_result\n", @@ -180,12 +180,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Appending to ./source_files/hamsim_template.py\n" + "Appending to ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "import numpy as np\n", "import json\n", @@ -255,7 +255,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "# Perform parameter validation\n", "\n", @@ -308,12 +308,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Appending to ./source_files/hamsim_template.py\n" + "Appending to ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "output = {}" ] @@ -350,12 +350,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Appending to ./source_files/hamsim_template.py\n" + "Appending to ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "import datetime\n", "import quimb.tensor\n", @@ -497,12 +497,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Appending to ./source_files/hamsim_template.py\n" + "Appending to ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "from qiskit_ibm_runtime import QiskitRuntimeService\n", "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", @@ -550,12 +550,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Appending to ./source_files/hamsim_template.py\n" + "Appending to ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "# Exit now if dry run; don't execute on hardware\n", "if dry_run:\n", @@ -594,12 +594,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Appending to ./source_files/hamsim_template.py\n" + "Appending to ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "# ## Step 3: Execute quantum experiments on backend\n", "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n", @@ -658,12 +658,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Appending to ./source_files/hamsim_template.py\n" + "Appending to ./source_files/function_template_hamsim.py\n" ] } ], "source": [ - "%%writefile --append ./source_files/hamsim_template.py\n", + "%%writefile --append ./source_files/function_template_hamsim.py\n", "\n", "save_result(output)" ] @@ -745,7 +745,7 @@ "source": [ "template = QiskitFunction(\n", " title=\"function_template_hamsim\",\n", - " entrypoint=\"function_template_hamsim.py\",\n", + " entrypoint=\"hfunction_template_hamsim.py\",\n", " working_dir=\"./source_files/\",\n", " dependencies=[\n", " \"qiskit-addon-utils==0.1.0\",\n", @@ -769,7 +769,7 @@ { "data": { "text/plain": [ - "QiskitFunction(hamsim_template)" + "QiskitFunction(function_template_hamsim)" ] }, "execution_count": 30, @@ -808,7 +808,7 @@ { "data": { "text/plain": [ - "[QiskitFunction(hamsim_template)]" + "[QiskitFunction(function_template_hamsim)]" ] }, "execution_count": 31, @@ -847,7 +847,7 @@ }, "outputs": [], "source": [ - "template = serverless.load(\"hamsim_template\")" + "template = serverless.load(\"function_template_hamsim\")" ] }, { diff --git a/scripts/config/notebook-testing.toml b/scripts/config/notebook-testing.toml index 60e7f4d6bd7..1c5ab32b911 100644 --- a/scripts/config/notebook-testing.toml +++ b/scripts/config/notebook-testing.toml @@ -46,7 +46,7 @@ notebooks_exclude = [ "docs/guides/ibm-circuit-function.ipynb", "docs/guides/qiskit-addons-sqd-get-started.ipynb", "docs/guides/fractional-gates.ipynb", - "docs/guides/serverless-hamsin-template.ipynb", + "docs/guides/serverless-hamsim-template.ipynb", "docs/guides/save-jobs.ipynb", ] From 90c780bf537a707b5c5e42f6615cd1c266f3bb0a Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 15:54:44 -0600 Subject: [PATCH 11/14] Edits --- docs/guides/serverless-hamsim-template.ipynb | 150 +++++++++++-------- 1 file changed, 84 insertions(+), 66 deletions(-) diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb index a0f36912cc6..815299fcddb 100644 --- a/docs/guides/serverless-hamsim-template.ipynb +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -2,6 +2,7 @@ "cells": [ { "cell_type": "markdown", + "id": "b1fde164-2b2b-473b-93b8-30168882076b", "metadata": { "editable": true, "slideshow": { @@ -15,6 +16,7 @@ }, { "cell_type": "markdown", + "id": "4bbc25a8-5315-417f-bf35-7ac715ebdf98", "metadata": { "editable": true, "slideshow": { @@ -44,6 +46,7 @@ }, { "cell_type": "markdown", + "id": "5092090f-0fb8-436e-8099-3d3059367efc", "metadata": { "editable": true, "slideshow": { @@ -52,17 +55,16 @@ "tags": [] }, "source": [ - "By now you've seen a basic example of how to get started writing, uploading, and running a program with Qiskit Serverless. The workloads you are building for your own use cases are likely not so simple. For example, you might need to carefully consider what domain-level inputs and outputs are relevant for your application, how to make sure your program can be reusable across a range of those inputs, and what kind of information you need returned to you during the execution of your job so that you can better evaluate the progress of your workload. You may even want to incorporate a dry run mode that lets you test the impact of a set of particular inputs before sending the resulting circuits to hardware.\n", + "By now you've seen a basic example of how to get started writing, uploading, and running a program with Qiskit Serverless. If you haven't, start with [What is Qiskit Serverless?](/guides/serverless) for some background information first. The workloads you are building for your own use cases are likely not as simple as the examples previously shown. For example, you might need to carefully consider what domain-level inputs and outputs are relevant for your application, how to make sure your program can be reusable across a range of those inputs, and what kind of information you need returned during the execution of the job so you can better evaluate the progress of your workload. You might even want to incorporate a \"dry run\" mode that lets you test the impact of a set of particular inputs before sending the resulting circuits to hardware.\n", "\n", + "A function template is an example of a realistic workload that uses a specific application domain to contextualize these aspects. It is meant to be a starting point for you to modify for your own needs so you don't have to start from scratch.\n", "\n", - "A function template is an example of a realistic workload using a specific application domain to contextualize these aspects. It is meant to be a starting point for you to take and modify for your own needs so that you don't have to start from scratch.\n", - "\n", - "\n", - "Here, we will see a function template for addressing Hamiltonian simulation problems." + "This guide walks through a function template for addressing Hamiltonian simulation problems." ] }, { "cell_type": "markdown", + "id": "efde8ea3-8ba4-4859-b7cd-7c4e5c049783", "metadata": { "editable": true, "slideshow": { @@ -73,14 +75,15 @@ "source": [ "## Write the function template\n", "\n", - "We will write a function template for Hamiltonian simulation using the AQC-Tensor Qiskit addon to map the problem description to a reduced-depth circuit for execution on hardware.\n", + "First, write a function template for Hamiltonian simulation that uses the [AQC-Tensor Qiskit addon](https://qiskit.github.io/qiskit-addon-aqc-tensor/) to map the problem description to a reduced-depth circuit for execution on hardware.\n", "\n", - "We will save the following code to `./source_files/function_template_hamsim.py`. This file is the function template we'll upload to and run remotely with Qiskit Serverless." + "Throughout, the code is saved to `./source_files/function_template_hamsim.py`. This file is the function template you can upload to and run remotely with Qiskit Serverless." ] }, { "cell_type": "code", "execution_count": 1, + "id": "921071c7-910c-48b7-87f1-f9f6f4a5ca61", "metadata": { "editable": true, "slideshow": { @@ -100,6 +103,7 @@ }, { "cell_type": "markdown", + "id": "227d4f76-14cd-4853-b986-f6b09cecb26a", "metadata": { "editable": true, "slideshow": { @@ -110,12 +114,13 @@ "source": [ "### Get the domain-level inputs\n", "\n", - "We start by getting the inputs for our template. In this case, we have domain-specific inputs relevant for Hamiltonian simulation (such as the Hamiltonian and observable) and capability-specific options (such as how much we want to compress the initial layers of our Trotter circuit using AQC-Tensor or advanced options for fine-tuning error suppression and mitigation beyond the defaults we have baked into for this example)." + "Start by getting the inputs for the template. This example has domain-specific inputs relevant for Hamiltonian simulation (such as the Hamiltonian and observable) and capability-specific options (such as how much you want to compress the initial layers of the Trotter circuit using AQC-Tensor or advanced options for fine-tuning error suppression and mitigation beyond the defaults that are part of this example)." ] }, { "cell_type": "code", "execution_count": 2, + "id": "0123aa49-25ee-44d3-93ce-9b1af13487df", "metadata": { "editable": true, "slideshow": { @@ -141,7 +146,7 @@ "\n", "# Extract parameters from arguments\n", "#\n", - "# We do this at the top of the program so we can fail early if any required arguments are missing or invalid.\n", + "# Do this at the top of the program so it fails early if any required arguments are missing or invalid.\n", "\n", "arguments = get_arguments()\n", "\n", @@ -168,6 +173,7 @@ { "cell_type": "code", "execution_count": 4, + "id": "68724647-f6aa-4977-ab40-5be3de997499", "metadata": { "editable": true, "slideshow": { @@ -192,7 +198,7 @@ "from mergedeep import merge\n", "\n", "\n", - "# Configure `EstimatorOptions`, to control the parameters of our hardware experiment\n", + "# Configure `EstimatorOptions`, to control the parameters of the hardware experiment\n", "#\n", "# Set default options\n", "estimator_default_options = {\n", @@ -221,19 +227,21 @@ "# Merge with user-provided options\n", "estimator_options = merge(\n", " arguments.get(\"estimator_options\", {}), estimator_default_options\n", - ")\n" + ")" ] }, { "cell_type": "markdown", + "id": "939b9b9c-34b7-40a1-92fc-2b1639aee349", "metadata": {}, "source": [ - "When the function template is running, it is helpful to return information in the logs, using print statements, so that you can better evaluate the progress of your workload. Here is a simple example of printing the estimator_options so that there is a record of the actual Estimator options used. There are many more example like this throughout the program to report back progress during execution. Including the value of the objective function during the iterative component of AQC-Tensor, or the two-qubit depth of the final ISA circuit intended for execution on hardware." + "When the function template is running, it is helpful to return information in the logs by using print statements, so that you can better evaluate the workload's progress. Following is a simple example of printing the `estimator_options` so there is a record of the actual Estimator options used. There are many more similar example throughout the program to report progress during execution, including the value of the objective function during the iterative component of AQC-Tensor, and the two-qubit depth of the final instruction set architecture (ISA) circuit intended for execution on hardware." ] }, { "cell_type": "code", "execution_count": null, + "id": "d8d67489-9c92-42c0-a7fc-a347077ac72e", "metadata": {}, "outputs": [], "source": [ @@ -242,16 +250,18 @@ }, { "cell_type": "markdown", + "id": "a6b70531-d5c4-42c5-8fcc-9e19c32f32e8", "metadata": {}, "source": [ "### Validate the inputs\n", "\n", - "An important aspect of ensuring reusability of the template across a range of inputs is to validate the inputs. Here is an example of how we check that the stopping fidelity during AQC-Tensor has been specified appropriately and, if not, return an informative error message for how to fix the error." + "An important aspect of ensuring that the template can be reused across a range of inputs is to validate them. The following code is an example of verifying that the stopping fidelity during AQC-Tensor has been specified appropriately and if not, return an informative error message for how to fix the error." ] }, { "cell_type": "code", "execution_count": null, + "id": "f1b690c4-2e06-4f2a-916c-827237a4632a", "metadata": {}, "outputs": [], "source": [ @@ -261,25 +271,13 @@ "\n", "if not 0.0 < aqc_stopping_fidelity <= 1.0:\n", " raise ValueError(\n", - " f\"Invalid stopping fidelity: {aqc_stopping_fidelity} - must be positive float no greater than 1\"\n", + " f\"Invalid stopping fidelity: {aqc_stopping_fidelity}. It must be a positive float no greater than 1.\"\n", " )" ] }, { "cell_type": "markdown", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "source": [ - "This `print()` call is also the first example of logging, so that there is a record of the actual Estimator options used. There are many more throughout the program below to report progress throughout the job." - ] - }, - { - "cell_type": "markdown", + "id": "7f4bfe7f-e457-433a-9420-06a680323a33", "metadata": { "editable": true, "slideshow": { @@ -290,12 +288,13 @@ "source": [ "### Perform the Hamiltonian simulation workflow using AQC-Tensor\n", "\n", - "First, we prepare a dictionary to hold all output of the function template. Keys will be added to this dict throughout the workflow, and it will be returned at the conclusion of the program." + "First, prepare a dictionary to hold all of the function template output. Keys will be added to this dictonary throughout the workflow, and it is returned at the end of the program." ] }, { "cell_type": "code", "execution_count": 5, + "id": "932e4d9c-2493-4cf4-84c3-54e679814842", "metadata": { "editable": true, "slideshow": { @@ -320,6 +319,7 @@ }, { "cell_type": "markdown", + "id": "8d09b59d-8065-446c-966d-b67f49eba6ec", "metadata": { "editable": true, "slideshow": { @@ -330,14 +330,15 @@ "source": [ "#### Step 1: Map\n", "\n", - "The AQC-Tensor optimization happens in step 1 of a Qiskit pattern. First, a target state is constructed, here from a target circuit that evolves the same hamiltonian for the same time period as the AQC portion. Then, an ansatz is generated from an equivalent circuit but with fewer Trotter steps. In the main portion of the AQC algorithm, that ansatz is brought closer to the target state in an iterative process. Then, the result is combined with the remainder of the Trotter steps needed to reach the desired evolution time.\n", + "The AQC-Tensor optimization happens in step 1 of a Qiskit pattern. First, a target state is constructed. In this example, it is constructed from a target circuit that evolves the same Hamiltonian for the same time period as the AQC portion. Then, an ansatz is generated from an equivalent circuit but with fewer Trotter steps. In the main portion of the AQC algorithm, that ansatz is iteratively brought closer to the target state. Finally, the result is combined with the remainder of the Trotter steps needed to reach the desired evolution time.\n", "\n", - "Note the additional examples of logging incorporated below." + "Note the additional examples of logging incorporated in the following code." ] }, { "cell_type": "code", "execution_count": 6, + "id": "05926050-da5d-4c16-a0e7-ea5a875ea9b0", "metadata": { "editable": true, "slideshow": { @@ -409,13 +410,13 @@ "print(\"Number of AQC parameters:\", len(aqc_initial_parameters))\n", "output[\"num_aqc_parameters\"] = len(aqc_initial_parameters)\n", "\n", - "# Calculate fidelity of ansatz circuit vs. the target state, before optimization\n", + "# Calculate the fidelity of ansatz circuit vs. the target state, before optimization\n", "good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)\n", "starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2\n", "print(\"Starting fidelity of AQC portion:\", starting_fidelity)\n", "output[\"aqc_starting_fidelity\"] = starting_fidelity\n", "\n", - "# Optimize the parameters of the ansatz using MPS calculations\n", + "# Optimize the ansatz parameters by using MPS calculations\n", "def callback(intermediate_result: OptimizeResult):\n", " fidelity = 1 - intermediate_result.fun\n", " print(f\"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}\")\n", @@ -447,7 +448,7 @@ "aqc_final_parameters = result.x\n", "output[\"aqc_final_parameters\"] = list(aqc_final_parameters)\n", "\n", - "# Construct optimized circuit for initial portion of time evolution\n", + "# Construct an optimized circuit for initial portion of time evolution\n", "aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)\n", "\n", "# Calculate fidelity after optimization\n", @@ -469,6 +470,7 @@ }, { "cell_type": "markdown", + "id": "5ae54748-f104-4022-9383-f54570be833f", "metadata": { "editable": true, "slideshow": { @@ -479,12 +481,13 @@ "source": [ "#### Step 2: Optimize\n", "\n", - "After the AQC portion of the workflow, the `final_circuit` is transpiled to hardware as usual." + "After the AQC portion of the workflow, the `final_circuit` is [transpiled for the hardware](/guides/transpile#instruction-set-architecture) as usual." ] }, { "cell_type": "code", "execution_count": 7, + "id": "971344cd-455e-4017-9faa-ec66f6b58316", "metadata": { "editable": true, "slideshow": { @@ -510,7 +513,7 @@ "service = QiskitRuntimeService()\n", "backend = service.backend(backend_name)\n", "\n", - "# Transpile pubs (circuits and observables) to match ISA\n", + "# Transpile PUBs (circuits and observables) to match ISA\n", "pass_manager = generate_preset_pass_manager(backend=backend, optimization_level=3)\n", "isa_circuit = pass_manager.run(final_circuit)\n", "isa_observable = observable.apply_layout(isa_circuit.layout)\n", @@ -522,6 +525,7 @@ }, { "cell_type": "markdown", + "id": "226d20da-391f-4131-8711-9cb7adad908b", "metadata": { "editable": true, "slideshow": { @@ -532,12 +536,13 @@ "source": [ "#### Exit early if using dry run mode\n", "\n", - "If dry run mode has been selected then the program is stopped before executing on hardware. This can be useful if, for example, you want first to inspect the two-qubit depth of the ISA circuit before deciding to execute on hardware." + "If dry run mode has been selected, then the program is stopped before executing on hardware. This can be useful if, for example, you want first to inspect the two-qubit depth of the ISA circuit before deciding to execute on hardware." ] }, { "cell_type": "code", "execution_count": 8, + "id": "8f6c84e3-3b18-4328-9f64-1a54a218946f", "metadata": { "editable": true, "slideshow": { @@ -561,13 +566,14 @@ "if dry_run:\n", " import sys\n", "\n", - " print(\"Aborting before hardware execution since `dry_run` is True.\")\n", + " print(\"Exiting before hardware execution since `dry_run` is True.\")\n", " save_result(output)\n", " sys.exit(0)" ] }, { "cell_type": "markdown", + "id": "34751113-6ad1-43a6-b2ac-fac10fe02eae", "metadata": { "editable": true, "slideshow": { @@ -582,6 +588,7 @@ { "cell_type": "code", "execution_count": 9, + "id": "18fa45c7-9f4e-4513-a9ff-2796aef65e69", "metadata": { "editable": true, "slideshow": { @@ -617,19 +624,20 @@ "hw_results = job.result()\n", "hw_results_dicts = [pub_result.data.__dict__ for pub_result in hw_results]\n", "\n", - "# Save hardware results to serverless output dict\n", + "# Save hardware results to serverless output dictionary\n", "output[\"hw_results\"] = hw_results_dicts\n", "\n", - "# Re-organize expectation values\n", + "# Reorganize expectation values\n", "hw_expvals = [pub_result_data[\"evs\"].tolist() for pub_result_data in hw_results_dicts]\n", "\n", - "# Save expectation values to serverless\n", + "# Save expectation values to Qiskit Serverless\n", "print(\"Hardware expectation values\", hw_expvals)\n", "output[\"hw_expvals\"] = hw_expvals[0]" ] }, { "cell_type": "markdown", + "id": "1ea7d04b-2696-42bd-9247-d20d67d47af3", "metadata": { "editable": true, "slideshow": { @@ -646,6 +654,7 @@ { "cell_type": "code", "execution_count": 10, + "id": "bc05e9a9-2b9e-4aef-b6d5-30858445d774", "metadata": { "editable": true, "slideshow": { @@ -670,19 +679,7 @@ }, { "cell_type": "markdown", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "source": [ - "This workflow grew out of a Jupyter notebook. Link to it. FIXME" - ] - }, - { - "cell_type": "markdown", + "id": "3eae249e-94a2-46db-942f-4935c8d70642", "metadata": { "editable": true, "slideshow": { @@ -693,16 +690,17 @@ "source": [ "## Deploy to IBM Quantum Platform\n", "\n", - "The previous section created a program to be run remotely. The code cells in this section upload that program to Qiskit Serverless.\n", + "The previous section created a program to be run remotely. The code in this section uploads that program to Qiskit Serverless.\n", "\n", - "Use `qiskit-ibm-catalog` to authenticate to `QiskitServerless` with your API token, which you can find in your [IBM Quantum account](https://quantum.ibm.com/account), and upload the program.\n", + "Use `qiskit-ibm-catalog` to authenticate to `QiskitServerless` with your API token, which you can find in your [IBM Quantum™ account](https://quantum.ibm.com/account), and upload the program.\n", "\n", - "You can use `save_account()` to save your credentials (See the \"Authenticate to the service\" step in the [Set up to use IBM Quantum Platform](./setup-channel#set-up-to-use-ibm-quantum-platform) section). Note that this writes your credentials to the same file as [`QiskitRuntimeService.save_account()`](/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#save_account)." + "You can optionally use `save_account()` to save your credentials (See the [\"Authenticate to the service\" step](./setup-channel#save-account)) in the Set up to use IBM Quantum Platform guide. Note that this writes your credentials to the same file as [`QiskitRuntimeService.save_account()`.](/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#save_account)" ] }, { "cell_type": "code", "execution_count": 11, + "id": "b3017f23-b5a9-40c1-80b9-d12232f723a8", "metadata": { "editable": true, "slideshow": { @@ -720,6 +718,7 @@ }, { "cell_type": "markdown", + "id": "faf301a3-32db-4a05-ae8b-45fc3caef05e", "metadata": { "editable": true, "slideshow": { @@ -728,12 +727,13 @@ "tags": [] }, "source": [ - "This program has custom `pip` dependencies, so we add them to a `dependencies` array when constructing the `QiskitFunction` instance:" + "This program has custom `pip` dependencies. Add them to a `dependencies` array when constructing the `QiskitFunction` instance:" ] }, { "cell_type": "code", "execution_count": 29, + "id": "08693aba-eeaf-4f0c-b7d9-b9ce709a36b3", "metadata": { "editable": true, "slideshow": { @@ -758,6 +758,7 @@ { "cell_type": "code", "execution_count": 30, + "id": "2407a391-4199-45d5-bf0f-4cd582860554", "metadata": { "editable": true, "slideshow": { @@ -783,6 +784,7 @@ }, { "cell_type": "markdown", + "id": "2fff9c39-620c-4307-b0b0-8f29ff3454b3", "metadata": { "editable": true, "slideshow": { @@ -797,6 +799,7 @@ { "cell_type": "code", "execution_count": 31, + "id": "10f9ee91-2539-4dc7-bd16-3c6b455865d8", "metadata": { "editable": true, "slideshow": { @@ -822,6 +825,7 @@ }, { "cell_type": "markdown", + "id": "c81a3d08-b43b-4160-b4c8-5b196ab0b204", "metadata": { "editable": true, "slideshow": { @@ -832,12 +836,13 @@ "source": [ "## Run the function template remotely\n", "\n", - "Now that we have uploaded the function template, we can run it remotely with Qiskit Serverless. First, we load the template by name:" + "The function template has been uploaded, so you can run it remotely with Qiskit Serverless. First, load the template by name:" ] }, { "cell_type": "code", "execution_count": 32, + "id": "8f06ef41-e551-484d-843c-23e9d3347757", "metadata": { "editable": true, "slideshow": { @@ -852,6 +857,7 @@ }, { "cell_type": "markdown", + "id": "d1f30310-ff43-42b5-9711-764d12deff09", "metadata": { "editable": true, "slideshow": { @@ -860,12 +866,13 @@ "tags": [] }, "source": [ - "Then, we run the template with the domain-level inputs for Hamiltonian simulation. In this example, we specify a simple 4-qubit hamiltonian along with an observable." + "Next, run the template with the domain-level inputs for Hamiltonian simulation. This example specifies simple four-qubit Hamiltonian and an observable." ] }, { "cell_type": "code", "execution_count": 33, + "id": "560eed26-78cb-4c48-9f35-7ac6e88aa648", "metadata": { "editable": true, "slideshow": { @@ -882,12 +889,15 @@ ") + SparsePauliOp.from_sparse_list(\n", " [(\"YY\", (i, i + 1), 1.0) for i in range(3)], num_qubits=4\n", ")\n", - "observable = SparsePauliOp.from_sparse_list([(\"ZZ\", (1, 2), 1.0)], num_qubits=4)" + "observable = SparsePauliOp.from_sparse_list(\n", + " [(\"ZZ\", (1, 2), 1.0)], num_qubits=4\n", + ")" ] }, { "cell_type": "code", "execution_count": 34, + "id": "f7f8cb70-8b81-4758-a105-0911faf0c9fa", "metadata": { "editable": true, "slideshow": { @@ -923,6 +933,7 @@ }, { "cell_type": "markdown", + "id": "efbf4bda-e434-4b51-a47a-9cd8b220c903", "metadata": { "editable": true, "slideshow": { @@ -931,12 +942,13 @@ "tags": [] }, "source": [ - "We can check the status of our job:" + "Check the status of the job:" ] }, { "cell_type": "code", "execution_count": null, + "id": "42fff535-84c7-4312-8fb9-e0f774a60405", "metadata": { "editable": true, "slideshow": { @@ -951,14 +963,16 @@ }, { "cell_type": "markdown", + "id": "df723b45-5083-4ee4-9194-1d2822f26982", "metadata": {}, "source": [ - "Once the job is running, we can fetch logs created from the `print()` outputs. These can provide actionable information about the progress of our Hamiltonian simulation workflow. For example, the value of the objective function during the iterative component of AQC, or the two-qubit depth of the final ISA circuit intended for execution on hardware." + "After the job is running, you can fetch logs created from the `print()` outputs. These can provide actionable information about the progress of the Hamiltonian simulation workflow. For example, the value of the objective function during the iterative component of AQC or the two-qubit depth of the final ISA circuit intended for execution on hardware." ] }, { "cell_type": "code", "execution_count": null, + "id": "37ffbb99-cfde-4e0b-90b5-2ae935897a15", "metadata": { "editable": true, "slideshow": { @@ -973,6 +987,7 @@ }, { "cell_type": "markdown", + "id": "ee48f1c7-2239-4a85-b907-37e27d6a98fb", "metadata": { "editable": true, "slideshow": { @@ -981,12 +996,13 @@ "tags": [] }, "source": [ - "Block until a result is available. And once the job is done, we can retrieve the results. These include the domain-level output of Hamiltonian simulation (expectation value) and useful metadata." + "Block the rest of the program until a result is available. After the job is done, you can retrieve the results. These include the domain-level output of Hamiltonian simulation (expectation value) and useful metadata." ] }, { "cell_type": "code", "execution_count": null, + "id": "adac32a9-e231-489a-a59e-2ecf449ea90a", "metadata": { "editable": true, "slideshow": { @@ -1001,6 +1017,7 @@ }, { "cell_type": "markdown", + "id": "98def6cc-186e-4b4a-982c-8d87e8fd6e09", "metadata": { "editable": true, "slideshow": { @@ -1013,7 +1030,7 @@ "\n", "\n", "\n", - "- See an [example of this function template](https://qiskit.github.io/qiskit-addon-aqc-tensor/) in action on a large-scale Hamiltonian simulation problem. \n", + "See an [example of this function template](https://qiskit.github.io/qiskit-addon-aqc-tensor/) in action on a large-scale Hamiltonian simulation problem.\n", "{/* - For a deeper dive into the AQC-Tensor Qiskit addon, check out the tutorial on the Learning Platform (add-link-when-live). */}\n", "\n", "" @@ -1022,6 +1039,7 @@ { "cell_type": "code", "execution_count": null, + "id": "c0984a9e-15e9-44ca-b41e-a2116fab00b0", "metadata": { "editable": true, "slideshow": { @@ -1043,7 +1061,7 @@ "metadata": { "description": "How to create a parallel transpilation program and deploy it to IBM Quantum Platform to use as a reusable remote service.", "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -1057,7 +1075,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.10" + "version": "3" }, "title": "Write your first Qiskit Serverless program" }, From 62d7ddd3f79c6e136aea0fc4c9e9ac0c306cc4bb Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 16:03:00 -0600 Subject: [PATCH 12/14] spelling --- docs/guides/serverless-hamsim-template.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb index 815299fcddb..13e1fc72b97 100644 --- a/docs/guides/serverless-hamsim-template.ipynb +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -288,7 +288,7 @@ "source": [ "### Perform the Hamiltonian simulation workflow using AQC-Tensor\n", "\n", - "First, prepare a dictionary to hold all of the function template output. Keys will be added to this dictonary throughout the workflow, and it is returned at the end of the program." + "First, prepare a dictionary to hold all of the function template output. Keys will be added to this dictionary throughout the workflow, and it is returned at the end of the program." ] }, { From d70feb630610753ae0ac1d6f2ed9d44cea9305f9 Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 16:19:04 -0600 Subject: [PATCH 13/14] add writefile --- docs/guides/serverless-hamsim-template.ipynb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb index 13e1fc72b97..525a1b8ca52 100644 --- a/docs/guides/serverless-hamsim-template.ipynb +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -245,6 +245,8 @@ "metadata": {}, "outputs": [], "source": [ + "%%writefile --append ./source_files/function_template_hamsim.py\n", + "\n", "print(\"estimator_options =\", json.dumps(estimator_options, indent=4))" ] }, From a260ea232bb244e40966dd6b79ed1805e11a8d56 Mon Sep 17 00:00:00 2001 From: Rebecca Dimock Date: Tue, 12 Nov 2024 16:36:30 -0600 Subject: [PATCH 14/14] Add link to new tutorial --- docs/guides/serverless-hamsim-template.ipynb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/guides/serverless-hamsim-template.ipynb b/docs/guides/serverless-hamsim-template.ipynb index 525a1b8ca52..210c80cd37a 100644 --- a/docs/guides/serverless-hamsim-template.ipynb +++ b/docs/guides/serverless-hamsim-template.ipynb @@ -1032,8 +1032,7 @@ "\n", "\n", "\n", - "See an [example of this function template](https://qiskit.github.io/qiskit-addon-aqc-tensor/) in action on a large-scale Hamiltonian simulation problem.\n", - "{/* - For a deeper dive into the AQC-Tensor Qiskit addon, check out the tutorial on the Learning Platform (add-link-when-live). */}\n", + "For a deeper dive into the AQC-Tensor Qiskit addon, check out the [Improved Trotterized Time Evolution with Approximate Quantum Compilation](https://learning.quantum.ibm.com/tutorial/improved-trotterized-time-evolution-with-approximate-quantum-compilation) tutorial.\n", "\n", "" ]