{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "78090c95-8fea-4731-a74a-515150e4f899",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Algoritmo de Shor\"\n",
        "description: \"Aprenda a usar o algoritmo de Shor para fatorar números compostos.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore checkmark */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "64abf08d-8e69-41f9-b802-8c0fbbc37555",
      "metadata": {},
      "source": [
        "<span id=\"shors-algorithm\" />\n",
        "\n",
        "# Algoritmo de Shor\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c257cbc3-7730-40cc-a240-19e57033d582",
      "metadata": {},
      "source": [
        "Para este módulo Qiskit in Classrooms, os alunos devem ter um ambiente de Python trabalho com os seguintes pacotes instalados:\n",
        "\n",
        "* v2.1.0`qiskit` ou mais recente\n",
        "* v0.40.1`qiskit-ibm-runtime` ou mais recente\n",
        "* v0.17.0`qiskit-aer` ou mais recente\n",
        "* `qiskit.visualization`\n",
        "* `numpy`\n",
        "* `pylatexenc`\n",
        "\n",
        "Para configurar e instalar os pacotes acima, consulte o guia [Instalar o Qiskit](/docs/guides/install-qiskit).\n",
        "Para executar tarefas em computadores quânticos reais, os alunos precisarão criar uma conta IBM Quantum® seguindo as etapas do guia [Configure sua IBM Cloud conta](/docs/guides/cloud-setup).\n",
        "\n",
        "Este módulo foi testado e utilizou três segundos de tempo de QPU. Esta é apenas uma estimativa. O seu uso real pode variar.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "500d10c9-17ca-4787-90e0-4c57bf86c80d",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Uncomment and modify this line as needed to install dependencies\n",
        "#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "72231ac3-5b60-4bcb-a072-0c2ecdd176aa",
      "metadata": {
        "jp-MarkdownHeadingCollapsed": true
      },
      "source": [
        "<span id=\"intro\" />\n",
        "\n",
        "## Introdução\n",
        "\n",
        "No início 1990s, havia um entusiasmo crescente em torno do potencial dos computadores quânticos para resolver problemas que eram difíceis para os computadores clássicos. Alguns cientistas da computação talentosos criaram algoritmos que demonstravam o poder da computação quântica para alguns problemas específicos e artificiais, mas ninguém havia encontrado um único “aplicativo revolucionário” da computação quântica que certamente revolucionaria o campo. Isso até 1994, quando Peter Shor criou o que hoje é chamado de algoritmo de Shor para fatorar números grandes.\n",
        "\n",
        "Era bem sabido na época que encontrar os fatores primos de um número grande era extremamente difícil para um computador clássico. Na verdade, os protocolos de segurança da Internet dependiam dessa dificuldade. Shor encontrou uma maneira de identificar esses fatores de forma exponencialmente mais eficiente, transferindo algumas das etapas mais desafiadoras para um computador quântico teórico futuro.\n",
        "\n",
        "Neste módulo, exploraremos o algoritmo de Shor. Primeiro, vamos contextualizar um pouco mais o algoritmo, formalizando o problema que ele resolve e explicando sua relevância para a segurança cibernética. A seguir, apresentaremos uma introdução à matemática modular e como aplicá-la ao problema da fatoração, mostrando como a fatoração se reduz a outro problema chamado “localização de ordem” Mostraremos como a Transformada de Fourier Quântica e a Estimativa de Fase Quântica, que aprendemos no módulo anterior, entram em ação e como usá-las para resolver o problema de encontrar a ordem.\n",
        "\n",
        "Finalmente, vamos executar o algoritmo de Shor em um computador quântico real! No entanto, tenha em mente que esse algoritmo só será realmente útil quando tivermos um computador quântico grande e tolerante a falhas, o que ainda levará alguns anos. Então, vamos apenas fatorar um número pequeno para demonstrar como o algoritmo funciona.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "22a38013-7bd5-46db-9a44-e89d66c2d06b",
      "metadata": {},
      "source": [
        "<span id=\"the-factoring-problem\" />\n",
        "\n",
        "## O problema da fatoração\n",
        "\n",
        "O objetivo do problema de fatoração é encontrar os fatores primos de um número $N$. Para alguns números $N$, isso é bastante fácil. Por exemplo, se $N$ for par, um de seus fatores primos será 2. Se $N$ é uma potência prima, ou seja, $N=p^k$ para algum número primo $p$, também é bastante fácil encontrar $p$ : basta aproximar a raiz $k^{\\text{th}}$ de $N$ e procurar primos próximos que possam ser $p$.\n",
        "\n",
        "No entanto, os computadores clássicos enfrentam dificuldades quando $N$ é ímpar e *não* é uma potência prima. Este é o caso tratado pelo algoritmo de Shor. O algoritmo encontra dois fatores $p$ e $q$ tais que $N=pq$. Ele pode ser aplicado recursivamente até que todos os fatores sejam primos. Nas próximas seções, veremos como esse problema é abordado.\n",
        "\n",
        "<span id=\"relevance-to-cyber-security\" />\n",
        "\n",
        "### Relevância para a segurança cibernética\n",
        "\n",
        "Muitos esquemas criptográficos foram criados com base no fato de que é difícil fatorar números grandes, incluindo um que é comumente usado hoje em dia, chamado RSA. Na RSA, uma chave pública é criada multiplicando-se dois grandes números primos para obter $N = p\\cdot q$. Em seguida, qualquer pessoa pode usar essa chave pública para criptografar dados. Mas apenas alguém com a chave privada, $p$ e $q$, pode descriptografar esses dados.\n",
        "\n",
        "Se $N$ fosse fácil fatorar, então qualquer pessoa seria capaz de determinar quais são $p$ $q$ e quebrar a criptografia. Mas não é. Este é um problema notoriamente difícil. Na verdade, os fatores primos de um número chamado RSA1024, que tem 1024 dígitos binários e 309 dígitos decimais, ainda não foram encontrados, apesar de um prêmio de US\\$ 100.000 ter sido oferecido para sua fatoração em 1991.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "01a0c5d4-922b-47af-8a8b-d87df8d520b0",
      "metadata": {},
      "source": [
        "<span id=\"shors-solution\" />\n",
        "\n",
        "## Solução de Shor\n",
        "\n",
        "Em 1994, Peter Shor percebeu que um computador quântico poderia fatorar um grande número de forma exponencialmente mais eficiente do que um computador clássico. Sua percepção baseava-se na relação entre esse problema de fatoração e *a aritmética modular*. Vamos fazer uma breve introdução à aritmética modular e, em seguida, veremos como podemos usar isso para fatorar $N$.\n",
        "\n",
        "<span id=\"modular-arithmetic\" />\n",
        "\n",
        "### Aritmética modular\n",
        "\n",
        "A aritmética modular é um sistema de contagem cíclico, o que significa que, embora a contagem comece da maneira usual, com os números inteiros 0, 1, 2, etc., em algum momento, após um período $N$, a contagem recomeça. Vamos ver como isso funciona com um exemplo. Digamos que nosso período seja 5. Então, enquanto estamos contando, onde normalmente chegaríamos a 5, começamos novamente do 0:\n",
        "\n",
        "$0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, ...$\n",
        "\n",
        "Isso ocorre porque, no mundo “” modulo-5, 5 é equivalente a 0. Dizemos que $5\\bmod 5 \\ = 0$. Na verdade, todos os múltiplos de 5 serão equivalentes a $0\\bmod 5$.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Use aritmética modular para resolver o seguinte problema:\n",
        "\n",
        "Você parte em uma longa viagem de trem transcontinental às 8h da manhã. A viagem de trem dura 60 horas. Que horas são quando você chega?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    O período é 24, já que há 24 horas em um dia. Portanto, esse problema pode ser escrito em aritmética modular como:\n",
        "\n",
        "    $(8+60)\\text{mod}(24) = 20$\n",
        "\n",
        "    Então, você chegaria ao seu destino às 20:00, ou 8 da noite.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "<span id=\"$mathbb{z}_n$-and-$mathbb{z}_n^*$\" />\n",
        "\n",
        "#### $\\mathbb{Z}_N$ e $\\mathbb{Z}_N^*$\n",
        "\n",
        "Muitas vezes, é útil introduzir dois conjuntos, $\\mathbb{Z}_N$ e $\\mathbb{Z}_N^*$. $\\mathbb{Z}_N$ é simplesmente o conjunto de números que existem em um mundo “módulo $N$ ”. Por exemplo, quando estávamos contando modulo-5, o conjunto seria $\\mathbb{Z}_5=\\{0,1,2,3,4\\}$. Outro exemplo: $\\mathbb{Z}_{15} = \\{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\\}$. Podemos realizar adição e multiplicação (módulo $N$ ) nos elementos em $\\mathbb{Z}_N$, e o resultado de cada uma dessas operações também é um elemento em $\\mathbb{Z}_N$, tornando $\\mathbb{Z}_N$ um objeto matemático chamado *anel*.\n",
        "\n",
        "Há um subconjunto especial de $\\mathbb{Z}_N$ que é de particular interesse para nós no algoritmo de Shor. Esse é o subconjunto de números em $\\mathbb{Z}_N$ tal que o maior divisor comum entre cada elemento e $N$ é 1, portanto, cada elemento é “coprimo” a $N$. Se considerarmos o conjunto desses números juntamente com a operação de multiplicação modular, isso forma outro objeto matemático, chamado *grupo*. Chamamos esse grupo $\\mathbb{Z}_N^*$ de. Acontece que, com $\\mathbb{Z}_N^*$ (e grupos finitos em geral), se escolhermos qualquer elemento $a \\in \\mathbb{Z}_N^*$ e multiplicarmos repetidamente $a$ por ele mesmo, sempre obteremos o número $1$. O número mínimo de vezes que se deve multiplicar $a$ por ele mesmo para obter $1$ é chamado de **ordem** de $a$. Esse fato será muito importante para nossa discussão sobre como fatorar números abaixo.\n",
        "\n",
        "<span id=\"check-your-understanding-1\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "O que é $\\mathbb{Z}_{15}^*$?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    $\\mathbb{Z}_{15}^* = \\{1,2,4,7,8,11,13,14\\} $\n",
        "\n",
        "    Excluímos os seguintes números:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    3: GCD(3,15)=3 \\\\\n",
        "    5: GCD(5,15)=5 \\\\\n",
        "    6: GCD(6,15)=3 \\\\\n",
        "    9: GCD(9,15)=3 \\\\\n",
        "    10: GCD(10,15)=5 \\\\\n",
        "    12: GCD(12,15)=3 \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Qual é a ordem de cada um dos elementos em $\\mathbb{Z}_{15}^*$?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    A ordem $r$ é o menor número tal que $a^r\\text{mod}(15)=1$ para cada elemento $a$.\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    1^1\\text{mod}(15) = 1, r=1 \\\\\n",
        "    2^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    4^2\\text{mod}(15) = 1, r=2 \\\\\n",
        "    7^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    8^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    11^2\\text{mod}(15) = 1, r=2 \\\\\n",
        "    13^4\\text{mod}(15) = 1, r=4 \\\\\n",
        "    14^2\\text{mod}(15) = 1, r=2 \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Observe que, embora tenhamos conseguido encontrar a ordem dos números em $\\mathbb{Z}_{15}^*$, isso NÃO é uma tarefa fácil em geral, para valores maiores de $N$. Esse é o cerne do problema da fatoração e a razão pela qual precisamos de um computador quântico. Veremos o motivo à medida que avançarmos pelo restante do caderno.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c19d2032-3c40-48ee-823b-607b1ed8b4f0",
      "metadata": {},
      "source": [
        "<span id=\"apply-modular-arithmetic-to-the-factoring-problem\" />\n",
        "\n",
        "### Aplique a aritmética modular ao problema da fatoração\n",
        "\n",
        "A chave para encontrar fatores $p$ e $q$ tais que $N=pq$ se resume a encontrar algum *outro* número inteiro $x$ tal que\n",
        "\n",
        "$x^2 \\equiv 1 \\bmod N$ e $x \\not\\equiv \\pm 1 \\bmod N.$\n",
        "\n",
        "Como é que encontrar nos ajuda $x$ a encontrar os fatores $p$ e $q$? Vamos agora analisar o argumento. Como $x^2 \\equiv 1 \\bmod N$, isso significa que $x^2 - 1 \\equiv 0 \\bmod N $. Em outras palavras, $x^2 - 1$ é um múltiplo de $N$. Portanto, para algum inteiro $l$,\n",
        "\n",
        "$x^2 - 1 = l N$\n",
        "\n",
        "Podemos fatorar $x^2 - 1$ para obter:\n",
        "\n",
        "$(x+1)(x-1) = l N$\n",
        "\n",
        "A partir das nossas suposições iniciais, sabemos que $x \\not\\equiv \\pm 1 \\bmod N$, portanto, $N$ não divide uniformemente nem $x+1$ nem $x-1$. Assim, os dois fatores de $N$, $p$ e, $q$ devem dividir $x-1$ e $x+1$, respectivamente. Ou $p$ é um fator de $x-1$ e $q$ é um fator de $x+1$, ou vice-versa. Portanto, se calcularmos os maiores divisores comuns (MDCs) entre $N$ e ambos $x-1$ e $x+1$, isso nos dará os fatores $p$ e $q$. Calcular o MDC entre dois números é uma tarefa clássica fácil que pode ser realizada, por exemplo, usando [o algoritmo de Euclides](https://en.wikipedia.org/wiki/Euclidean_algorithm).\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Pode ser complicado entender cada etapa da lógica acima, então tente trabalhar com um exemplo. Use $N=15$ e $x=11$. Primeiro, verifique se $x^2 \\equiv 1 \\text{mod}(N)$ e $x \\not\\equiv \\pm 1 \\bmod N$. Em seguida, continue a verificar cada etapa. Por fim, calcule $\\text{GCD}(11\\pm1,15)$ e verifique se eles são os fatores de $15$.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    $11^2 = 121$, que é $15*8 + 1$, portanto $11^2\\bmod 15 = 1$. $\\checkmark$\n",
        "\n",
        "    $ 11 - 1 = 10$, que não é equivalente a $0\\bmod 15$. $\\checkmark$\n",
        "\n",
        "    $ 11 + 1 = 12$, que não é equivalente a $0\\bmod 15$. $\\checkmark$\n",
        "\n",
        "    Agora, sabemos que $(x+1)(x-1) = l N$ para algum número inteiro $l$. Isso é verificado quando inserimos $x$ e $N$ : $(12)(10) = l 15$ quando $l = 8$. $\\checkmark$\n",
        "\n",
        "    Agora, precisamos calcular $\\text{GCD}(12,15)$ e $\\text{GCD}(10,15)$.\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    \\text{GCD}(12,15) = 3 \\\\\n",
        "    \\text{GCD}(10,15) = 5\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Então, encontramos nossos fatores de $15$!\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "<span id=\"the-algorithm\" />\n",
        "\n",
        "### O algoritmo\n",
        "\n",
        "Agora que vimos como encontrar um número inteiro $x$ tal que nos $x^2 \\equiv 1\\bmod N$ ajuda a fatorar $N$, podemos passar pelo algoritmo de Shor. Essencialmente, resume-se a encontrar $x$ :\n",
        "\n",
        "1. **Escolha um número inteiro aleatório**\n",
        "   Escolha um número inteiro aleatório $a$ tal que $1 < a < N$.\n",
        "\n",
        "* Calcule $\\text{GCD}(a, N)$ de forma clássica.\n",
        "  * Se $\\text{GCD}(a, N) > 1$, você já encontrou um fator. Pare.\n",
        "  * Caso contrário, continue.\n",
        "\n",
        "2. **Encontre a ordem $r$ do $a$ módulo**\n",
        "   $N$ Encontre o menor número inteiro positivo $r$ que satisfaz $a^r \\equiv 1 \\pmod N$.\n",
        "\n",
        "3. **Verifique se o pedido está correto**\n",
        "\n",
        "* Se $r$ for ímpar, volte à etapa 1 e escolha um novo $a$.\n",
        "* Se $r$ for par, continue para a etapa 4.\n",
        "\n",
        "4. **Calcular $x = a^{r/2} \\bmod N$**\n",
        "\n",
        "* Verifique se $x \\not\\equiv 1 \\pmod N$ e $x \\not\\equiv -1 \\pmod N$.\n",
        "  * Se $x \\equiv \\pm 1 \\pmod N$, volte à etapa 1 e escolha um novo $a$.\n",
        "* Caso contrário, calcule os gcds para extrair os fatores:\n",
        "\n",
        "$$\n",
        "p = \\text{GCD}(x-1, N), \\quad q = \\text{GCD}(x+1, N)\n",
        "$$\n",
        "\n",
        "Estes serão fatores não triviais de $N$.\n",
        "\n",
        "5. **Fatorar recursivamente, se necessário**\n",
        "\n",
        "* Se $p$ e/ou não $q$ forem primos, aplique o algoritmo recursivamente para fatorá-los completamente.\n",
        "* Quando todos os fatores forem primos, a fatoração estará concluída.\n",
        "\n",
        "Com base nesse procedimento, pode não ser óbvio por que um computador quântico é necessário para realizar essa tarefa. Isso é necessário porque a etapa 2, encontrar a ordem do $a$ módulo $N$, é classicamente um problema muito difícil. A complexidade aumenta exponencialmente com o número $N$. Mas, com um computador quântico, basta usar a Estimativa de Fase Quântica para resolvê-la. O passo 4, encontrar o MDC de dois números inteiros, é na verdade algo bastante fácil de fazer de forma clássica. Portanto, a única etapa que realmente precisa do poder de um computador quântico é a etapa de localização de pedidos. Dizemos que o problema da fatoração “se reduz” ao problema de encontrar a ordem.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "d4771244-0604-4b2e-bd99-a52280456f43",
      "metadata": {},
      "source": [
        "<span id=\"the-hard-part-order-finding\" />\n",
        "\n",
        "### A parte difícil: encontrar o pedido\n",
        "\n",
        "Agora, vamos ver como podemos usar um computador quântico para encontrar resultados. Primeiro, vamos esclarecer o que entendemos por “ordem” É claro que já expliquei o que a ordem significa matematicamente: é o primeiro número inteiro $r$ diferente de zero tal que $a^r = 1 \\pmod N.$ Mas vamos ver se conseguimos entender melhor esse conceito.\n",
        "\n",
        "Para valores suficientemente pequenos $N$, podemos simplesmente determinar a ordem calculando cada potência de $a$, obtendo o módulo $N$ desse número e parando quando encontrarmos a potência $r$ que satisfaz $a^r = 1 \\text{mod}(N)$. Foi isso que fizemos com o nosso exemplo, $N=15$, acima. Vamos dar uma olhada em alguns gráficos dessas potências modulares para alguns valores de amostra de $a$ e $N$ :\n",
        "\n",
        "![Valor de a elevado à potência k módulo N versus a potência k, onde a=2 e N=15. Vemos que, à medida que k aumenta, surge um padrão repetitivo, mostrando que a^k módulo N é periódico em k.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/shors-algorithm/a2n15.avif)\n",
        "\n",
        "![Valor de a elevado à potência k módulo N versus a potência k, onde a=5 e N=21. Vemos que, à medida que k aumenta, surge um padrão repetitivo, mostrando que a^k módulo N é periódico em k.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/shors-algorithm/a5n21.avif)\n",
        "\n",
        "Percebeu alguma coisa? Estas são funções periódicas! E a ordem $r$ é a mesma do período! **Portanto, encontrar a ordem é equivalente a encontrar o período.**\n",
        "\n",
        "Os computadores quânticos são muito adequados para encontrar o período das funções. Para isso, podemos usar uma sub-rotina algorítmica chamada Estimativa de Fase Quântica. Discutimos o QPE e sua relação com a Transformada de Fourier Quântica no módulo anterior. Para uma revisão detalhada, acesse o módulo QFT ou a aula de John Watrous sobre [Estimativa de Fase Quântica](/learning/courses/fundamentals-of-quantum-algorithms/phase-estimation-and-factoring/shor-algorithm) em seu curso Algoritmos Quânticos. Vamos passar agora pelo essencial do procedimento:\n",
        "\n",
        "Na Estimativa de Fase Quântica (QPE), começamos com uma unidade $U$ e um estado próprio dessa unidade $|\\psi\\rangle$. Em seguida, usamos a QPE para aproximar o valor próprio correspondente, que, como o operador é unitário, terá a forma $e^{2\\pi i \\theta}$. Portanto, encontrar o valor próprio é equivalente a encontrar o valor de $\\theta$ na função periódica. O circuito tem a seguinte aparência:\n",
        "\n",
        "![Diagrama do circuito do procedimento de estimativa da fase quântica. Os qubits de controle superiores são preparados em superposições com portas Hadamard, depois portas unitárias controladas são aplicadas aos qubits inferiores, que estão em um estado próprio da unitária. Por fim, uma transformada de Fourier quântica inversa é aplicada aos qubits superiores e eles são medidos.](https://quantum.cloud.ibm.com/learning/images/modules/computer-science/shors-algorithm/QPE.avif)\n",
        "\n",
        "onde o número de qubits de controle (os qubits $m$ superiores na figura acima) determina a precisão da aproximação.\n",
        "\n",
        "No algoritmo de Shor, usamos QPE no operador $M_a$ unitário:\n",
        "\n",
        "$ M_a|y\\rangle \\equiv |ay \\mod N \\rangle .$\n",
        "\n",
        "Aqui, $|y\\rangle$ denota um estado de base computacional do registro multi-qubit, onde o valor binário dos qubits corresponde ao número inteiro $y$. Por exemplo, se $N=15$ e $y = 2$, então $|y\\rangle$ é representado pelo estado de base de quatro $|0010\\rangle$ qubits, uma vez que são necessários quatro qubits para codificar números até 15. (Se este conceito não lhe for familiar, consulte o [módulo introdutório Qiskit nas salas de aula](/learning/modules/quantum-mechanics/get-started-with-qiskit) para uma atualização sobre a codificação binária dos estados quânticos.)\n",
        "\n",
        "Agora, precisamos descobrir um estado próprio dessa unidade. Se começarmos no estado $|1\\rangle$, podemos ver que cada aplicação sucessiva de $U$ multiplicará o estado do nosso registro por $a \\pmod N$, e após $r$ aplicações chegaremos ao estado $|1\\rangle$ novamente. Por exemplo, com $a = 3$ e $N = 35$ :\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "M_3|1\\rangle &= |3\\rangle & \\\\\n",
        "M_3^2|1\\rangle &= |9\\rangle \\\\\n",
        "M_3^3|1\\rangle &= |27\\rangle \\\\\n",
        "& \\vdots \\\\\n",
        "M_3^{(r-1)}|1\\rangle &= |12\\rangle \\\\\n",
        "M_3^r|1\\rangle &= |1\\rangle\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "Portanto, as superposições dos estados neste ciclo ( $|\\psi_j\\rangle$ ) da forma:\n",
        "\n",
        "$|\\psi_j\\rangle = \\tfrac{1}{\\sqrt{r}}\\sum_{k=0}^{r-1}{e^{\\frac{2 \\pi i j k}{r}} |a^k \\rangle} $\n",
        "\n",
        "são todos estados próprios de $M_a$. (Existem mais estados próprios além destes. Mas só nos interessam os que têm a forma acima.)\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Encontre um estado próprio da unidade correspondente a $a=2$ e $N = 15$.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    M_2|1\\rangle &= |2\\rangle & \\\\\n",
        "    M_2^2|1\\rangle &= |4\\rangle \\\\\n",
        "    M_2^3|1\\rangle &= |8\\rangle \\\\\n",
        "    M_2^4|1\\rangle &= |1\\rangle \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Portanto, a ordem $r=4$. Os estados próprios que nos interessam serão uma superposição igual de todos os estados que foram percorridos acima, com várias fases:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    |\\psi_0\\rangle &= \\frac{1}{2}(|1\\rangle+|2\\rangle+|4\\rangle+|8\\rangle) \\\\\n",
        "    |\\psi_1\\rangle &= \\frac{1}{2}(e^{2 \\pi i \\frac{0}{4}}|1\\rangle+e^{2 \\pi i \\frac{1}{4}}|2\\rangle+e^{2 \\pi i \\frac{2}{4}}|4\\rangle+e^{2 \\pi i \\frac{3}{4}}|8\\rangle) \\\\\n",
        "    &= \\frac{1}{2}(|1\\rangle+i|2\\rangle-|4\\rangle-i|8\\rangle) \\\\\n",
        "    |\\psi_2\\rangle &= \\frac{1}{2}(e^{2 \\pi i \\frac{0}{4}}|1\\rangle+e^{2 \\pi i \\frac{2}{4}}|2\\rangle+e^{2 \\pi i \\frac{4}{4}}|4\\rangle+e^{2 \\pi i \\frac{6}{4}}|8\\rangle) \\\\\n",
        "    &= \\frac{1}{2}(|1\\rangle-|2\\rangle+|4\\rangle-|8\\rangle) \\\\\n",
        "    |\\psi_3\\rangle &= \\frac{1}{2}(e^{2 \\pi i \\frac{0}{4}}|1\\rangle+e^{2 \\pi i \\frac{3}{4}}|2\\rangle+e^{2 \\pi i \\frac{6}{4}}|4\\rangle+e^{2 \\pi i \\frac{9}{4}}|8\\rangle) \\\\\n",
        "    &= \\frac{1}{2}(|1\\rangle-i|2\\rangle-|4\\rangle+i|8\\rangle) \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Digamos que conseguimos inicializar nosso estado qubit em um desses estados próprios (spoiler — não conseguimos). Ou, pelo menos, não facilmente. Explicaremos em breve por que e o que podemos fazer em vez disso. Então, poderíamos usar QPE para estimar o valor próprio correspondente, $\\omega_j = e^{2 \\pi i \\theta_j}$ onde $\\theta_j = \\frac{j}{r}$. Assim, poderemos determinar a ordem $r$ pela equação simples:\n",
        "\n",
        "$r = \\frac{j}{\\theta_j}.$\n",
        "\n",
        "Mas lembre-se, eu disse que o QPE *estima*$\\theta_j$ — ele não nos dá um valor exato. Precisamos que a estimativa seja boa o suficiente para diferenciar entre $r$ e $r+1$. Quanto mais qubits de $m$ controle tivermos, melhor será a estimativa. Nos problemas no final da lição, você será solicitado a determinar o mínimo $m$ necessário para fatorar um número $N$.\n",
        "\n",
        "Agora, temos que resolver um problema. Todas as explicações acima sobre como encontrar $r$ começam com a preparação do estado próprio $|\\psi_j\\rangle = \\tfrac{1}{\\sqrt{r}}\\sum_{k=0}^{r-1}{e^{\\frac{2 \\pi i j k}{r}} |a^k \\rangle}$. Mas não sabemos como fazer isso sem já saber o que $r$ é. A lógica é circular. Precisamos de uma maneira de estimar o valor próprio *sem* inicializar o estado próprio.\n",
        "\n",
        "Em vez de começar com um estado próprio de $M_a$, podemos preparar o estado inicial no estado $n$ de -qubit correspondente a $|1\\rangle$ em binário (como em ) $|000...01\\rangle$. Embora esse estado em si não seja obviamente um estado próprio de $M_a$, ele é uma superposição sobre todos os estados próprios $|\\psi_k\\rangle$ :\n",
        "\n",
        "$|1\\rangle = \\frac{1}{\\sqrt{r}} \\sum\\limits_{k=0}^{r-1}{|\\psi_k\\rangle}$\n",
        "\n",
        "<span id=\"check-your-understanding-1\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Verifique se $|1\\rangle$ é equivalente à superposição sobre os estados próprios que você encontrou para $N=15$ e $a=2$ na questão anterior.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Os quatro estados próprios eram:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    |\\psi_0\\rangle &= \\frac{1}{2}(|1\\rangle+|2\\rangle+|4\\rangle+|8\\rangle) \\\\\n",
        "    |\\psi_1\\rangle &= \\frac{1}{2}(|1\\rangle+i|2\\rangle-|4\\rangle-i|8\\rangle) \\\\\n",
        "    |\\psi_2\\rangle &= \\frac{1}{2}(|1\\rangle-|2\\rangle+|4\\rangle-|8\\rangle) \\\\\n",
        "    |\\psi_3\\rangle &= \\frac{1}{2}(|1\\rangle-i|2\\rangle-|4\\rangle+i|8\\rangle) \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Então,\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    \\frac{1}{\\sqrt{r}} \\sum\\limits_{k=0}^{r-1}{|\\psi_k\\rangle} &= \\frac{1}{2}(|\\psi_0\\rangle + |\\psi_1\\rangle + |\\psi_2\\rangle + |\\psi_3\\rangle ) \\\\\n",
        "    &= \\frac{1}{4}(|1\\rangle+|2\\rangle+|4\\rangle+|8\\rangle+|1\\rangle+i|2\\rangle-|4\\rangle-i|8\\rangle+|1\\rangle-|2\\rangle+|4\\rangle-|8\\rangle + |1\\rangle-i|2\\rangle-|4\\rangle+i|8\\rangle) \\\\\n",
        "    &= \\frac{1}{4}(4|1\\rangle) = |1\\rangle\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Como isso nos permite encontrar a ordem $r$? Como o estado inicial é uma superposição sobre todos os estados próprios da forma listada acima, o algoritmo QPE estima simultaneamente cada um dos $\\theta_k$ correspondentes a esses estados próprios. Portanto, a medição dos qubits $m$ de controle no final produzirá uma aproximação do valor $k/r$, onde $k \\in \\{0,1,2,...,r-1\\}$ é um dos valores próprios escolhidos aleatoriamente. Se repetirmos esse circuito algumas vezes e obtivermos algumas amostras com valores diferentes de $k$, poderemos deduzir rapidamente $r$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "099389d1-1370-472c-af29-a642532beff4",
      "metadata": {},
      "source": [
        "<span id=\"implement-in-qiskit\" />\n",
        "\n",
        "## Implementar no Qiskit\n",
        "\n",
        "Como mencionamos anteriormente, nosso hardware ainda não está em condições de processar números enormes como RSA1024. Vamos apenas fatorar um número pequeno para demonstrar como o algoritmo funciona. Para esta demonstração, usaremos uma versão simplificada do código apresentado no [tutorial](/docs/tutorials/shors-algorithm) do algoritmo de Shor. Se desejar mais detalhes, visite o tutorial.\n",
        "\n",
        "Executaremos o algoritmo usando nossa estrutura padrão para resolver problemas quânticos, chamada estrutura de padrões Qiskit. Isso consiste em quatro etapas:\n",
        "\n",
        "1. Mapeando seu problema para um circuito quântico\n",
        "2. Otimize o circuito para ser executado em hardware quântico\n",
        "3. Execute seu circuito no computador quântico\n",
        "4. Pós-processamento das medições\n",
        "\n",
        "<span id=\"1-map\" />\n",
        "\n",
        "### 1. Mapa\n",
        "\n",
        "Vamos fatorar $N=15$, selecionando $a=2$ como nosso inteiro coprimo.\n",
        "\n",
        "Primeiro, precisamos construir o circuito que implementará a unidade de multiplicação modular. $M_a$ Essa é, na verdade, a parte mais complicada de toda a implementação e pode ser muito dispendiosa em termos computacionais, dependendo de como for feita. Para isso, vamos trapacear um pouco: sabemos que estamos começando no estado $|1\\rangle$ e, a partir de uma pergunta anterior,\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "M_2|1\\rangle &= |2\\rangle & \\\\\n",
        "M_2|2\\rangle &= |4\\rangle \\\\\n",
        "M_2|4\\rangle &= |8\\rangle \\\\\n",
        "M_2|8\\rangle &= |1\\rangle \\\\\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "Portanto, construiremos uma unidade que execute as operações corretas nesses quatro estados, mas deixe todos os outros estados inalterados. Isso é trapaça, porque estamos usando nosso conhecimento da ordem de $2\\bmod 15$ para simplificar a unitária. Se estivéssemos realmente tentando fatorar um número cujos fatores nos eram desconhecidos, não seríamos capazes de fazer isso.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Com o seu conhecimento sobre como o $M_2$ operador transforma os estados acima, construa o operador a partir de uma série de portas SWAP, que trocam os estados de dois qubits. (Dica: escrever cada estado $|i\\rangle$ em binário ajudará.)\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Vamos reescrever a ação de $M_2$ nos estados em binário:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    M_2|0001\\rangle &= |0010\\rangle \\\\\n",
        "    M_2|0010\\rangle &= |0100\\rangle \\\\\n",
        "    M_2|0100\\rangle &= |1000\\rangle \\\\\n",
        "    M_2|1000\\rangle &= |0001\\rangle \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Cada uma dessas ações pode ser realizada com uma simples troca (SWAP). $M_2|0001\\rangle$ é obtido trocando-se os estados dos qubits $0$ e $1$. $M_2|0010\\rangle$ é obtido trocando-se os estados dos qubits $1$ e $2$. E assim por diante. Assim, podemos decompor a $M_2$ matriz na seguinte série de portas SWAP:\n",
        "\n",
        "    $$\n",
        "    M_2 = SWAP(0,1)SWAP(1,2)SWAP(2,3)\n",
        "    $$\n",
        "\n",
        "    Lembrando que os operadores atuam da direita para a esquerda, vamos verificar se isso tem o efeito desejado em cada um dos estados:\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    M_2|0001\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|0001\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|0001\\rangle \\\\\n",
        "    &= SWAP(0,1)|0001\\rangle \\\\\n",
        "    &=|0010\\rangle  \\checkmark \\\\\n",
        "    M_2|0010\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|0010\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|0010\\rangle \\\\\n",
        "    &= SWAP(0,1)|0100\\rangle \\\\\n",
        "    &=|0100\\rangle  \\checkmark \\\\\n",
        "    M_2|0100\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|0100\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|1000\\rangle \\\\\n",
        "    &= SWAP(0,1)|1000\\rangle \\\\\n",
        "    &=|1000\\rangle  \\checkmark \\\\\n",
        "    M_2|1000\\rangle &= SWAP(0,1)SWAP(1,2)SWAP(2,3)|1000\\rangle \\\\\n",
        "    &= SWAP(0,1)SWAP(1,2)|0100\\rangle \\\\\n",
        "    &= SWAP(0,1)|0010\\rangle \\\\\n",
        "    &=|0001\\rangle  \\checkmark \\\\\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "Agora podemos codificar o circuito equivalente a esse operador no Qiskit.\n",
        "\n",
        "Primeiro, importamos os pacotes necessários:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "95c8d21b-d2e6-45c3-a2d2-a7288db4171f",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Import necessary packages\n",
        "\n",
        "import numpy as np\n",
        "from fractions import Fraction\n",
        "from math import floor, gcd, log\n",
        "\n",
        "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
        "from qiskit.circuit.library import QFTGate\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.visualization import plot_histogram\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f8d46443-d3d3-4d27-8026-27974f5d6702",
      "metadata": {},
      "source": [
        "Em seguida, criamos o $M_2$ operador:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "1396a7ff-718a-4169-9c63-85ae218b58a4",
      "metadata": {},
      "outputs": [],
      "source": [
        "def M2mod15():\n",
        "    \"\"\"\n",
        "    M2 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 2\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(2, 3)\n",
        "    U.swap(1, 2)\n",
        "    U.swap(0, 1)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "\n",
        "    return U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "e7521fba-fe3e-45bc-b9ce-fe876bddad33",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/e7521fba-fe3e-45bc-b9ce-fe876bddad33-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 31,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the M2 operator\n",
        "M2 = M2mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(4)\n",
        "circ.compose(M2, inplace=True)\n",
        "circ.decompose(reps=2).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6f1e1a5d-bd34-4379-9237-d91ecba9d435",
      "metadata": {},
      "source": [
        "O algoritmo QPE utiliza um portão $U$ controlado. Então, agora que temos um $M_2$ circuito, precisamos torná-lo um circuito $M_2$\\* controlado\\* :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "36d1020c-c0af-4211-bd50-be865d057f75",
      "metadata": {},
      "outputs": [],
      "source": [
        "def controlled_M2mod15():\n",
        "    \"\"\"\n",
        "    Controlled M2 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 2\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(2, 3)\n",
        "    U.swap(1, 2)\n",
        "    U.swap(0, 1)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "    c_U = U.control()\n",
        "\n",
        "    return c_U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "5bf4f10d-5d52-406d-b62d-ad4a8d366c02",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/5bf4f10d-5d52-406d-b62d-ad4a8d366c02-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the controlled-M2 operator\n",
        "controlled_M2 = controlled_M2mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(5)\n",
        "circ.compose(controlled_M2, inplace=True)\n",
        "circ.decompose(reps=1).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fd98c560-530f-424f-b8f8-0f9fe9615c5e",
      "metadata": {},
      "source": [
        "Agora temos nosso portão $U$ controlado. Mas, para executar o algoritmo de Estimativa de Fase Quântica, precisaremos de controlado $U^2$, controlado $U^4$, até controlado $U^{2^{m-1}}$, onde $m$ é o número de qubits usados para estimar a fase. Quanto mais qubits, mais precisa será a estimativa de fase. Usaremos qubits $m=8$ de controle para nosso procedimento de estimativa de fase. Portanto, precisamos de:\n",
        "\n",
        "$$\n",
        "M_{a^{2^k}}|y\\rangle \\equiv |a^{2^k} y \\bmod N \\rangle\n",
        "$$\n",
        "\n",
        "onde o índice $k$, com $0 \\le k \\le m-1 = 7$, corresponde ao qubit de controle. Agora vamos calcular $a^{2^k}\\bmod N $ para cada valor de $k$ :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "1463f000-c7ab-4e09-b111-5cb3d279e06b",
      "metadata": {},
      "outputs": [],
      "source": [
        "def a2kmodN(a, k, N):\n",
        "    \"\"\"Compute a^{2^k} (mod N) by repeated squaring\"\"\"\n",
        "    for _ in range(k):\n",
        "        a = int(np.mod(a**2, N))\n",
        "    return a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "ac0f44f1-e5fa-46b8-a1d2-5255ed63e3b9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[2, 4, 1, 1, 1, 1, 1, 1]\n"
          ]
        }
      ],
      "source": [
        "k_list = range(8)\n",
        "b_list = [a2kmodN(2, k, 15) for k in k_list]\n",
        "\n",
        "print(b_list)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a2654cb9-a2ad-4947-8441-a1e2799501b8",
      "metadata": {},
      "source": [
        "Como $a^{2^k} \\bmod N = 1$ para $k \\ge 2$, todos os operadores correspondentes ( $M_8$ e acima) são equivalentes à identidade. Portanto, só precisamos construir mais uma matriz, $M_4.$\n",
        "\n",
        "**Observação:** essa simplificação só funciona aqui porque a ordem de $2 \\bmod 15 $ é $4$. Uma vez que $k=2$ (portanto, $2^k = 4$ ), cada potência subsequente do operador é a identidade. Em geral, para números maiores $N$ ou diferentes escolhas de $a$, você não pode pular a construção das potências mais altas. Essa é uma das razões pelas quais isso é considerado um *exemplo simplificado* : os números pequenos permitem atalhos que não funcionariam em casos maiores.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "29bc2fb5-511d-4593-8c48-7b1c7c7eeed0",
      "metadata": {},
      "outputs": [],
      "source": [
        "def M4mod15():\n",
        "    \"\"\"\n",
        "    M4 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 4\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(1, 3)\n",
        "    U.swap(0, 2)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "\n",
        "    return U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "id": "ea4fc641-e97c-400d-a761-5f67a0b7d65e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/ea4fc641-e97c-400d-a761-5f67a0b7d65e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 37,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the M4 operator\n",
        "M4 = M4mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(4)\n",
        "circ.compose(M4, inplace=True)\n",
        "circ.decompose(reps=2).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f6712a0c-a695-4c1d-a99a-a9fd67a95c92",
      "metadata": {},
      "source": [
        "E, como antes, tornamos isso um operador $M_4$\\* controlado\\* :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "id": "c8ec99c7-5e03-4623-b6f7-22dae558de04",
      "metadata": {},
      "outputs": [],
      "source": [
        "def controlled_M4mod15():\n",
        "    \"\"\"\n",
        "    Controlled M4 (mod 15)\n",
        "    \"\"\"\n",
        "    b = 4\n",
        "    U = QuantumCircuit(4)\n",
        "\n",
        "    U.swap(1, 3)\n",
        "    U.swap(0, 2)\n",
        "\n",
        "    U = U.to_gate()\n",
        "    U.name = f\"M_{b}\"\n",
        "    c_U = U.control()\n",
        "\n",
        "    return c_U"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "id": "37caf888-276e-4f19-a0d0-59517c5ee44e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/37caf888-276e-4f19-a0d0-59517c5ee44e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 39,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the controlled-M4 operator\n",
        "controlled_M4 = controlled_M4mod15()\n",
        "\n",
        "# Add it to a circuit and plot\n",
        "circ = QuantumCircuit(5)\n",
        "circ.compose(controlled_M4, inplace=True)\n",
        "circ.decompose(reps=1).draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "db3f989d-ef17-48af-99c6-aae08eb59001",
      "metadata": {},
      "source": [
        "Agora, podemos juntar tudo para encontrar a ordem de $2\\bmod 15$ com um circuito quântico, usando estimativa de fase:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 48,
      "id": "d1b111c8-1a12-420b-bbc2-4ecdd1ac5a97",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/d1b111c8-1a12-420b-bbc2-4ecdd1ac5a97-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 48,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Order finding problem for N = 15 with a = 2\n",
        "N = 15\n",
        "a = 2\n",
        "\n",
        "# Number of qubits\n",
        "num_target = floor(log(N - 1, 2)) + 1  # for modular exponentiation operators\n",
        "num_control = 2 * num_target  # for enough precision of estimation\n",
        "\n",
        "# List of M_b operators in order\n",
        "k_list = range(num_control)\n",
        "b_list = [a2kmodN(2, k, 15) for k in k_list]\n",
        "\n",
        "# Initialize the circuit\n",
        "control = QuantumRegister(num_control, name=\"C\")\n",
        "target = QuantumRegister(num_target, name=\"T\")\n",
        "output = ClassicalRegister(num_control, name=\"out\")\n",
        "circuit = QuantumCircuit(control, target, output)\n",
        "\n",
        "# Initialize the target register to the state |1>\n",
        "circuit.x(num_control)\n",
        "\n",
        "# Add the Hadamard gates and controlled versions of the\n",
        "# multiplication gates\n",
        "for k, qubit in enumerate(control):\n",
        "    circuit.h(k)\n",
        "    b = b_list[k]\n",
        "    if b == 2:\n",
        "        circuit.compose(\n",
        "            M2mod15().control(), qubits=[qubit] + list(target), inplace=True\n",
        "        )\n",
        "    elif b == 4:\n",
        "        circuit.compose(\n",
        "            M4mod15().control(), qubits=[qubit] + list(target), inplace=True\n",
        "        )\n",
        "    else:\n",
        "        continue  # M1 is the identity operator\n",
        "\n",
        "# Apply the inverse QFT to the control register\n",
        "circuit.compose(QFTGate(num_control).inverse(), qubits=control, inplace=True)\n",
        "\n",
        "# Measure the control register\n",
        "circuit.measure(control, output)\n",
        "\n",
        "circuit.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b3659616-39b4-4544-8def-54012b40dbfa",
      "metadata": {},
      "source": [
        "<span id=\"2-optimize\" />\n",
        "\n",
        "### 2. Otimizar\n",
        "\n",
        "Agora que mapeamos nosso circuito, o próximo passo é otimizá-lo para ser executado em um computador quântico específico. Primeiro, precisamos carregar o backend.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 49,
      "id": "92b92fd3-0dca-43db-a304-0a933f293d8f",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "\n",
        "backend = service.backend(\"ibm_marrakesh\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4e27bee-66de-4ffc-b1e3-40a458840e7a",
      "metadata": {},
      "source": [
        "Se você não tiver tempo disponível em sua conta ou quiser usar um simulador por qualquer motivo, execute a célula abaixo para configurar um simulador que imitará o dispositivo quântico que selecionamos acima:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 50,
      "id": "4aa86bd6-1240-49cb-aad0-c3dbc64602c5",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2q-depth: 188\n",
            "2q-size: 281\n",
            "Operator counts: OrderedDict({'sx': 548, 'rz': 380, 'cz': 281, 'measure': 8, 'x': 6})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/4aa86bd6-1240-49cb-aad0-c3dbc64602c5-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 50,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(optimization_level=2, backend=backend)\n",
        "\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "print(f\"2q-depth: {transpiled_circuit.depth(lambda x: x.operation.num_qubits==2)}\")\n",
        "print(f\"2q-size: {transpiled_circuit.size(lambda x: x.operation.num_qubits==2)}\")\n",
        "print(f\"Operator counts: {transpiled_circuit.count_ops()}\")\n",
        "transpiled_circuit.draw(output=\"mpl\", fold=-1, style=\"clifford\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b0425c46-2f2e-436f-9d37-a29fbc3a0006",
      "metadata": {},
      "source": [
        "<span id=\"3-execute\" />\n",
        "\n",
        "### 3. Executar\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 51,
      "id": "6ee53841-d7e0-4a23-a3eb-bed31465374f",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Sampler primitive to obtain the probability distribution\n",
        "sampler = Sampler(backend)\n",
        "\n",
        "# Turn on dynamical decoupling with sequence XpXm\n",
        "sampler.options.dynamical_decoupling.enable = True\n",
        "sampler.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "# Enable gate twirling\n",
        "sampler.options.twirling.enable_gates = True\n",
        "\n",
        "pub = transpiled_circuit\n",
        "job = sampler.run([pub], shots=1024)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 52,
      "id": "7fb6178e-76bd-4067-9607-1d7e0ac051f3",
      "metadata": {},
      "outputs": [],
      "source": [
        "result = job.result()[0]\n",
        "counts = result.data[\"out\"].get_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 53,
      "id": "6744e165-6929-46c6-9cad-55e78fe21f07",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/shors-algorithm/extracted-outputs/6744e165-6929-46c6-9cad-55e78fe21f07-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 53,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plot_histogram(counts, figsize=(35, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2eae47e9-1161-44e5-9e00-7b0d225bcf5f",
      "metadata": {},
      "source": [
        "Observamos quatro picos claros em `00000000`, `01000000`, `10000000` e `11000000`, com algumas contagens em outras cadeias de bits devido ao ruído no computador quântico. Vamos ignorar esses e manter apenas os quatro dominantes, impondo um limite: apenas contagens acima desse limite são consideradas um sinal verdadeiro acima do ruído.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "948f404b-a2a9-4645-a034-31b696ba24b7",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Dictionary of bitstrings and their counts to keep\n",
        "counts_keep = {}\n",
        "# Threshold to filter\n",
        "threshold = np.max(list(counts.values())) / 2\n",
        "\n",
        "for key, value in counts.items():\n",
        "    if value > threshold:\n",
        "        counts_keep[key] = value\n",
        "\n",
        "print(counts_keep)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f9bac651-2d89-4b4e-9930-ea585a4c042e",
      "metadata": {},
      "source": [
        "<span id=\"4-post-process\" />\n",
        "\n",
        "### 4. Pós-processamento\n",
        "\n",
        "No algoritmo de Shor, grande parte do algoritmo é executada de forma clássica. Então, colocaremos o restante na etapa de “pós-processamento”, depois de obtermos nossas medições do computador quântico. Cada uma das medidas acima pode ser convertida em números inteiros que, após dividirmos por $2^m$, são nossas aproximações para $\\frac{k}{r}$, onde $k$ é aleatório a cada vez.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 55,
      "id": "aad78e69-adb8-416f-bc68-c2086f900bef",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "ATTEMPT 0:\n",
            "Phase: theta = 0.0\n",
            "Order of 2 modulo 15 estimated as: r = 1\n",
            "\n",
            "ATTEMPT 1:\n",
            "Phase: theta = 0.75\n",
            "Order of 2 modulo 15 estimated as: r = 4\n",
            "*** Non-trivial factor found: 3 ***\n"
          ]
        }
      ],
      "source": [
        "a = 2\n",
        "N = 15\n",
        "\n",
        "FACTOR_FOUND = False\n",
        "num_attempt = 0\n",
        "\n",
        "while not FACTOR_FOUND:\n",
        "    print(f\"\\nATTEMPT {num_attempt}:\")\n",
        "    # Here, we get the bitstring by iterating over outcomes\n",
        "    # of a previous hardware run with multiple shots.\n",
        "    # Instead, we can also perform a single-shot measurement\n",
        "    # here in the loop.\n",
        "    bitstring = list(counts_keep.keys())[num_attempt]\n",
        "    num_attempt += 1\n",
        "    # Find the phase from measurement\n",
        "    decimal = int(bitstring, 2)\n",
        "    phase = decimal / (2**num_control)  # phase = k / r\n",
        "    print(f\"Phase: theta = {phase}\")\n",
        "\n",
        "    # Guess the order from phase\n",
        "    frac = Fraction(phase).limit_denominator(N)\n",
        "    r = frac.denominator  # order = r\n",
        "    print(f\"Order of {a} modulo {N} estimated as: r = {r}\")\n",
        "\n",
        "    if phase != 0:\n",
        "        # Guesses for factors are gcd(a^{r / 2} ± 1, 15)\n",
        "        if r % 2 == 0:\n",
        "            x = pow(a, r // 2, N) - 1\n",
        "            d = gcd(x, N)\n",
        "            if d > 1:\n",
        "                FACTOR_FOUND = True\n",
        "                print(f\"*** Non-trivial factor found: {x} ***\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c88c65c3-2dfb-47fd-bef9-59f02440f418",
      "metadata": {},
      "source": [
        "<span id=\"conclusion\" />\n",
        "\n",
        "## Conclusão\n",
        "\n",
        "Depois de concluir o módulo, você poderá ficar impressionado com a genialidade de Peter Shor por ter criado um algoritmo tão inteligente. Mas espero que você também tenha alcançado um novo nível de compreensão sobre sua simplicidade enganosa. Embora o algoritmo possa parecer impressionantemente (ou intimidadoramente) complexo, se você o dividir em cada etapa lógica e analisá-lo lentamente, você também será capaz de executar o algoritmo de Shor.\n",
        "\n",
        "Embora ainda estejamos longe de usar esse algoritmo para fatorar números como RSA1024, nossos computadores quânticos estão ficando melhores a cada dia e, assim que um limite chamado *tolerância a falhas* for atingido, algoritmos como esses logo surgirão. É um momento emocionante para aprender sobre computação quântica!\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f1e3bb2-9732-406f-9f17-862178724285",
      "metadata": {},
      "source": [
        "<span id=\"problems\" />\n",
        "\n",
        "## Problemas\n",
        "\n",
        "<span id=\"critical-concepts\" />\n",
        "\n",
        "### Conceitos críticos:\n",
        "\n",
        "* Os sistemas criptográficos modernos dependem da dificuldade clássica de fatorar números inteiros grandes.\n",
        "* A aritmética modular — incluindo as estruturas $\\mathbb{Z}_N$ e $\\mathbb{Z}_N^*$ — fornece a base matemática para o algoritmo de Shor.\n",
        "* O problema de fatorar um número inteiro $N$ pode ser reduzido ao problema de encontrar a ordem de um número módulo $N$.\n",
        "* A localização de ordem quântica utiliza técnicas de estimativa de fase quântica para determinar o período da função $a^x \\mod N$.\n",
        "* O algoritmo de Shor consiste em um fluxo de trabalho híbrido clássico-quântico que seleciona uma base, realiza a localização da ordem quântica e, em seguida, calcula classicamente os fatores a partir do resultado.\n",
        "\n",
        "<span id=\"true/false\" />\n",
        "\n",
        "### Verdadeiro/Falso:\n",
        "\n",
        "1. V/F A eficiência do algoritmo de Shor ameaça a segurança da criptografia RSA.\n",
        "2. V/F O algoritmo de Shor pode ser executado de forma eficiente em qualquer computador quântico moderno.\n",
        "3. V/F O algoritmo de Shor usa a estimativa de fase quântica (QPE) como uma sub-rotina fundamental.\n",
        "4. V/F A parte clássica do algoritmo de Shor envolve o cálculo do maior divisor comum (MDC).\n",
        "5. V/F O algoritmo de Shor só funciona para fatorar números pares.\n",
        "6. V/F Uma execução bem-sucedida do algoritmo de Shor sempre garante os fatores corretos.\n",
        "\n",
        "<span id=\"short-answer\" />\n",
        "\n",
        "### Resposta curta:\n",
        "\n",
        "1. Por que o algoritmo de Shor é considerado uma ameaça potencial futura à criptografia RSA?\n",
        "2. Por que encontrar o período, ou ordem, de uma função exponencial modular é útil para fatorar um número no algoritmo de Shor?\n",
        "\n",
        "<span id=\"challenge-problems\" />\n",
        "\n",
        "### Problemas desafiadores:\n",
        "\n",
        "1. Quantos qubits de controle $m$ precisamos para um determinado número $N$ que estamos tentando fatorar para obter a precisão no QPE necessária para encontrar o valor correto da ordem $r$?\n",
        "\n",
        "2. Seguindo o procedimento que descrevemos aqui para fatorar 15, tente agora fatorar 21.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "in_page_toc_max_heading_level": 2,
    "in_page_toc_min_heading_level": 2,
    "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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}