{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Getting up and running with Quil-T\n", "\n", "## Language Documentation\n", "\n", "See the [Quil specification](https://quil-lang.github.io/#12Annex-T--Pulse-Level-Control) for documentation on the Quil-T language" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Construct a `QuantumComputer` object linked to the Quil-T compiler" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pyquil import Program, get_qc\n", "qc = get_qc(\"Aspen-M-3\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a sanity check, the following call should work." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'quilc': '1.26.0'}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qc.compiler.get_version_info()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Get Quil-T Calibrations\n", "\n", "A production QPU has a set of calibrations associated with it. These include frame definitions, gate and measurement calibrations, and custom waveforms. Below we show how to get the default calibrations." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "cals = qc.compiler.get_calibration_program()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `calibration_program` property of `QPUCompiler` provides *cached* access to the QPU calibration information. Upon first using this property a request will be made for the calibration information and may take some time to complete. Subsequent usage of this property will use the cached calibrations and thus will be instantaneous. It should be noted therefore that calibrations **will vary with time** and should be **regularly refreshed** though the specifics of when to refresh the calibrations is left as an exercise for the user. See `QPUCompiler#refresh_calibration_program`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Frame Definitions\n", "\n", "Frame definitions correspond to specific hardware channels. These have a name (e.g. `0 \"ro_rx\"` for the hardware readout receive channel on Qubit 0), and some metadata (DAC sample rate, initial frame frequency, and a direction).\n", "\n", "**Note**: These are fixed and should not be edited. If you wish to set a frame's frequency to one different from its initial frequency, your Quil-T program should use `SET-FREQUENCY` (for an absolute value) or `SHIFT-FREQUENCY` (for a relative shift)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEFFRAME 111 112 \"cz\":\n", "\tDIRECTION: \"tx\"\n", "\tINITIAL-FREQUENCY: 335285390.8518622\n", "\tCENTER-FREQUENCY: 375000000\n", "\tSAMPLE-RATE: 1000000000\n", "\tHARDWARE-OBJECT: \"q112_ff\"\n" ] } ], "source": [ "from pyquil.quilatom import Frame\n", "\n", "# Look for CZ frames.\n", "cz_frames = filter(lambda f: f[0].name == \"cz\", cals.frames.items())\n", "# The first elt is the frame (of type Frame) and the second elt is\n", "# the frame definition (of type DefFrame).\n", "print(next(cz_frames)[1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Gate Calibrations\n", "\n", "Gate and Measurement calibrations present the current Quil-T specification of Rigetti's native gates. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1230 total calibrations, peeking at first two:\n", "\n", "DEFCAL I %q:\n", "\tDELAY q 4e-8\n", "DEFCAL RX(pi/2) 0:\n", "\tFENCE 0\n", "\tNONBLOCKING PULSE 0 \"rf\" drag_gaussian(alpha: 0.3183552471062913, anh: -220655329.522463, detuning: -321047.14178613486, duration: 2.4000000000000003e-8, fwhm: 6.000000000000001e-9, phase: 0, scale: 0.293772761206776, t0: 1.2000000000000002e-8)\n", "\tFENCE 0\n" ] } ], "source": [ "print(len(cals.calibrations), \"total calibrations, peeking at first two:\\n\")\n", "for defn in cals.calibrations[:2]:\n", " print(defn)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Waveform Definitions\n", "\n", "Certain gates (e.g. `RX` gates above) use template waveforms. Others, notably `CZ` gates, use custom waveforms. The `waveforms` member maps waveform names to their definitions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is what one of these definitions looks like." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEFWAVEFORM q0_q103_cphase/sqrtCPHASE:\n", "\t0, 0, 0, 0, 0, 0, 0, 0, 0.00016140365893729274, 0.0006638156567620885, 0.0023252271377397662, 0.006955991101434095, 0.01783536736835849, 0.03938036134796462, 0.07534636051838922, 0.12595803048478235, 0.1859963237398621, 0.2460346169949419, 0.296646286961335, 0.3326122861317597, 0.35415728011136577, 0.36503665637829014, 0.36966742034198447, 0.37132883182296217, 0.371831243820787, 0.37195929423950663, 0.37198679964711867, 0.3719917787062675, 0.3719925382330088, 0.37199263586195475, 0.371992646435631, 0.371992647400474, 0.3719926474746463, 0.3719926474794497, 0.3719926474797117, 0.37199264747972377, 0.3719926474797242, 0.3719926474797242, 0.3719926474797242, 0.3719926474797242, 0.3719926474797242, 0.3719926474797242, 0.3719926474797242, 0.3719926474797242, 0.37199264747972377, 0.3719926474797117, 0.3719926474794497, 0.3719926474746463, 0.371992647400474, 0.371992646435631, 0.37199263586195475, 0.3719925382330088, 0.3719917787062675, 0.37198679964711867, 0.37195929423950663, 0.371831243820787, 0.37132883182296217, 0.3696674203419845, 0.36503665637829014, 0.3541572801113659, 0.33261228613175986, 0.29664628696133527, 0.24603461699494242, 0.18599632373986255, 0.1259580304847826, 0.0753463605183896, 0.03938036134796485, 0.017835367368358553, 0.006955991101434095, 0.0023252271377397662, 0.0006638156567621092, 0, 0, 0, 0, 0, 0, 0, 0, 0\n" ] } ], "source": [ "print(next(iter(cals.waveforms.values()), None))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Compiling and running a Quil-T Program\n", "\n", "\n", "There are three ways to access the compiler from pyQuil:\n", "\n", "* `qc.compile` is the usual pipeline, and **only works for Quil code**\n", "* `qc.compiler.quil_to_native_quil` is the entry point for compiling Quil to native Quil\n", "* `qc.compiler.native_quil_to_executable` is the entry point for compiling **Quil-T** programs\n", "\n", "In particular, the usual workflow of just delegating to `qc.compile` does not currently work with Quil-T. If you wish to use Quil-T right now, your workflow should involve\n", "1. calling `qc.compiler.quil_to_native_quil` on code blocks which do not involve Quil-T or Quil-T calibrations\n", "2. subsequently calling `qc.compiler.native_quil_to_executable` on blocks involving Quil-T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Compiling Quil Programs\n", "\n", "`qc.compiler.native_quil_to_executable` requires native Quil + Quil-T operations. In particular, it is assumed that the only gates used are those Rigetti native gates, or ones for which you have provided explicit calibrations. For example, the program below expresses\n", "\n", "```\n", "DECLARE ro BIT\n", "H 0\n", "CNOT 0 1\n", "MEASURE 0 ro\n", "```\n", "\n", "using Rigetti native gates by first using `qc.compiler.quil_to_native_quil`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": true }, "outputs": [], "source": [ "prog = Program(\n", " 'DECLARE ro BIT',\n", " 'H 0',\n", " 'CNOT 0 1',\n", " 'MEASURE 0 ro'\n", ")\n", "compiled = qc.compiler.quil_to_native_quil(prog)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "exe = qc.compiler.native_quil_to_executable(compiled)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: The above compilation may be done even at any time, however, the QPU settings used for compilation may go stale. Therefore, we suggest that although you may rely on `qc.compiler.native_quil_to_executable` for development purposes (for example, to verify correct Quil-T syntax), when executing on a QPU all Quil-T programs should be compiled afresh.\n", "\n", "Running the executable proceeds as before:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ro': array([[1]])}" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result = qc.run(exe)\n", "result.get_register_map()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Another example: a simple T1 experiment\n", "\n", "As an example of mixing Quil with the new Quil-T instructions, we consider a simple T1 experiment. In short, we\n", "\n", "1. excite the qubit state\n", "2. wait some amount of time\n", "3. measure out\n", "\n", "In this example, we do not do any further data analysis. The purpose here is simply to demonstrate how to compile and run a Quil-T program." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def t1_program(time, qubit, num_shots=1000):\n", " prog = Program( \"DECLARE ro BIT\\n\"\n", " f\"RX(pi) {qubit}\\n\"\n", " f\"FENCE 0\\n\"\n", " f\"DELAY {qubit} {time}\\n\"\n", " f\"MEASURE {qubit} ro\")\n", " prog.wrap_in_numshots_loop(num_shots)\n", " return prog" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "time: 2.00e-08 \tprob: 0.92\n", "time: 3.88e-08 \tprob: 0.92\n", "time: 7.54e-08 \tprob: 0.91\n", "time: 1.47e-07 \tprob: 0.9\n", "time: 2.85e-07 \tprob: 0.85\n", "time: 5.53e-07 \tprob: 0.81\n", "time: 1.07e-06 \tprob: 0.68\n", "time: 2.08e-06 \tprob: 0.66\n", "time: 4.05e-06 \tprob: 0.48\n", "time: 7.86e-06 \tprob: 0.38\n", "time: 1.53e-05 \tprob: 0.23\n", "time: 2.96e-05 \tprob: 0.11\n", "time: 5.76e-05 \tprob: 0.084\n", "time: 1.12e-04 \tprob: 0.074\n", "time: 2.17e-04 \tprob: 0.068\n", "time: 4.22e-04 \tprob: 0.068\n", "time: 8.19e-04 \tprob: 0.079\n", "time: 1.59e-03 \tprob: 0.08\n", "time: 3.09e-03 \tprob: 0.094\n", "time: 6.00e-03 \tprob: 0.079\n" ] } ], "source": [ "import numpy as np\n", "\n", "probs = []\n", "\n", "times = np.geomspace(20e-9, 60e-4, 20)\n", "for time in times:\n", " prog = t1_program(time, 0)\n", " exe = qc.compiler.native_quil_to_executable(prog)\n", " results = qc.run(exe).get_register_map().get(\"ro\")\n", " prob = np.sum(results) / results.size\n", " probs.append(prob)\n", " print(f\"time: {time:.2e} \\tprob: {prob:.2}\")" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkMAAAG1CAYAAAD6GvACAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA780lEQVR4nO3deXxU9aH+8Wdmksk+Q0I2AoGwhUU2TQBRELFRtBWtW7lARbnV3vqztJXSW7kqVNtCr7Vea0WtVK3tVUG97lCsIqgoCoSC7HtIWJIQskwWss3M748ko5GwJTNzZvm8X695xZyck3nmmDBPvud7zjG53W63AAAAwpTZ6AAAAABGogwBAICwRhkCAABhjTIEAADCGmUIAACENcoQAAAIa5QhAAAQ1ihDAAAgrEUYHcDfXC6Xjh49qoSEBJlMJqPjAACAc+B2u1VdXa2MjAyZzd4dywm7MnT06FFlZmYaHQMAAHRCUVGRevXq5dXvGXZlKCEhQVLLzrTZbAanAQAA58LhcCgzM9PzPu5NYVeG2g6N2Ww2yhAAAEHGF1NcmEANAADCGmUIAACENcoQAAAIa5QhAAAQ1ihDAAAgrFGGAABAWKMMAQCAsEYZAgAAYY0yBAAAwhplCAAAhDXKEAAACGuUIQAAENbC7katvlJ4ok5zX9ui5HirkuKsSoqLUve4lv/uHmdV9/goJcVZlRgbqQgLHRQAgEBBGfKSYke91h8sP6d1u8VGekpSUmtRavvvluUtxSk53qrEOKsiKU8AAPgMZchL+qXE6U/TLlR5baNO1DaqvLZBJ2ra/rvlUVHXKLdbqqxrUmVdkw4crz2n722LjvAUpr7JcRqYFq+BaQkamBqvDHuMzGaTj18dAAChy+R2u91Gh/Anh8Mhu92uqqoq2Ww2vz630+VWRV1LMTpR01aSGlRW81VhOlHb4Pl6RV2jXGf5vxNrtWhgarwGpCZoYFq8stPiNTA1QT27UZIAAKHDl+/fjAz5kcVsUnJ8lJLjo6S0s6/vdLlVdbLJM8pUWt2g/cdrtLe0RntLqnWwrFZ1jU5tOVylLYer2m0bE2nRgNT4lqKUFq/s1rLUKzFWFkoSAAAelKEAZjGbPPOIBqSe+vUmp0uHTtRpb0l1S0FqLUkHjtfqZJNTW49UaeuR9iUpOtKs/iktJantUNvAtAT1TqIkAQDCE4fJQlCz06XC8jrtKanRvtKWorSnpEb7j9eosdnV4TbWCLMGpsbrot6Jys1KVG5Wknp2i/FzcgAAOubL92/KUBhxutwqKq9rLUfV2ldao72lLR/rm04tST3s0crpk6jRWUnK6ZOoIT1sjB4BAAxBGfKicC5Dp+N0uXWk4qS2Ha3SxoIK5R8q1/ajDjV/Y/Z2nNWii/okKqdPonL7JOnC3t0UF8WRVgCA71GGvIgydG7qGpu1uahS+QUV2nioQpsOVai6obndOmaTNDTDptw+LSNHuVmJ6mHn0BoAwPsoQ15EGeocp8utPSXV2nioQvkF5dpQUKEjlSdPWa9nt5iWOUd9WuYdZaclcGgNANBllCEvogx5T3FVvTYeKtfGggptPFSuHUcdp1wXKSEqQhf2aSlHeUPSNDSDfQ4AOH+UIS+iDPlObUPLobUNBeXKbz20Vtvo9HzdbJJ+MXmwfjSxn0wmRosAAOeOMuRFlCH/aXa6tKu4WvmHKrRmd6lW7z4uSbpqaJoe+d5I2aIjDU4IAAgWlCEvogwZw+126+X1RfrV29vV6HQpq3usnr41R4PT+X8AADg7X75/czt0+IXJZNL0sb316o/GqWe3GBWcqNN3F3+qN/91xOhoAIAwRxmCX43M7KZ3Zo/XhIHJqm9y6WfLNmv+W9tOe2VsAAB8jTIEv0uKs+qvs8boJ1cMkCT9bd0hTX1mnY5VnXqqPgAAvkYZgiEsZpPmXDVIz92eK1t0hP5VWKlrH1+rz/aVGR0NABBmKEMw1BWD0/Tu7Aka2sOmE7WN+v6zX+jJNfsUZvP6AQAGogzBcL27x+r1/3eJbsnpJZdbenjlbv3w7/ly1DcZHQ0AEAYoQwgI0ZEWPXzzCC26cbisFrPe31Gi6/60VjuPOYyOBgAIcZQhBAyTyaRpY3rrtbu+Ov3+hic/1Rv/Omx0NABACKMMIeCM6NVN784er8uyU1Tf5NI9y7bogTc5/R4A4BuUIQSkxDirnr99tH7yrYGSpL9/fkjf+/M6Ha3k9HsAgHdRhhCwLGaT5lyZredvHy1bdIQ2F1Xq2j+t1aecfg8A8CLKEALepMGpWv6TCbogw6by2kbd+uwXWrx6n1wuTr8HAHQdZQhBITMpVv931yX6Xm7L6fe/f6/l9Puqk5x+DwDoGsoQgkbL6fcj9bsbh8saYdYHO0t0/ROcfg8A6BrKEILOv43prdd+1P70+9c3cfo9AKBzKEMISm2n309sPf1+zitb9PNXtqispsHoaACAIEMZQtBKjLPqudtH66ffGiiTSfq/TYd1xSNr9MJnBWp2ck0iAMC5oQwhqFnMJt1zZbZe+9E4XZBhk6O+WQve3q4pT3yqDQXlRscDAAQBkzvMbg/ucDhkt9tVVVUlm81mdBx4kdPl1svrC/X793Z7zjK74cKemnfNYKXaog1OBwDoCl++fzMyhJBhMZv0/Yv7aPXcyzVtTKZMJumNfx3RFX/4SH/55ICaOHQGAOgAI0MIWVuKKjX/7e3aUlQpSRqYGq8Hr79Al/RPNjYYAOC8+fL9mzKEkOZyufVqfpH+e+Vuldc2SpK+M6KH7v/OEPWwxxicDgBwrjhMBnSS2WzS1NG99eHPJ2rmuD4ym6TlXx7TFY98pCfX7FNDs9PoiAAAgzEyhLCy/WiVFry1XRsPVUiS+iXHacF1F2hidorByQAAZ8JhMi+iDMHtduuNfx3RwhW7PBdpvGpomh64dqgyk2INTgcA6AiHyQAvMplMuvGiXvpw7kT9YHxfWcwm/XNHifIe/Uh//GCv6ps4dAYA4YSRIYS9PSXVmv/WNn1+oOUijb2TYjX/2qHKG5pmcDIAQBsOk3kRZQgdcbvdevfLY/rt8p0qdtRLkq4YnKr51w5VVnKcwekAAJQhL6IM4UxqG5r1pw/36dm1B9TkdMtqMeuHl/XT3ZMGKMZqMToeAIQt5gwBfhIXFaF7rxmslT+7TBMGJqvR6dITq/cp79GPtKvYYXQ8AIAPUIaADvRPidff/n2Mnv5+jnp2i9GRypP6zbs7jY4FAPABw8vQ4sWLlZWVpejoaI0dO1br168/4/qPPfaYBg0apJiYGGVmZuqee+5RfX29n9IinJhMJl09LF1Lf3ixLGaT1u4r07YjVUbHAgB4maFlaNmyZZozZ44WLFigTZs2aeTIkZo8ebJKS0s7XP+ll17SvffeqwULFmjnzp169tlntWzZMv3Xf/2Xn5MjnGQmxeraET0kSX/++IDBaQAA3mZoGXr00Ud15513atasWRo6dKiefvppxcbG6rnnnutw/c8++0yXXnqppk+frqysLF111VWaNm3aWUeTgK764WX9JEnLvzyqovI6g9MAALzJsDLU2Nio/Px85eXlfRXGbFZeXp7WrVvX4TaXXHKJ8vPzPeXnwIEDWrFihb797W+f9nkaGhrkcDjaPYDzdUGGXRMGJsvllv7yCaNDABBKDCtDZWVlcjqdSktrf2G7tLQ0FRcXd7jN9OnT9dBDD2n8+PGKjIxU//79dfnll5/xMNmiRYtkt9s9j8zMTK++DoSPH03sL0latrFI5bWNBqcBAHiL4ROoz8eaNWu0cOFCPfnkk9q0aZNef/11LV++XL/+9a9Pu828efNUVVXleRQVFfkxMULJJf27a1hPm+qbXHrhswKj4wAAvMSwMpScnCyLxaKSkpJ2y0tKSpSent7hNg888IBuvfVW3XHHHRo+fLhuuOEGLVy4UIsWLZLL5epwm6ioKNlstnYPoDNMJpNndOhv6wpU19hscCIAgDcYVoasVqtycnK0atUqzzKXy6VVq1Zp3LhxHW5TV1cns7l9ZIul5arAYXYhbRjk6gvS1TspVhV1TXp142Gj4wAAvMDQw2Rz5szRkiVL9MILL2jnzp266667VFtbq1mzZkmSZs6cqXnz5nnWnzJlip566iktXbpUBw8e1Pvvv68HHnhAU6ZM8ZQiwJciLGbdOaGvJGnJJwfU7Ox4RBIAEDwijHzyqVOn6vjx45o/f76Ki4s1atQorVy50jOpurCwsN1I0P333y+TyaT7779fR44cUUpKiqZMmaLf/va3Rr0EhKGbczL1Px/s1eGKk1qxrVjXjcwwOhIAoAu4USvQCX/8YK/+54M9uiDDpndnj5fJZDI6EgCENG7UCgSYmeP6KCbSou1HHVq7r8zoOACALqAMAZ2QGGfV1NEt16z680dchBEAghllCOikH4zvyw1cASAEUIaATuIGrgAQGihDQBdwA1cACH6UIaALuIErAAQ/yhDQRdzAFQCCG2UI6KJL+nfX8J52buAKAEGKMgR0kclk0n9MbJk7xA1cASD4UIYAL+AGrgAQvChDgBdwA1cACF6UIcBLbs7JVFKc1XMDVwBAcKAMAV4SY7XotnFZkqQ/f7RfYXYPZAAIWpQhwIu4gSsABB/KEOBF3MAVAIIPZQjwMm7gCgDBhTIEeBk3cAWA4EIZAnyAG7gCQPCgDAE+wA1cASB4UIYAH+EGrgAQHChDgI9wA1cACA6UIcBHuIErAAQHyhDgQ9zAFQACH2UI8CFu4AoAgY8yBPgYN3AFgMBGGQJ8jBu4AkBgowwBfsANXAEgcFGGAD/gBq4AELgoQ4CfcANXAAhMlCHAT7iBKwAEJsoQ4EfcwBUAAg9lCPAjbuAKAIGHMgT42V3cwBUAAgplCPCzcdzAFQACCmUI8DNu4AoAgYUyBBiAG7gCQOCgDAEG4AauABA4KEOAQbiBKwAEBsoQYJAYq0W3X5IlSXp6zX5GhwDAIJQhwEC3XtxyA9cdxxy69L8/1B/+uZuLMQKAn1GGAAMlxlm16MbhSoqzqsTRoD99uE+X/X61Zj63Xiu3HVMTo0UA4HMmt9vtNjqEPzkcDtntdlVVVclmsxkdB5AkNTa79P6OEr28vlBr95V5lifHR+mW3F76t9GZ6tM9zsCEAGAsX75/U4aAAHPoRK2WbSjSKxsPq6ymwbP80gHdNW1Mb101NF3WCAZ1AYQXypAXUYYQLJqcLq3aWaqX1xfq473H1fab2j3OqptyWkaL+qXEGxsSAPyEMuRFlCEEo6LyOr26sUjLNhapxPHVaNHYvkmaPra3Jl+QruhIi4EJAcC3KENeRBlCMGt2urR693EtXV+o1btL5Wr97e0WG6kbL+ylaWMyNTAtwdiQAOADlCEvogwhVBytPKlXNhbplQ1FOlpV71me2ydR08b01ndG9GC0CEDIoAx5EWUIocbpcuvjPcf10vpCfbirVM7W4SJbdIRuuLCnpo3trcHp/KwDCG6UIS+iDCGUlTjq9erGIi3dUKTDFSc9y2+8qKf+cMtImUwmA9MBQOdRhryIMoRw4HK5tXZfmV5eX6j3thfL5Zb+8dMJGtKDn3kAwcmX799crAQIQWazSZdlp+ip7+foyqFpkqS3Nh81OBUABCbKEBDirh/VU5L0zpajCrOBYAA4J5QhIMRdMThV8VEROlJ5UpsKK4yOAwABhzIEhLjoSIuuuoBDZQBwOpQhIAxcNzJDkrT8y2NqdroMTgMAgYUyBISBSwckq3ucVSdqG/Xp/hNGxwGAgEIZAsJApMWsbw/vIUl6m0NlANAOZQgIE9ePajlU9t72YtU3OQ1OAwCBgzIEhImLeieqZ7cY1TQ0a/WuUqPjAEDAoAwBYcJsNunakS2HyjirDAC+QhkCwsj1I1suwPjh7lI56psMTgMAgYEyBISRIT0SNCA1Xo3NLr23rdjoOAAQEChDQBgxmUy6vvWaQ29v4VAZAEiUISDsTGktQ5/uK9Px6gaD0wCA8ShDQJjJSo7TyMxucrmlFVuPGR0HAAxHGQLCUNvtOd7afMTgJABgPMoQEIamjOghk0naVFipovI6o+MAgKEML0OLFy9WVlaWoqOjNXbsWK1fv/6M61dWVuruu+9Wjx49FBUVpezsbK1YscJPaYHQkGqL1rh+3SVJ73zJRGoA4c3QMrRs2TLNmTNHCxYs0KZNmzRy5EhNnjxZpaUdXx23sbFRV155pQoKCvTaa69p9+7dWrJkiXr27Onn5EDwa7s9B/cqAxDuTG63223Uk48dO1ajR4/WE088IUlyuVzKzMzU7Nmzde+9956y/tNPP63f//732rVrlyIjIzv1nA6HQ3a7XVVVVbLZbF3KDwSzqrom5f72fTU53XrvZ5dpUHqC0ZEA4LR8+f5t2MhQY2Oj8vPzlZeX91UYs1l5eXlat25dh9u8/fbbGjdunO6++26lpaVp2LBhWrhwoZzO0990sqGhQQ6Ho90DgGSPjdTlg1IlSW9vYSI1gPBlWBkqKyuT0+lUWlpau+VpaWkqLu74yrgHDhzQa6+9JqfTqRUrVuiBBx7QH/7wB/3mN7857fMsWrRIdrvd88jMzPTq6wCC2XVfuwCjgYPEAGAowydQnw+Xy6XU1FQ988wzysnJ0dSpU3Xffffp6aefPu028+bNU1VVledRVFTkx8RAYMsbkqZYq0VF5Sf1r6JKo+MAgCEMK0PJycmyWCwqKSlpt7ykpETp6ekdbtOjRw9lZ2fLYrF4lg0ZMkTFxcVqbGzscJuoqCjZbLZ2DwAtYqwWXTW0ZXSWidQAwpVhZchqtSonJ0erVq3yLHO5XFq1apXGjRvX4TaXXnqp9u3bJ5fL5Vm2Z88e9ejRQ1ar1eeZgVB0XetZZe9+eUzNTtdZ1gaA0GPoYbI5c+ZoyZIleuGFF7Rz507dddddqq2t1axZsyRJM2fO1Lx58zzr33XXXSovL9dPf/pT7dmzR8uXL9fChQt19913G/USgKA3YWCKEmMjVVbToM8PlBsdBwD8LsLIJ586daqOHz+u+fPnq7i4WKNGjdLKlSs9k6oLCwtlNn/V1zIzM/Xee+/pnnvu0YgRI9SzZ0/99Kc/1S9/+UujXgIQ9CItZl0zvIde+qJQb20+ovEDk42OBAB+Zeh1hozAdYaAU31x4ISmPvO5EqIjtOG+PEVHWs6+EQD4UUheZwhA4BidlaQe9mhV1zdrze7jRscBAL+iDAGQ2WzSlNZrDr2zhbPKAIQXyhAASV9dgPGDnSWqrm8yOA0A+A9lCIAk6YIMm/qlxKmh2aX3d5ScfQMACBGUIQCSJJPJ1O72HAAQLihDADzaytAne8t0oqbB4DQA4B+UIQAe/VLiNbynXU6XWyu2dXzDZAAINZQhAO1c33p7jrc3HzE4CQD4B2UIQDvXjsiQySRtKKjQkcqTRscBAJ+jDAFoJ90erTFZSZK45hCA8EAZAnCK60f1lCS9vZkyBCD0UYYAnOKaYemKMJu045hD+0qrjY4DAD5FGQJwisQ4qyZmp0hidAhA6KMMAejQda1nlb215ajcbrfBaQDAdyhDADqUNyRNMZEWHTpRpy8PVxkdBwB8hjIEoENxURHKG5omSXqLQ2UAQhhlCMBpXd96e453vzwqp4tDZQBCE2UIwGldlp0ie0ykSqsb9MWBE0bHAQCfoAwBOC1rhFnfHp4uiTvZAwhdlCEAZzSl9VDZiq3H1NDsNDgNAHgfZQjAGY3t211ptig56pv18Z4yo+MAgNdRhgCckcVs0rUjWu9kz6EyACGIMgTgrK5vvQDj+zuKVdvQbHAaAPAuyhCAsxre066s7rGqb3Lpg50lRscBAK+iDAE4K5PJpOtaJ1JzAUYAoYYyBOCctN2r7OM9x1VR22hwGgDwHsoQgHMyIDVBQ3vY1Oxya8W2Y0bHAQCvoQwBOGdtE6nf5lAZgBBCGQJwzq5tnTe0vqBcx6pOGpwGALyDMgTgnPXsFqMxWUlyu6V3t3CoDEBooAwBOC9TWg+VvbXliMFJAMA7KEMAzst3hvdQhNmkbUcc2n+8xug4ANBlXS5DbrdbbrfbG1kABIGkOKvGD0yWxERqAKGh02Xo2Wef1bBhwxQdHa3o6GgNGzZMf/nLX7yZDUCAajur7J0tR/ljCEDQi+jMRvPnz9ejjz6q2bNna9y4cZKkdevW6Z577lFhYaEeeughr4YEEFiuHJquqIitOlBWq21HHBrey250JADoNJO7E3/WpaSk6PHHH9e0adPaLX/55Zc1e/ZslZWVeS2gtzkcDtntdlVVVclmsxkdBwhad7+0Scu/PKY7J/TVfd8ZanQcACHOl+/fnTpM1tTUpNzc3FOW5+TkqLmZO1oD4aDtXmXvbDkml4tDZQCCV6fK0K233qqnnnrqlOXPPPOMZsyY0eVQAALf5YNSlBAdoWJHvdYXlBsdBwA6rVNzhqSWCdT//Oc/dfHFF0uSvvjiCxUWFmrmzJmaM2eOZ71HH3206ykBBJyoCIuuGZauVzYe1v/lH9bF/bobHQkAOqVTZWjbtm266KKLJEn79++XJCUnJys5OVnbtm3zrGcymbwQEUCg+l5upl7ZeFiv/+uI7pjQT4PSE4yOBADnrVNlaPXq1d7OASAI5WYl6eoL0rVye7EefGe7XrxjLH8EAQg6XIEaQJfc950hskaY9dn+E3pve4nRcQDgvFGGAHRJZlKsfjihnyTptyt2qL7JaXAiADg/lCEAXfb/JvVXui1aReUn9ZdPDhgdBwDOC2UIQJfFWiM079uDJUmLV+/XsaqTBicCgHNHGQLgFdeNzFBun0SdbHLqd//YZXQcADhnlCEAXmEymfSr6y6QySS9tfmoNnIhRgBBgjIEwGuG9bRram6mJOlX72znNh0AggJlCIBXzZ08SAlREdp2xKFX84uMjgMAZ0UZAuBVyfFR+mneQEnS79/bLUd9k8GJAODMKEMAvG7muCz1S4lTWU2jHv9gr9FxAOCMKEMAvM4aYdb8a4dKkv76WYH2ldYYnAgATo8yBMAnLh+Uqm8NTlWzy61fv7tDbjeTqQEEJsoQAJ+5/9qhirSY9NGe41q9u9ToOADQIcoQAJ/pmxynf7+0ryTp1+/uVGOzy+BEAHAqyhAAn/rxFQOUHB+lg2W1ev7Tg0bHAYBTUIYA+FRCdKR+efUgSdKfPtyn0up6gxMBQHuUIQA+d9NFvTQys5tqGpr18MrdRscBgHYoQwB8zmw26VdTWk61fy3/sDYXVRobCAC+hjIEwC8u7J2oGy/qKUn61dvctwxA4KAMAfCbX149WLFWizYXVerNzUeMjgMAkihDAPwozRatH18xQJL0u3/sUk1Ds8GJAIAyBMDPfjC+r/p0j1VpdYMWr95ndBwAoAwB8K+oCIvu/07LZOpnPzmogrJagxMBCHeUIQB+lzckVRMGJqvR6dJvV+w0Og6AMEcZAuB3JpNJC6YMlcVs0vs7SvTJ3uNGRwIQxihDAAwxIDVBM8f1kSQ9+M4ONTm5bxkAY1CGABjmZ3nZSoqzal9pjf6+7pDRcQCEqYAoQ4sXL1ZWVpaio6M1duxYrV+//py2W7p0qUwmk7773e/6NiAAn7DHRGruVS33LfufD/boRE2DwYkAhCPDy9CyZcs0Z84cLViwQJs2bdLIkSM1efJklZaWnnG7goICzZ07VxMmTPBTUgC+MHV0pi7IsKm6vlmP/HOP0XEAhCHDy9Cjjz6qO++8U7NmzdLQoUP19NNPKzY2Vs8999xpt3E6nZoxY4YefPBB9evXz49pAXibxWzSgikXSJKWbijU9qNVBicCEG4MLUONjY3Kz89XXl6eZ5nZbFZeXp7WrVt32u0eeughpaam6gc/+MFZn6OhoUEOh6PdA0BgGdM3SVNGZsjtlh58e4fcbu5bBsB/DC1DZWVlcjqdSktLa7c8LS1NxcXFHW6zdu1aPfvss1qyZMk5PceiRYtkt9s9j8zMzC7nBuB9864ZrOhIs9YXlOvdL48ZHQdAGDH8MNn5qK6u1q233qolS5YoOTn5nLaZN2+eqqqqPI+ioiIfpwTQGRndYnTXxJb7li1asVMnG50GJwIQLiKMfPLk5GRZLBaVlJS0W15SUqL09PRT1t+/f78KCgo0ZcoUzzKXq+XaJBEREdq9e7f69+/fbpuoqChFRUX5ID0Ab/uPif30ysYiHak8qac+2q85V2YbHQlAGDB0ZMhqtSonJ0erVq3yLHO5XFq1apXGjRt3yvqDBw/W1q1btXnzZs/juuuu06RJk7R582YOgQFBLjrSovu+M0SS9OeP9utwRZ3BiQCEA0NHhiRpzpw5uu2225Sbm6sxY8boscceU21trWbNmiVJmjlzpnr27KlFixYpOjpaw4YNa7d9t27dJOmU5QCC0zXD0nVxvyR9fqBci1bs0uIZFxkdCUCIM7wMTZ06VcePH9f8+fNVXFysUaNGaeXKlZ5J1YWFhTKbg2pqE4AuaLlv2QX6zuOfaPnWY/r+/hMa17+70bEAhDCTO8zOYXU4HLLb7aqqqpLNZjM6DoDTuP/Nrfrfzws1OD1B784erwgLfxQB4cyX79/86wIgIP38ykGyx0RqV3G1Xv/XEaPjAAhhlCEAASkxzqofTWw5O5SbuALwJcoQgID1vdxeslrM2nqkSlsPc5sOAL5BGQIQsLrHR+nqYS3XHHtpPaNDAHyDMgQgoE0f21uS9Nbmo6qubzI4DYBQRBkCENDG9k1S/5Q41TU69dbmo0bHARCCKEMAAprJZNK0MS2jQy9+Ucgd7QF4HWUIQMC7OaeXrBFm7Tzm0OaiSqPjAAgxlCEAAa9brFXXDu8hSXrpi0KD0wAINZQhAEGhbSL1O18eVdVJJlID8B7KEICgkNMnUdlp8apvculNrkgNwIsoQwCCgslk0nTPROpDTKQG4DWUIQBB44aLeik60qw9JTXKP1RhdBwAIYIyBCBo2GMiNWVEhiQmUgPwHsoQgKDSNpH63a3HVFnXaHAaAKGAMgQgqIzK7KYhPWxqbHbp/zYxkRpA11GGAAQVk8nkGR16iYnUALyAMgQg6Hx3VIZirRbtP16rLw6WGx0HQJCjDAEIOgnRkbp+FBOpAXgHZQhAUJo+po8kaeW2YpXXMpEaQOdRhgAEpeG97Bre065Gp0uv5RcZHQdAEKMMAQhabROpX15fxERqAJ1GGQIQtK4bmaH4qAgdLKvVuv0njI4DIEhRhgAErbioCH33wpaJ1C8ykRpAJ1GGAAS1tonU720v1vHqBoPTAAhGlCEAQW1ohk2jMrup2eXWq0ykBtAJlCEAQa9tIvXS9UVyuZhIDeD8UIYABL0pIzKUEB2hwvI6rd1XZnQcAEGGMgQg6MVYLbrpol6SpBe/OGRwGgDBhjIEICS0HSr7YGepShz1BqcBEEwoQwBCQnZagnL7JMrpcuuVDUykBnDuKEMAQoZnIvWGIjmZSA3gHFGGAISMbw/vIXtMpI5UntTHe44bHQdAkKAMAQgZ0ZEW3ZzTNpGaK1IDODeUIQAhZdqYlkNlH+4q0dHKkwanARAMKEMAQsqA1HiN7Zskl1taxkRqAOeAMgQg5LRNpF62oUjNTpfBaQAEOsoQgJBz9bB0JcVZVeyo1+rdTKQGcGaUIQAhJyrColtaJ1K/xBWpAZwFZQhASGqbSL1mz3EdrqgzOA2AQEYZAhCSspLjdOmA7nK7W+5mDwCnQxkCELKmj+kjSVq2sUhNTKQGcBqUIQAh68qhaUqOt+p4dYNW7SwxOg6AAEUZAhCyrBFmfS83UxJXpAZwepQhACFt2pjeMpmkT/aWqfAEE6kBnIoyBCCkZSbFasLAFEnSS+sZHQJwKsoQgJA3vfU0+9fyi9TYzERqAO1RhgCEvG8NSVVqQpTKahr1zx3FRscBEGAoQwBCXqTFrKmjWyZSv8REagDfQBkCEBb+bUxvmU3SZ/tP6GBZrdFxAAQQyhCAsNCzW4wuH5QqSXqZidQAvoYyBCBstE2kfnVjkeqbnAanARAoKEMAwsblg1LUwx6tiromvbedidQAWlCGAISNiK9NpOaK1ADaUIYAhJV/G91bFrNJ6w+Wa19ptdFxAAQAyhCAsJJuj9YVg1smUr/0RZHBaQAEAsoQgLAzfexXV6RmIjUAyhCAsHPZwBT17BYjR32zln95zOg4AAxGGQIQdixmk6aNab0iNdccAsIeZQhAWPpebqYizCblH6rQ1sNVRscBYCDKEICwlGqL1pSRGZKkP67aY3AaAEaiDAEIW7OvGCCzSfpgZ6m+PFxpdBwABqEMAQhb/VLi9d1RPSVJj32w1+A0AIxCGQIQ1mZ/a6AsZpM+3FWqzUWVRscBYADKEICw1jc57mujQ8wdAsIRZQhA2PvJtwbIYjZpze7j2lRYYXQcAH5GGQIQ9vp0j9ONFzJ3CAhXAVGGFi9erKysLEVHR2vs2LFav379adddsmSJJkyYoMTERCUmJiovL++M6wPAuZh9xUBFmE36eM9x5R9idAgIJ4aXoWXLlmnOnDlasGCBNm3apJEjR2ry5MkqLS3tcP01a9Zo2rRpWr16tdatW6fMzExdddVVOnLkiJ+TAwglvbvH6qaLekli7hAQbkxut9ttZICxY8dq9OjReuKJJyRJLpdLmZmZmj17tu69996zbu90OpWYmKgnnnhCM2fOPOv6DodDdrtdVVVVstlsXc4PIHQUlddp0iNr1Oxy67UfjVNuVpLRkQC08uX7t6EjQ42NjcrPz1deXp5nmdlsVl5entatW3dO36Ourk5NTU1KSuIfLQBdk5kUq1tyW0aH/ofRISBsGFqGysrK5HQ6lZaW1m55WlqaiouLz+l7/PKXv1RGRka7QvV1DQ0Ncjgc7R4AcDp3TxqgSItJn+47ofUHy42OA8APDJ8z1BW/+93vtHTpUr3xxhuKjo7ucJ1FixbJbrd7HpmZmX5OCSCY9EqM1S25Lf9O/M/7jA4B4cDQMpScnCyLxaKSkpJ2y0tKSpSenn7GbR955BH97ne/0z//+U+NGDHitOvNmzdPVVVVnkdRUZFXsgMIXW2jQ+sOnNDnB04YHQeAjxlahqxWq3JycrRq1SrPMpfLpVWrVmncuHGn3e7hhx/Wr3/9a61cuVK5ublnfI6oqCjZbLZ2DwA4k57dYjR1NKNDQLgw/DDZnDlztGTJEr3wwgvauXOn7rrrLtXW1mrWrFmSpJkzZ2revHme9f/7v/9bDzzwgJ577jllZWWpuLhYxcXFqqmpMeolAAhBd08aIKvFrC8Oluuz/WVGxwHgQ4aXoalTp+qRRx7R/PnzNWrUKG3evFkrV670TKouLCzUsWPHPOs/9dRTamxs1M0336wePXp4Ho888ohRLwFACOphj9G/jWkZHXrs/b0y+CokAHzI8OsM+RvXGQJwroqr6nXZ71ersdmlF+8Yq0sHJBsdCQhbIXudIQAIZOn2aE0f01tSy9yhMPvbEQgblCEAOIO7Lu+vqAizNh6q0Np9zB0CQhFlCADOIM0WreljGR0CQhllCADO4q6JLaNDmwor9fFeRoeAUEMZAoCzSLVF6/sX95HE6BAQiihDAHAOfjSxv6IjzdpcVKk1e44bHQeAF1GGAOAcpCRE6dbW0aHHGB0CQgplCADO0X9M7K+YSIu2HK7S6t2lRscB4CWUIQA4R8nxUZo5rnV06AOuSg2ECsoQAJyHH17WT7FWi748XKVVOxkdAkIBZQgAzkP3+CjNHJclSXpsFXOHgFBAGQKA8/TDy/opzmrRtiMOvb+jxOg4ALqIMgQA5ykpzqrbLsmSxNwhIBRQhgCgE+6c0E/xURHaccyh97YzOgQEM8oQAHRCYpxVt3tGh/bI5WJ0CAhWlCEA6KQ7JvRVQlSEdhVX673txUbHAdBJlCEA6KRusVbNujRLUsvcIUaHgOBEGQKALvjB+H5KiIrQ7pJq/WMbo0NAMKIMAUAX2GMjNWt8X0nSH1cxdwgIRpQhAOiiH4zvq4ToCO0pqdHyrceMjgPgPFGGAKCL7DGR+oFndGivnIwOAUGFMgQAXvDv4/vKFh2hfaU1evfLo0bHAXAeKEMA4AW26EjdMaGfJOlxRoeAoEIZAgAvmXVpluwxkdp/vFbvbGF0CAgWlCEA8JKE6EjdOaFl7tDjq/aq2ekyOBGAc0EZAgAvuu2SLHWLjdSBslq9zegQEBQoQwDgRS2jQ1/NHWJ0CAh8lCEA8LLbLslSYmykCk7U6c3NjA4BgY4yBABeFh8VoR9e1l+SdN8bWzXv9S+1q9hhcCoAp0MZAgAfuO2SPhrTN0kNzS69vL5IVz/2iaY987ne217MafdAgDG53e6w+q10OByy2+2qqqqSzWYzOg6AEOZ2u7WhoEJ//eyg3tte4ilBvRJjNHNcH03N7S17bKTBKYHg4Mv3b8oQAPjBkcqT+t/PD+nl9YWqrGuSJMVEWnTDRT0165IsDUxLMDghENgoQ15EGQJgpPomp97afETPf1qgXcXVnuXjByTr9kuyNGlwqixmk4EJgcBEGfIiyhCAQOB2u/X5gXL99bODen9HidqmEfVOitXMcX10S26m7DEcQgPaUIa8iDIEINAUldd5DqE56pslSbFWi266qJduuyRLA1LjDU6IYOZ2u1Vwok4bCsqVX1ChTYUVMpmkMX2TNLZvd43tl6TUhGijY54VZciLKEMAAlVdY7Pe/NdR/fWzg9pTUuNZfll2imZdkqWJ2SkycwgNZ9HY7NK2o1XaWFCujQUVyj9UoRO1jWfcpl9KnC7u111j+ybp4n7dlWYLvHJEGfIiyhCAQOd2u7Vu/wk9/1mBPthZorZ/pbO6x+q2S7J0c04vJURzCA0tKusatamwQhsKKpRfUKEthyvV0Nz+yufWCLNG9rIrp0+Scvskyul26/MDJ/TFgXLtLHbom02gb3KcLu7XMnJ0cb/uSrcbX44oQ15EGQIQTApP1Olv6wq0bGORqlsPocVZLbolN1Mzx/VRvxQOoYUTt9utwvI6bSyo0MZDLSM/e0trTlkvMTZSuVktxSc3K1HDetoVFWHp8HtW1TVpfUF5Szk6eELbj55ajrK6x7YUo/4tBSmjW4wvXt4ZUYa8iDIEIBjVNjTr9X8d0V8/Paj9x2s9yzOTYjQwNUEDU+M1MK3l44DUeMVFRRiYFt7S5HRp+1GH55DXxkMVKqtpOGW9fslxyumTqNFZScrJSlS/5DiZTJ07pFp1skkbPeWoXNuOVOmb1wntnRTrOaQ2tl+SeiXGduq5zgdlyIsoQwCCmdvt1tp9ZfrrpwX6cHfpKX/Bt+nZLUYD0+JPKUkcXvOOhmanGptdcrrcana51ex0q9nV8edNTnfr8tavO1vWcbpcX/ta+8+PVzdo46FybS6qVH1T+0NekRaThve0e0Z+cvokqnt8lM9eq6O+SfkFFfr8wAl93lqOvnkV9V6JMa2H1FoKUq/EmE6XsdPmoAx5D2UIQKioqG3U7pJq7S2t0b6Sau0pqdHe0poORw7aZNijNaC1HGWnxWtAaoIGpsXLRknqkMvVclhqV7FDO45Va+cxh3YVO1RUftJvGbrFRiqnd6JyslpGfob3tCs6suNDXv5Q09DcOnJUri8OntCXh08tRxdk2LT8JxO8+ryUIS+iDAEIdRW1jdpbWqO9pdXaW/LVx9Lq05ekdFu0Bqa1jB5lt5al/inx6hYb6fW/8ANVdX2Tdhe3FJ6drR93F1errtF51m0jLSZZzCZFmM2ymE2nfB5hMSnCbJLFbG79eOo6X/88PipCo3p3U26fRPVPiQ/oswhrG5qVf6jCc1htS1GlvjUkVX++Nderz0MZ8iLKEIBwVVXX1FKMSmvalaRiR/1pt7FGmJVmi1JqQrTnY0pClNJs0Ur92sdgKk3fHO3ZdcyhnWcY7bFGmDUoLUFDeiRocLpNQ3rYNCg9QXFRFkWYzTKbFDSv3R/qGptVdbJJPezenWRNGfIiyhAAtOeob9Lekhrtay1He1oPux2tOn1J+iarxayUhCil2qKUlhDd8tHWUpy+XpoSY61+HeXwjPa0jficZbSnhz1ag9MTNKSHrfWRoKzucYqwmP2WGR3z5fs3pxsAQJizRUcqp3Ui7tfVNzl1vLpBpdX1KnE0qNRRr9Lqhpb/rq5XaevHiromNTpdOlJ5UkcqzzyXJtJiUkp8lFJs0bJFR/hsRMXlcutQee1ZR3u+XnwGpycoMc7qkzwIbJQhAECHoiMtykyKVWbSmU+bbmhuK01fL0xtZanlv49XN+hEbaOanG4drao/r1Gnrkq3Rbcc4motPUMZ7cE3UIYAAF0SFWFRr8TYs15rprHZpbKarwpSbUOzT3Ol26M1JN3GaA/OijIEAPALa4RZGd1iDLl6MXAmjBECAICwRhkCAABhjTIEAADCGmUIAACENcoQAAAIa5QhAAAQ1ihDAAAgrFGGAABAWKMMAQCAsEYZAgAAYY0yBAAAwhplCAAAhDXKEAAACGthd9d6t9stSXI4HAYnAQAA56rtfbvtfdybwq4MVVdXS5IyMzMNTgIAAM5XdXW17Ha7V7+nye2LihXAXC6Xjh49qoSEBJlMJq9//9GjR2vDhg0+3e5s657u6+e6vKP12pY5HA5lZmaqqKhINpvtnPJ2Rmf34/ls6+v92NGyr3/uj30ZyPvxdF8LxP14ulze3o7fbe9sy++2d7YNtN9tt9ut6upqZWRkyGz27iyfsBsZMpvN6tWrl8++v8Vi6dQP//lsd7Z1T/f1c13e0XrfXGaz2Xz6D2Zn9+P5bOvr/djRso7W8eW+DOT9eLqvBeJ+PN1zens7fre9sy2/297ZNhB/t709ItSGCdRedvfdd/t8u7Ote7qvn+vyjtbr7OvqrK4837lu6+v92NEy9uPZvxaI+7Erz8nvtveej99t7zwfv9unCrvDZOgah8Mhu92uqqoqn/71GA7Yl97BfvQO9qP3sC+9w5/7kZEhnJeoqCgtWLBAUVFRRkcJeuxL72A/egf70XvYl97hz/3IyBAAAAhrjAwBAICwRhkCAABhjTIEAADCGmUIAACENcoQAAAIa5Qh+Mzu3bs1atQozyMmJkZvvvmm0bGC0sGDBzVp0iQNHTpUw4cPV21trdGRglJWVpZGjBihUaNGadKkSUbHCXp1dXXq06eP5s6da3SUoFRZWanc3FyNGjVKw4YN05IlS4yOFJSKiop0+eWXa+jQoRoxYoReffXV8/4enFoPv6ipqVFWVpYOHTqkuLg4o+MEnYkTJ+o3v/mNJkyYoPLyctlsNkVEhN3ddLosKytL27ZtU3x8vNFRQsJ9992nffv2KTMzU4888ojRcYKO0+lUQ0ODYmNjVVtbq2HDhmnjxo3q3r270dGCyrFjx1RSUqJRo0apuLhYOTk52rNnz3m91zAyBL94++239a1vfYsi1Anbt29XZGSkJkyYIElKSkqiCMFwe/fu1a5du3TNNdcYHSVoWSwWxcbGSpIaGhrkdrvF+MT569Gjh0aNGiVJSk9PV3JyssrLy8/re1CGwtjHH3+sKVOmKCMjQyaTqcNDWIsXL1ZWVpaio6M1duxYrV+/vlPP9corr2jq1KldTByYfL0f9+7dq/j4eE2ZMkUXXXSRFi5c6MX0gcMfP48mk0kTJ07U6NGj9eKLL3opeeDxx76cO3euFi1a5KXEgckf+7GyslIjR45Ur1699Itf/ELJycleSh84/Plek5+fL6fTqczMzPPajjIUxmprazVy5EgtXry4w68vW7ZMc+bM0YIFC7Rp0yaNHDlSkydPVmlpqWedtmPd33wcPXrUs47D4dBnn32mb3/72z5/TUbw9X5sbm7WJ598oieffFLr1q3T+++/r/fff99fL89v/PHzuHbtWuXn5+vtt9/WwoUL9eWXX/rltfmbr/flW2+9pezsbGVnZ/vrJRnCHz+T3bp105YtW3Tw4EG99NJLKikp8ctr8yd/vdeUl5dr5syZeuaZZ84/pBtwu92S3G+88Ua7ZWPGjHHffffdns+dTqc7IyPDvWjRovP63n/729/cM2bM8EbMgOeL/fjZZ5+5r7rqKs/nDz/8sPvhhx/2St5A5cufxzZz5851P//8811IGRx8sS/vvfded69evdx9+vRxd+/e3W2z2dwPPvigN2MHHH/8TN51113uV199tSsxA56v9mN9fb17woQJ7r/97W+dysXIEDrU2Nio/Px85eXleZaZzWbl5eVp3bp15/W9QvkQ2dl4Yz+OHj1apaWlqqiokMvl0scff6whQ4b4KnJA8sZ+rK2tVXV1taSWCf0ffvihLrjgAp/kDWTe2JeLFi1SUVGRCgoK9Mgjj+jOO+/U/PnzfRU5IHljP5aUlHh+JquqqvTxxx9r0KBBPskbqLyxH91ut26//XZdccUVuvXWWzuVgzKEDpWVlcnpdCotLa3d8rS0NBUXF5/z96mqqtL69es1efJkb0cMCt7YjxEREVq4cKEuu+wyjRgxQgMHDtS1117ri7gByxv7saSkROPHj9fIkSN18cUXa+bMmRo9erQv4gY0b/1uhztv7MdDhw5pwoQJGjlypCZMmKDZs2dr+PDhvogbsLyxHz/99FMtW7ZMb775pudSLlu3bj2vHJySAp+y2+0heQzc36655hrO2umifv36acuWLUbHCDm333670RGC1pgxY7R582ajYwS98ePHy+Vydel7MDKEDiUnJ8tisZxSZEpKSpSenm5QquDDfvQO9qP3sC+9g/3oHYGyHylD6JDValVOTo5WrVrlWeZyubRq1SqNGzfOwGTBhf3oHexH72Ffegf70TsCZT9ymCyM1dTUaN++fZ7PDx48qM2bNyspKUm9e/fWnDlzdNtttyk3N1djxozRY489ptraWs2aNcvA1IGH/egd7EfvYV96B/vRO4JiP3bqHDSEhNWrV7slnfK47bbbPOv86U9/cvfu3dtttVrdY8aMcX/++efGBQ5Q7EfvYD96D/vSO9iP3hEM+5F7kwEAgLDGnCEAABDWKEMAACCsUYYAAEBYowwBAICwRhkCAABhjTIEAADCGmUIAACENcoQAAAIa5QhAAAQ1ihDAAyzZs0amUwmVVZWGvL8q1at0pAhQ+R0Os+67sqVKzVq1Ci5XC4/JAPgT5QhAH5x+eWX62c/+1m7ZZdccomOHTsmu91uSKb//M//1P333y+LxXLWda+++mpFRkbqxRdf9EMyAP5EGQJgGKvVqvT0dJlMJr8/99q1a7V//37ddNNN57zN7bffrscff9yHqQAYgTIEwOduv/12ffTRR/rjH/8ok8kkk8mkgoKCUw6T/fWvf1W3bt307rvvatCgQYqNjdXNN9+suro6vfDCC8rKylJiYqJ+8pOftDu01dDQoLlz56pnz56Ki4vT2LFjtWbNmjNmWrp0qa688kpFR0d7lm3ZskWTJk1SQkKCbDabcnJytHHjRs/Xp0yZoo0bN2r//v1e3T8AjBVhdAAAoe+Pf/yj9uzZo2HDhumhhx6SJKWkpKigoOCUdevq6vT4449r6dKlqq6u1o033qgbbrhB3bp104oVK3TgwAHddNNNuvTSSzV16lRJ0o9//GPt2LFDS5cuVUZGht544w1dffXV2rp1qwYOHNhhpk8++UTTp09vt2zGjBm68MIL9dRTT8lisWjz5s2KjIz0fL13795KS0vTJ598ov79+3tp7wAwGmUIgM/Z7XZZrVbFxsYqPT39jOs2NTXpqaee8pSNm2++WX//+99VUlKi+Ph4DR06VJMmTdLq1as1depUFRYW6vnnn1dhYaEyMjIkSXPnztXKlSv1/PPPa+HChR0+z6FDhzzrtyksLNQvfvELDR48WJI6LFIZGRk6dOjQee8DAIGLMgQgoMTGxrYbdUlLS1NWVpbi4+PbLSstLZUkbd26VU6nU9nZ2e2+T0NDg7p3737a5zl58mS7Q2SSNGfOHN1xxx36+9//rry8PN1yyy2njADFxMSorq6u068PQOChDAEIKF8/LCVJJpOpw2Vtp7jX1NTIYrEoPz//lLPCvl6gvik5OVkVFRXtlv3qV7/S9OnTtXz5cv3jH//QggULtHTpUt1www2edcrLy5WSktKp1wYgMFGGAPiF1Wo9p+v5nK8LL7xQTqdTpaWlmjBhwnltt2PHjlOWZ2dnKzs7W/fcc4+mTZum559/3lOG6uvrtX//fl144YVeyw/AeJxNBsAvsrKy9MUXX6igoEBlZWVeu3hhdna2ZsyYoZkzZ+r111/XwYMHtX79ei1atEjLly8/7XaTJ0/W2rVrPZ+fPHlSP/7xj7VmzRodOnRIn376qTZs2KAhQ4Z41vn8888VFRWlcePGeSU7gMBAGQLgF3PnzpXFYtHQoUOVkpKiwsJCr33v559/XjNnztTPf/5zDRo0SN/97ne1YcMG9e7d+7TbzJgxQ9u3b9fu3bslSRaLRSdOnNDMmTOVnZ2t733ve7rmmmv04IMPerZ5+eWXNWPGDMXGxnotOwDjmdxut9voEABghF/84hdyOBz685//fNZ1y8rKNGjQIG3cuFF9+/b1QzoA/sLIEICwdd9996lPnz7ndMiuoKBATz75JEUICEGMDAEAgLDGyBAAAAhrlCEAABDWKEMAACCsUYYAAEBYowwBAICwRhkCAABhjTIEAADCGmUIAACENcoQAAAIa/8fp57SPniK4bcAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "plt.semilogx(times, probs, '-')\n", "plt.xlabel('time (s)')\n", "plt.ylabel('p')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using a Custom Calibration\n", "\n", "All gate and measure applications in a Quil-T program are translated according to either user-supplied or Rigetti calibrations. To easily check which calibration applies to a specific gate, use the `Program.match_calibrations` method." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEFCAL RX(pi) 0:\n", "\tFENCE 0\n", "\tNONBLOCKING PULSE 0 \"rf\" drag_gaussian(alpha: 0.3183552471062913, anh: -220655329.522463, detuning: -321047.14178613486, duration: 2.4000000000000003e-8, fwhm: 6.000000000000001e-9, phase: 0, scale: 0.625214040700785, t0: 1.2000000000000002e-8)\n", "\tFENCE 0\n" ] } ], "source": [ "from math import pi\n", "from pyquil.gates import RX\n", "\n", "print(cals.get_calibration(RX(pi, 0)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "None of the above programs needed us to specify calibrations. By default, the Rigetti native calibrations are used. However, if you specify a calibration in a program, it will take precedence over the native calibrations." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "prog = t1_program(1e-6, 0)\n", "\n", "# Note: we did NOT specify a calibration for RX(pi) 0 in our previous program\n", "assert prog.match_calibrations(RX(pi, 0)) is None\n", "# The Quil-T translator provided the default: namely, the same calibration we obtained for ourselves\n", "# with `qc.compiler.get_calibration_program()`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the example below, we use a custom calibration, we conjugate the usual pulse with a frequency shift. There's no motivation for the particular value used, beyond simply showing what is possible." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DECLARE ro BIT[1]\n", "DEFCAL RX(pi/2) 0:\n", "\tFENCE 0\n", "\tSET-SCALE 0 \"rf\" 0.353088482172993\n", "\tSHIFT-FREQUENCY 0 \"rf\" 1000000\n", "\tNONBLOCKING PULSE 0 \"rf\" drag_gaussian(alpha: 6.389096630631076, anh: -210000000, duration: 6.000000000000001e-8, fwhm: 1.5000000000000002e-8, t0: 3.0000000000000004e-8)\n", "\tSHIFT-FREQUENCY 0 \"rf\" -1000000\n", "\tFENCE 0\n", "RX(pi/2) 0\n", "MEASURE 0 ro[0]\n", "\n" ] } ], "source": [ "prog = Program(\"\"\"DEFCAL RX(pi/2) 0:\n", " FENCE 0\n", " SET-SCALE 0 \"rf\" 0.353088482172993\n", " SHIFT-FREQUENCY 0 \"rf\" 1e6\n", " NONBLOCKING PULSE 0 \"rf\" drag_gaussian(duration: 6.000000000000001e-08, fwhm: 1.5000000000000002e-08, t0: 3.0000000000000004e-08, anh: -210000000.0, alpha: 6.389096630631076)\n", " SHIFT-FREQUENCY 0 \"rf\" -1e6\n", " FENCE 0\n", "\n", "DECLARE ro BIT\n", "RX(pi/2) 0\n", "MEASURE 0 ro\"\"\")\n", "print(prog)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEFCAL RX(pi/2) 0:\n", "\tFENCE 0\n", "\tSET-SCALE 0 \"rf\" 0.353088482172993\n", "\tSHIFT-FREQUENCY 0 \"rf\" 1000000\n", "\tNONBLOCKING PULSE 0 \"rf\" drag_gaussian(alpha: 6.389096630631076, anh: -210000000, duration: 6.000000000000001e-8, fwhm: 1.5000000000000002e-8, t0: 3.0000000000000004e-8)\n", "\tSHIFT-FREQUENCY 0 \"rf\" -1000000\n", "\tFENCE 0\n" ] } ], "source": [ "print(prog.get_calibration(RX(pi/2, 0)))" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "exe = qc.compiler.native_quil_to_executable(prog)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ro': array([[0]])}" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qc.run(exe).get_register_map()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, it is not required to use calibrations. One can construct an equivalent program by replacing the `RX` gate with the body of the calibration:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "prog = Program(\"\"\"\n", "DECLARE ro BIT\n", "FENCE 0\n", "SET-SCALE 0 \"rf\" 0.353088482172993\n", "SHIFT-FREQUENCY 0 \"rf\" 1e6\n", "NONBLOCKING PULSE 0 \"rf\" drag_gaussian(duration: 6.000000000000001e-08, fwhm: 1.5000000000000002e-08, t0: 3.0000000000000004e-08, anh: -210000000.0, alpha: 6.389096630631076)\n", "SHIFT-FREQUENCY 0 \"rf\" -1e6\n", "FENCE 0\n", "MEASURE 0 ro\n", "\"\"\".strip())" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "exe = qc.compiler.native_quil_to_executable(prog)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ro': array([[1]])}" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qc.run(exe).get_register_map()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Parametric Calibrations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some calibrations (e.g. for `RX`) are defined for specific parameter values. Others may depend on general symbolic values, as with `RZ`." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEFCAL RZ(%theta) 0:\n", "\tFENCE 0\n", "\tSHIFT-PHASE 0 \"rf\" -1*%theta\n", "\tSHIFT-PHASE 0 1 \"xy\" -0.5*%theta\n", "\tSHIFT-PHASE 0 103 \"xy\" -0.5*%theta\n", "\tFENCE 0\n" ] } ], "source": [ "from pyquil.gates import RZ\n", "\n", "print(cals.get_calibration(RZ(pi,0)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get more information about how the matching calibration applies to a specific gate, use `Program.match_calibrations`. The result is a `CalibrationMatch` object which indicates not just the calibration, but the value for parameters." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEFCAL RZ(%theta) 0:\n", "\tFENCE 0\n", "\tSHIFT-PHASE 0 \"rf\" -1*%theta\n", "\tSHIFT-PHASE 0 1 \"xy\" -0.5*%theta\n", "\tSHIFT-PHASE 0 103 \"xy\" -0.5*%theta\n", "\tFENCE 0\n", "{Parameter('theta'): (3.141592653589793+0j)}\n" ] } ], "source": [ "match = cals.match_calibrations(RZ(pi,0))\n", "print(match.cal)\n", "print(match.settings)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You may conveniently recover the body of the calibration, with the matched parameters substituted, using `Program.calibrate`." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FENCE 0\n", "SHIFT-PHASE 0 \"rf\" -1*3.141592653589793\n", "SHIFT-PHASE 0 1 \"xy\" -0.5*3.141592653589793\n", "SHIFT-PHASE 0 103 \"xy\" -0.5*3.141592653589793\n", "FENCE 0\n" ] } ], "source": [ "instrs = cals.calibrate(RZ(pi,0))\n", "for instr in instrs:\n", " print(instr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Non-Native Gates\n", "As mentioned above, the `qc.compiler.native_quil_to_executable` call will provide calibrations for Rigetti native gates, if they are not provided by a user. However, a program with non-native gates and no corresponding user-provided calibrations will result in a compilation failure." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Fails on non-native operations {H, CNOT} as expected.\n" ] } ], "source": [ "prog = Program(\"DECLARE ro BIT\\n\"\n", " \"H 0\\n\"\n", " \"CNOT 0 1\\n\"\n", " \"MEASURE 0 ro\")\n", "\n", "try:\n", " qc.compiler.native_quil_to_executable(prog)\n", "except Exception as e:\n", " print(\"Fails on non-native operations {H, CNOT} as expected.\")" ] } ], "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.8.14" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }