Zelfstudie: Programma's op qubitniveau schrijven en simuleren in Q#

Welkom bij de zelfstudie over de Quantum Development Kit (QDK) over het schrijven en simuleren van een basis kwantumprogramma dat op afzonderlijke qubits werkt.

Hoewel voornamelijk is gemaakt als een programmeertaal op hoog niveau voor grootschalige kwantumprogramma's, kan deze net zo eenvoudig worden gebruikt om het lagere niveau van kwantumprogramma's te verkennen: het rechtstreeks adresseren van specifieke Q# qubits. Door de flexibiliteit van kunnen gebruikers kwantumsystemen benaderen vanaf een dergelijk abstractieniveau. In deze zelfstudie gaan we dieper in Q# op de qubits zelf.

In deze zelfstudie wordt met name de Quantum Fourier Transformonder dekend, een subroutine die een integraal onderdeel is van veel grotere kwantumalgoritmen.

Houd er rekening mee dat deze weergave op laagniveau van kwantumgegevensverwerking vaak wordt beschreven in termen van 'kwantumcircuits', die de sequentiële toepassing van poorten naar specifieke qubits van een systeem vertegenwoordigen.

De bewerkingen met één en meerdere qubits die we opeenvolgend toepassen, kunnen dus gemakkelijk worden weergegeven in een 'circuitdiagram'. In dit geval definieert u een bewerking voor het uitvoeren van de volledige Kwantum Fourier-transformatie met drie qubits, die de volgende Q# weergave als een circuit heeft:


Three qubit quantum Fourier transform circuit diagram

Vereisten

In deze zelfstudie leert u het volgende:

  • Kwantumbewerkingen definiëren in Q#
  • Bewerkingen Q# rechtstreeks aanroepen vanaf de opdrachtprompt of met behulp van een klassiek hostprogramma
  • Een kwantumbewerking simuleren van qubittoewijzing naar meetuitvoer
  • Kijk hoe de gesimuleerde golffunctie van het kwantumsysteem zich tijdens de bewerking ontwikkelt

Het uitvoeren van een kwantumprogramma met de QDK bestaat doorgaans uit twee delen:

  1. Het programma zelf, dat wordt geïmplementeerd met behulp van de kwantumprogrammeertaal en vervolgens wordt aangeroepen om te worden uitgevoerd op een Q# kwantumcomputer of kwantumsimulator. Deze bestaan uit
    • Q# bewerkingen: subroutines die op kwantumregisters werken, en
    • Q# functions: klassieke subroutines die worden gebruikt binnen het kwantumalgoritme.
  2. Het toegangspunt dat wordt gebruikt om het kwantumprogramma aan te roepen en de doelcomputer op te geven waarop het moet worden uitgevoerd. Dit kan rechtstreeks vanaf de opdrachtprompt of via een hostprogramma dat is geschreven in een klassieke programmeertaal zoals Python of C#. Deze zelfstudie bevat instructies voor elke methode die u wilt gebruiken.

qubits toewijzen en kwantumbewerkingen definiëren

Het eerste deel van deze zelfstudie bestaat uit het definiëren van de bewerking , waarmee de Q# Perform3qubitQFT quantum Fourier-transformatie op drie qubits wordt uitgevoerd.

Daarnaast wordt de functie gebruikt om te zien hoe de gesimuleerde golffunctie van ons drie DumpMachine qubitsysteem zich tijdens de bewerking ontwikkelt.

De eerste stap is het maken van Q# uw project en bestand. De stappen hiervoor zijn afhankelijk van de omgeving die u gebruikt om het programma aan te roepen. U vindt de details in de betreffende installatiehandleidingen.

In deze zelfstudie doorloop u stapsgewijs de onderdelen van het bestand, maar de code is ook beschikbaar als een volledig blok hieronder.

Naamruimten voor toegang tot andere Q# bewerkingen

Definieer in het bestand eerst de NamespaceQFT naamruimte die wordt gebruikt door de compiler. Voor deze bewerking kunt u gebruikmaken van bestaande Q# bewerkingen door de relevante naamruimten te Microsoft.Quantum.<> openen.

namespace NamespaceQFT {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Diagnostics;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Arrays;

    // operations go here
}

Bewerkingen definiëren met argumenten en retourneert

Definieer vervolgens de Perform3qubitQFT bewerking:

    operation Perform3qubitQFT() : Unit {
        // do stuff
    }

De bewerking heeft op dit moment geen argumenten en retourneert niets---in dit geval schrijven we dat er een -object wordt retourneert, dat vergelijkbaar is met in C# of een lege Unit void tuple, Tuple[()] , in Python. Later wordt deze gewijzigd om een matrix met meetresultaten te retourneren, waarna deze Unit wordt vervangen door Result[] .

qubits toewijzen met use

Wijs Q# binnen de bewerking een register van drie qubits toe met het trefwoord use :

        use qs = Qubit[3];

        Message("Initial state |000>:");
        DumpMachine();

Met worden de qubits automatisch toegewezen in de use $\ket$-toestand. {0} U kunt dit controleren met behulp van en , waarmee een tekenreeks en de huidige status van het systeem naar de Message(<string>) DumpMachine() console worden afgedrukt.

Notitie

De Message(<string>) functies DumpMachine() en Microsoft.Quantum.Intrinsic (respectievelijk van en ) worden rechtstreeks Microsoft.Quantum.Diagnostics naar de console afgedrukt. Net als bij een echte kwantumberekening kunnen Q# we niet rechtstreeks toegang krijgen tot qubit-toestanden. Als echter de huidige status van de doelmachine wordt afgedrukt, kan deze waardevolle inzichten bieden voor het debuggen en leren wanneer deze wordt gebruikt in combinatie met de DumpMachine simulator voor volledige status.

Eén qubit en gecontroleerde poorten toepassen

Pas vervolgens de poorten toe waaruit de bewerking zelf bestaat. Q# bevat al veel eenvoudige kwantumpoorten als bewerkingen in de Microsoft.Quantum.Intrinsic naamruimte, en deze vormen geen uitzondering.

Binnen een bewerking worden de instructies die aanroepbare instructies aanroepen, natuurlijk Q# in sequentiële volgorde uitgevoerd. Daarom is de (Hadamard) de eerste poort die moet worden toegepast H op de eerste qubit:


Circuit diagram for three qubit QFT through first Hadamard

Als u vanuit een register een bewerking wilt toepassen op een specifieke qubit (bijvoorbeeld één uit een Qubit matrix ), gebruiken we een Qubit[] standaardindex notatie. Het toepassen van de op H de eerste qubit van ons register qs heeft dus de volgende vorm:

            H(qs[0]);

Naast het toepassen van H de (Hadamard)-poort op afzonderlijke qubits, bestaat het QFT-circuit voornamelijk uit gecontroleerde R1 rotaties. Een bewerking in het algemeen laat het $\ket$-onderdeel van de qubit ongewijzigd, terwijl een rotatie van R1(θ, <qubit>) {0} $e^{i\theta}$ wordt toegepast op het $\ket$-onderdeel. {1}

Beheerde bewerkingen

Q# maakt het zeer eenvoudig om de run van een bewerking te conditionren op een of meer controle-qubits. Over het algemeen wordt de aanroep alleen vooraf laten gaan door Controlled , en veranderen de bewerkingsargumenten als:

Op(<normal args>) $\to$ Controlled Op([<control qubits>], (<normal args>)) .

Houd er rekening mee dat de besturingsqubits moeten worden opgegeven als een matrix, zelfs als het één qubit is.

Na de zijn de volgende poorten de poorten die op de eerste H R1 qubit handelen (en worden beheerd door de tweede/derde):


Circuit diagram for three qubit QFT through first qubit

U kunt deze aanroepen met:

            Controlled R1([qs[1]], (PI()/2.0, qs[0]));
            Controlled R1([qs[2]], (PI()/4.0, qs[0]));

Houd er rekening mee PI() dat de functie uit de Microsoft.Quantum.Math naamruimte wordt gebruikt om de roulaties te definiëren in termen van pi-radialen. Daarnaast delen de codes door een (bijvoorbeeld ) omdat delen door een geheel getal Double 2.0 een 2 typefout zou genereren.

Tip

R1(π/2) en R1(π/4) zijn gelijk aan de bewerkingen en S T (ook in Microsoft.Quantum.Intrinsic ).

Na het toepassen van de relevante H bewerkingen en gecontroleerde rotaties op de tweede en derde qubit:

            //second qubit:
            H(qs[1]);
            Controlled R1([qs[2]], (PI()/2.0, qs[1]));

            //third qubit:
            H(qs[2]);

