Bagikan melalui


Tutorial: Menerapkan Transformasi Quantum Fourier di Q#

Tutorial ini menunjukkan cara menulis dan mensimulasikan program kuantum dasar yang beroperasi pada qubit individu.

Meskipun Q# terutama dibuat sebagai bahasa pemrograman tingkat tinggi untuk program kuantum skala besar, itu juga dapat digunakan untuk menjelajahi tingkat yang lebih rendah dari pemrograman kuantum, yaitu, secara langsung menangani qubit tertentu. Secara khusus, tutorial ini melihat lebih dekat pada Quantum Fourier Transform (QFT), subrutin yang merupakan bagian besar integral dari banyak algoritma kuantum yang lebih besar.

Dalam tutorial ini, Anda mempelajari cara:

  • Tentukan operasi kuantum dalam Q#.
  • Buat sirkuit Transformasi Fourier Kuantum
  • Simulasikan operasi kuantum dari alokasi kubit hingga output pengukuran.
  • Amati bagaimana fungsi gelombang simulasi sistem kuantum berevolusi sepanjang operasi.

Catatan

Tampilan level yang lebih rendah dari pemrosesan informasi kuantum ini sering dijelaskan dalam hal sirkuit kuantum, yang mewakili penerapan berurutan gerbang kuantum, atau operasi, pada qubit tertentu dalam suatu sistem. Dengan demikian, operasi tunggal dan multi-qubit yang Anda terapkan secara berurutan dapat dengan mudah diwakili dalam diagram sirkuit. Misalnya, transformasi Fourier kuantum tiga-qubit lengkap yang digunakan dalam tutorial ini memiliki representasi berikut sebagai sirkuit: Diagram sirkuit Transformasi Fourier Kuantum.

Tip

Jika Anda ingin mempercepat perjalanan komputasi kuantum Anda, lihat Kode dengan Azure Quantum, fitur unik dari situs web Azure Quantum. Di sini, Anda dapat menjalankan sampel bawaan Q# atau program Anda sendiri Q# , menghasilkan kode baru Q# dari perintah Anda, membuka dan menjalankan kode Anda di Visual Studio Code untuk Web dengan satu klik, dan mengajukan pertanyaan apa pun tentang komputasi kuantum.

Prasyarat

Membuat file baru Q#

  1. Di Visual Studio Code, pilih File > Teks Baru
  2. Simpan file sebagai QFTcircuit.qs. File ini berisi kode Q# untuk program Anda.
  3. Buka QFTcircuit.qs.

Tulis sirkuit QFT di Q#

Bagian pertama dari tutorial ini terdiri dari mendefinisikan Q# operasi Main, yang melakukan transformasi Fourier kuantum pada tiga qubit. Fungsi DumpMachine digunakan untuk mengamati bagaimana fungsi gelombang simulasi dari sistem tiga-qubit berkembang di seluruh operasi. Di bagian kedua tutorial, Anda menambahkan fungsi pengukuran dan membandingkan status pra-dan pasca-pengukuran qubit.

Anda membangun operasi langkah demi langkah. Salin dan tempel kode di bagian berikut ke dalam file QFTcircuit.qs .

Anda dapat melihat kode Q# lengkap untuk bagian ini sebagai referensi.

Mengimpor pustaka yang diperlukan Q#

Di dalam file Q# Anda, impor namespace Microsoft.Quantum.* yang relevan.

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

// operations go here

Mendefinisikan operasi dengan argumen dan pengembalian

Selanjutnya, tentukan operasi Main:

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

Operasi Main() tidak pernah mengambil argumen, dan untuk saat ini mengembalikan objek Unit, yang setara dengan mengembalikan void dalam C# atau tuple kosong Tuple[()] di Python. Nantinya, Anda memodifikasi operasi untuk mengembalikan array hasil pengukuran.

Mengalokasikan kubit

Dalam Q# operasi, alokasikan sebuah daftar dari tiga qubit dengan kata kunci use. Dengan use, qubit secara otomatis dialokasikan dalam status $\ket{0}$.

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

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

Seperti dalam komputasi kuantum nyata, Q# tidak memungkinkan Anda untuk langsung mengakses status kuantum. Namun, operasi DumpMachine mencetak status komputer target saat ini, sehingga dapat memberikan wawasan berharga untuk penelusuran kesalahan dan pembelajaran ketika digunakan bersama dengan simulator status penuh.

Menerapkan operasi qubit tunggal dan terkontrol

Selanjutnya, Anda menerapkan operasi yang terdiri dari Main itu sendiri. Q# sudah berisi banyak dari operasi-operasi ini, dan operasi kuantum dasar lainnya, dalam namespace Microsoft.Quantum.Intrinsic.

Catatan

Perhatikan bahwa Microsoft.Quantum.Intrinsic tidak diimpor dalam cuplikan kode sebelumnya bersama dengan namespace lainnya, karena dimuat secara otomatis oleh pengompilasi untuk semua Q# program.

Operasi pertama yang diterapkan adalah operasi (Hadamard) H ke qubit pertama.

Diagram memperlihatkan sirkuit untuk tiga QFT qubit melalui Hadamard pertama.

Untuk menerapkan operasi ke qubit tertentu dari register (misalnya, satu Qubit dari array Qubit[]), gunakan notasi indeks standar. Jadi, menerapkan operasi H pada qubit pertama dari register qs berbentuk:

H(qs[0]);

Selain menerapkan operasi H pada qubit individu, sirkuit QFT terutama terdiri dari rotasi terkendali R1. Operasi R1(θ, <qubit>) secara umum meninggalkan komponen $\ket{0}$ dari kubit tidak berubah saat menerapkan rotasi $e^{i\theta}$ ke komponen $\ket{1}$.

Q# memudahkan pengaturan pelaksanaan operasi berdasarkan satu atau beberapa qubit kontrol. Secara umum, panggilan diawali dengan Controlled, dan argumen operasi berubah sebagai berikut:

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

Perhatikan bahwa argumen qubit kontrol harus berupa array, meskipun untuk satu qubit.

Operasi terkontrol dalam QFT adalah operasi R1 yang mempengaruhi qubit pertama (dan dikendalikan oleh qubit kedua dan ketiga):

Diagram memperlihatkan sirkuit untuk tiga qubit Transformasi Fourier Kuantum melalui qubit pertama.

Dalam file Q# Anda, panggil operasi ini dengan pernyataan-pernyataan ini:

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

Fungsi PI() ini digunakan untuk menentukan rotasi dalam satuan radian pi.

Menerapkan operasi SWAP

Setelah Anda menerapkan operasi H yang relevan dan rotasi terkontrol ke qubit kedua dan ketiga, sirkuit terlihat seperti ini:

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

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

Terakhir, Anda menerapkan SWAP operasi ke qubit pertama dan ketiga untuk menyelesaikan sirkuit. Operasi ini diperlukan karena transformasi quantum Fourier menghasilkan qubit dalam urutan terbalik, sehingga pertukaran memungkinkan integrasi subroutine yang mulus menjadi algoritma yang lebih besar.

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

Sekarang Anda telah selesai menulis operasi tingkat qubit dari transformasi Fourier kuantum menjadi operasi Q# Anda.

Diagram memperlihatkan sirkuit untuk tiga qubit Quantum Fourier Transform.

Melakukan dealokasi qubits

Langkah terakhir adalah memanggil DumpMachine() lagi untuk melihat keadaan pasca operasi, dan untuk membatalkan alokasi qubit. Qubit berada dalam keadaan $\ket{0}$ ketika Anda mengalokasikannya dan perlu diatur ulang ke keadaan awal mereka menggunakan operasi ResetAll.

Mengharuskan semua qubit diatur ulang secara eksplisit ke $\ket{0}$ adalah fitur dasar dari Q#, karena memungkinkan operasi lain untuk mengetahui statusnya dengan tepat ketika mereka mulai menggunakan qubit yang sama (sumber daya yang langka). Selain itu, mengatur ulang mereka memastikan bahwa mereka tidak terjerat dengan qubit lain dalam sistem. Jika reset tidak dilakukan di akhir blok alokasi use, kesalahan runtime mungkin muncul.

Tambahkan baris berikut ke file Q# Anda :

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

ResetAll(qs); // deallocate qubits

Operasi QFT lengkap

Program Q# selesai. File QFTcircuit.qs Anda sekarang akan terlihat seperti ini:

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

}                                                                                                                                                                               

Jalankan sirkuit QFT

