{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# This cell is added by sphinx-gallery\n# It can be customized to whatever you like\n%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Givens rotations for quantum chemistry\n======================================\n\n::: {.meta}\n:property=\\\"og:description\\\": Discover the building blocks of quantum\ncircuits for quantum chemistry\n\n:property=\\\"og:image\\\":\n\n:::\n\n::: {.related}\ntutorial\\_quantum\\_chemistry Building molecular Hamiltonians\ntutorial\\_vqe A brief overview of VQE\n:::\n\n*Author: Juan Miguel Arrazola --- Posted: 30 June 2021. Last updated: 30\nJune 2021.*\n\nIn the book [\\\"Sophie\\'s\nworld\\\"](https://en.wikipedia.org/wiki/Sophie%27s_World), the young\nprotagonist receives a white envelope containing a letter with an\nintriguing question: \\\"Why is Lego the most ingenious toy in the\nworld?\\\" At first baffled by this curious message, she decides to\nreflect on the question. As told by the book\\'s narrator, she arrives at\na conclusion:\n\n*The best thing about them was that with Lego she could construct any\nkind of object. And then she could separate the blocks and construct\nsomething new. What more could one ask of a toy? Sophie decided that\nLego really could be called the most ingenious toy in the world.*\n\n![](../demonstrations/givens_rotations/lego-circuit.svg){.align-center\nwidth=\"50.0%\"}\n\nIn this tutorial, you will learn about the building blocks of quantum\ncircuits for quantum chemistry: Givens rotations. These are operations\nthat can be used to construct any kind of particle-conserving circuit.\nWe discuss single and double excitation gates, which are particular\ntypes of Givens rotations that play an important role in quantum\nchemistry. Notably, controlled single excitation gates are universal for\nparticle-conserving unitaries. You will also learn how to use these\ngates to build arbitrary states of a fixed number of particles.\n\nParticle-conserving unitaries\n-----------------------------\n\nUnderstanding the electronic structure of molecules is arguably the\ncentral problem in quantum chemistry. Quantum computers tackle this\nproblem by using systems of qubits to represent the quantum states of\nthe electrons. One method is to consider a collection of [molecular\norbitals](https://en.wikipedia.org/wiki/Molecular_orbital), which\ncapture the three-dimensional region of space occupied by the electrons.\nEach orbital can be occupied by at most two electrons, each with a\ndifferent spin orientation. In this case we refer to *spin orbitals*\nthat can be occupied by a single electron.\n\nThe state of electrons in a molecule can then be described by specifying\nhow the orbitals are occupied. The [Jordan-Wigner\nrepresentation](https://en.wikipedia.org/wiki/Jordan%E2%80%93Wigner_transformation)\nprovides a convenient way to do this: we associate a qubit with each\nspin orbital and use its states to represent occupied $|1\\rangle$ or\nunoccupied $|0\\rangle$ spin orbitals.\n\nAn $n$-qubit state with [Hamming\nweight](https://en.wikipedia.org/wiki/Hamming_weight) $k$, i.e., with\n$k$ qubits in state $|1\\rangle$, represents a state of $k$ electrons in\n$n$ spin orbitals. For example $|1010\\rangle$ is a state of two\nelectrons in two spin orbitals. More generally, superpositions over all\nbasis states with a fixed number of particles are valid states of the\nelectrons in a molecule. These are states such as\n\n$$|\\psi\\rangle = c_1|1100\\rangle + c_2|1010\\rangle + c_3|1001\\rangle + c_4|0110\\rangle +\nc_5|0101\\rangle + c_6|0011\\rangle,$$\n\nfor some coefficients $c_i$.\n\n![States of a system with six spin orbitals and three electrons.\nOrbitals are for illustration; they correspond to carbon dioxide, which\nhas more electrons and\norbitals.](../demonstrations/givens_rotations/orbitals+states.png){.align-center\nwidth=\"50.0%\"}\n\nBecause the number of electrons in a molecule is fixed, any\ntransformation must conserve the number of particles. We refer to these\nas **particle-conserving unitaries**. When designing quantum circuits\nand algorithms for quantum chemistry, it is desirable to employ only\nparticle-conserving gates that guarantee that the states of the system\nremain valid. This raises the questions: what are the simplest\nparticle-conserving unitaries? Like Legos, how can they be used to\nconstruct any quantum circuit for quantum chemistry applications?\n\nGivens rotations\n----------------\n\nConsider single-qubit gates. In their most general form, they perform\nthe transformation\n\n$$\\begin{aligned}\nU|0\\rangle &= a |0\\rangle + b |1\\rangle,\\\\\nU|1\\rangle &= c |1\\rangle + d |0\\rangle,\n\\end{aligned}$$\n\nwhere $|a|^2+|b|^2=|c|^2+|d|^2=1$ and $ab^* + cd^*=0$. This gate is\nparticle-conserving only if $b=d=0$, which means that the only\nsingle-qubit gates that preserve particle number are diagonal gates of\nthe form\n\n$$\\begin{aligned}\nU = \\begin{pmatrix}\ne^{i\\theta} & 0\\\\\n0 & e^{i\\phi}\n\\end{pmatrix}.\n\\end{aligned}$$\n\nOn their own, these gates are not very interesting. They can only be\nused to change the relative phases of states in a superposition; they\ncannot be used to create and control such superpositions. So let\\'s take\na look at two-qubit gates.\n\nBasis states of two qubits can be categorized depending on their number\nof particles.\n\nWe have:\n\n- $|00\\rangle$ with zero particles,\n- $|01\\rangle,|10\\rangle$ with one particle, and\n- $|11\\rangle$ with two particles.\n\nWe can now consider transformations that couple the states\n$|01\\rangle,|10\\rangle$. These are gates of the form\n\n$$\\begin{aligned}\nU|01\\rangle &= a |01\\rangle + b |10\\rangle\\\\\nU|10\\rangle &= c |10\\rangle + d |01\\rangle.\n\\end{aligned}$$\n\nThis should be familiar: the unitary has the same form as a single-qubit\ngate, except that the states $|01\\rangle, |10\\rangle$ respectively take\nthe place of $|0\\rangle,\n|1\\rangle$. This correspondence has a name: the [dual-rail\nqubit](https://en.wikipedia.org/wiki/Optical_cluster_state), where a\ntwo-level system is constructed by specifying in which of two possible\nsystems a single particle is located. The difference compared to\nsingle-qubit gates is that any values of the parameters $a,\nb,c,d$ give rise to a valid particle-conserving unitary. Take for\ninstance the two-qubit gate\n\n$$\\begin{aligned}\nG(\\theta)=\\begin{pmatrix}\n1 & 0 & 0 & 0\\\\\n0 & \\cos (\\theta/2) & -\\sin (\\theta/2) & 0\\\\\n0 & \\sin(\\theta/2) & \\cos(\\theta/2) & 0\\\\\n0 & 0 & 0 & 1\n\\end{pmatrix}.\n\\end{aligned}$$\n\nThis is an example of a [Givens\nrotation](https://en.wikipedia.org/wiki/Givens_rotation): a rotation in\na two-dimensional subspace of a larger Hilbert space. In this case, we\nare performing a Givens rotation in a two-dimensional subspace of the\nfour-dimensional space of two-qubit states. This gate allows us to\ncreate superpositions by exchanging the particle between the two qubits.\nSuch transformations can be interpreted as a **single excitation**,\nwhere we view the exchange from $|10\\rangle$ to $|01\\rangle$ as exciting\nthe electron from the first to the second qubit.\n\n![A Givens rotation can be used to couple states that differ by a single\nexcitation.](../demonstrations/givens_rotations/Givens_rotations_1.png){.align-center\nwidth=\"35.0%\"}\n\nThis gate is implemented in PennyLane as the\n`~.pennylane.SingleExcitation`{.interpreted-text role=\"class\"}\noperation. We can use it to prepare an equal superposition of\nthree-qubit states with a single particle\n$\\frac{1}{\\sqrt{3}}(|001\\rangle + |010\\rangle + |100\\rangle)$. We apply\ntwo single excitation gates with parameters $\\theta, \\phi$ to the\ninitial state $|100\\rangle$. The excitation gates act on qubits 0,1 and\n0,2 respectively. This yields the state\n\n$$|\\psi\\rangle = \\cos(\\theta/2)\\cos(\\phi/2)|100\\rangle - \\sin(\\theta/2)|010\\rangle -\n\\cos(\\theta/2)\\sin(\\phi/2)|001\\rangle.$$\n\nSince the amplitude of $|010\\rangle$ must be $1/\\sqrt{3}$, we conclude\nthat $-\\sin(\\theta/2)=1/\\sqrt{3}$. This in turn implies that\n$\\cos(\\theta/2)=\\sqrt{2/3}$ and therefore $-\\sin(\\phi/2)=1/\\sqrt{2}$.\nThus, to prepare an equal superposition state we choose the angles of\nrotation to be\n\n$$\\begin{aligned}\n\\theta &= - 2 \\arcsin(1/\\sqrt{3}),\\\\\n\\phi &= - 2 \\arcsin(1/\\sqrt{2}).\n\\end{aligned}$$\n\nThis can be implemented in PennyLane as follows:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import pennylane as qml\nimport numpy as np\n\ndev = qml.device('default.qubit', wires=3)\n\n@qml.qnode(dev)\ndef circuit(x, y):\n # prepares the reference state |100>\n qml.BasisState(np.array([1, 0, 0]), wires=[0, 1, 2])\n # applies the single excitations\n qml.SingleExcitation(x, wires=[0, 1])\n qml.SingleExcitation(y, wires=[0, 2])\n return qml.state()\n\nx = -2 * np.arcsin(np.sqrt(1/3))\ny = -2 * np.arcsin(np.sqrt(1/2))\nprint(circuit(x, y))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The components of the output state are ordered according to their binary\nrepresentation, so entry 1 is $|001\\rangle$, entry 2 is $|010\\rangle$,\nand entry 4 is $|100\\rangle$, meaning we indeed prepared the desired\nstate. We can check this by reshaping the output state\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"tensor_state = circuit(x, y).reshape(2, 2, 2)\nprint(\"Amplitude of state |001> = \", tensor_state[0, 0, 1])\nprint(\"Amplitude of state |010> = \", tensor_state[0, 1, 0])\nprint(\"Amplitude of state |100> = \", tensor_state[1, 0, 0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also study **double excitations** involving the transfer of two\nparticles. For example, consider a Givens rotation in the subspace\nspanned by the states $|1100\\rangle$ and $|0011\\rangle$. These states\ndiffer by a double excitation since we can map $|1100\\rangle$ to\n$|0011\\rangle$ by exciting the particles from the first two qubits to\nthe last two. Mathematically, this gate can be represented by a unitary\n$G^{(2)}(\\theta)$ that performs the mapping\n\n$$\\begin{aligned}\nG^{(2)}|0011\\rangle &= \\cos (\\theta/2)|0011\\rangle + \\sin (\\theta/2)|1100\\rangle\\\\\nG^{(2)}|1100\\rangle &= \\cos (\\theta/2)|1100\\rangle - \\sin (\\theta/2)|0011\\rangle,\n\\end{aligned}$$\n\nwhile leaving all other basis states unchanged. This gate is implemented\nin PennyLane as the `~.pennylane.DoubleExcitation`{.interpreted-text\nrole=\"class\"} operation.\n\n![A Givens rotation can also be used to couple states that differ by a\ndouble\nexcitation.](../demonstrations/givens_rotations/Givens_rotations_2.png){.align-center\nwidth=\"35.0%\"}\n\nIn the context of quantum chemistry, it is common to consider\nexcitations on a fixed reference state and include only the excitations\nthat preserve the spin orientation of the electron. For a system with\n$n$ qubits and $k$ particles, this reference state is typically chosen\nas the state with the first $k$ qubits in state $|1\\rangle$, and the\nremainder in state $|0\\rangle$. PennyLane allows you to obtain all such\nexcitations using the function\n`~.pennylane.qchem.excitations`{.interpreted-text role=\"func\"}. Let\\'s\nemploy it to build a circuit that includes all single and double\nexcitations acting on a reference state of three particles in six\nqubits. We apply a random rotation for each gate:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"nr_particles = 3\nnr_qubits = 6\n\nsingles, doubles = qml.qchem.excitations(3, 6)\nprint(f\"Single excitations = {singles}\")\nprint(f\"Double excitations = {doubles}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we continue to build the circuit:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"dev2 = qml.device('default.qubit', wires=6)\n\n@qml.qnode(dev2)\ndef circuit2(x, y):\n # prepares reference state\n qml.BasisState(np.array([1, 1, 1, 0, 0, 0]), wires=[0, 1, 2, 3, 4, 5])\n # apply all single excitations\n for i, s in enumerate(singles):\n qml.SingleExcitation(x[i], wires=s)\n # apply all double excitations\n for j, d in enumerate(doubles):\n qml.DoubleExcitation(y[j], wires=d)\n return qml.state()\n\n# random angles of rotation\nx = np.random.normal(0, 1, len(singles))\ny = np.random.normal(0, 1, len(doubles))\n\noutput = circuit2(x, y)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can check which basis states appear in the resulting superposition to\nconfirm that they involve only states with three particles.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# constructs binary representation of states with non-zero amplitude\nstates = [np.binary_repr(i, width=6) for i in range(len(output)) if output[i] != 0]\nprint(states)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Besides these Givens rotations, there are other versions that have been\nreported in the literature and used to construct circuits for quantum\nchemistry. For instance, Ref. considers a different sign convention for\nsingle-excitation gates,\n\n$$\\begin{aligned}\nG(\\theta)=\\begin{pmatrix}\n1 & 0 & 0 & 0\\\\\n0 & \\cos (\\theta/2) & \\sin (\\theta/2) & 0\\\\\n0 & -\\sin(\\theta/2) & \\cos(\\theta/2) & 0\\\\\n0 & 0 & 0 & 1\n\\end{pmatrix},\n\\end{aligned}$$\n\nand Ref. introduces the particle-conserving gates listed below, which\nare all Givens rotations\n\n$$\\begin{aligned}\nU_1(\\theta, \\phi) &= \\begin{pmatrix}\n1 & 0 & 0 & 0\\\\\n0 & \\cos (\\theta) & e^{i\\phi}\\sin (\\theta) & 0\\\\\n0 & e^{-i\\phi}\\sin(\\theta) & -\\cos(\\theta) & 0\\\\\n0 & 0 & 0 & 1\n\\end{pmatrix},\\\\[12pt]\n\\end{aligned}$$$$\\begin{aligned}\nU_2(\\theta) &= \\begin{pmatrix}\n1 & 0 & 0 & 0\\\\\n0 & \\cos (2\\theta) & -i\\sin (2\\theta) & 0\\\\\n0 & -i\\sin(2\\theta) & \\cos(2\\theta) & 0\\\\\n0 & 0 & 0 & 1\n\\end{pmatrix}.\n\\end{aligned}$$\n\nGivens rotations are a powerful abstraction for understanding quantum\ncircuits for quantum chemistry. Instead of thinking of single-qubit\ngates and CNOTs as the building-blocks of quantum circuits, we can be\nmore clever and select two-dimensional subspaces spanned by states with\nan equal number of particles, and use Givens rotations in that subspace\nto construct the circuits. \ud83e\udde0\n\nControlled excitation gates\n===========================\n\nSingle-qubit gates and CNOT gates are universal for quantum computing:\nthey can be used to implement any conceivable quantum computation. If\nGivens rotations are analogous to single-qubit gates, then\n**controlled** Givens rotations are analogous to two-qubit gates. In\nuniversality constructions, the ability to control operations based on\nthe states of other qubits is essential, so for this reason it\\'s\nnatural to study controlled Givens rotations. The simplest of these are\ncontrolled single-excitation gates, which are three-qubit gates that\nperform the mapping\n\n$$\\begin{aligned}\nCG(\\theta) |101\\rangle &= \\cos (\\theta/2)|101\\rangle + \\sin (\\theta/2)|110\\rangle,\\\\\nCG(\\theta) |110\\rangle &= \\cos (\\theta/2)|110\\rangle - \\sin (\\theta/2)|101\\rangle,\n\\end{aligned}$$\n\nwhile leaving all other basis states unchanged. This gate only excites a\nparticle from the second to third qubit, and vice versa, if the first\n(control) qubit is in state $\\ket{1}$. This is a useful property: as the\nname suggests, it provides us with better control over the\ntransformations we want to apply. Suppose we aim to prepare the state\n\n$$|\\psi\\rangle = \\frac{1}{2}(\\ket{110000} + \\ket{001100} + \\ket{000011} + \\ket{100100}).$$\n\nSome inspection is enough to see that the states $\\ket{001100}$ and\n$\\ket{000011}$ differ by a double excitation from the reference state\n$\\ket{110000}$. Meanwhile, the state $\\ket{100100}$ differs by a single\nexcitation. It is thus tempting to think that applying two\ndouble-excitation gates and a single-excitation gate can be used to\nprepare the target state. It won\\'t work! Applying the single-excitation\ngate on qubits 1 and 3 will also lead to an undesired contribution for\nthe state $|011000\\rangle$ through a coupling with $\\ket{001100}$.\nLet\\'s check that this is the case:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"dev = qml.device('default.qubit', wires=6)\n\n@qml.qnode(dev)\ndef circuit3(x, y, z):\n qml.BasisState(np.array([1, 1, 0, 0, 0, 0]), wires=[i for i in range(6)])\n qml.DoubleExcitation(x, wires=[0, 1, 2, 3])\n qml.DoubleExcitation(y, wires=[0, 1, 4, 5])\n qml.SingleExcitation(z, wires=[1, 3])\n return qml.state()\n\nx = -2 * np.arcsin(np.sqrt(1/4))\ny = -2 * np.arcsin(np.sqrt(1/3))\nz = -2 * np.arcsin(np.sqrt(1/2))\n\noutput = circuit3(x, y, z)\nstates = [np.binary_repr(i, width=6) for i in range(len(output)) if output[i] != 0]\nprint(states)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Indeed, we have a non-zero coefficient for $|011000\\rangle$. To address\nthis problem, we can instead apply the single-excitation gate controlled\non the state of the first qubit. This ensures that there is no coupling\nwith the state $\\ket{\n001100}$ since here the first qubit is in state $|0\\rangle$. Let\\'s\nimplement the circuit above, this time controlling on the state of the\nfirst qubit and verify that we can prepare the desired state. To perform\nthe control, we use the `~.pennylane.ctrl`{.interpreted-text\nrole=\"func\"} transform:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"@qml.qnode(dev)\ndef circuit4(x, y, z):\n qml.BasisState(np.array([1, 1, 0, 0, 0, 0]), wires=[i for i in range(6)])\n qml.DoubleExcitation(x, wires=[0, 1, 2, 3])\n qml.DoubleExcitation(y, wires=[0, 1, 4, 5])\n # single excitation controlled on qubit 0\n qml.ctrl(qml.SingleExcitation, control=0)(z, wires=[1, 3])\n return qml.state()\n\noutput = circuit4(x, y, z)\nstates = [np.binary_repr(i, width=6) for i in range(len(output)) if output[i] != 0]\nprint(states)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It was proven in Ref. that controlled single-excitation gates are\nuniversal for particle-conserving unitaries. With enough ingenuity, you\ncan use these operations to construct any kind of circuit for quantum\nchemistry applications. What more could you ask from a gate?\n\nState preparation\n=================\n\nWe can bring all these pieces together and implement a circuit capable\nof preparing four-qubit states of two particles with real coefficients.\nThe main idea is that we can perform the construction one basis state at\na time by applying a suitable excitation gate, which may need to be\ncontrolled.\n\n![A circuit for preparing four-qubit states with two\nparticles.](../demonstrations/givens_rotations/circuit.png){.align-center\nwidth=\"70.0%\"}\n\nStarting from the reference state $\\ket{1100}$, we create a\nsuperposition with the state $\\ket{1010}$ by applying a\nsingle-excitation gate on qubits 1 and 2. Similarly, we create a\nsuperposition with the state $\\ket{1001}$ with a single excitation\nbetween qubits 1 and 3. This leaves us with a state of the form\n\n$$|\\psi\\rangle = a \\ket{1100} + b \\ket{1010} + c \\ket{1001}.$$\n\nWe can now perform two single excitations from qubit 0 to qubits 2 and\n3. These will have to be controlled on the state of qubit 1. Finally,\napplying a double-excitation gate on all qubits can create a\nsuperposition of the form\n\n$$|\\psi\\rangle = c_1|1100\\rangle + c_2|1010\\rangle + c_3|1001\\rangle + c_4|0110\\rangle +\nc_5|0101\\rangle + c_6|0011\\rangle,$$\n\nwhich is our intended outcome. Let\\'s use this approach to create an\nequal superposition over all two-particle states on four qubits. We\nfollow the same strategy as before, setting the angle of the $k$-th\nGivens rotation as $-2 \\arcsin(1/\\sqrt{n-k})$, where $n$ is the number\nof basis states in the superposition.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"dev = qml.device('default.qubit', wires=4)\n\n@qml.qnode(dev)\ndef state_preparation(params):\n qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3])\n qml.SingleExcitation(params[0], wires=[1, 2])\n qml.SingleExcitation(params[1], wires=[1, 3])\n # single excitations controlled on qubit 1\n qml.ctrl(qml.SingleExcitation, control=1)(params[2], wires=[0, 2])\n qml.ctrl(qml.SingleExcitation, control=1)(params[3], wires=[0, 3])\n qml.DoubleExcitation(params[4], wires=[0, 1, 2, 3])\n return qml.state()\n\nn = 6\nparams = np.array([-2 * np.arcsin(1/np.sqrt(n-i)) for i in range(n-1)])\n\noutput = state_preparation(params)\n# sets very small coefficients to zero\noutput[np.abs(output) < 1e-10] = 0\nstates = [np.binary_repr(i, width=4) for i in range(len(output)) if output[i] != 0]\nprint(\"Basis states = \", states)\nprint(\"Output state =\", output)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Success! This is the equal superposition state we wanted to prepare. \ud83d\ude80\n\nWhen it comes to quantum circuits for quantum chemistry, a wide variety\nof architectures have been proposed. Researchers in the field are faced\nwith the apparent choice of making a selection among these circuits to\nconduct their computations and benchmark new algorithms. Like a kid in a\ntoy store, it is challenging to pick just one.\n\nUltimately, the aim of this tutorial is to provide you with the\nconceptual and software tools to implement any of these proposed\ncircuits, and **also to design your own**. It\\'s not only fun to play\nwith toys; it\\'s also fun to build them.\n\nReferences\n==========\n\nAbout the author\n================\n"
]
}
],
"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.9.15"
}
},
"nbformat": 4,
"nbformat_minor": 0
}