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:
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
De nieuwste versie van Visual Studio Code of open VS Code op het web.
De nieuwste versie van de Azure-extensieQuantum Development Kit. Zie QDK installeren in VS Code voor installatiedetails.
Als u Jupyter Notebooks wilt gebruiken, moet u ook Python- en Jupyter-extensies en het nieuwste
qsharp
Python-pakket installeren. Hiervoor opent u een terminal en voert u de volgende opdracht uit:$ pip install --upgrade qsharp
Een nieuw Q# bestand maken
- Selecteer in VS Code Bestand > nieuw tekstbestand
- Sla het bestand op als QFTcircuit.qs. Dit bestand bevat de Q# code voor uw programma.
- 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 use
worden 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:
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 Controlled
en 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):
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:
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.
- 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.
- 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. - De
Message
enDumpMachine
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 resultArray
toegevoegd, 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.
- 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.
- 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. - De
Message
enDumpMachine
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:
- 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. - Vanaf de postmeting ziet u dat de meting
DumpMachine
de 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.
Vervang alles van de eerste
H
bewerking tot deSWAP
bewerking, inclusief:ApplyQFT(qs);
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; }
Voer het Q# programma opnieuw uit en u ziet dat de uitvoer hetzelfde is als voorheen.
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.
Gerelateerde inhoud
Bekijk andere Q# zelfstudies:
- Kwantumgenerator voor willekeurige getallen laat zien hoe u een Q# programma schrijft waarmee willekeurige getallen uit qubits in superpositie worden gegenereerd.
- Het zoekalgoritmen van Grover laten zien hoe u een Q# programma schrijft dat gebruikmaakt van het zoekalgoritmen van Grover.
- Kwantumverstrengeling laat zien hoe u een Q# programma schrijft dat qubits bewerkt en meet en de effecten van superpositie en verstrengeling demonstreert.
- De Quantum Katas zijn zelfstudies in eigen tempo en programmeeroefeningen die zijn gericht op het leren van de elementen van kwantumcomputing en Q# programmeren op hetzelfde moment.