Estrutura de um Q# programa

Este artigo explora os componentes gerais que constituem um Q# programa. Tenha em atenção que Q# os programas escritos nos Blocos de Notas do Jupyter não utilizam alguns destes componentes. Estas diferenças são descritas em cada secção.

Considere o seguinte Q# programa:

namespace Superposition {

    @EntryPoint()
    operation MeasureOneQubit() : Result {
        // Allocate a qubit, by default it is in zero state      
        use q = Qubit();  
        // We apply a Hadamard operation H to the state
        // It now has a 50% chance of being measured 0 or 1  
        H(q);      
        // Now we measure the qubit in Z-basis.
        let result = M(q);
        // We reset the qubit before releasing it.
        Reset(q);
        // Finally, we return the result of the measurement.
        return result;
    }
}

Ao ler apenas os comentários (//), pode dizer que este programa atribui um qubit, aplica uma operação para colocá-lo em sobreposição, mede o estado do qubit e, em seguida, repõe-o e devolve o resultado.

Para executar este programa no Visual Studio Code, veja Introdução aos Q# programas e ao VS Code.

Espaços de nomes de utilizador

Q# os programas normalmente começam com um espaço de nomes com o nome de utilizador, como

namespace Superposition {
    // Your code goes here.
}

Os espaços de nomes ajudam-no a organizar as funcionalidades relacionadas. Os espaços de nomes têm o nome de utilizador e só pode haver um namespace por ficheiro qsharp (*.qs).

A Q# biblioteca padrão tem espaços de nomes predefinidos que contêm funções e operações que pode utilizar em programas quânticos. Para obter mais informações, veja Espaços de nomes incorporados.

Os Jupyter Notebooks não utilizam espaços de nomes de utilizador.

EntryPoint()

O @EntryPoint() atributo indica ao Q# compilador onde começar a executar o programa. Em programas com múltiplas definições de função e operação, o @EntryPoint() pode ser colocado antes de qualquer uma das funções ou operações e fluxo de programa começar a partir daí e continuar sequencialmente.

    ...
    @EntryPoint()
    operation MeasureOneQubit() : Result {
        ...

Os Jupyter Notebooks não utilizam pontos de entrada.

O comando %%qsharp

Por predefinição, Q# os programas no Jupyter Notebooks utilizam o kernel do Python ipykernel . Para adicionar Q# código a uma célula do bloco de notas, tem de utilizar o %%qsharp comando, que está ativado com o qsharp pacote Python. Por exemplo, o código de exemplo anterior numa Jupyter Notebook tem o seguinte aspeto:

import qsharp
%%qsharp

    operation MeasureOneQubit() : Result {
        // Allocate a qubit, by default it is in zero state      
        use q = Qubit();  
        // We apply a Hadamard operation H to the state
        // It now has a 50% chance of being measured 0 or 1  
        H(q);      
        // Now we measure the qubit in Z-basis.
        let result = M(q);
        // We reset the qubit before releasing it.
        Reset(q);
        // Display the result
        Message($"Result is {result}");
        // Finally, we return the result of the measurement.
        return result;
    
    }
    MeasureOneQubit();

Tenha em atenção a ausência de um espaço de nomes de utilizador ou de um @EntryPoint(), que não são necessários para o Jupyter Notebooks. Em vez de um ponto de entrada, a operação é chamada diretamente na última linha. Tenha também em atenção que foi adicionada uma Message instrução ao código Jupyter Notebook para apresentar o resultado. Quando executa o programa anterior Q# no VS Code, o simulador incorporado apresenta o resultado por predefinição.

Ao utilizar o %%qsharp comando:

  • Tem de executar import qsharp primeiro para ativar o %%qsharp comando.
  • O %%qsharp comando está no âmbito de toda a célula na qual aparece.
  • O Q# código que se segue ao comando tem de cumprir a sintaxe de codificação padrão Q# . Por exemplo, indica comentários utilizando // em vez de dentro %%qsharp de # células e as linhas de código têm de terminar com um ponto e vírgula ;.
  • O %%qsharp comando não pode ser precedido ou seguido de uma instrução Python na respetiva célula.

Para obter um exemplo de trabalho com um programa Jupyter Notebook, veja Introdução aos Q# programas e ao VS Code.

Tipos

Q# fornece muitos tipos incorporados que são comuns à maioria dos idiomas, incluindo Int, Double, Bool, e String, juntamente com tipos específicos da computação quântica. Por exemplo, o Result tipo representa o resultado de qualquer medição de qubit e pode ter um de dois valores definidos possíveis: One e Zero. No programa de exemplo, a operação MeasureOneQubit() espera um tipo de retorno de Result e a M operação mede o qubit e devolve o Result.

...
// operation definition expecting a return type of Result
operation MeasureOneQubit() : Result {
    ...
    // Now we measure the qubit in Z-basis, returning a Result type
    let result = M(q);
    ...
}

Q# também fornece tipos que definem intervalos, matrizes e cadeias de identificação. Pode até definir os seus próprios tipos personalizados.

Atribuição de qubits

No Q#, os qubits são alocados através da use palavra-chave.

O nosso exemplo define um único qubit:

// Allocate a qubit.
use q = Qubit();
...

mas também pode alocar vários qubits e aceder a cada um através do respetivo índice:

...
use qubits = Qubit[2];
X(qubits[1]);
H(qubits[0]);
...

Por predefinição, todos os qubits que alocar com a use palavra-chave começam no estado zero. Cada qubit tem de ser reposto para o estado zero antes de ser lançado no final do programa. A falha ao repor um qubit aciona um erro de runtime.

// Reset a qubit.
Reset(q);
...

Operações quânticas

Uma vez alocado, um qubit pode ser transmitido para operações e funções, também referidas como callables. As operações são os blocos modulares básicos de um Q# programa. Uma Q# operação é uma subroutina quântica. Ou seja, é uma rotina que pode ser chamada que contém operações quânticas que modificam o estado do registo qubit.

Para definir uma Q# operação, especifique um nome para a operação juntamente com as respetivas entradas e o respetivo resultado. No nosso exemplo, a operação única é essencialmente todo o programa. Não utiliza parâmetros e espera um tipo de retorno de Result:

operation MeasureOneQubit() : Result {
    ...
}

Eis um exemplo básico que não utiliza parâmetros e não espera nenhum valor devolvido. O Unit valor é equivalente a NULL noutros idiomas.

operation SayHelloQ() : Unit {
    Message("Hello quantum world!");
}

A Q# biblioteca padrão também fornece operações que pode utilizar nos seus programas, por exemplo, o Hadamard ou a H operação que é utilizada no programa de exemplo. Tendo em conta um qubit na base Z, a H operação coloca o qubit numa sobreposição uniforme . Uma vez em sobreposição, o qubit tem 50% de probabilidade de ser medido como zero ou um.

Medir qubits

Existem muitos tipos de medições quânticas, mas Q# foca-se em medições projectivas em qubits únicos, também conhecidos como medições de Pauli. Após a medição numa determinada base (por exemplo, a base computacional $\ket{0},\ket{1}$), o estado qubit é projetado para o estado de base medido, destruindo assim qualquer sobreposição entre os dois.

O nosso programa de exemplo utiliza a M operação, que efetua uma medição de um único qubit na base Pauli Z e devolve um Result tipo.

Espaços de nomes incorporados

A biblioteca padrão Q# utiliza espaços de nomes incorporados que contêm funções e operações que pode utilizar em programas quânticos. Por exemplo, o espaço de nomes Microsoft.Quantum.Intrinsic contém operações e funções frequentemente utilizadas, como M, para medir resultados e Message, para apresentar mensagens de utilizador em qualquer parte do programa.

Pode chamar uma função ou operação ao especificar o espaço de nomes completo ou utilizar uma instrução open para disponibilizar todas as funções e operações desse espaço de nomes e tornar o seu código mais fácil de ler. Estes dois exemplos chamam a mesma operação:

 Microsoft.Quantum.Intrinsic.Message("Hello quantum world!");
open Microsoft.Quantum.Intrinsic;
Message("Hello quantum world!");

Repare que, no programa de exemplo, não open existem instruções ou chamadas com espaços de nomes completos. Isto deve-se ao facto de o Q# ambiente de desenvolvimento carregar automaticamente dois espaços de nomes por predefinição - Microsoft.Quantum.Core e Microsoft.Quantum.Intrinsic - que contêm funções e operações frequentemente utilizadas.

Pode tirar partido do Microsoft.Quantum.Measurement espaço de nomes e utilizar a MResetZ operação para otimizar o código no programa de exemplo. MResetZ combina as operações de medição e reposição num único passo, como no exemplo seguinte:

namespace Superposition {

    // open the namespace for the MResetZ operation
    open Microsoft.Quantum.Measurement;

    @EntryPoint()
    operation MeasureOneQubit() : Result {
        // Allocate a qubit, by default it is in zero state      
        use q = Qubit();  
        // We apply a Hadamard operation H to the state
        // It now has a 50% chance of being measured 0 or 1  
        H(q);   
        // Measure and reset the qubit, and return the result value   
        return MResetZ(q);
    }
    
}