Exercício: Criar diferentes estados de superposição com Q#

Concluído

Nas unidades anteriores, você aprendeu sobre a superposição e a notação Dirac. Chega de teoria por enquanto! Vamos explorar a superposição em Q# escrevendo algum código.

Nesta unidade, você criará uma superposição quântica e a se aprofundar nas probabilidades com Q# utilizando a função DumpMachine. A função DumpMachine exibe informações sobre o estado atual do sistema quântico no ponto em que é chamado.

Crie um novo arquivo em Q#

  1. Abra o Visual Studio Code.
  2. No Visual Studio Code, selecione Arquivo > Novo Arquivo de Texto e salve o arquivo como Main.q.
  3. Selecione Exibir -> Paleta de Comandos e digite Q#: Defina o perfil de destino do QIR do Azure Quantum. Pressione Enter.
  4. Selecione Q#: Sem restrições.

Introdução à superposição

Vamos começar com um programa simples que gera um bit aleatório usando um qubit na superposição. Você usará a função DumpMachine para ver o estado do qubit em diferentes pontos do programa.

  1. Adicione o seguinte código ao arquivo Main.qs:

    import Microsoft.Quantum.Diagnostics.*;
    
    operation Main() : Result {
        use q = Qubit();
        Message("Initialized qubit:");
        DumpMachine(); // First dump
        Message(" ");
        H(q);
        Message("Qubit after applying H:");
        DumpMachine(); // Second dump
        Message(" ");
        let randomBit = M(q);
        Message("Qubit after the measurement:");
        DumpMachine(); // Third dump
        Message(" ");
        Reset(q);
        Message("Qubit after resetting:");
        DumpMachine(); // Fourth dump
        Message(" ");
        return randomBit;
    }
    

    Aqui, você chama DumpMachine quatro vezes:

    • Depois que o qubit é alocado.
    • Depois de colocar o qubit em superposição.
    • Depois de medir o estado do qubit.
    • Depois de redefinir o qubit.

    Você divide a operação MResetZ em duas operações: M e Reset. Você faz isso para inspecionar o estado após a medição.

  2. Para executar seu programa no simulador interno, selecione Executar acima da operação Main ou pressione Ctrl+F5. A saída será exibida no console de depuração.

  3. A função DumpMachine cria uma tabela de informações que descreve o estado do registro de qubit. Ela fornece especificamente a amplitude de probabilidade, a probabilidade e a fase em radianos para cada estado de base.

  4. No final do programa, você deve obter o resultado Zero ou One. Vamos examinar cada etapa.

    1. Qubit inicializado: Cada qubit que é alocado com a instrução use começa no estado $|0\rangle$. Portanto, DumpMachine produz as informações que correspondem a um registro de qubit único no estado $|0\rangle$.

      Initialized qubit:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |0⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
    2. Qubit após aplicar H: Depois da aplicação de H, preparamos o qubit no estado de superposição $|\psi\rangle=\frac1{\sqrt2} |0\rangle + \frac1{\sqrt2} |1\rangle$.

      Qubit after applying H:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |0⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
         |1⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
      
    3. Qubit após a medida: Depois de medirmos e armazenarmos o resultado, que pode ser um Zero ou One. Por exemplo, se o estado resultante for One, o estado dos registros será recolhido para $|1\rangle$ e não ficará mais em superposição.

      Qubit after the measurement:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |1⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
    4. Qubit após a redefinição: A operação Reset redefine o qubit para o estado $|0\rangle$. Lembre-se de que, em qualquer operação Q#, você sempre precisará deixar os qubits usados no estado $|0\rangle$ para que outras operações possam usá-lo.

      Qubit after resetting:
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
         |0⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      

    Observação

    Suas saídas podem ser diferentes porque o gerador de número aleatório é probabilístico. As probabilidades dos resultados não são determinísticas.

Explorar outros tipos de estados de superposição

Agora que você sabe como inspecionar o estado de um registro, pode visualizar mais operações que modificam o estado dos qubits e colocá-las em uma superposição.

O gerador de número aleatório atual produz Zero ou One com 50% de probabilidade. Vejamos um segundo exemplo que gera números aleatórios com uma probabilidade diferente.

Gerador de bit aleatório distorcido

Suponha que você queira criar um gerador de bits aleatório que seja distorcido, ou seja, a probabilidade de obter Zero é diferente da probabilidade de obter One.

Por exemplo, você deseja o resultado Zero com probabilidade $P$ e o resultado One com probabilidade $1-P$. Aqui está um estado de qubit válido que produz um gerador de bits aleatório:

$$|\psi\rangle=\sqrt{P}|0\rangle+\sqrt{1-P}|1\rangle$$

Aqui, $\alpha=\sqrt{P}$ e $\beta=\sqrt{1-P}$ são as amplitudes dos estados de base $|0\rangle$ e $|1\rangle$, respectivamente.

É possível obter esse estado por meio da aplicação sequencial do operador $R_y(2\arccos\sqrt{P})$ a um qubit no estado $|0\rangle.$. Você pode conseguir esse resultado no Q# usando a operação Ry da Biblioteca padrão.

Dica

Para saber mais sobre a matemática por trás de operações de qubit único, confira o tutorial sobre portas de Qubit Único no Quantum Katas.

  1. Modifique Main.qs como no seguinte exemplo e salve o arquivo. Este exemplo escolhe $\alpha$ para ser cerca de $\frac13$.

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Math.*;
    
    operation Main() : Result {
        use q = Qubit();
        let P = 0.333333; // P is 1/3
        Ry(2.0 * ArcCos(Sqrt(P)), q);
        Message("The qubit is in the desired state.");
        Message("");
        DumpMachine(); // Dump the state of the qubit 
        Message("");
        Message("Your skewed random bit is:");
        let skewedrandomBit = M(q);
        Reset(q);
        return skewedrandomBit;
    }
    
  2. Para executar seu programa no simulador interno, selecione Executar acima da operação Main ou pressione Ctrl+F5. A saída será exibida no console de depuração.

  3. Você pode ver como DumpMachine exibe o estado esperado depois de aplicar as operações e mostra as probabilidades associadas. Observe que a probabilidade de obter Zero é de cerca de 33,33%, e a probabilidade de obter One é de cerca de 66,67%. Assim, o gerador de bits aleatório é distorcido.

    The qubit is in the desired state.
    
    DumpMachine:
    
     Basis | Amplitude      | Probability | Phase
     -----------------------------------------------
       |0⟩ |  0.5773+0.0000𝑖 |    33.3333% |   0.0000
       |1⟩ |  0.8165+0.0000𝑖 |    66.6667% |   0.0000
    
    
    Your skewed random bit is:
    Result: "One"
    

    Observação

    Sua saída pode ser diferente porque o gerador de número aleatório é probabilístico. As probabilidades dos resultados não são determinísticas.

Superposição de vários qubits

Agora, vamos explorar as superposições de um registro que inclui vários qubits. Por exemplo, se o seu registro consistir em três qubits, você terá oito estados de base:

$$|000\rangle,|001\rangle,|010\rangle,|011\rangle,|100\rangle,|101\rangle, |110\rangle,|111\rangle $$

Portanto, você pode expressar um estado arbitrário de três qubits como:

$$|\psi\rangle=\alpha_0|000\rangle+\alpha_1|001\rangle+\alpha_2|010\rangle+\alpha_3|011\rangle+\alpha_4|100\rangle+\alpha_5|101\rangle+\alpha_6 |110\rangle+\alpha_7|111\rangle$$

Aqui, $\alpha_i$ são números complexos que atendem a $\sum|\alpha_i|^2=1$.

Por exemplo, você pode colocar qubits em uma superposição uniforme aplicando H a cada um deles. Você pode usar essa superposição uniforme para criar uma versão diferente do gerador de número quântico aleatório que gera números de três bits medindo três qubits na superposição em vez de medir um qubit três vezes.

Base Número
$\ket{000}$ 0
$\ket{001}$ 1
$\ket{010}$ 2
$\ket{011}$ 3
$\ket{100}$ 4
$\ket{101}$ 5
$\ket{110}$ 6
$\ket{111}$ 7
  1. Modifique Main.qs como no seguinte exemplo e salve o arquivo.

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Math.*;
    import Microsoft.Quantum.Convert.*;
    import Microsoft.Quantum.Arrays.*;
    
    operation Main() : Int {
        use qubits = Qubit[3];
        ApplyToEach(H, qubits);
        Message("The qubit register in a uniform superposition: ");
        DumpMachine();
        let result = ForEach(M, qubits);
        Message("Measuring the qubits collapses the superposition to a basis state.");
        DumpMachine();
        ResetAll(qubits);
        return BoolArrayAsInt(ResultArrayAsBoolArray(result));
    }
    

    Aqui, você verá três conceitos:

    • A variável qubits agora representa uma matriz de Qubit que tem um comprimento igual a três.
    • As operações ApplyToEach e ForEach são úteis para medir e agir em vários qubits e usam menos códigos. As bibliotecas do Q# oferecem muitos tipos de operações e funções que tornam mais eficiente escrever programas quânticos.
    • As funções BoolArrayAsInt e ResultArrayAsBoolArray da biblioteca Microsoft.Quantum.Convert transformam a matriz binária Result que é retornada por ForEach(M, qubits) em um número inteiro.
  2. Para executar o programa, selecione Executar acima da operação Main ou pressione Ctrl+F5. A saída será exibida no console de depuração.

  3. Ao usar DumpMachine, você verá como o ato de medir os três qubits recolhe o estado do registro para um dos oito estados de base possíveis. Por exemplo, se você receber o resultado 3, isso significa que o estado do registro caiu para $|110\rangle$.

    The qubit register in a uniform superposition:
    
    DumpMachine:
    
     Basis | Amplitude      | Probability | Phase
     -----------------------------------------------
     |000⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
     |001⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
     |010⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
     |011⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
     |100⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
     |101⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
     |110⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
     |111⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
    
    Measuring the qubits collapses the superposition to a basis state.
    
    DumpMachine:
    
     Basis | Amplitude      | Probability | Phase
     -----------------------------------------------
     |110⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
    
    Result: "3"
    

    Observação

    Sua saída pode ser diferente porque o gerador de número aleatório é probabilístico. As probabilidades dos resultados não são determinísticas.

  4. A operação ForEach(M, qubit) mede um qubit por vez, recolhendo gradualmente o estado. Você também pode despejar os estados intermediários após cada medição. Para isso, modifique Main.qs como no seguinte exemplo e salve o arquivo.

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Measurement.*;
    import Microsoft.Quantum.Math.*;
    import Microsoft.Quantum.Convert.*;
    
    operation Main() : Int {
        use qubits = Qubit[3];
        ApplyToEach(H, qubits);
        Message("The qubit register in a uniform superposition: ");
        DumpMachine();
        mutable results = [];
        for q in qubits {
            Message(" ");
            set results += [M(q)];
            DumpMachine();
        }
        Message(" ");
        Message("Your random number is: ");
        ResetAll(qubits);
        return BoolArrayAsInt(ResultArrayAsBoolArray(results));
    }
    
  5. Aqui, você usa um loop for para agir sequencialmente em cada qubit. O Q# tem recursos de controle de fluxo clássico, como loops de for e instruções if, que você pode usar para controlar o fluxo do programa.

  6. Para executar o programa, selecione Executarna lista de comandos acima da operação Main ou pressione Ctrl+F5.

  7. Você pode ver como cada medição consecutiva altera o estado quântico e, portanto, as probabilidades de obter cada resultado. Por exemplo, se o resultado for o número cinco, você obterá a saída a seguir. Vamos examinar rapidamente cada etapa:

    1. Preparação do estado: depois de aplicar H a cada qubit do registro, obtemos uma superposição uniforme.

      The qubit register in a uniform superposition: 
      
      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |000⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
       |001⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
       |010⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
       |011⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
       |100⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
       |101⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
       |110⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
       |111⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
      
    2. Primeira medição: nela, o resultado foi One. Portanto, todas as amplitudes dos estados cujo qubit mais à direita é Zero não estão mais presentes. As amplitudes são $|0\rangle=|000\rangle, |2\rangle=|010\rangle, |4\rangle=|100\rangle$ e $|6\rangle=|110\rangle$. As outras amplitudes aumentam para atender à condição de normalização.

      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |001⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
       |011⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
       |101⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
       |111⟩ |  0.5000+0.0000𝑖 |    25.0000% |   0.0000
      
    3. Segunda medição: nela, o resultado foi Zero. Portanto, todas as amplitudes dos estados cujo segundo qubit mais à direita (meio) é One desaparecem. As amplitudes são $|3\rangle=|011\rangle$ e $|7\rangle=|111\rangle$. As outras amplitudes aumentam para atender à condição de normalização.

      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |001⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
       |101⟩ |  0.7071+0.0000𝑖 |    50.0000% |   0.0000
      
    4. Terceira medição: nela, o resultado foi One. Portanto, todas as amplitudes dos estados cujo qubit mais à esquerda é Zero são limpas. O único estado compatível é $|5\rangle=|101\rangle$. Esse estado obtém uma probabilidade de amplitude de $1$.

      DumpMachine:
      
       Basis | Amplitude      | Probability | Phase
       -----------------------------------------------
       |101⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000
      
      
      Your random number is: 
      Result: "5"
      

    Observação

    Sua saída pode ser diferente porque o gerador de número aleatório é probabilístico. As probabilidades dos resultados não são determinísticas.