Gestão de Memória Quântica

Um programa é sempre iniciado sem qubits, o que significa que não pode transmitir valores do tipo Qubit como argumentos de ponto de entrada. Esta restrição é intencional, uma vez que o objetivo é Q# expressar e raciocinar sobre um programa na sua totalidade. Em vez disso, um programa aloca e liberta qubits, ou memória quântica, à medida que avança. A este respeito, Q# modela o computador quântico como uma área dinâmica de qubits.

Em vez de suportar instruções de alocação e versão separadas para memória quântica, Q# suporta a alocação de memória quântica na forma de instruções de bloco, em que a memória só está acessível no âmbito dessa instrução de bloco. O bloco de instrução pode ser definido implicitamente ao alocar qubits durante a duração do âmbito atual, conforme descrito mais detalhadamente nas secções sobre as use instruções e borrow . Tentar aceder aos qubits alocados depois de a instrução terminar resulta numa exceção de runtime.

Q# tem duas instruções, use e borrow, que instanciam valores qubit, matrizes de qubits ou qualquer combinação das mesmas. Só pode utilizar estas instruções em operações. Recolhem os valores de qubit instanciados, vinculam-nos às variáveis especificadas na instrução e, em seguida, executam um bloco de instruções. No final do bloco, as variáveis vinculadas ficam fora do âmbito e já não estão definidas.

Q# distingue entre a alocação de qubits limpos e sujos . Os qubits limpos não são apresentados e não são utilizados por outra parte da computação. Os qubits sujos são qubits cujo estado é desconhecido e podem até ser entrelaçados com outras partes da memória do processador quântico.

Instrução de utilização

Os qubits limpos são atribuídos pela use instrução.

  • A instrução consiste na palavra-chave use seguida de um enlace e de um bloco de instrução opcional.
  • Se estiver presente um bloco de instrução, os qubits só estão disponíveis nesse bloco. Caso contrário, os qubits estão disponíveis até ao fim do âmbito atual.
  • O enlace segue o mesmo padrão let que as instruções: um único símbolo ou uma cadeia de identificação de símbolos, seguido de um sinal =de igual e uma única cadeia de identificação ou uma cadeia de identificação correspondente de inicializadores.

Os inicializadores estão disponíveis para um único qubit, indicado como Qubit(), ou uma matriz de qubits, Qubit[n], onde n é uma expressão Int . Por exemplo,

use qubit = Qubit();
// ...

use (aux, register) = (Qubit(), Qubit[5]);
// ...

use qubit = Qubit() {
    // ...
}

use (aux, register) = (Qubit(), Qubit[5]) {
    // ...
}

É garantido que os qubits estão num estado |0⟩ após a alocação. São libertados no final do âmbito e têm de estar num estado |0⟩ após o lançamento. Este requisito não é imposto pelo compilador, uma vez que isso exigiria uma avaliação simbólica que rapidamente se torna proibitivamente dispendiosa. Ao executar em simuladores, o requisito pode ser aplicado ao runtime. Nos processadores quânticos, o requisito não pode ser aplicado ao runtime; um qubit não incomensurado pode ser reposto para |0⟩ através da transformação unitária. Se não o fizer, resulta num comportamento incorreto.

A use instrução atribui os qubits da área de dados de qubits gratuita do processador quântico e devolve-os à área de trabalho o mais tardar no final do âmbito em que os qubits estão vinculados.

Extração emprestada

A borrow instrução concede acesso a qubits que já estão alocados, mas que não estão atualmente a ser utilizados. Estes qubits podem estar num estado arbitrário e precisam de estar novamente no mesmo estado quando a declaração de empréstimo terminar. Alguns algoritmos quânticos podem utilizar qubits sem depender do respetivo estado exato e sem exigir que não sejam iniciados com o resto do sistema. Ou seja, necessitam de qubits extra temporariamente, mas podem garantir que esses qubits são devolvidos exatamente ao seu estado original, independentemente do estado que estava.

Se existirem qubits que estão a ser utilizados, mas que não são tocados durante partes de uma subroutina, esses qubits podem ser emprestados para utilização por esse algoritmo em vez de alocar memória quântica adicional. Contrair empréstimos em vez de alocar pode reduzir significativamente os requisitos globais de memória quântica de um algoritmo e é um exemplo quântico de uma troca de espaço-tempo típica.

Uma borrow instrução segue o mesmo padrão descrito anteriormente para a use instrução, com os mesmos inicializadores disponíveis. Por exemplo,

borrow qubit = Qubit();
// ...

borrow (aux, register) = (Qubit(), Qubit[5]);
// ...

borrow qubit = Qubit() {
    // ...
}

borrow (aux, register) = (Qubit(), Qubit[5]) {
    // ...
}

Os qubits emprestados estão num estado desconhecido e ficam fora do âmbito no final do bloco de instrução. O mutuário compromete-se a deixar os qubits no mesmo estado que quando foram emprestados; ou seja, o seu estado no início e no fim do bloco de instrução deverá ser o mesmo.

A borrow instrução obtém qubits em utilização que garantem não ser utilizados pelo programa desde o momento em que o qubit está vinculado até à última utilização desse qubit. Se não existirem qubits suficientes disponíveis para pedir emprestado, os qubits são alocados e devolvidos à área dinâmica como uma use instrução.

Nota

Entre os casos de utilização conhecidos de qubits sujos estão implementações de portas CNOT multicontrolados que requerem muito poucos qubits e implementações de incrementadores. Este trabalho sobre a fatoração com qubits fornece um exemplo de um algoritmo que utiliza qubits emprestados.