{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "83596f71-5e63-4aa2-907b-75de8813d85a",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Executar circuitos dinâmicos\"\n",
        "description: \"Use Qiskit Runtime para fluxo de controle e feedforward clássicos, também conhecidos como circuitos dinâmicos\"\n",
        "---\n",
        "\n",
        "<span id=\"execute-dynamic-circuits\" />\n",
        "\n",
        "# Executar circuitos dinâmicos\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2228a8a2-02b7-4a0b-bbe8-0c2933fbe44a",
      "metadata": {},
      "source": [
        "Os circuitos dinâmicos são ferramentas poderosas que permitem medir qubits no meio da execução de um circuito quântico e, em seguida, realizar operações lógicas clássicas dentro do circuito, com base no resultado dessas medições realizadas no meio do circuito.  Esse processo também é conhecido como *feedforward clássico*. Embora ainda estejamos nos estágios iniciais da compreensão sobre a melhor forma de aproveitar os circuitos dinâmicos, a comunidade de pesquisa quântica já identificou vários casos de uso, tais como os seguintes:\n",
        "\n",
        "* Preparação eficiente de estados quânticos, tais como [o estado GHZ](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.5.030339), [o estado W](https://arxiv.org/abs/2403.07604) (para mais informações sobre o estado W, consulte também [“Preparação de estados por circuitos rasos utilizando feed forward”](https://arxiv.org/abs/2307.14840) ) e uma ampla classe de [estados de produto matricial](https://arxiv.org/abs/2404.16083)\n",
        "* [Entrelacamento eficiente de longo alcance](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.5.030339) entre qubits no mesmo chip por meio do uso de circuitos de profundidade reduzida\n",
        "* [Amostragem](https://arxiv.org/pdf/2505.04705) eficiente de circuitos do tipo IQP\n",
        "\n",
        "Essas melhorias proporcionadas pelos circuitos dinâmicos, no entanto, vêm acompanhadas de desvantagens. As medições no meio do circuito e as operações clássicas costumam ter um tempo de execução mais longo do que as portas de dois qubits, e esse aumento no tempo pode anular os benefícios da redução da profundidade do circuito. Portanto, reduzir a duração da medição no meio do circuito é uma área prioritária de melhoria, à medida que a IBM Quantum® lança a [nova versão](/docs/guides/latest-updates#new-version-dynamic-circuits) dos circuitos dinâmicos.  Para conhecer outras restrições ao usar circuitos dinâmicos, consulte a tabela de compatibilidade [do](/docs/guides/estimator-options#options-compatibility-table) Estimador ou [do Amostrador](/docs/guides/sampler-options#options-compatibility-table).\n",
        "\n",
        "[A especificação](https://openqasm.com/language/classical.html#looping-and-branching) do OpenQASM 3 define várias estruturas de fluxo de controle, mas o Qiskit Runtime atualmente suporta apenas a instrução `if` condicional. Em Qiskit SDK, isso corresponde ao método [if\\_test](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#if_test) em [QuantumCircuit](/docs/api/qiskit/qiskit.circuit.QuantumCircuit). Este método retorna um [gerenciador de contexto](https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers) e é normalmente usado em uma `with` instrução. Este guia descreve como usar essa instrução condicional.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Os exemplos de código neste guia utilizam a instrução de medição padrão para medições no meio do circuito. No entanto, recomenda-se que você use a `MidCircuitMeasure` instrução em vez disso, caso o backend seja compatível com ela. Consulte a [seção “Medições no meio do circuito”](#midcircuit) para obter mais detalhes.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e9dc06d-85fa-4425-9bd1-ce5085be9741",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Versões do pacote\">\n",
        "    O código desta página foi desenvolvido com base nos seguintes requisitos.\n",
        "    Recomendamos usar essas versões ou versões mais recentes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.0\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4616d43-f296-4a84-a79c-deb37fcdac15",
      "metadata": {},
      "source": [
        "<span id=\"find-backends-that-support-dynamic-circuits\" />\n",
        "\n",
        "## Encontre backends que suportem circuitos dinâmicos\n",
        "\n",
        "Para encontrar todos os backends aos quais sua conta tem acesso e que oferecem suporte a circuitos dinâmicos, execute um código como o seguinte.  Este exemplo pressupõe que você tenha [salvo suas credenciais de login](/docs/guides/save-credentials).  Você também pode [especificar explicitamente as credenciais](/docs/guides/initialize-account#explicit) ao inicializar sua conta de serviço do Qiskit Runtime.  Isso permitiria que você visualizasse os back-ends disponíveis em uma instância específica ou em um determinado tipo de plano, por exemplo.\n",
        "\n",
        "<Admonition type=\"note\" title=\"Notas\">\n",
        "  * Os backends disponíveis para a conta dependem da instância especificada nas credenciais.\n",
        "  * A nova versão dos circuitos dinâmicos já está disponível para todos os usuários em todos os backends. Consulte [o anúncio](/docs/guides/latest-updates#new-dynamic-circuits) para obter mais detalhes.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "a63f07b1-9e8a-4086-ab01-552bd444dc9b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_boston')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_kingston')>]\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "dc_backends = service.backends(dynamic_circuits=True)\n",
        "print(dc_backends)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1dca7d79-99ea-42bd-86f7-182266907a85",
      "metadata": {},
      "source": [
        "<span id=\"midcircuit\" />\n",
        "\n",
        "<span id=\"mid-circuit-measurements\" />\n",
        "\n",
        "## Medições no meio do circuito\n",
        "\n",
        "Antes do ` `qiskit-ibm-runtime`v0.43.0 `, `measure` essa era a única instrução de medição no Qiskit. As medições no meio do circuito, no entanto, têm requisitos de ajuste diferentes das medições *nos terminais* (medições realizadas no final de um circuito). Por exemplo, é preciso levar em conta a duração da instrução ao ajustar uma medição no meio do circuito, pois instruções mais longas geram mais ruído nos circuitos. Não é necessário levar em conta a duração das instruções nas medições finais, pois não há instruções após essas medições.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  A `MidCircuitMeasure` instrução corresponde à `measure_2` instrução relatada no arquivo. do backend `supported_instructions`. No entanto, não `measure_2` é compatível com todos os backends. Use `service.backends(filters=lambda b: \"measure_2\" in b.supported_instructions)` para encontrar back-ends compatíveis.  Novas medidas poderão ser adicionadas no futuro, mas isso não é garantido.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"midcircuitmeasure-method\" />\n",
        "\n",
        "### método `MidCircuitMeasure`\n",
        "\n",
        "Em `qiskit-ibm-runtime` v0.43.0, a `MidCircuitMeasure` instrução foi apresentada. Como o nome sugere, trata-se de uma nova instrução de medição otimizada para execução em meio de circuito nas QPUs d IBM®.  Embora seja possível usar `QuantumCircuit.measure` para uma medição no meio do circuito, devido ao seu design, `MidCircuitMeasure` é normalmente a melhor opção.  Por exemplo, isso gera menos sobrecarga no seu circuito do que quando se usa `QuantumCircuit.measure`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "87dfb9c7-1dc2-4752-bdc1-17b9144369f4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "     ┌───┐┌────────────┐\n",
            "q_0: ┤ X ├┤0           ├\n",
            "     └───┘│            │\n",
            "q_1: ─────┤  Measure_2 ├\n",
            "          │            │\n",
            "c_0: ═════╡0           ╞\n",
            "          └────────────┘\n",
            "c_1: ═══════════════════\n",
            "                        \n"
          ]
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime.circuit import MidCircuitMeasure\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, dynamic_circuits=True\n",
        ")\n",
        "\n",
        "circ = QuantumCircuit(2, 2)\n",
        "circ.x(0)\n",
        "circ.append(MidCircuitMeasure(), [0], [0])\n",
        "# circ.measure([0], [0])\n",
        "# circ.measure_all()\n",
        "print(circ.draw(cregbundle=False))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2b603f88-2e0e-4819-8342-8e3662949ff3",
      "metadata": {},
      "source": [
        "<Admonition type=\"attention\" title=\"Avisos Importantes\">\n",
        "  * É necessário haver pelo menos um registro clássico para utilizar as medições.\n",
        "  * A primitiva Sampler requer medições do circuito. É possível adicionar medidas de circuito com a primitiva Estimator, mas elas são ignoradas.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9401a5cc-49e0-48b6-8deb-88e9b7da5a5a",
      "metadata": {},
      "source": [
        "<span id=\"store\" />\n",
        "\n",
        "## `Store`\n",
        "\n",
        "A partir `qiskit-ibm-runtime` da versão 0.47.0, é possível usar a [`store`](/docs/api/qiskit/circuit#store) instrução para salvar o resultado de uma expressão clássica, caso essa expressão venha a ser utilizada repetidamente. As operações são paralelizadas automaticamente, tornando seu código significativamente mais eficiente em tempo de execução.\n",
        "\n",
        "Para obter mais informações, consulte o guia [sobre alimentação direta clássica e fluxo de controle](/docs/guides/classical-feedforward-and-control-flow#store).\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Quando você usa `store` para salvar um valor em um registro clássico em um backend real, esse valor é salvo apenas na memória durante a execução e não é copiado nem retornado no resultado da tarefa.\n",
        "\n",
        "  Por exemplo, no código a seguir, `temp` tem o mesmo valor que `creg` durante a execução, e o `if_test` funciona como esperado. Mas, após a conclusão da tarefa, o `temp` `BitArray` retornado no resultado da tarefa **não** contém o valor de `creg`.  Ou seja, `job.result()[0].data.temp` é `0`.\n",
        "\n",
        "  ```python\n",
        "  creg = ClassicalRegister(3, \"c\")\n",
        "  temp = ClassicalRegister(3, \"temp\")\n",
        "  ...\n",
        "  qc.store(temp, creg)\n",
        "  with circuit.if_test((temp, 0b001)):\n",
        "      ...\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f374a74-c331-40de-8594-686e471058a2",
      "metadata": {},
      "source": [
        "<span id=\"full-example\" />\n",
        "\n",
        "## Exemplo completo\n",
        "\n",
        "O código a seguir cria e executa um circuito dinâmico em um hardware d IBM®.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "a7a9c998-4031-432f-978b-83edc040798f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            ">>>  Job ID:    d9bjipbv6alc73ct567g (DONE)\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import SamplerV2, QiskitRuntimeService\n",
        "from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, dynamic_circuits=True\n",
        ")\n",
        "\n",
        "# Create a dynamic circuit\n",
        "\n",
        "qubits = QuantumRegister(1)\n",
        "clbits = ClassicalRegister(1)\n",
        "qc = QuantumCircuit(qubits, clbits)\n",
        "(q0,) = qubits\n",
        "(c0,) = clbits\n",
        "\n",
        "qc.h(q0)\n",
        "qc.measure(q0, c0)\n",
        "with qc.if_test((c0, 1)):\n",
        "    qc.x(q0)\n",
        "qc.measure(q0, c0)\n",
        "\n",
        "\n",
        "# Convert to an ISA circuit for the given backend\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
        "isa_circuit = pm.run(qc)\n",
        "\n",
        "# Generate samplers for backend targets\n",
        "sampler = SamplerV2(backend)\n",
        "\n",
        "# Submit jobs\n",
        "sampler_job = sampler.run([isa_circuit])\n",
        "result = sampler_job.result()\n",
        "\n",
        "print(\n",
        "    f\">>> {' Job ID:':<10}  {sampler_job.job_id()} ({sampler_job.status()})\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c5b14dcf-edf4-4fef-bb49-e6b86f06afb0",
      "metadata": {},
      "source": [
        "<span id=\"qiskit-runtime-limitations\" />\n",
        "\n",
        "## Qiskit Runtime limitações\n",
        "\n",
        "Esteja ciente das seguintes restrições ao executar circuitos dinâmicos no `Qiskit Runtime`.\n",
        "\n",
        "* Devido à memória física limitada dos componentes eletrônicos de controle, há também um limite para o número de `if` instruções e o tamanho de seus operandos. Esse limite depende do número de transmissões e do número de bits transmitidos em um trabalho (não em um circuito).\n",
        "\n",
        "  Ao processar uma `if` condição, os dados de medição precisam ser transferidos para a lógica de controle a fim de realizar essa avaliação. Uma transmissão é uma transferência de dados clássicos únicos, e os bits transmitidos correspondem ao número de bits clássicos que estão sendo transferidos. Considere o seguinte:\n",
        "\n",
        "  ```python\n",
        "  c0 = ClassicalRegister(3)\n",
        "  c1 = ClassicalRegister(5)\n",
        "  ...\n",
        "  with circuit.if_test((c0, 1)) ...\n",
        "  with circuit.if_test((c0, 3)) ...\n",
        "  with circuit.if_test((c1[2], 1)) ...\n",
        "  ```\n",
        "\n",
        "  No exemplo de código anterior, os dois primeiros `if_test` objetos em `c0` são considerados uma única transmissão, pois o conteúdo de não `c0` sofreu alterações e, portanto, não precisa ser retransmitido. A transmissão `if_test` em questão `c1` é uma segunda transmissão. O primeiro transmite os três bits, `c0` e o segundo transmite apenas um bit, totalizando quatro bits transmitidos.\n",
        "\n",
        "  Atualmente, se você transmitir 60 bits por vez, o trabalho poderá ter aproximadamente 300 transmissões. No entanto, se você transmitir apenas um bit de cada vez, a tarefa poderá ter 2.400 transmissões.\n",
        "\n",
        "* O operando utilizado em uma `if_test` instrução deve ter 32 bits ou menos. Portanto, se você estiver comparando um inteiro `ClassicalRegister`, o tamanho desse inteiro `ClassicalRegister` deve ser de 32 bits ou menos. No entanto, se você estiver comparando apenas um único bit de um `ClassicalRegister`, esse `ClassicalRegister` pode ter qualquer tamanho (já que o operando é de apenas um bit).\n",
        "\n",
        "  Por exemplo, o bloco de código \"Não válido\" não funciona porque `cr` tem mais de 32 bits.  No entanto, você pode usar um registro clássico com mais de 32 bits se estiver testando apenas um bit, conforme mostrado no bloco de código \"Válido\".\n",
        "\n",
        "  <Tabs>\n",
        "    <TabItem value=\"Not valid\" label=\"Not valid\">\n",
        "      ```python\n",
        "         cr = ClassicalRegister(50)\n",
        "         qr = QuantumRegister(50)\n",
        "         circuit = QuantumCircuit(qr, cr)\n",
        "         ...\n",
        "         circ.measure(qr, cr)\n",
        "         with circ.if_test((cr, 15)):\n",
        "            ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "\n",
        "    <TabItem value=\"Valid\" label=\"Valid\">\n",
        "      ```python\n",
        "         cr = ClassicalRegister(50)\n",
        "         qr = QuantumRegister(50)\n",
        "         circuit = QuantumCircuit(qr, cr)\n",
        "         ...\n",
        "         circ.measure(qr, cr)\n",
        "         with circ.if_test((cr[5], 1)):\n",
        "            ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "  </Tabs>\n",
        "\n",
        "* Não são permitidas condições aninhadas. Por exemplo, o bloco de código a seguir não funcionará porque contém um `if_test` dentro de outro `if_test`:\n",
        "\n",
        "  <Tabs>\n",
        "    <TabItem value=\"Not valid\" label=\"Not valid\">\n",
        "      ```python\n",
        "         c1 = ClassicalRegister(1, \"c1\")\n",
        "         c2 = ClassicalRegister(2, \"c2\")\n",
        "         ...\n",
        "         with circ.if_test((c1, 1)):\n",
        "          with circ.if_test(c2, 1)):\n",
        "           ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "\n",
        "    <TabItem value=\"Valid\" label=\"Valid\">\n",
        "      ```python\n",
        "      cr = ClassicalRegister(2)\n",
        "      ...\n",
        "      with circuit.if_test((cr, 0b11)):\n",
        "        ...\n",
        "      ```\n",
        "    </TabItem>\n",
        "  </Tabs>\n",
        "\n",
        "* Não é permitido incluir `reset` ou medidas dentro de expressões condicionais.\n",
        "\n",
        "* As operações aritméticas não são suportadas.\n",
        "\n",
        "* Consulte a [tabela de recursos do `OpenQASM` 3](/docs/guides/qasm-feature-table) para determinar quais recursos do `OpenQASM` 3 são compatíveis com o Qiskit e o `Qiskit Runtime`.\n",
        "\n",
        "* Quando se utiliza ` OpenQASM 3` (em vez de `QuantumCircuit`) como formato de entrada para passar circuitos para as primitivas d Qiskit Runtime, apenas são suportadas as instruções que podem ser carregadas no Qiskit. As operações clássicas, por exemplo, não são compatíveis, pois não podem ser carregadas no Qiskit. Consulte [Importar um programa do `OpenQASM` 3 para o Qiskit](/docs/guides/interoperate-qiskit-qasm3#import-an-openqasm-3-program-into-qiskit) para obter mais informações.\n",
        "\n",
        "* As `for`instruções `switch` , `while`, e não são suportadas.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ca6e0493-d364-40bf-9f47-2e3feed9f82c",
      "metadata": {},
      "source": [
        "<span id=\"use-dynamic-circuits-with-estimator\" />\n",
        "\n",
        "## Use circuitos dinâmicos com o Estimator\n",
        "\n",
        "Como o Estimator não suporta circuitos dinâmicos, você pode usar [o Sampler](/docs/guides/get-started-with-sampler) e criar seus próprios circuitos de medição.\n",
        "\n",
        "Para reproduzir o comportamento do Estimator, siga este procedimento:\n",
        "\n",
        "1. Agrupe os termos de todas as variáveis observáveis em uma partição.  Isso pode ser feito usando o [`PauliList` API](/docs/api/qiskit/qiskit.quantum_info.PauliList#group_qubit_wise_commuting), por exemplo.\n",
        "   <Admonition type=\"note\">\n",
        "     Você pode usar o [`BitArray`](/docs/en/api/qiskit/qiskit.primitives.BitArray#expectation_values) atributo `primitive` para calcular os valores esperados das observáveis fornecidas.\n",
        "   </Admonition>\n",
        "2. Execute um circuito de mudança de base por partição (conforme a mudança de base necessária para cada partição). Consulte o [módulo `measurement_bases`](https://qiskit.github.io/qiskit-addon-utils/apidocs/qiskit_addon_utils.exp_vals.html#qiskit_addon_utils.exp_vals.get_measurement_bases) utilitário complementar “Bases de medição” para obter mais informações. Para obter mais informações, consulte a [documentação](https://qiskit.github.io/qiskit-addon-utils/) do pacote de utilitários do complemento Qiskit.\n",
        "3. Some os resultados de cada partição.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "07045397-6db8-4151-a1e4-de24a8f39ab6",
      "metadata": {},
      "source": [
        "<span id=\"restrictions\" />\n",
        "\n",
        "## Restrições\n",
        "\n",
        "Consulte qualquer [tabela de compatibilidade de recursos](/docs/guides/estimator-options#options-compatibility-table) para entender as restrições ao usar circuitos dinâmicos. Observe que a compatibilidade dos recursos não depende das primitivas.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6688e2e3-766b-4194-99db-ae097e9b8bc7",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Próximas etapas\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendações\">\n",
        "  * Saiba como implementar um desacoplamento dinâmico preciso usando [o stretch](/docs/guides/stretch).\n",
        "  * Consulte o guia [clássico sobre alimentação direta e fluxo de controle](/docs/guides/classical-feedforward-and-control-flow).\n",
        "  * Use [a visualização do cronograma do circuito](/docs/guides/qiskit-runtime-circuit-timing) para depurar e otimizar seus circuitos dinâmicos.\n",
        "  * Nem todas as funções são compatíveis com circuitos dinâmicos. Consulte a seção de compatibilidade de recursos do [Sampler](/docs/guides/sampler-options#feature-compatibility) para obter mais detalhes.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}