U hoeft alleen een poort SWAP toe te passen om het circuit te voltooien:

            SWAP(qs[2], qs[0]);

Dit is nodig omdat de aard van de kwantum-Fourier-transformatie de qubits in omgekeerde volgorde uitvoert, zodat de wisselingen naadloze integratie van de subroutine in grotere algoritmen mogelijk maken.

Daarom bent u klaar met het schrijven van de bewerkingen op qubitniveau van de quantum Fourier-transformatie in onze Q# bewerking:

Three qubit quantum Fourier transform circuit diagram

De qubits hadden echter de status $\ket $ toen we ze toe hadden toegewezen. Daarom moet u de toewijzing ervan ingetrokken om de begintoestand {0} opnieuw in te stellen.

De toewijzing van qubits in de weg

Roep opnieuw aan om de status na de bewerking te zien en pas ten slotte toe op het qubitregister om onze qubits opnieuw in te stellen op $\ket $ voordat u de bewerking DumpMachine() ResetAll {0} voltooit:

            Message("After:");
            DumpMachine();

            ResetAll(qs);

Vereisen dat alle niet-toegewezen qubits expliciet worden ingesteld op $\ket $ is een basisfunctie van , omdat hiermee andere bewerkingen hun status nauwkeurig kunnen kennen wanneer ze dezelfde {0} Q# qubits gaan gebruiken (een beperkte resource). Bovendien zorgt dit ervoor dat ze niet verstrengeld zijn met andere qubits in het systeem. Als het opnieuw instellen niet wordt uitgevoerd aan het einde van een toewijzingsblok, kan er een use runtimefout optreden.

Het volledige Q# bestand moet er nu als volgende uitzien:

namespace NamespaceQFT {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Diagnostics;
    open Microsoft.Quantum.Math;
    open Microsoft.Quantum.Arrays;

    operation Perform3qubitQFT() : Unit {

        use qs = Qubit[3];

        Message("Initial state |000>:");
        DumpMachine();

        //QFT:
        //first qubit:
        H(qs[0]);
        Controlled R1([qs[1]], (PI()/2.0, qs[0]));
        Controlled R1([qs[2]], (PI()/4.0, qs[0]));

        //second qubit:
        H(qs[1]);
        Controlled R1([qs[2]], (PI()/2.0, qs[1]));

        //third qubit:
        H(qs[2]);

        SWAP(qs[2], qs[0]);

        Message("After:");
        DumpMachine();

        ResetAll(qs);

    }
}

Als het Q# bestand en de bewerking zijn voltooid, is het kwantumprogramma klaar om te worden aangeroepen en gesimuleerd.

Het programma uitvoeren

Nadat u de bewerking in een bestand hebt gedefinieerd, moet u die bewerking Q# .qs aanroepen en eventuele geretourneerde klassieke gegevens bekijken. Er wordt momenteel niets geretourneerd (zoals eerder gedefinieerde bewerking retourneert ), maar wanneer u de bewerking later wijzigt om een matrix met meetresultaten () te retourneren, wordt dit Unit Q# Result[] adresseerd.

Hoewel het programma overal is in de omgevingen die worden gebruikt om het programma aan te roepen, zal de manier waarop dit gebeurt natuurlijk Q# variëren. Volg dus gewoon de instructies op het tabblad dat overeenkomt met uw installatie: werken vanuit de toepassing of met behulp van een Q# hostprogramma in Python of C#.

Voor het Q# uitvoeren van het programma vanaf de opdrachtprompt is slechts een kleine wijziging in het bestand Q# vereist.

Voeg gewoon @EntryPoint() toe aan een regel vóór de bewerkingsdefinitie:

    @EntryPoint()
    operation Perform3qubitQFT() : Unit {
        // ...

Als u het programma wilt uitvoeren, opent u de terminal in de map van uw project en voert u in

dotnet run

Als dit is voltooid, ziet u dat de Message DumpMachine onderstaande uitvoer en worden weergegeven in uw console.

Initial state |000>:
# wave function for qubits with ids (least to most significant): 0;1;2
|0>:     1.000000 +  0.000000 i  ==     ******************** [ 1.000000 ]     --- [  0.00000 rad ]
|1>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]                   
|2>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]                   
|3>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]                   
|4>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]                   
|5>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]                   
|6>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]                   
|7>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]                   
After:
# wave function for qubits with ids (least to most significant): 0;1;2
|0>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|1>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|2>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|3>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|4>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|5>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|6>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|7>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]

Wanneer deze wordt aangeroepen in de simulator voor volledige toestand, geeft deze meerdere weergaven van de golffunctie van DumpMachine() de kwantumtoestand. De mogelijke staten van een $n$-qubitsysteem kunnen worden vertegenwoordigd door $2^n$ rekenbasisstanden, elk met een bijbehorende complexe coëfficiënt (gewoon een amplitude en een fase). De berekeningsbasiscijfers komen overeen met alle mogelijke binaire tekenreeksen met lengte $n$---dat wil zeggen dat alle mogelijke combinaties van qubits $\ket$ en $\ket $, waarbij elk binair cijfer overeenkomt met een afzonderlijke {0} {1} qubit.

De eerste rij bevat een opmerking met de ID's van de bijbehorende qubits in hun significante volgorde. Qubit is de 'belangrijkste' betekent gewoon dat in de binaire weergave van 2 de basistoestandsvector $\ket{i}$ de toestand van de qubit overeenkomt met het meest linkse 2 cijfer. $\ket = \ket $ bestaat bijvoorbeeld uit qubits en beide {6} {110} in 2 $\ket $ en 1 {1} qubit 0 in $\ket {0} $.

De rest van de rijen beschrijft de waarschijnlijkheids amplitude van het meten van de basistoestandsvector $\ket{i}$ in zowel cartesische als polaire indelingen. In detail voor de eerste rij van de invoertoestand $\ket {000} $:

  • |0>: Deze rij komt overeen met de rekenkundige basistoestand (gezien het feit dat onze initiële toestand na de toewijzing $\ket $was, verwachten we dat dit op dit moment de enige status met waarschijnlijkheids 0 {000} amplitude is).
  • 1.000000 + 0.000000 i: de waarschijnlijkheids amplitude in Cartesische notatie.
  • ==: het equal teken scheidt beide equivalente weergaven.
  • ********************: Een grafische weergave van de magnitude, het aantal is evenredig aan de waarschijnlijkheid * van het meten van deze toestandsvector.
  • [ 1.000000 ]: de numerieke waarde van de magnitude
  • ---: Een grafische weergave van de fase van de amplitude.
  • [ 0.0000 rad ]: de numerieke waarde van de fase (in radialen).

Zowel de magnitude als de fase worden weergegeven met een grafische weergave. De magnitudeweergave is eenvoudig: het toont een staaf van , en hoe hoger de * waarschijnlijkheid, hoe groter de balk. Zie Testen en debuggen: dumpfuncties voor de mogelijke symboolweergaven op basis van hoekbereiken voor de fase.

De afgedrukte uitvoer illustreert dus dat onze geprogrammeerde poorten onze status hebben getransformeerd van

$$ \ket{\psi} _ {initial} = \ket {000} $$

tot

$$ \begin{align} \ket{\psi} _ {final} &= \frac {1} {\sqrt {8} } \left( \ket {000} + \ket + {001} {010} \ket + {011} \ket + {100} \ket + {101} \ket + {110} \ket + \ket {111} \right) \ \ &= \frac {1} {\sqrt{2^n}}\sum _ {j=0}^{2^n-1} \ket{j}, \end{align} $$

dat is precies het gedrag van de vier qubit-transformatie van 3 qubits.

Als u wilt weten hoe andere invoer staten worden beïnvloed, raden we u aan om te spelen met het toepassen van qubitbewerkingen vóór de transformatie.

Metingen toevoegen

Helaas vertelt een hoeksteen van kwantummechanica ons dat een echt kwantumsysteem een dergelijke functie niet kan DumpMachine hebben. In plaats daarvan wordt de informatie geëxtraheerd via metingen, die over het algemeen niet alleen niet de volledige kwantumtoestand bieden, maar ook het systeem zelf drastisch kunnen wijzigen. Er zijn veel soorten kwantummetingen, maar we richten ons op de meest basale: projectieve metingen op één qubit. Bij een meting op een bepaalde basis (bijvoorbeeld de rekenkundige basis $ \ket , \ket $), wordt de toestand van de qubit geprojecteerd op basis van welke basistoestand is { {0} {1} gemeten---hence waarbij een superpositie tussen de twee } wordt vernietigd.

