{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Placing bounds on model parameters\n", "This tutorial shows how to place simple bounds on the values of a model's parameters. This can be especially useful when building your own objects (see the [custom operator tutorial](CustomOperator.ipynb)) that might have restrictions on their allowed parameters.\n", "\n", "First, we construct a model. It doesn't really matter what type of model this is, as the procedure we outline below is the same regardless of the model type. We choose to create a simple 1-qubit model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pygsti\n", "from pygsti.modelpacks import smq1Q_XYI\n", "\n", "mdl = smq1Q_XYI.target_model(\"H+S\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we choose which parameter(s) to add bounds for. Let's suppose that we want to restrict the Hamiltonian (coherent) Z error rate on the $X(\\pi/2)$ gate to be between 0 and 0.2, restricting the gate error to being *over*-rotation of magnitude at most 0.2 radians. First, let's find the modelmember and parameter value we want to bound." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Here's the X(pi/2) gate:\n", "print(mdl.operations[('Gxpi2', 0)])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# this is the error generator whose parameters we want to bound\n", "eg = mdl.operations[('Gxpi2', 0)].factorops[1].errorgen\n", "for i, lbl in enumerate(eg.parameter_labels):\n", " print(i, lbl)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This shows us that we want to set bounds for the parameter with index 2. Currently the bounds are set to `None`, which means there aren't any:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(eg.parameter_bounds)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can set the `parameter_bounds` attribute of a model member to be a 2D NumPy array of shape (num_params, 2), that has rows equal to (min, max) values for each parameter. We can use `numpy.inf` and `-numpy.inf` for parameters where we don't want one or both bounds. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "bounds = np.empty((eg.num_params, 2), 'd')\n", "bounds[:, 0] = -np.inf # initial lower bounds\n", "bounds[:, 1] = np.inf # initial upper bounds\n", "bounds[2, :] = (0, 0.2) # bounds for \"Z Hamiltonian error coefficient\" parameter\n", "eg.parameter_bounds = bounds" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After we've set the bounds on constituent members, we should retrieve the model's number of parameters (`.num_params`) to ensure that the bounds get propagated throughout the model:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Model bounds before getting the number of parameters:\\n\",mdl.parameter_bounds)\n", "mdl.num_params # triggers re-building of model's parameters and parameter bounds based on its members.\n", "print(\"\\nModel bounds after getting the number of parameters:\\n\",mdl.parameter_bounds)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, when model `mdl` is optimized, the optimizer will limit range of this parameter as desired." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }