Partilhar via


Tutorial: Explore o emaranhamento quântico com Q#

Neste tutorial, você escreve um Q# programa que manipula e mede qubits e demonstra os efeitos de sobreposição e emaranhamento. Você prepara dois qubits em um estado quântico específico, aprende a operar em qubits para Q# mudar seu estado e demonstra os efeitos da superposição e do emaranhamento. Você constrói seu Q# programa peça por peça para introduzir estados, operações e medições de qubit.

Aqui estão alguns conceitos-chave para entender antes de começar:

  • Onde os bits clássicos possuem um único valor binário, como 0 ou 1, o estado de um qubit pode estar em uma superposição de dois estados quânticos, 0 e 1. Cada estado quântico possível tem uma amplitude de probabilidade associada.
  • O ato de medir um qubit produz um resultado binário com uma certa probabilidade, e muda o estado do qubit fora da superposição.
  • Vários qubits podem ser emaranhados de tal forma que não podem ser descritos independentemente uns dos outros. Ou seja, o que quer que aconteça com um qubit em um par emaranhado também acontece com o outro qubit.

Neste tutorial, irá aprender a:

  • Crie Q# operações para inicializar um qubit para um estado desejado.
  • Coloque um qubit em superposição.
  • Enredar um par de qubits.
  • Meça um qubit e observe os resultados.

Gorjeta

Se você quiser acelerar sua jornada de computação quântica, confira Código com o Azure Quantum, um recurso exclusivo do site do Azure Quantum. Aqui, você pode executar amostras internas Q# ou seus próprios Q# programas, gerar novo Q# código a partir de seus prompts, abrir e executar seu código no VS Code for the Web com um clique e fazer perguntas ao Copilot sobre computação quântica.

Pré-requisitos

Para executar o exemplo de código no Copilot para Azure Quantum, você precisa:

  • Uma conta de email da Microsoft (MSA).

Para obter mais informações sobre o Copilot, consulte Explore Azure Quantum.

Inicializar um qubit para um estado conhecido

A primeira etapa é definir uma Q# operação que inicializará um qubit para um estado conhecido. Isso pode ser chamado para definir um qubit para um estado clássico, o que significa que, quando medido, ele retorna Zero 100% do tempo ou retorna One 100% do tempo. A medição de um qubit retorna um Q# tipo Result, que só pode ter um valor de Zero ou One.

Abra o Copilot para Azure Quantum e copie o código a seguir na janela do editor de código. Não clique em Executar ainda, você executará o código mais adiante no tutorial.

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }
   }

O exemplo de código apresenta duas operações M padrão e X, que transformam o estado de um qubit.

A SetQubitState operação:

  1. Usa dois parâmetros: um tipo Result, chamado desired, que representa o estado desejado para o qubit estar em (Zero ou One), e um tipo Qubit.
  2. Executa uma operação de medição, M, que mede o estado do qubit (Zero ou One) e compara o resultado com o valor especificado em desired.
  3. Se a medição não corresponder ao valor comparado, ela executa uma X operação, que inverte o estado do qubit para onde as probabilidades de uma medição retornam Zero e One são invertidas. Desta forma, SetQubitState sempre coloca o qubit alvo no estado desejado.

Escrever uma operação de teste para testar o estado Bell

Em seguida, para demonstrar o efeito da SetQubitState operação, crie outra operação chamada TestBellState. Esta operação irá alocar dois qubits, chamar SetQubitState para definir o primeiro qubit para um estado conhecido e, em seguida, medir os qubits para ver os resultados.

Copie o código a seguir na janela do editor de código, abaixo da SetQubitState operação.

operation TestBellState() : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;
    let count = 1000;
    let initial = One;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2);           

        // Count the number of 'Ones' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

    // reset the qubits
    SetQubitState(Zero, q1);             
    SetQubitState(Zero, q2);
    

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

No código, as count variáveis e initial são definidas como 1000 e One respectivamente. Isso inicializa o primeiro qubit e One mede cada qubit 1000 vezes.

A TestBellStateoperação:

  1. Define variáveis para o contador e o estado qubit inicial.
  2. Chama a use instrução para inicializar dois qubits.
  3. Loops para count iterações. Para cada loop,
    1. Chamadas SetQubitState para definir um valor especificado initial no primeiro qubit.
    2. Chama SetQubitState novamente para definir o segundo qubit para um Zero estado.
    3. Usa a M operação para medir cada qubit.
    4. Armazena o número de medidas para cada qubit que retornam One.
  4. Depois que o loop é concluído, ele chama SetQubitState novamente para redefinir os qubits para um estado conhecido (Zero) para permitir que outros aloquem os qubits em um estado conhecido. Esta operação é exigida pela instrução use.
  5. Finalmente, ele usa a Message função para imprimir os resultados nas janelas de saída do Copilot antes de retornar os resultados.

Execute o código no Copilot para Azure Quantum

Antes de passar para os procedimentos de sobreposição e emaranhamento, você pode testar o código até este ponto para ver a inicialização e a medição dos qubits.

Para executar o código como um programa independente, o Q# compilador no Copilot precisa saber onde iniciar o programa. Isso é feito no Q# arquivo adicionando um @EntryPoint() diretamente anterior à operação que você deseja executar primeiro. Por exemplo, neste caso é a TestBellState operação.

Nota

@EntryPoint() só é necessário para programas autónomos Q# . Ao executar um Q# programa no Jupyter Notebooks, ou chamar um Q# programa de um arquivo host Python, ele não é necessário e lançará um erro se incluído.

Adicione o imediatamente antes TestBellState da @EntryPoint() operação e seu Q# programa até este ponto agora deve ter esta aparência:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

    operation SetQubitState(desired : Result, target : Qubit) : Unit {
        if desired != M(target) {
            X(target);
        }
    }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
            
            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Copie e cole o exemplo de código completo na janela de código Copilot for Azure Quantum , defina o slide para o número de capturas como "1" e clique em Executar. Os resultados são exibidos no histograma e nos campos Resultados .

Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0

Como os qubits ainda não foram manipulados, eles mantiveram seus valores iniciais: o primeiro qubit retorna One toda vez e o segundo qubit retorna Zero.

Se você alterar o valor de initial para Zero e executar o programa novamente, você deve observar que o primeiro qubit também retorna Zero toda vez.

Q1 - Zeros: 1000
Q1 - Ones: 0
Q2 - Zeros: 1000
Q2 - Ones: 0

Coloque um qubit em superposição

Atualmente, os qubits no programa estão todos em um estado clássico, ou seja, eles são 1 ou 0. Você sabe disso porque o programa inicializa os qubits para um estado conhecido e você não adicionou nenhum processo para manipulá-los. Antes de enredar os qubits, você colocará o primeiro qubit em um estado de superposição, onde uma medição do qubit retornará Zero ~50% do tempo e One ~50% do tempo. Conceitualmente, o qubit pode ser pensado como tendo uma probabilidade igual de medir um Zero ou One.

Para colocar um qubit em superposição, Q# fornece a Hoperação , ou Hadamard. Lembre-se X da operação de Inicializar um qubit para um procedimento de estado conhecido anteriormente, que inverteu um qubit de 0 para 1 (ou vice-versa), a H operação inverte o qubit no meio do caminho para um estado de probabilidades iguais de Zero ou One. Quando medido, um qubit em superposição deve retornar aproximadamente um número igual de Zero e One resultados.

Modifique o TestBellState código na operação redefinindo o valor inicial e One inserindo uma linha para a H operação:

for test in 1..count {
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        H(q1);                // Add the H operation after initialization and before measurement

        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2); 
        ...

Agora, quando você executa o programa, você pode ver os resultados do primeiro qubit em superposição.

Q1 - Zeros: 523            // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0

Toda vez que você executar o programa, os resultados para o primeiro qubit variarão ligeiramente, mas serão próximos de 50% One e 50%, Zeroenquanto os resultados para o segundo qubit permanecerão Zero o tempo todo.

Q1 - Zeros: 510           
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0

Inicializar o primeiro qubit para Zero retornar resultados semelhantes.

Q1 - Zeros: 504           
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0

Nota

Ao mover o controle deslizante no Copilot para Azure Quantum e aumentar o número de disparos, você pode ver como os resultados da sobreposição variam ligeiramente ao longo da distribuição dos disparos.

Emaranhar dois qubits

Como mencionado anteriormente, qubits emaranhados são conectados de tal forma que não podem ser descritos independentemente uns dos outros. Ou seja, qualquer operação que aconteça com um qubit, também acontece com o qubit emaranhado. Isso permite que você saiba o estado resultante de um qubit sem medi-lo, apenas medindo o estado do outro qubit. (Este exemplo usa dois qubits; no entanto, também é possível emaranhar três ou mais qubits).

Para permitir o emaranhamento, Q# fornece a CNOT operação, que significa Controlled-NOT. O resultado da execução desta operação em dois qubits é inverter o segundo qubit se o primeiro qubit for One.

Adicione a CNOT operação ao seu programa imediatamente após a H operação. Seu programa completo deve ter esta aparência:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = Zero;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
        
            H(q1);            
            CNOT(q1, q2);      // Add the CNOT operation after the H operation

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Agora, quando você executar o programa, você deve ver algo como:

Q1 - Zeros: 502           // results will vary
Q1 - Ones: 498
Q2 - Zeros: 502
Q2 - Ones: 498

Observe que as estatísticas para o primeiro qubit não mudaram (ainda há uma chance de ~50/50 de uma Zero ou uma One medição posterior), mas os resultados da medição para o segundo qubit são sempre os mesmos que a medição do primeiro qubit, não importa quantas vezes você execute o programa. A CNOT operação entrelaçou os dois qubits, de modo que o que quer que aconteça a um deles, aconteça ao outro.

Pré-requisitos

Para desenvolver e executar o exemplo de código em seu ambiente de desenvolvimento local:

Criar um novo Q# ficheiro

  1. Abra o Visual Studio Code e selecione File > New Text File para criar um novo arquivo.
  2. Guarde o ficheiro como CreateBellStates.qs. Este ficheiro irá conter o código para o Q# seu programa.

Inicializar um qubit para um estado conhecido

A primeira etapa é definir uma Q# operação que inicializará um qubit para um estado conhecido. Isso pode ser chamado para definir um qubit para um estado clássico, o que significa que ele retorna Zero 100% do tempo ou retorna One 100% do tempo. Zero e One são Q# valores que representam os dois únicos resultados possíveis de uma medição de um qubit.

Abra CreateBellStates.qs e copie o seguinte código:

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }
   }

O exemplo de código apresenta duas operações M padrão e X, que transformam o estado de um qubit.

A SetQubitState operação:

  1. Usa dois parâmetros: um tipo Result, chamado desired, que representa o estado desejado para o qubit estar em (Zero ou One), e um tipo Qubit.
  2. Executa uma operação de medição, M, que mede o estado do qubit (Zero ou One) e compara o resultado com o valor especificado em desired.
  3. Se a medição não corresponder ao valor comparado, ela executa uma X operação, que inverte o estado do qubit para onde as probabilidades de uma medição retornam Zero e One são invertidas. Desta forma, SetQubitState sempre coloca o qubit alvo no estado desejado.

Escrever uma operação de teste para testar o estado Bell

Em seguida, para demonstrar o efeito da SetQubitState operação, crie outra operação chamada TestBellState. Esta operação irá alocar dois qubits, chamar SetQubitState para definir o primeiro qubit para um estado conhecido e, em seguida, medir os qubits para ver os resultados.

Adicione a seguinte operação ao seu CreateBellStates.qs arquivo após a SetQubitState operação:

operation TestBellState() : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;
    let count = 1000;
    let initial = One;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2);           

        // Count the number of 'Ones' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

    // reset the qubits
    SetQubitState(Zero, q1);             
    SetQubitState(Zero, q2);
    

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

No código, as count variáveis e initial são definidas como 1000 e One respectivamente. Isso inicializa o primeiro qubit e One mede cada qubit 1000 vezes.

A TestBellStateoperação:

  1. Usa dois parâmetros: count, o número de vezes para executar uma medição e initial, o estado desejado para inicializar o qubit.
  2. Chama a use instrução para inicializar dois qubits.
  3. Loops para count iterações. Para cada loop,
    1. Chamadas SetQubitState para definir um valor especificado initial no primeiro qubit.
    2. Chama SetQubitState novamente para definir o segundo qubit para um Zero estado.
    3. Usa a M operação para medir cada qubit.
    4. Armazena o número de medidas para cada qubit que retornam One.
  4. Depois que o loop é concluído, ele chama SetQubitState novamente para redefinir os qubits para um estado conhecido (Zero) para permitir que outros aloquem os qubits em um estado conhecido. Esta operação é exigida pela instrução use.
  5. Finalmente, ele usa a Message função para imprimir uma mensagem para o console antes de retornar os resultados.

Executar o código

Antes de passar para os procedimentos de sobreposição e emaranhamento, teste o código até este ponto para ver a inicialização e medição dos qubits.

Isso é feito no Q# arquivo adicionando um @EntryPoint() diretamente anterior à operação que você deseja executar. Por exemplo, neste caso é a TestBellState operação.

Nota

@EntryPoint() só é necessário para programas autónomos Q# . Ao executar um Q# programa no Jupyter Notebooks, ou chamar um Q# programa de um arquivo host Python, ele não é necessário e lançará um erro se incluído.

  1. O seu CreateBellStates.qs ficheiro deve agora ter o seguinte aspeto:

    namespace Bell {
        open Microsoft.Quantum.Intrinsic;
        open Microsoft.Quantum.Canon;
    
           operation SetQubitState(desired : Result, target : Qubit) : Unit {
               if desired != M(target) {
                   X(target);
               }
           }
    
        @EntryPoint()
        operation TestBellState() : (Int, Int, Int, Int) {
            mutable numOnesQ1 = 0;
            mutable numOnesQ2 = 0;
            let count = 1000;
            let initial = One;
    
            // allocate the qubits
            use (q1, q2) = (Qubit(), Qubit());   
            for test in 1..count {
                SetQubitState(initial, q1);
                SetQubitState(Zero, q2);
    
                // measure each qubit
                let resultQ1 = M(q1);            
                let resultQ2 = M(q2);           
    
                // Count the number of 'Ones' returned:
                if resultQ1 == One {
                    set numOnesQ1 += 1;
                }
                if resultQ2 == One {
                    set numOnesQ2 += 1;
                }
            }
    
            // reset the qubits
            SetQubitState(Zero, q1);             
            SetQubitState(Zero, q2);
    
    
            // Display the times that |0> is returned, and times that |1> is returned
            Message($"Q1 - Zeros: {count - numOnesQ1}");
            Message($"Q1 - Ones: {numOnesQ1}");
            Message($"Q2 - Zeros: {count - numOnesQ2}");
            Message($"Q2 - Ones: {numOnesQ2}");
            return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
    
        }
    }
    
  2. Antes de executar o programa, você precisa definir o perfil de destino como Irrestrito. Selecione Exibir -> Paleta de comandos, procure QIR, selecione Q#: Definir o perfil de destino do Azure Quantum QIR e, em seguida, selecione Q#: irrestrito.

    Nota

    Se o perfil de destino não estiver definido como Sem restrições, você receberá um erro ao executar o programa.

  3. Para executar o programa, selecione Executar arquivo na lista suspensa do ícone de reprodução no canto superior direito, clique em Executar na lista de comandos abaixo @EntryPoint()ou pressione Ctrl+F5. Q# O programa executa a operação ou função marcada com o @EntryPoint() atributo no simulador padrão.

  4. Sua saída aparece no console de depuração.

    Q1 - Zeros: 0
    Q1 - Ones: 1000
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    

    Como os qubits ainda não foram manipulados, eles mantiveram seus valores iniciais: o primeiro qubit retorna One toda vez e o segundo qubit retorna Zero.

  5. Se você alterar o valor de initial para Zero e executar o programa novamente, você deve observar que o primeiro qubit também retorna Zero toda vez.

    Q1 - Zeros: 1000
    Q1 - Ones: 0
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    