Untuk saat ini, Main operasi tidak mengembalikan nilai apa pun - operasi mengembalikan Unit nilai. Kemudian, Anda memodifikasi operasi untuk mengembalikan array hasil pengukuran (Result[]).

  1. Sebelum menjalankan program, verifikasi di bilah status di bagian bawah Visual Studio Code bahwa target profil diatur ke Q#: Tidak dibatasi. Untuk mengubah target profil, pilih target profil di bilah status, dan pilih Tidak Dibatasi dari menu dropdown. Jika profil target tidak diatur ke Tidak Dibatasi, Anda akan mendapatkan kesalahan saat menjalankan program.
  2. Untuk menjalankan program Anda, pilih Jalankan Q# File dari menu drop-down ikon putar di kanan atas, atau tekan Ctrl+F5. Program menjalankan Main() operasi pada simulator default.
  3. Output Message dan DumpMachine muncul di konsol debug.

Jika Anda ingin tahu tentang bagaimana status input lain terpengaruh, Anda didorong untuk bereksperimen dengan menerapkan operasi qubit lainnya sebelum transformasi.

Menambahkan pengukuran ke sirkuit QFT

Tampilan dari fungsi DumpMachine menunjukkan hasil operasi, tetapi sayangnya, landasan mekanika kuantum menyatakan bahwa sistem kuantum nyata tidak dapat memiliki fungsi DumpMachine seperti itu. Sebaliknya, informasi diekstraksi melalui pengukuran, yang secara umum tidak hanya gagal memberikan informasi tentang keadaan kuantum penuh, tetapi juga dapat secara drastis mengubah sistem itu sendiri.

Ada banyak jenis pengukuran kuantum, tetapi contoh di sini berfokus pada yang paling mendasar: pengukuran proyektif pada qubit tunggal. Setelah pengukuran dalam basis tertentu (misalnya, basis komputasi $ { \ket{0}, \ket{1} } $), keadaan qubit diproyeksikan ke keadaan dasar mana pun yang diukur, sehingga menghancurkan superposisi apa pun di antara keduanya.

Mengubah operasi QFT

Untuk menerapkan pengukuran dalam suatu program Q#, gunakan operasi M, yang mengembalikan jenis Result.

Pertama, memodifikasi operasi Main untuk mengembalikan array hasil pengukuran, Result[], bukan Unit.

operation Main() : Result[] {

Menentukan dan menginisialisasi array Result[]

Sebelum mengalokasikan qubit, deklarasikan dan ikat array tiga elemen (satu Result untuk setiap qubit):

mutable resultArray = [Zero, size = 3];

Kata kunci kata pengantar mutableresultArray memungkinkan variabel untuk dimodifikasi nanti dalam kode, misalnya, saat menambahkan hasil pengukuran Anda.

Melakukan pengukuran dalam satu perulangan for dan menambahkan hasil ke array

Setelah operasi transformasi QFT, sisipkan kode berikut:

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

Fungsi IndexRange yang dipanggil pada array (misalnya, array qubit, qs) mengembalikan rentang indeks dari array. Di sini, ini digunakan dalam perulangan for untuk mengukur setiap qubit secara berurutan menggunakan pernyataan M(qs[i]). Setiap jenis Result yang diukur (baik Zero atau One) kemudian ditambahkan ke posisi indeks dalam resultArray yang sesuai dengan pernyataan pembaruan dan penetapan ulang.

Catatan

Sintaks pernyataan ini unik untuk Q#, tetapi sesuai dengan penugasan ulang variabel serupa yang resultArray[i] <- M(qs[i]) terlihat dalam bahasa lain seperti F # dan R.

Kata kunci set selalu digunakan untuk menetapkan kembali variabel yang terikat menggunakan mutable.

Mengembalikan resultArray

Dengan ketiga qubit yang diukur dan hasilnya ditambahkan ke resultArray, Anda dapat dengan aman mereset dan mendekalokasikan qubit seperti yang telah dilakukan sebelumnya. Untuk mengembalikan pengukuran, masukkan:

return resultArray;

Jalankan sirkuit QFT dengan pengukuran

Sekarang ubah penempatan fungsi DumpMachine untuk mengeluarkan status sebelum dan sesudah pengukuran. Kode Q# terakhir Anda akan terlihat seperti ini:

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) {
        resultArray w/= i <- M(qs[i]);
    }

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

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

}

Tips

