Delen via


Zelfstudie: De Quantum Fourier-transformatie implementeren in Q#

In deze zelfstudie leert u hoe u een eenvoudig kwantumprogramma schrijft en simuleert dat werkt op afzonderlijke qubits.

Hoewel Q# het voornamelijk is gemaakt als een programmeertaal op hoog niveau voor grootschalige kwantumprogramma's, kan het ook worden gebruikt om het lagere niveau van kwantumprogrammering te verkennen, dat wil gezegd, rechtstreeks om specifieke qubits aan te pakken. In deze zelfstudie wordt met name gekeken naar de QFT (Quantum Fourier Transform), een subroutine die integraal is voor veel grotere kwantumalgoritmen.

In deze zelfstudie leert u het volgende:

  • Kwantumbewerkingen definiëren in Q#.
  • Het Quantum Fourier-transformatiecircuit schrijven
  • Simuleer een kwantumbewerking van qubittoewijzing naar metingsuitvoer.
  • Bekijk hoe de gesimuleerde golffunctie van het kwantumsysteem zich tijdens de bewerking ontwikkelt.

Notitie

Deze weergave op een lager niveau van kwantuminformatieverwerking wordt vaak beschreven in kwantumcircuits, die de sequentiële toepassing van poorten of bewerkingen vertegenwoordigen voor specifieke qubits van een systeem. De bewerkingen met één en meerdere qubits die u opeenvolgend toepast, kunnen dus direct worden weergegeven in circuitdiagrammen. De volledige kwantum-fouriertransformatie met drie qubits die in deze zelfstudie wordt gebruikt, heeft bijvoorbeeld de volgende weergave als circuit: Diagram van een Quantum Fourier Transform-circuit.

Tip

Als u uw kwantumcomputingtraject wilt versnellen, bekijkt u Code met Azure Quantum, een unieke functie van de Azure Quantum-website. Hier kunt u ingebouwde Q# voorbeelden of uw eigen Q# programma's uitvoeren, nieuwe Q# code genereren vanuit uw prompts, uw code openen en uitvoeren in VS Code voor het web met één klik en Copilot vragen stellen over kwantumcomputing.

Vereisten

Een nieuw Q# bestand maken

  1. Selecteer in VS Code Bestand > nieuw tekstbestand
  2. Sla het bestand op als QFTcircuit.qs. Dit bestand bevat de Q# code voor uw programma.
  3. Open QFTcircuit.qs.

Een QFT-circuit schrijven in Q#

Het eerste deel van deze zelfstudie bestaat uit het definiëren van de Q# bewerking Main, waarmee de kwantum Fourier-transformatie op drie qubits wordt uitgevoerd. De DumpMachine functie wordt gebruikt om te zien hoe de gesimuleerde golffunctie van het drie-qubitsysteem zich ontwikkelt tijdens de bewerking. In het tweede deel van de zelfstudie voegt u meetfunctionaliteit toe en vergelijkt u de pre- en postmetingsstatussen van de qubits.

U gaat de bewerking stap voor stap bouwen. Kopieer en plak de code in de volgende secties in het bestand QFTcircuit.qs .

U kunt de volledige Q# code voor deze sectie bekijken als naslaginformatie.

Vereiste Q# bibliotheken importeren

Importeer de relevante Microsoft.Quantum.* naamruimten in het Q# bestand.

import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;

// operations go here

Bewerkingen definiëren met argumenten en retourneert

Definieer vervolgens de Main bewerking:

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

De Main() bewerking heeft nooit argumenten en retourneert nu een Unit object, dat vergelijkbaar is met het retourneren void in C# of een lege tuple, Tuple[()]in Python. Later wijzigt u de bewerking om een matrix met meetresultaten te retourneren.

Qubits toewijzen

Wijs binnen de Q# bewerking een register van drie qubits toe met het use trefwoord. Met useworden de qubits automatisch toegewezen in de status $\ket{0}$.

use qs = Qubit[3]; // allocate three qubits

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

Net als bij echte kwantumberekeningen kunt Q# u geen rechtstreeks toegang krijgen tot qubitstatussen. De DumpMachine bewerking drukt echter de huidige status van de target machine af, zodat deze waardevolle inzichten kan bieden voor foutopsporing en leren wanneer deze wordt gebruikt in combinatie met de simulator voor volledige status.

Bewerkingen met één qubit en gecontroleerde bewerkingen toepassen

Vervolgens past u de bewerkingen toe die de Main bewerking zelf vormen. Q# bevat al veel van deze en andere eenvoudige kwantumbewerkingen in de Microsoft.Quantum.Intrinsic naamruimte.

Notitie

Houd er rekening mee dat Microsoft.Quantum.Intrinsic het niet is geïmporteerd in het eerdere codefragment met de andere naamruimten, omdat het automatisch wordt geladen door de compiler voor alle Q# programma's.

De eerste bewerking die is toegepast, is de H bewerking (Hadamard) op de eerste qubit:

Diagram van een circuit voor drie qubit QFT via eerste Hadamard.

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

H(qs[0]);

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

Q# maakt het eenvoudig om de uitvoering van een bewerking op een of meerdere qubits te bepalen. Over het algemeen wordt de aanroep voorafgegaan door Controlleden veranderen de bewerkingsargumenten als volgt:

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

Houd er rekening mee dat het argument controle-qubit een matrix moet zijn, zelfs als het voor één qubit is.

De gecontroleerde bewerkingen in de QFT zijn de R1 bewerkingen die handelen op de eerste qubit (en beheerd door de tweede en derde qubits):

Diagram van een circuit voor drie qubit Quantum Fourier Transform via eerste qubit.

Roep in uw Q# bestand deze bewerkingen aan met de volgende instructies:

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

De PI() functie wordt gebruikt om de rotaties te definiëren in termen van pi radialen.

SWAP-bewerking toepassen

Nadat de relevante H bewerkingen en gecontroleerde rotaties op de tweede en derde qubits zijn toegepast, ziet het circuit er als volgt uit:

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

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

Ten slotte past u een SWAP bewerking toe op de eerste en derde qubits om het circuit te voltooien. 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.

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

Nu bent u klaar met het schrijven van de bewerkingen op qubitniveau van de kwantum fouriertransformatie naar uw Q# bewerking:

Diagram met een circuit voor drie qubit Quantum Fourier Transform.

Toewijzing van qubits ongedaan maken

De laatste stap is opnieuw aanroepen DumpMachine() om de status na de bewerking te zien en de toewijzing van de qubits ongedaan te maken. De qubits hadden de status $\ket{0}$ toen u ze toedeelde en opnieuw moeten worden ingesteld op de oorspronkelijke status met behulp van de ResetAll bewerking.

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

Voeg de volgende regels toe aan uw Q# bestand:

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

ResetAll(qs); // deallocate qubits

De volledige QFT-bewerking

Het Q# programma is voltooid. Uw QFTcircuit.qs-bestand moet er nu als volgt uitzien:

import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;

operation Main() : Unit {

    use qs = Qubit[3]; // allocate three qubits

    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); // deallocate qubits

}                                                                                                                                                                               

Het QFT-circuit uitvoeren

Op dit moment retourneert de Main bewerking geen waarde. De bewerking retourneert Unit een waarde. Later wijzigt u de bewerking om een matrix met meetresultaten (Result[]) te retourneren.

  1. Voordat u het programma uitvoert, controleert u in de statusbalk onder aan VS Code of het target profiel is ingesteld Q#op: Onbeperkt. Als u het target profiel wilt wijzigen, selecteert u het target profiel op de statusbalk en selecteert u Onbeperkt in de vervolgkeuzelijst. Als het target profiel niet is ingesteld op Onbeperkt, krijgt u een foutmelding wanneer u het programma uitvoert.
  2. Als u het programma wilt uitvoeren, selecteert u Bestand Q# uitvoeren in de vervolgkeuzelijst Voor afspelen in de rechterbovenhoek of drukt u op Ctrl+F5. Het programma voert de Main() bewerking uit op de standaardsimulator.
  3. De Message en DumpMachine uitvoer worden weergegeven in de console voor foutopsporing.

Als u wilt weten hoe andere invoerstatussen worden beïnvloed, wordt u aangeraden te experimenteren met het toepassen van andere qubitbewerkingen vóór de transformatie.

Metingen toevoegen aan het QFT-circuit

De weergave van de DumpMachine functie toont de resultaten van de bewerking, maar helaas stelt een hoeksteen van de kwantummechanica dat een echt kwantumsysteem geen dergelijke DumpMachine functie kan hebben. In plaats daarvan wordt de informatie geëxtraheerd via metingen, die in het algemeen niet alleen informatie verstrekken over de volledige kwantumstatus, maar ook het systeem zelf drastisch kan wijzigen.

Er zijn veel soorten kwantummetingen, maar het voorbeeld hier richt zich op de meest elementaire: projectieve metingen op enkele qubits. Bij meting in een bepaalde basis (bijvoorbeeld de rekenkundige basis $ { \ket{0}, \ket{1} } $), wordt de qubitstatus geprojecteerd op de basisstatus die is gemeten, waardoor elke superpositie tussen de twee wordt vernietigd.

De QFT-bewerking wijzigen

Als u metingen binnen een Q# programma wilt implementeren, gebruikt u de M bewerking, die een Result type retourneert.

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

operation Main() : Result[] {

Matrix definiëren en initialiseren Result[]

Voordat u qubits toegeeft, declareert en bindt u een matrix met drie elementen (één Result voor elke qubit):

mutable resultArray = [Zero, size = 3];

Met mutable de prefacing voor trefwoorden resultArray kan de variabele later in de code worden gewijzigd, bijvoorbeeld wanneer u de meetresultaten toevoegt.

Metingen uitvoeren in een for lus en resultaten toevoegen aan matrix

Voeg na de transformatiebewerkingen van QFT de volgende code in:

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

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

Notitie

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

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

Terugkeren resultArray

Wanneer alle drie de qubits zijn gemeten en de resultaten zijn resultArraytoegevoegd, kunt u de qubits veilig opnieuw instellen en de toewijzing ervan ongedaan maken zoals voorheen. Als u de metingen wilt retourneren, voegt u het volgende in:

return resultArray;

Het QFT-circuit uitvoeren met de metingen

Wijzig nu de plaatsing van de DumpMachine functies om de status vóór en na de metingen uit te voeren. De uiteindelijke Q# code moet er als volgt uitzien:

import Microsoft.Quantum.Diagnostics.*;
import Microsoft.Quantum.Math.*;
import Microsoft.Quantum.Arrays.*;

operation Main() : Result[] {

    mutable resultArray = [Zero, size = 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);
    Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: ");
    return resultArray;

}

Tip

Vergeet niet om uw bestand op te slaan telkens wanneer u een wijziging in de code aanbrengt voordat u het opnieuw uitvoert.

  1. Voordat u het programma uitvoert, controleert u in de statusbalk onder aan VS Code of het target profiel is ingesteld Q#op: Onbeperkt. Als u het target profiel wilt wijzigen, selecteert u het target profiel op de statusbalk en selecteert u Onbeperkt in de vervolgkeuzelijst. Als het target profiel niet is ingesteld op Onbeperkt, krijgt u een foutmelding wanneer u het programma uitvoert.
  2. Als u het programma wilt uitvoeren, selecteert u Bestand Q# uitvoeren in de vervolgkeuzelijst Voor afspelen in de rechterbovenhoek of drukt u op Ctrl+5. Het programma voert de Main() bewerking uit op de standaardsimulator.
  3. De Message en DumpMachine uitvoer worden weergegeven in de console voor foutopsporing.

Uw uitvoer ziet er ongeveer als volgt uit:

Before measurement: 

 Basis | Amplitude      | Probability | Phase
 -----------------------------------------------
 |000⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |001⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |010⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |011⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |100⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |101⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |110⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000
 |111⟩ |  0.3536+0.0000𝑖 |    12.5000% |   0.0000

After measurement: 

 Basis | Amplitude      | Probability | Phase
 -----------------------------------------------
 |010⟩ |  1.0000+0.0000𝑖 |   100.0000% |   0.0000

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

[Zero, One, Zero]

In deze uitvoer ziet u een aantal verschillende dingen:

  1. Het vergelijken van het geretourneerde resultaat met de premeting DumpMachine, illustreert duidelijk niet de post-QFT-superpositie over basistoestanden. Een meting retourneert slechts één basistoestand, met een waarschijnlijkheid die wordt bepaald door de amplitude van die toestand in de golffunctie van het systeem.
  2. Vanaf de postmeting ziet u dat de meting DumpMachinede status zelf verandert, waarbij deze wordt geprojecteerd vanaf de eerste superpositie over basistoestanden tot de enkele basisstatus die overeenkomt met de gemeten waarde.

Als u deze bewerking vaak herhaalt, ziet u dat de resultaatstatistieken de even gewogen superpositie van de post-QFT-status illustreren die bij elke opname een willekeurig resultaat oplevert. Behalve inefficiënt en nog steeds onvolkomen te zijn, zou dit echter alleen de relatieve amplitudes van de basistoestanden reproduceren, niet de relatieve fasen ertussen. Dit laatste is geen probleem in dit voorbeeld, maar u ziet dat relatieve fasen worden weergegeven als u een complexere invoer voor de QFT krijgt dan $\ket{000}$.

Gebruik de Q# bewerkingen om het QFT-circuit te vereenvoudigen

Zoals vermeld in de inleiding, rust veel van Q#de macht in het feit dat u hiermee de zorgen over afzonderlijke qubits kunt abstraheren. Inderdaad, als u volledig schalende, toepasselijke kwantumprogramma's wilt ontwikkelen, moet u zich zorgen maken over of een H bewerking vóór of na een bepaalde rotatie alleen maar vertraagt. Azure Quantum biedt de ApplyQFT bewerking, die u kunt gebruiken en toepassen op een willekeurig aantal qubits.

  1. Vervang alles van de eerste H bewerking tot de SWAP bewerking, inclusief:

    ApplyQFT(qs);
    
  2. Uw code moet er nu als volgt uitzien

    import Microsoft.Quantum.Diagnostics.*;
    import Microsoft.Quantum.Math.*;
    import Microsoft.Quantum.Arrays.*;
    
    operation Main() : Result[] {
    
        mutable resultArray = [Zero, size = 3];
    
        use qs = Qubit[3];
    
        //QFT:
        //first qubit:
    
        ApplyQFT(qs);
    
        Message("Before measurement: ");
        DumpMachine();
    
        for i in IndexRange(qs) {
            set resultArray w/= i <- M(qs[i]);
        }
    
        Message("After measurement: ");
        DumpMachine();
    
        ResetAll(qs);
        Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: ");
        return resultArray;
    
    }
    
  3. Voer het Q# programma opnieuw uit en u ziet dat de uitvoer hetzelfde is als voorheen.

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

mutable resultArray = [Zero, size = 4];

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

U kunt dus de juiste QFT toepassen voor een bepaald aantal qubits, zonder dat u zich zorgen hoeft te maken over het toevoegen van nieuwe H bewerkingen en rotaties voor elke qubit.

Bekijk andere Q# zelfstudies: