Trabalhar com qubitsWorking with qubits

Qubits são o objeto fundamental da informação na computação quântica.Qubits are the fundamental object of information in quantum computing. Para uma introdução geral aos qubits, consulte a computação quântica,e mergulhe mais profundamente na sua representação matemática, consulte O Qubit.For a general introduction to qubits, see Understanding quantum computing, and to dive deeper into their mathematical representation, see The Qubit.

Este artigo explora como usar e trabalhar com qubits num Q# programa.This article explores how to use and work with qubits in a Q# program.

Importante

Nenhuma das declarações discutidas neste artigo é válida dentro do corpo de uma função.None of the statements discussed in this article are valid within the body of a function. Só são válidos dentro das operações.They are only valid within operations.

Atribuição de QubitsAllocating Qubits

Como os qubits físicos são um recurso precioso num computador quântico, parte do trabalho do compilador é garantir que estão a ser usados o mais eficientemente possível.Because physical qubits are a precious resource in a quantum computer, part of the compiler's job is to make sure they are being used as efficiently as possible. Como tal, tem de dizer Q# para alocar qubits para utilização dentro de um determinado bloco de declaração.As such, you need to tell Q# to allocate qubits for use within a particular statement block. Você pode alocar qubits como um único qubit, ou como uma variedade de qubits, conhecido como um registo .You can allocate qubits as a single qubit, or as an array of qubits, known as a register .

Qubits limposClean qubits

Utilize a using declaração para alocar novos qubits para utilização durante um bloco de declaração.Use the using statement to allocate new qubits for use during a statement block.

A declaração consiste na using palavra-chave, seguida de uma ligação em parênteses e do bloco de declaração dentro do qual os ( ) qubits estão disponíveis.The statement consists of the keyword using, followed by a binding enclosed in parentheses ( ) and the statement block within which the qubits are available. A ligação segue o mesmo padrão que let as declarações: ou um único símbolo ou um tuple de símbolos, seguido de um sinal de iguais = , e um único valor ou um tuple de inicializadores correspondentes .The binding follows the same pattern as let statements: either a single symbol or a tuple of symbols, followed by an equals sign =, and either a single value or a matching tuple of initializers .

Os inicializadores estão disponíveis para um único qubit, indicado como Qubit() , ou uma matriz de qubits, onde é uma Qubit[n] n Int expressão.Initializers are available either for a single qubit, indicated as Qubit(), or an array of qubits, Qubit[n], where n is an Int expression. Por exemplo,For example,

using (qubit = Qubit()) {
    // ...
}
using ((auxiliary, register) = (Qubit(), Qubit[5])) {
    // ...
}

Quaisquer qubits atribuídos desta forma começam no estado $\ket$ {0}Any qubits allocated in this way start off in the $\ket{0}$ state. Assim, no exemplo anterior, auxiliary é um único qubit no estado $\ket {0} $, e está no estado de register cinco qubits $\ket {00000} = \ket {0} \otimes {0} \otimes \otimes \otimes \otimes \ket {0} $.Thus in the previous example, auxiliary is a single qubit in the state $\ket{0}$, and register is in the five-qubit state $\ket{00000} = \ket{0} \otimes \ket{0} \otimes \cdots \otimes \ket{0}$. No final do using bloco, quaisquer qubits atribuídos por esse bloco são imediatamente transcilhados e não podem ser usados mais.At the end of the using block, any qubits allocated by that block are immediately deallocated and cannot be used further.

Aviso

As máquinas-alvo podem reutilizar qubits deallocados e oferecê-los a outros using blocos para alocação.Target machines can reuse deallocated qubits and offer them to other using blocks for allocation. Como tal, a máquina-alvo espera que os qubits estejam no estado de $\ket {0} $ imediatamente antes da negociação.As such, the target machine expects that qubits are in the $\ket{0}$ state immediately before deallocation. Sempre que possível, utilize operações unitárias para devolver quaisquer qubits atribuídos a $\ket {0} $.Whenever possible, use unitary operations to return any allocated qubits to $\ket{0}$. Se necessário, pode utilizar a @"microsoft.quantum.intrinsic.reset" operação, que devolve o qubit a $\ket {0} $ medindo-o e realizando condicionalmente uma operação com base no resultado.If need be, you can use the @"microsoft.quantum.intrinsic.reset" operation, which returns the qubit to $\ket{0}$ by measuring it and conditionally performing an operation based on the result. Tal medição destrói qualquer emaranhado com os qubits restantes e pode, assim, impactar a computação.Such a measurement destroys any entanglement with the remaining qubits and can thus impact the computation.

