{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# How to create dephasing and amplitude robust single-qubit gates\n",
"\n",
"**Incorporate robustness into the design of optimal pulses**\n",
"\n",
"Boulder Opal exposes a highly-flexible optimization engine for general-purpose gradient-based optimization. It can be directly applied to model-based control optimization for arbitrary-dimensional quantum systems. Boulder Opal's optimization engine also allows the user to design pulses that are robust against certain types of noise. In this notebook, we demonstrate how to produce single qubit gates that are simultaneously robust to dephasing and amplitude noises.\n",
"\n",
"\n",
"## Summary workflow\n",
"### 1. Define robustness condition in computational graph\n",
"The flexible Boulder Opal optimization engine expresses all optimization problems as [data flow graphs](https://docs.q-ctrl.com/boulder-opal/user-guides/how-to-represent-quantum-systems-using-graphs), which describe how optimization variables (variables that can be tuned by the optimizer) are transformed into the cost function (the objective that the optimizer attempts to minimize). \n",
"\n",
"For an optimal control problem, the cost is typically given by the gate infidelity using, for example, the `graph.infidelity_pwc` graph operation. To enforce robustness, we use the same function and just add a list with noise operators to the parameter `noise_operators`: \n",
"```python\n",
"cost = graph.infidelity_pwc(\n",
" hamiltonian=hamiltonian,\n",
" target=target_operator,\n",
" noise_operators=noise_list,\n",
" name=\"robust_cost\"\n",
")\n",
"```\n",
"\n",
"You would typically choose this list to be made of the operators characterizing the dominant noise in your system dynamics, such as the dephasing and control noise operators demonstrated in this guide. The addition of this parameter in `graph.infidelity_pwc` ensures that the optimization cost will take into account both the infidelity with respect to the defined `target` operation and the robustness term.\n",
"\n",
"### 2. Execute graph-based optimization\n",
"\n",
"With the graph object created, an optimization can be run using the `qctrl.functions.calculate_optimization` function. The function returns the results of the optimization. Note that this example code block uses naming that should be replaced with the naming used in your graph.\n",
"```python\n",
"optimization_result = qctrl.functions.calculate_optimization(\n",
" graph=graph, cost_node_name=\"robust_cost\", output_node_names=[\"alpha\", \"gamma\"]\n",
")\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example: Single qubit gate robust to amplitude and dephasing noises\n",
"\n",
"We present a detailed example of robust optimization in a single-qubit system. Specifically, we consider a single-qubit system represented by the following Hamiltonian:\n",
"$$\n",
"H(t) = \\frac{(1+\\beta_{\\gamma}(t))}{2}\\left(\\gamma(t)\\sigma_{-} + \\gamma^*(t)\\sigma_{+}\\right) + \\frac{\\alpha(t)}{2} \\sigma_{z} + \\eta(t) \\sigma_{z} , \n",
"$$\n",
"where $\\gamma(t)$ and $\\alpha(t)$ are, respectively, complex and real time-dependent pulses, $\\sigma_{\\pm}$ are the qubit ladder operators and $\\sigma_{z}$ is the Pauli-Z operator. $\\eta(t)$ and $\\beta_{\\gamma}(t)$ are small, slowly-varying stochastic processes corresponding to dephasing and amplitude noise, respectively.\n",
"\n",
"The functions of time $\\gamma(t)$ and $\\alpha(t)$ are not predetermined, and instead are optimized by the Boulder Opal optimization engine in order to achieve some target operation."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"pycharm": {
"is_executing": true,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"from qctrlvisualizer import plot_controls\n",
"\n",
"from qctrl import Qctrl\n",
"\n",
"# Start a Boulder Opal session\n",
"qctrl = Qctrl()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We start by defining operators and parameters:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"pycharm": {
"is_executing": true,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"# Define physical constants\n",
"gamma_max = 2 * np.pi * 0.5e6 # Hz\n",
"alpha_max = 2 * np.pi * 0.5e6 # Hz\n",
"segment_count = 50\n",
"duration = 10e-6 # s\n",
"sinc_cutoff_frequency = 5e6"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Below we show how to create a data flow graph for optimizing the single-qubit system described above. Comments in the code explain the details of each step. Note that we are using a filter to produce smooth pulses as explained in our [How to add smoothing and band-limits to optimized controls](https://docs.q-ctrl.com/boulder-opal/user-guides/how-to-add-smoothing-and-band-limits-to-optimized-controls) user guide. "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"pycharm": {
"is_executing": true,
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"# Define the data flow graph describing the system\n",
"graph = qctrl.create_graph()\n",
"\n",
"# Create a complex piecewise-constant (PWC) signal, with optimizable modulus\n",
"# and phase, representing gamma(t)\n",
"gamma = graph.utils.complex_optimizable_pwc_signal(\n",
" segment_count=segment_count, duration=duration, maximum=gamma_max\n",
")\n",
"# Create a real PWC signal, with optimizable amplitude, representing\n",
"# alpha(t)\n",
"alpha = graph.utils.real_optimizable_pwc_signal(\n",
" segment_count=segment_count,\n",
" minimum=-alpha_max,\n",
" maximum=alpha_max,\n",
" duration=duration,\n",
")\n",
"\n",
"# Create filtered signals\n",
"rediscretized_gamma = graph.utils.filter_and_resample_pwc(\n",
" pwc=gamma, cutoff_frequency=sinc_cutoff_frequency, segment_count=256, name=\"gamma\"\n",
")\n",
"rediscretized_alpha = graph.utils.filter_and_resample_pwc(\n",
" pwc=alpha, cutoff_frequency=sinc_cutoff_frequency, segment_count=256, name=\"alpha\"\n",
")\n",
"\n",
"# Create PWC operators representing the Hamiltonian terms\n",
"drive = graph.hermitian_part(rediscretized_gamma * graph.pauli_matrix(\"M\"))\n",
"shift = rediscretized_alpha * graph.pauli_matrix(\"Z\") / 2\n",
"\n",
"# Create a constant PWC operator representing the dephasing noise\n",
"# (note that we scale by 1/duration to ensure consistent units between\n",
"# the noise Hamiltonian and the control Hamiltonian)\n",
"dephasing = graph.pauli_matrix(\"Z\") / duration\n",
"\n",
"# Create the noise list with the dephasing and drive operators\n",
"noise_list = [dephasing, drive]\n",
"\n",
"# Create the target operator\n",
"target_operator = graph.target(operator=graph.pauli_matrix(\"Y\"))\n",
"\n",
"# Create infidelity\n",
"cost = graph.infidelity_pwc(\n",
" hamiltonian=drive + shift,\n",
" noise_operators=noise_list,\n",
" target=target_operator,\n",
" name=\"robust_cost\",\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Execute graph-based optimization"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/100 [00:00"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plot_controls(\n",
" {\n",
" \"$\\\\alpha$\": optimization_result.output[\"alpha\"],\n",
" \"$\\\\gamma$\": optimization_result.output[\"gamma\"],\n",
" },\n",
" polar=False,\n",
")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"| Package | Version |\n",
"| --------------------- | ------------ |\n",
"| Python | 3.10.8 |\n",
"| matplotlib | 3.6.3 |\n",
"| numpy | 1.24.1 |\n",
"| scipy | 1.10.0 |\n",
"| qctrl | 20.1.1 |\n",
"| qctrl-commons | 17.7.0 |\n",
"| boulder-opal-toolkits | 2.0.0-beta.3 |\n",
"| qctrl-visualizer | 4.4.0 |\n"
]
}
],
"source": [
"from qctrl.utils import print_environment_related_packages\n",
"\n",
"print_environment_related_packages()"
]
}
],
"metadata": {
"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.10.8"
}
},
"nbformat": 4,
"nbformat_minor": 4
}