Ingatlah untuk menyimpan file Anda setiap kali Anda memperkenalkan perubahan pada kode sebelum menjalankannya lagi.

  1. Sebelum menjalankan program, verifikasi di bilah status di bagian bawah Visual Studio Code bahwa target profil diatur ke Q#: Tidak dibatasi. Untuk mengubah target profil, pilih target profil di bilah status, dan pilih Tidak Dibatasi dari menu dropdown. Jika profil target tidak diatur ke Tidak Dibatasi, Anda akan mendapatkan kesalahan saat menjalankan program.
  2. Untuk menjalankan program Anda, pilih Jalankan Q# file dari menu drop-down ikon putar di kanan atas, atau tekan Ctrl+5. Program menjalankan Main() operasi pada simulator default.
  3. Output Message dan DumpMachine muncul di konsol debug.

Output Anda akan terlihat mirip dengan ini:

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]

Output ini menggambarkan beberapa hal yang berbeda:

  1. Ketika Anda membandingkan hasil yang dikembalikan dengan pra-pengukuran DumpMachine, itu jelas tidak mengilustrasikan superposisi pasca-QFT atas status dasar. Pengukuran hanya mengembalikan keadaan dasar tunggal, dengan peluang ditentukan oleh amplitudo keadaan itu dalam fungsi gelombang sistem.
  2. Dari pasca-pengukuran DumpMachine, Anda melihat bahwa pengukuran mengubah keadaan itu sendiri, memproyeksikannya dari superposisi awal atas status dasar ke keadaan dasar tunggal yang sesuai dengan nilai yang diukur.

Jika Anda mengulangi operasi ini berkali-kali, Anda akan melihat bahwa statistik hasil mulai menggambarkan superposisi yang tertimbang secara merata dari keadaan pasca-QFT, yang menghasilkan hasil acak pada setiap pengukuran. Namun, selain tidak efisien dan masih tidak sempurna, ini hanya akan mereproduksi amplitudo relatif dari keadaan dasar, bukan fase relatif di antara mereka. Yang terakhir bukan masalah dalam contoh ini, tetapi Anda akan melihat fase relatif muncul jika diberikan input yang lebih kompleks ke QFT daripada $\ket{000}$.

Q# Gunakan operasi untuk menyederhanakan sirkuit QFT

Seperti disebutkan dalam pendahuluan, sebagian besar kekuatan Q# terletak pada kenyataan bahwa itu memungkinkan Anda untuk menghapus kekhawatiran dari berurusan dengan qubit individu. Memang, jika Anda ingin mengembangkan program kuantum yang dapat diterapkan skala penuh, mengkhawatirkan apakah operasi H dilakukan sebelum atau sesudah rotasi tertentu hanya akan memperlambat Anda. Azure Quantum menyediakan ApplyQFT operasi, yang dapat Anda gunakan dan terapkan untuk sejumlah qubit.

  1. Ganti semuanya dari operasi pertama H ke SWAP operasi, inklusif, dengan:

    ApplyQFT(qs);
    
  2. Kode Anda sekarang akan terlihat seperti ini

    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) {
            resultArray w/= i <- M(qs[i]);
        }
    
        Message("After measurement: ");
        DumpMachine();
    
        ResetAll(qs);
        Message("Post-QFT measurement results [qubit0, qubit1, qubit2]: ");
        return resultArray;
    
    }
    
  3. Jalankan Q# program lagi dan perhatikan bahwa outputnya sama seperti sebelumnya.

  4. Untuk melihat manfaat nyata menggunakan Q# operasi, ubah jumlah qubit menjadi sesuatu selain 3:

mutable resultArray = [Zero, size = 4];

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

Anda dengan demikian dapat menerapkan QFT yang tepat untuk sejumlah kubit tertentu, tanpa harus khawatir tentang menambahkan operasi dan rotasi baru H pada setiap qubit.

Jelajahi tutorial Q# lainnya:

  • Penghasil Angka Acak Kuantum menunjukkan bagaimana menulis Q# program yang menghasilkan angka acak dengan qubit dalam superposisi.
  • Algoritma pencarian Grover menunjukkan cara menulis Q# program yang menggunakan algoritma pencarian Grover.
  • Keterkaitan kuantum menunjukkan cara menulis Q# program yang memanipulasi dan mengukur qubit dan menunjukkan efek superposisi dan keterkaitan.
  • Quantum Katas adalah tutorial dan latihan pemrograman mandiri yang bertujuan untuk mengajarkan elemen komputasi dan Q# pemrograman kuantum secara bersamaan.