Qubits emprestadosBorrowed Qubits

Utilize a borrowing declaração para alocar qubits para uso temporário, que não precisam de estar num estado específico.Use the borrowing statement to allocate qubits for temporary use, which do not need to be in a specific state.

Você pode usar qubits emprestados como espaço de arranhão durante uma computação.You can use borrowed qubits as scratch space during a computation. Estes qubits geralmente não estão em um estado limpo, isto é, eles não são necessariamente inicializados em um estado conhecido como $\ket {0} $.These qubits are generally not in a clean state, that is, they are not necessarily initialized in a known state such as $\ket{0}$. Estes são muitas vezes referidos como qubits "sujos" porque o seu estado é desconhecido e pode mesmo ser enredado com outras partes da memória do computador quântico.These are often referred to as "dirty" qubits because their state is unknown and can even be entangled with other parts of the quantum computer's memory.

A ligação segue o mesmo padrão e regras que a using declaração.The binding follows the same pattern and rules as the using statement. Por exemplo,For example,

borrowing (qubit = Qubit()) {
    // ...
}
borrowing ((auxiliary, register) = (Qubit(), Qubit[5])) {
    // ...
}

Os qubits emprestados estão num estado desconhecido e ficam fora de alcance no final do bloco de declaração.The borrowed qubits are in an unknown state and go out of scope at the end of the statement block. O mutuário compromete-se a deixar os qubits no mesmo estado em que estavam quando os pediram emprestado; isto é, o seu estado no início e no fim do bloco de declaração deve ser o mesmo.The borrower commits to leaving the qubits in the same state they were in when they borrowed them; that is, their state at the beginning and the end of the statement block should be the same. Como este estado não é necessariamente um estado clássico, na maioria dos casos, os âmbitos de empréstimo não devem conter medições.Because this state is not necessarily a classical state, in most cases borrowing scopes should not contain measurements.

Ao pedir qubits emprestados, o sistema tenta primeiro preencher o pedido de qubits que estão em uso mas não acedidos durante o corpo da borrowing declaração.When borrowing qubits, the system first tries to fill the request from qubits that are in use but not accessed during the body of the borrowing statement. Se não houver qubits suficientes, então atribui novos qubits para completar o pedido.If there aren't enough such qubits, then it allocates new qubits to complete the request.

Entre os casos de uso conhecido de qubits sujos estão implementações de portas CNOT multi-controladas que requerem apenas muito poucos qubits e implementação de incrementadores.Among the known use cases of dirty qubits are implementations of multi-controlled CNOT gates that require only very few qubits and implementation of incrementers. Para um exemplo da sua utilização em Q# , consulte Borrowing Qubits Exemplo neste artigo, ou o papel Factoring usando 2n+2 qubits com multiplicação modular baseada em Toffoli (Haner, Roetteler e Svore 2017) para um algoritmo que utiliza qubits emprestados.For an example of their use in Q#, see Borrowing Qubits Example in this article, or the paper Factoring using 2n+2 qubits with Toffoli based modular multiplication (Haner, Roetteler, and Svore 2017) for an algorithm which utilizes borrowed qubits.

Operações IntrínsecasIntrinsic Operations

Uma vez atribuído, pode passar um qubit para funções e operações.Once allocated, you can pass a qubit to functions and operations. Em certo sentido, isto é tudo o que um Q# programa pode fazer com um qubit, uma vez que as ações que podem ser tomadas são todas definidas como operações.In some sense, this is all that a Q# program can do with a qubit, as the actions that can be taken are all defined as operations.

Este artigo discute algumas operações úteis Q# que pode usar para interagir com qubits.This article discusses a few useful Q# operations that you can use to interact with qubits. Para obter mais detalhes sobre estes e outros, consulte Operações e Funções Intrínsecas.For more detail about these and others, see Intrinsic Operations and Functions.

Em primeiro lugar, os operadores de Pauli de um único qubit $X$, $Y$, e $Z$ são representados Q# pelas operações intrínsecas, X e , cada uma delas tem tipo Y Z (Qubit => Unit is Adj + Ctl) .First, the single-qubit Pauli operators $X$, $Y$, and $Z$ are represented in Q# by the intrinsic operations X, Y, and Z, each of which has type (Qubit => Unit is Adj + Ctl).

Como descrito em Operações e Funções Intrínsecas,pense em $X$ e, portanto, X como uma operação de inversão de marcha ou portão NÃO.As described in Intrinsic Operations and Functions, think of $X$ and hence of X as a bit-flip operation or NOT gate. Você pode usar a X operação para preparar estados do formulário $\ket{s_0 s_1 \dots s_n}$ para algum fio de bit clássico $s$:You can use the X operation to prepare states of the form $\ket{s_0 s_1 \dots s_n}$ for some classical bit string $s$:

operation PrepareBitString(bitstring : Bool[], register : Qubit[]) : Unit
is Adj + Ctl {
    let nQubits = Length(register);
    for (idxQubit in 0..nQubits - 1) {
        if (bitstring[idxQubit]) {
            X(register[idxQubit]);
        }
    }
}

operation RunExample() : Unit {
    using (register = Qubit[8]) {
        PrepareBitString(
            [true, true, false, false, true, false, false, true],
            register
        );
        // At this point, register now has the state |11001001〉.
        // Remember to reset the qubits before deallocation:
        ResetAll(register);
    }
}

Dica

Mais tarde, verá formas mais compactas de escrever esta operação que não requerem fluxo manual de controlo.Later, you will see more compact ways of writing this operation that do not require manual control flow.

Também pode preparar estados como $\ket{+} = \left(\ket {0} + \ket {1} \ket \right) / \sqrt {2} $ e $\ket {-} = \left(\ket {0} \ket {1} \right) / \sqrt {2} $ usando a transformação Hadamard $H$, que é representada Q# pela operação intrínseca H (também do tipo (Qubit => Unidade é Aj + Ctl)):)):You can also prepare states such as $\ket{+} = \left(\ket{0} + \ket{1}\right) / \sqrt{2}$ and $\ket{-} = \left(\ket{0} - \ket{1}\right) / \sqrt{2}$ by using the Hadamard transform $H$, which is represented in Q# by the intrinsic operation H (also of type (Qubit => Unit is Adj + Ctl)`):

operation PreparePlusMinusState(bitstring : Bool[], register : Qubit[]) : Unit {
    // First, get a computational basis state of the form
    // |s_0 s_1 ... s_n〉 by using PrepareBitString in the earlier example.
    PrepareBitString(bitstring, register);
    // Next, use that |+〉 = H|0〉 and |-〉 = H|1〉 to
    // prepare the desired state.
    for (idxQubit in IndexRange(register)) {
        H(register[idxQubit]);
    }
}

MediçõesMeasurements

As medições de qubits individuais podem ser realizadas em diferentes bases, cada uma representada por um eixo Pauli na esfera bloch.Measurements of individual qubits can be performed in different bases, each represented by a Pauli axis on the Bloch sphere. A base computacional refere-se à PauliZ base, e é a base mais comum utilizada para a medição.The computational basis refers to the PauliZ basis, and is the most common basis used for measurement.

Meça um único qubit na PauliZ baseMeasure a single qubit in the PauliZ basis

Utilize a M operação, que é uma operação não unitária incorporada, para medir um único qubit na PauliZ base e atribuir um valor clássico ao resultado.Use the M operation, which is a built-in intrinsic non-unitary operation, to measure a single qubit in the PauliZ basis and assign a classical value to the result. M tem um tipo de retorno reservado, Result que só pode tomar valores ou corresponder aos Zero One estados medidos $\ket {0} $ ou $\ket {1} $ - indicando que o resultado já não é um estado quântico.M has a reserved return type, Result, which can only take values Zero or One corresponding to the measured states $\ket{0}$ or $\ket{1}$ - indicating that the result is no longer a quantum state.

Um exemplo simples é a seguinte operação, que atribui um qubit no estado $\ket {0} $, em seguida, aplica uma operação Hadamard H a ele e mede o resultado na PauliZ base.A simple example is the following operation, which allocates one qubit in the $\ket{0}$ state, then applies a Hadamard operation H to it and measures the result in the PauliZ basis.

operation MeasureOneQubit() : Result {
    // The following using block creates a fresh qubit and initializes it
    // in the |0〉 state.
    using (qubit = Qubit()) {
        // Apply a Hadamard operation H to the state, thereby preparing the
        // state 1 / sqrt(2) (|0〉 + |1〉).
        H(qubit);
        // Now measure the qubit in Z-basis.
        let result = M(qubit);
        // As the qubit is now in an eigenstate of the measurement operator,
        // reset the qubit before releasing it.
        if (result == One) { X(qubit); }
        // Finally, return the result of the measurement.
        return result;
    }
}

Medir um ou mais qubits em bases específicasMeasure one or more qubits in specific bases

Para medir um conjunto de um ou mais qubits em bases específicas, pode utilizar a Measure operação.To measure an array of one or more qubits in specific bases, you can use the Measure operation.