Gorjeta

Lembre-se de salvar seu arquivo sempre que introduzir uma alteração no código antes de executá-lo novamente.

Coloque um qubit em superposição

Atualmente, os qubits no programa estão todos em um estado clássico, ou seja, eles são 1 ou 0. Você sabe disso porque o programa inicializa os qubits para um estado conhecido e você não adicionou nenhum processo para manipulá-los. Antes de emaranhar os qubits, você colocará o primeiro qubit em um estado de superposição, onde uma medição do qubit retornará Zero 50% do tempo e One 50% do tempo. Conceitualmente, o qubit pode ser pensado como meio caminho entre o Zero e One.

Para colocar um qubit em superposição, Q# fornece a Hoperação , ou Hadamard. Lembre-se da X operação do procedimento Inicializar um qubit para um estado conhecido anteriormente, que inverteu um qubit de Zero para One (ou vice-versa), a H operação inverte o qubit no meio do caminho para um estado de probabilidades iguais de Zero ou One. Quando medido, um qubit em superposição deve retornar aproximadamente um número igual de Zero e One resultados.

  1. Modifique o código na TestBellState operação para incluir a H operação:

        for test in 1..count {
            use (q1, q2) = (Qubit(), Qubit());   
            for test in 1..count {
                SetQubitState(initial, q1);
                SetQubitState(Zero, q2);
    
                H(q1);                // Add the H operation after initialization and before measurement
    
                // measure each qubit
                let resultQ1 = M(q1);            
                let resultQ2 = M(q2); 
                ...
    
  2. Agora, quando você executa o programa, você pode ver os resultados do primeiro qubit em superposição:

    Q1 - Zeros: 523            // results will vary
    Q1 - Ones: 477
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    
  3. Toda vez que você executar o programa, os resultados para o primeiro qubit variarão ligeiramente, mas serão próximos de 50% One e 50%, Zeroenquanto os resultados para o segundo qubit permanecerão Zero o tempo todo.

    Q1 - Zeros: 510           
    Q1 - Ones: 490
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    
  4. Inicializar o primeiro qubit para Zero retornar resultados semelhantes.

    Q1 - Zeros: 504           
    Q1 - Ones: 496
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    

Emaranhar dois qubits

Como mencionado anteriormente, qubits emaranhados são conectados de tal forma que não podem ser descritos independentemente uns dos outros. Ou seja, qualquer operação que aconteça com um qubit, também acontece com o qubit emaranhado. Isso permite que você saiba o estado resultante de um qubit sem medi-lo, apenas medindo o estado do outro qubit. (Este exemplo usa dois qubits; no entanto, também é possível emaranhar três ou mais qubits).

Para permitir o emaranhamento, Q# fornece a CNOT operação, que significa Controlled-NOT. O resultado da execução desta operação em dois qubits é inverter o segundo qubit se o primeiro qubit for One.

  1. Adicione a CNOT operação ao seu programa imediatamente após a H operação. Seu programa completo deve ter esta aparência:

    namespace Bell {
        open Microsoft.Quantum.Intrinsic;
        open Microsoft.Quantum.Canon;
    
           operation SetQubitState(desired : Result, target : Qubit) : Unit {
               if desired != M(target) {
                   X(target);
               }
           }
    
        @EntryPoint()
        operation TestBellState() : (Int, Int, Int, Int) {
            mutable numOnesQ1 = 0;
            mutable numOnesQ2 = 0;
            let count = 1000;
            let initial = One;
    
            // allocate the qubits
            use (q1, q2) = (Qubit(), Qubit());   
            for test in 1..count {
                SetQubitState(initial, q1);
                SetQubitState(Zero, q2);
    
                H(q1);            
                CNOT(q1, q2);      // Add the CNOT operation after the H operation
    
                // measure each qubit
                let resultQ1 = M(q1);            
                let resultQ2 = M(q2);           
    
                // Count the number of 'Ones' returned:
                if resultQ1 == One {
                    set numOnesQ1 += 1;
                }
                if resultQ2 == One {
                    set numOnesQ2 += 1;
                }
            }
    
            // reset the qubits
            SetQubitState(Zero, q1);             
            SetQubitState(Zero, q2);
    
    
            // Display the times that |0> is returned, and times that |1> is returned
            Message($"Q1 - Zeros: {count - numOnesQ1}");
            Message($"Q1 - Ones: {numOnesQ1}");
            Message($"Q2 - Zeros: {count - numOnesQ2}");
            Message($"Q2 - Ones: {numOnesQ2}");
            return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
    
        }
    }
    
    
    Q1 - Zeros: 502           
    Q1 - Ones: 498       // results will vary
    Q2 - Zeros: 502
    Q2 - Ones: 498
    

As estatísticas para o primeiro qubit não mudaram (uma chance de 50/50 de uma Zero ou uma One medição posterior), mas os resultados da medição para o segundo qubit são sempre os mesmos que a medição do primeiro qubit. A CNOT operação entrelaçou os dois qubits, de modo que o que quer que aconteça a um deles, aconteça ao outro.

Traçar o histograma de frequência

Vamos visualizar a distribuição dos resultados obtidos com a execução do programa quântico várias vezes. O histograma de frequência ajuda a visualizar a distribuição de probabilidade desses resultados.

  1. Selecione View -> Command Palette, ou pressione Ctrl+Shift+P e digite "histograma", que deve exibir a Q#opção : Executar arquivo e mostrar histograma . Você também pode clicar em Histograma na lista de comandos abaixo @EntryPoint(). Selecione esta opção para abrir a janela do Q# histograma.

  2. Insira um número de tiros para executar o programa, por exemplo, 100 tiros e pressione Enter. O histograma será exibido na janela do Q# histograma.

  3. Cada barra no histograma corresponde a um resultado possível, e sua altura representa o número de vezes que o resultado é observado. Neste caso, existem 50 resultados únicos diferentes. Note que para cada resultado os resultados da medição para o primeiro e o segundo qubit são sempre os mesmos.

    Captura de tela da janela de Q# histograma no Visual Studio Code.

    Gorjeta

    Você pode ampliar o histograma usando a roda de rolagem do mouse ou um gesto do trackpad. Quando ampliado, você pode mover o gráfico pressionando 'Alt' enquanto rola.

  4. Clique em uma barra para exibir a porcentagem desse resultado.

  5. Clique no ícone de configurações no canto superior esquerdo para exibir as opções. Você pode exibir os 10 melhores resultados, os 25 melhores resultados ou todos os resultados. Você também pode classificar os resultados de alto para baixo ou baixo para alto.

    Captura de tela da janela de Q# histograma no Visual Studio Code mostrando como exibir configurações.

Explore outros Q# tutoriais:

  • O algoritmo de pesquisa de Grover mostra como escrever um Q# programa que usa o algoritmo de pesquisa de Grover.
  • Quantum Fourier Transform explora como escrever um Q# programa que aborda diretamente qubits específicos.
  • Os Quantum Katas são tutoriais individualizados e exercícios de programação destinados a ensinar os elementos da computação quântica e Q# programação ao mesmo tempo.