Als u metingen binnen een programma Q# wilt implementeren, gebruikt u de M bewerking (van ), die een type Microsoft.Quantum.Intrinsic Result retourneert.

Wijzig eerst de bewerking Perform3QubitQFT om een matrix met meetresultaten te retourneren, , in plaats van Result[] Unit .

    operation Perform3QubitQFT() : Result[] {

Matrix definiëren en Result[] initialiseren

Voordat u zelfs qubits toewijst (bijvoorbeeld vóór de instructie), declareer en bindt u deze matrix use met lengte-3 (één Result voor elke qubit):

        mutable resultArray = new Result[3];

Met het prefacing van trefwoorden kan de variabele later in de code worden --- bijvoorbeeld bij het toevoegen van de mutable resultArray meetresultaten.

Metingen uitvoeren in een lus for en resultaten toevoegen aan matrix

Voeg na de transformatiebewerkingen van Fourier de volgende code in:

            for i in IndexRange(qs) {
                set resultArray w/= i <- M(qs[i]);
            }

De functie die wordt aangeroepen op een matrix (bijvoorbeeld onze matrix van qubits, ) retourneert een bereik IndexRange qs over de indexen van de matrix. Hier wordt deze in de lus gebruikt for om elke qubit opeenvolgend te meten met behulp van de M(qs[i]) instructie . Elk gemeten type (of ) wordt vervolgens toegevoegd aan de overeenkomstige indexpositie in met een Result Zero instructie One resultArray update-and-reassign.

Notitie

De syntaxis van deze instructie is uniek voor , maar komt overeen met de vergelijkbare variabele opnieuw toewijzen gezien in andere talen, zoals Q# resultArray[i] <- M(qs[i]) F# en R.

Het set trefwoord wordt altijd gebruikt voor het opnieuw toewijzen van variabelen die zijn gebonden met mutable .

Terug resultArray

Nu alle drie de qubits zijn gemeten en de resultaten zijn toegevoegd aan , kunt u de qubits opnieuw instellen en de toewijzing van de resultArray qubits op dezelfde manier in de weg staan. Als u de metingen wilt retourneren, voegt u het volgende in:

        return resultArray;

Inzicht in de effecten van metingen

We gaan de plaatsing van onze functies wijzigen om de status vóór en na de DumpMachine metingen uit te voeren. De uiteindelijke bewerkingscode moet er als volgende uitzien:

    operation Perform3QubitQFT() : Result[] {

        mutable resultArray = new Result[3];

        use qs = Qubit[3];

        //QFT:
        //first qubit:
        H(qs[0]);
        Controlled R1([qs[1]], (PI()/2.0, qs[0]));
        Controlled R1([qs[2]], (PI()/4.0, qs[0]));

        //second qubit:
        H(qs[1]);
        Controlled R1([qs[2]], (PI()/2.0, qs[1]));

        //third qubit:
        H(qs[2]);

        SWAP(qs[2], qs[0]);

        Message("Before measurement: ");
        DumpMachine();

        for i in IndexRange(qs) {
            set resultArray w/= i <- M(qs[i]);
        }

        Message("After measurement: ");
        DumpMachine();

        ResetAll(qs);

        return resultArray;

    }

Als u vanaf de opdrachtprompt werkt, wordt de geretourneerde matrix aan het einde van de run rechtstreeks in de console weergegeven. Werk anders uw hostprogramma bij om de geretourneerde matrix te verwerken.

Als u meer inzicht wilt krijgen in de geretourneerde matrix die wordt afgedrukt in de -console, kunt u net vóór de instructie nog een matrix Message toevoegen aan Q# het return bestand:

        Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: ");
        return resultArray;

Voer het project uit. De uitvoer moet er ongeveer als volgt uitzien:

Before measurement: 
# wave function for qubits with ids (least to most significant): 0;1;2
|0>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|1>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|2>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|3>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|4>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|5>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|6>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
|7>:     0.353553 +  0.000000 i  ==     ***                  [ 0.125000 ]     --- [  0.00000 rad ]
After measurement:
# wave function for qubits with ids (least to most significant): 0;1;2
|0>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
|1>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
|2>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
|3>:     1.000000 +  0.000000 i  ==     ******************** [ 1.000000 ]     --- [  0.00000 rad ]
|4>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
|5>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
|6>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]
|7>:     0.000000 +  0.000000 i  ==                          [ 0.000000 ]

Post-QFT measurement results [qubit0, qubit1, qubit2]: 
[One,One,Zero]

Deze uitvoer illustreert een aantal verschillende dingen:

  1. Als u het geretourneerde resultaat vergelijkt met de premeting , illustreert het duidelijk niet de DumpMachine post-QFT-superpositie ten opzichte van basisposities. Een meting retourneert slechts één basistoestand, met een waarschijnlijkheid die wordt bepaald door de amplitude van die status in de golffunctie van het systeem.
  2. In de postmeting zien we dat meting de status zelf wijzigt, door deze vanaf de eerste superpositie over basistoestanden te projecteren naar de enkelvoudige basistoestand die overeenkomt met de gemeten DumpMachine waarde.

Als u deze bewerking meerdere keren zou herhalen, ziet u dat de resultaatstatistieken beginnen met het illustreren van de even gewogen superpositie van de post-QFT-status die bij elke opname een willekeurig resultaat geeft. Maar behalve dat dit inefficiënt en nog steeds niet efficiënt is, zou dit niettemin alleen de relatieve amplitudes van de basisfasen reproduceren, niet de relatieve fasen ertussen. Het laatste is geen probleem in dit voorbeeld, maar u ziet relatieve fasen verschijnen als u een complexere invoer voor de QFT krijgt dan $\ket {000} $.

Gedeeltelijke metingen

Als u wilt verkennen hoe het meten van slechts enkele qubits van het register van invloed kan zijn op de status van het systeem, voegt u het volgende toe binnen de lus, na for de meetregel:

                let iString = IntAsString(i);
                Message("After measurement of qubit " + iString + ":");
                DumpMachine();

Houd er rekening mee dat u moet IntAsString toevoegen om toegang te krijgen tot de functie

    open Microsoft.Quantum.Convert;

met de rest van de open naamruimte-instructies.

In de resulterende uitvoer ziet u de geleidelijke projectie in subruimten terwijl elke qubit wordt gemeten.

De bibliotheken Q# gebruiken

Zoals vermeld in de inleiding, ligt de kracht van een groot deel ervan in het feit dat u hiermee de zorgen van het omgaan met afzonderlijke Q# qubits kunt abstraheeren. Als u op volledige schaal van toepassing zijnde kwantumprogramma's wilt ontwikkelen, zou het maken van een bewerking vóór of na een bepaalde rotatie u alleen H maar vertragen.

De Q# bibliotheken bevatten de QFT-bewerking, die u eenvoudig kunt uitvoeren en toepassen op een groot aantal qubits. Als u het wilt proberen, definieert u een nieuwe bewerking in uw bestand met dezelfde inhoud van , maar met alles van de eerste tot de vervangen door Q# Perform3QubitQFT twee eenvoudige H SWAP regels:

            let register = BigEndian(qs);    //from Microsoft.Quantum.Arithmetic
            QFT(register);                   //from Microsoft.Quantum.Canon

Met de eerste regel maakt u eenvoudigweg een expressie van de toegewezen matrix van qubits, , die door de BigEndian qs QFT-bewerking als argument wordt gebruikt. Dit komt overeen met de indexvolgorde van de qubits in het register.

Als u toegang wilt hebben tot deze bewerkingen, voegt u -instructies toe voor hun respectieve open naamruimten aan het begin van het Q# bestand:

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Arithmetic;

Pas nu uw hostprogramma aan om de naam van de nieuwe bewerking aan te roepen (bijvoorbeeld ) en PerformIntrinsicQFT geef het een e-mail.

Als u het werkelijke voordeel van het gebruik van de bibliotheekbewerkingen wilt zien, wijzigt u het aantal Q# qubits in iets anders dan 3 :

        mutable resultArray = new Result[4];

        use qs = Qubit[4];
        //...

U kunt dus de juiste QFT toepassen voor elk gegeven aantal qubits, zonder dat u zich zorgen hoeft te maken over de nieuwe bewerkingen en H rotaties op elke qubit.

Houd er rekening mee dat het uitvoeren van de kwantumsimulator exponentieel meer tijd in beslag neemt wanneer u het aantal qubits verhoogt---voorbereiding waarom we naar echte kwantumhardware kijken.