As entradas Measure são uma matriz de Pauli tipos (por exemplo, [PauliX, PauliZ, PauliZ] ) e uma matriz de qubits.The inputs to Measure are an array of Pauli types (for example, [PauliX, PauliZ, PauliZ]) and an array of qubits.

Um exemplo um pouco mais complicado é dado pela seguinte operação, que devolve o valor Boolean true se todos os qubits num registo de tipo Qubit[] estiverem no estado zero quando medidos numa base Pauli especificada, e que retorna false de outra forma.A slightly more complicated example is given by the following operation, which returns the Boolean value true if all qubits in a register of type Qubit[] are in the state zero when measured in a specified Pauli basis, and which returns false otherwise.

operation MeasureIfAllQubitsAreZero(qubits : Qubit[], pauli : Pauli) : Bool {
    mutable value = true;
    for (qubit in qubits) {
        if (Measure([pauli], [qubit]) == One) {
            set value = false;
        }
    }
    return value;
}

Note que este exemplo ainda só funciona Measure em qubits individuais um de cada vez, mas a operação pode ser estendida a medições articulares em múltiplos qubits.Note that this example still only performs Measure on individual qubits one at a time, but the operation can be extended to joint measurements on multiple qubits.

Exemplo de Qubits emprestadoBorrowing Qubits Example

Existem exemplos no cânone que usam a borrowing palavra-chave, como a seguinte função MultiControlledXBorrow .There are examples in the canon that use the borrowing keyword, such as the following function MultiControlledXBorrow. Se controls denotar os qubits de controlo para adicionar a uma X operação, então o número de ancillas sujas adicionadas por esta implementação é Length(controls)-2 .If controls denotes the control qubits to add to an X operation, then the number of dirty ancillas added by this implementation is Length(controls)-2.

operation MultiControlledXBorrow ( controls : Qubit[] , target : Qubit ) : Unit
is Adj + Ctl {

    body (...) {
        ... // skipping some case handling here
        let numberOfDirtyQubits = numberOfControls - 2;
        borrowing( dirtyQubits = Qubit[ numberOfDirtyQubits ] ) {

            let allQubits = [ target ] + dirtyQubits + controls;
            let lastDirtyQubit = numberOfDirtyQubits;
            let totalNumberOfQubits = Length(allQubits);

            let outerOperation1 = 
                CCNOTByIndexLadder(
                    numberOfDirtyQubits + 1, 1, 0, numberOfDirtyQubits , _ );
            
            let innerOperation = 
                CCNOTByIndex(
                    totalNumberOfQubits - 1, totalNumberOfQubits - 2, lastDirtyQubit, _ );
            
            WithA(outerOperation1, innerOperation, allQubits);
            
            let outerOperation2 = 
                CCNOTByIndexLadder(
                    numberOfDirtyQubits + 2, 2, 1, numberOfDirtyQubits - 1 , _ );
            
            WithA(outerOperation2, innerOperation, allQubits);
        }
    }

    controlled(extraControls, ...) {
        MultiControlledXBorrow( extraControls + controls, target );
    }
}

Note-se que este exemplo utilizou extensivamente o With combinador, na sua forma aplicável às operações que suportam, por exemplo, WithA .Note that this example used extensive use of the With combinator, in its form that is applicable for operations that support adjoint, for example, WithA. Este é um bom estilo de programação, porque adicionar controlo às estruturas que envolvem With o controlo de propagações apenas para o funcionamento interno.This is good programming style, because adding control to structures involving With propagates control only to the inner operation. Note-se ainda que, para além body da operação, foi explicitamente fornecida uma implementação controlled do corpo da operação, em vez de recorrer a um controlled auto comunicado.Also note that, in addition to the body of the operation, an implementation of the controlled body of the operation was explicitly provided, rather than resorting to a controlled auto statement. A razão para isso é que, devido à estrutura do circuito, é fácil adicionar mais controlos, o que é benéfico em comparação com a adição de controlo a cada portão do body .The reason for this is that, because of the structure of the circuit, it is easy to add further controls, which is beneficial compared to adding control to each gate in the body.

É instrutivo comparar este código com outra função canónica MultiControlledXClean que alcança o mesmo objetivo de implementar uma operação controlada por multi-animais, no X entanto, que utiliza vários qubits limpos usando o using mecanismo.It is instructive to compare this code with another canon function MultiControlledXClean which achieves the same goal of implementing a multiply-controlled X operation, however, which uses several clean qubits using the using mechanism.

Passos seguintesNext steps

Saiba mais sobre o Control Flow em Q# .Learn about Control Flow in Q#.