Q# Struktura programu

W tym artykule omówiono ogólne składniki tworzące Q# program. Należy pamiętać, że Q# programy napisane w notesach Jupyter Notebook nie używają niektórych z tych składników — te różnice są opisane w każdej sekcji.

Rozważmy następujący Q# program:

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;
    }
}

Po prostu czytając komentarze (//), możesz powiedzieć, że ten program przydziela kubit, stosuje operację, aby umieścić ją w superpozycji, mierzy stan kubitu, a następnie resetuje go i zwraca wynik.

Aby uruchomić ten program w Visual Studio Code, zobacz Wprowadzenie do Q# programów i programu VS Code.

Przestrzenie nazw użytkowników

Q# programy zazwyczaj zaczynają się od przestrzeni nazw o nazwie użytkownika, takiej jak

namespace Superposition {
    // Your code goes here.
}

Przestrzenie nazw ułatwiają organizowanie powiązanych funkcji. Przestrzenie nazw mają nazwę użytkownika i może istnieć tylko jeden namespace plik qsharp (*.qs).

Biblioteka Q# standardowa ma wstępnie zdefiniowane przestrzenie nazw, które zawierają funkcje i operacje, których można używać w programach kwantowych. Aby uzyskać więcej informacji, zobacz Wbudowane przestrzenie nazw.

Notesy Jupyter Notebook nie używają przestrzeni nazw użytkowników.

EntryPoint()

Atrybut @EntryPoint() informuje Q# kompilator, gdzie rozpocząć wykonywanie programu. W programach z wieloma definicjami @EntryPoint() funkcji i operacji można je umieścić, zanim którykolwiek z funkcji lub operacji i przepływu programu rozpocznie się od tego miejsca i będzie kontynuowany sekwencyjnie.

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

Notesy Jupyter Notebook nie używają punktów wejścia.

Polecenie %%qsharp

Domyślnie Q# programy w notesach Jupyter Notebook używają jądra języka Python ipykernel . Aby dodać Q# kod do komórki notesu, należy użyć %%qsharp polecenia , które jest włączone z pakietem qsharp języka Python. Na przykład poprzedni przykładowy kod w Jupyter Notebook wygląda następująco:

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();

Zwróć uwagę na brak przestrzeni nazw użytkownika lub elementu @EntryPoint(), które nie są wymagane w przypadku notesów Jupyter Notebook. Zamiast punktu wejścia operacja jest wywoływana bezpośrednio w ostatnim wierszu. Należy również zauważyć, że Message instrukcja została dodana do kodu Jupyter Notebook w celu wyświetlenia wyniku. Po uruchomieniu wcześniejszego Q# programu w programie VS Code wbudowany symulator domyślnie wyświetla wynik.

W przypadku korzystania z %%qsharp polecenia:

  • Najpierw należy uruchomić polecenie import qsharp , aby włączyć %%qsharp polecenie.
  • Polecenie %%qsharp jest ograniczone do całej komórki, w której jest wyświetlana. Należy pamiętać, że zmienia typ komórki notesu z języka Python na Q#.
  • Kod Q# , który jest zgodny z poleceniem, musi być zgodny ze standardową Q# składnią kodowania. Na przykład oznaczasz komentarze, używając // zamiast # w %%qsharp komórkach, a wiersze kodu muszą kończyć się średnikiem ;.
  • Nie %%qsharp można poprzedzić polecenia ani po nim instrukcji języka Python w komórce.

Aby zapoznać się z przykładem pracy z programem Jupyter Notebook, zobacz Wprowadzenie do Q# programów i programu VS Code.

Typy

Q# Udostępnia wiele wbudowanych typów , które są wspólne dla większości języków, w tym Int, Double, Booli String, wraz z typami specyficznymi dla obliczeń kwantowych. Na przykład Result typ reprezentuje wynik dowolnej miary kubitu i może mieć jedną z dwóch możliwych zdefiniowanych wartości: One i Zero. W przykładowym programie operacja MeasureOneQubit() oczekuje zwracanego Result typu i M operacja mierzy kubit i zwraca wartość 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# Udostępnia również typy definiujące zakresy, tablice i krotki. Możesz nawet zdefiniować własne typy niestandardowe.

Przydzielanie kubitów

W Q#pliku kubity są przydzielane za pomocą słowa kluczowego use .

W naszym przykładzie zdefiniowano pojedynczy kubit:

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

ale można również przydzielić wiele kubitów i uzyskać do nich dostęp za pośrednictwem indeksu:

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

Domyślnie każdy kubit przydzielany za pomocą słowa kluczowego use zaczyna się w stanie zerowym. Każdy kubit musi zostać zresetowany z powrotem do stanu zera, zanim zostanie zwolniony na końcu programu. Nie można zresetować kubitu wyzwala błąd czasu wykonywania.

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

Operacje kwantowe

Po przydzieleniu kubit może być przekazywany do operacji i funkcji, nazywanych również elementami wywołującymi. Operacje to podstawowe bloki Q# konstrukcyjne programu. Q# Operacja jest podroutyną kwantową. Oznacza to, że jest to procedura wywoływana, która zawiera operacje kwantowe modyfikujące stan rejestru kubitu.

Aby zdefiniować operację Q# , należy określić nazwę operacji wraz z danymi wejściowymi i jego danymi wyjściowymi. W naszym przykładzie pojedyncza operacja jest zasadniczo całym programem. Nie przyjmuje żadnych parametrów i oczekuje zwracanego Resulttypu :

operation MeasureOneQubit() : Result {
    ...
}

Oto podstawowy przykład, który nie przyjmuje parametrów i nie oczekuje wartości zwracanej. Wartość jest równoważna UnitNULL w innych językach.

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

Biblioteka Q# standardowa udostępnia również operacje, których można używać w programach, na przykład Hadamard lub H operacji używanej w przykładowym programie. Biorąc pod uwagę kubit W-basis, H operacja umieszcza kubit w parzysty superpozycji. Raz w superpozycji kubit ma 50% szans na pomiar jako zero lub jeden.

Mierzenie kubitów

Istnieje wiele typów pomiarów kwantowych, ale Q# koncentruje się na pomiarach projektowych na pojedynczych kubitach, znanych również jako pomiary Pauli. Po pomiarze w danej podstawie (na przykład podstawa obliczeniowa $\ket,\ket{0}{1}$) stan kubitu jest przewidywany w zależności od tego, który stan podstawy został zmierzony, co powoduje zniszczenie każdej superpozycji między nimi.

Nasz przykładowy program używa M operacji, która wykonuje pomiar pojedynczego kubitu w zasadzie Pauli Z i zwraca Result typ.

Wbudowane przestrzenie nazw

Biblioteka standardowa Q# korzysta z wbudowanych przestrzeni nazw zawierających funkcje i operacje, których można używać w programach kwantowych. Na przykład przestrzeń nazw Microsoft.Quantum.Intrinsic zawiera często używane operacje i funkcje, takie jak M, do mierzenia wyników i Message, aby wyświetlać komunikaty użytkowników w dowolnym miejscu w programie.

Możesz wywołać funkcję lub operację, określając pełną przestrzeń nazw lub używając open instrukcji , aby udostępnić wszystkie funkcje i operacje dla tej przestrzeni nazw oraz ułatwić odczytywanie kodu. W tych dwóch przykładach wywołaj tę samą operację:

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

Zauważ, że w przykładowym programie nie open ma instrukcji ani wywołań z pełnymi przestrzeniami nazw. Dzieje się tak, ponieważ Q# środowisko programistyczne automatycznie ładuje domyślnie dwie przestrzenie nazw — Microsoft.Quantum.Core i Microsoft.Quantum.Intrinsic — które zawierają często używane funkcje i operacje.

Możesz skorzystać z Microsoft.Quantum.Measurement przestrzeni nazw i użyć MResetZ operacji , aby zoptymalizować kod w przykładowym programie. MResetZ łączy operacje pomiaru i resetowania w jeden krok, jak w poniższym przykładzie:

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);
    }
    
}