Udostępnij za pośrednictwem


Zarządzanie pamięcią kwantową

Program zawsze uruchamia się bez kubitów, co oznacza, że nie można przekazać wartości typu Qubit jako argumentów punktu wejścia. To ograniczenie jest zamierzone, ponieważ celem Q# programu jest wyrażenie i uzasadnienie w całości. Zamiast tego program przydziela i zwalnia kubity lub pamięć kwantową w miarę jego działania. W tym względzie Q# modeluje komputer kwantowy jako stertę kubitu.

Zamiast obsługiwać oddzielne instrukcje przydzielania i wydawania dla pamięci kwantowej, Q# obsługuje alokację pamięci kwantowej w postaci instrukcji blokowych, gdzie pamięć jest dostępna tylko w zakresie tej instrukcji bloku. Blok instrukcji można niejawnie zdefiniować podczas przydzielania kubitów na czas trwania bieżącego zakresu, zgodnie z opisem bardziej szczegółowo w sekcjach dotyczących use instrukcji i borrow . Próba uzyskania dostępu do przydzielonych kubitów po zakończeniu instrukcji powoduje wyjątek środowiska uruchomieniowego.

Q# ma dwie instrukcje i useborrow, które tworzy wystąpienie wartości kubitów, tablice kubitów lub dowolną kombinację. Tych instrukcji można używać tylko w ramach operacji. Zbierają utworzone wartości kubitów, wiążą je ze zmiennymi określonymi w instrukcji, a następnie uruchamiają blok instrukcji. Na końcu bloku powiązane zmienne wykraczają poza zakres i nie są już zdefiniowane.

Q# rozróżnia alokację czystych i zanieczyszczonych kubitów. Czyste kubity są niezaangangledowane i nie są używane przez inną część obliczeń. Zanieczyszczone kubity to kubity, których stan jest nieznany, a nawet może być splątane z innymi częściami pamięci procesora kwantowego.

Use, instrukcja

Czyste kubity są przydzielane przez instrukcję use .

  • Instrukcja składa się ze słowa kluczowego use , po którym następuje powiązanie i opcjonalny blok instrukcji.
  • Jeśli blok instrukcji jest obecny, kubity są dostępne tylko w tym bloku. W przeciwnym razie kubity są dostępne do końca bieżącego zakresu.
  • Powiązanie jest zgodne z tym samym wzorcem co let instrukcje: pojedynczy symbol lub krotka symboli, a następnie znak =równości , oraz pojedyncza krotka lub pasująca krotka inicjatorów.

Inicjatory są dostępne dla pojedynczego kubitu wskazanego jako Qubit(), lub tablicy kubitów, Qubit[n]gdzie n jest wyrażeniem Int . Na przykład

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

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

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

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

Po alokacji kubity muszą mieć stan |0⟩. Są one zwalniane na końcu zakresu i muszą być w stanie |0⟩ po wydaniu. To wymaganie nie jest wymuszane przez kompilator, ponieważ wymagałoby to symbolicznej oceny, która szybko staje się zbyt kosztowna. W przypadku uruchamiania w symulatorach można wymusić wymaganie w czasie wykonywania. W przypadku procesorów kwantowych nie można wymusić wymagania w czasie wykonywania; Kubit niezmierzony może zostać zresetowany do |0⟩ za pomocą transformacji unitarnej. Nie można tego zrobić powoduje nieprawidłowe zachowanie.

Instrukcja use przydziela kubity z wolnego sterty kubitu procesora kwantowego i zwraca je do sterty nie później niż koniec zakresu, w którym są powiązane kubity.

Pożyczanie instrukcji

Instrukcja borrow udziela dostępu do kubitów, które są już przydzielone, ale nie są obecnie używane. Te kubity mogą być w dowolnym stanie i muszą być w tym samym stanie ponownie po zakończeniu oświadczenia pożyczki. Niektóre algorytmy kwantowe mogą używać kubitów bez polegania na ich dokładnym stanie i nie wymagając, aby były niezaangangowane w pozostałej części systemu. Oznacza to, że wymagają one tymczasowo dodatkowych kubitów, ale mogą zapewnić, że te kubity są zwracane dokładnie do ich pierwotnego stanu, niezależnie od tego, który stan był.

Jeśli istnieją kubity, które są używane, ale nie dotykane podczas części podprokucji, te kubity można pożyczyć do użycia przez taki algorytm zamiast przydzielać dodatkową pamięć kwantową. Pożyczki zamiast przydzielania mogą znacząco zmniejszyć ogólne wymagania dotyczące pamięci kwantowej algorytmu i jest kwantowym przykładem typowego kompromisu w czasie kosmicznym.

Instrukcja borrow jest zgodna z tym samym wzorcem opisanym wcześniej dla instrukcjiuse z dostępnymi tymi samymi inicjatorami. Na przykład

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

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

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

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

Pożyczone kubity są w nieznanym stanie i wychodzą z zakresu na końcu bloku instrukcji. Kredytobiorca zobowiązuje się do opuszczenia kubitów w tym samym stanie, co kiedy zostały one pożyczone; oznacza to, że ich stan na początku i koniec bloku instrukcji powinien być taki sam.

Instrukcja borrow pobiera kubity w użyciu, które mają gwarancję, że nie będą używane przez program od momentu, gdy kubit jest powiązany do ostatniego użycia tego kubitu. Jeśli nie ma wystarczającej liczby kubitów dostępnych do wypożyczania, kubity są przydzielane z i zwracane do sterty jak use instrukcja.

Uwaga

Wśród znanych przypadków użycia brudnych kubitów są implementacje wielokontrolerowych bram CNOT, które wymagają bardzo niewielu kubitów i implementacji inkrementatorów. Ten dokument dotyczący faktorowania za pomocą kubitów zawiera przykład algorytmu wykorzystującego pożyczone kubity.