Samouczek: eksplorowanie splątania kwantowego za pomocą polecenia Q#

W tym samouczku pokazano, jak napisać Q# program, który manipuluje kubitami i mierzy je oraz demonstruje efekty superpozycji i splątania. Przygotowujesz dwa kubity w określonym stanie kwantowym, dowiesz się, jak działać na kubitach Q# , aby zmienić ich stan, i zademonstrować skutki superpozycji i splątania. Program jest kompilowany po kawałku, Q# aby wprowadzić stany, operacje i pomiary kubitu.

Uwaga

Zestaw Microsoft Quantum Development Kit (klasyczny zestaw QDK) nie będzie już obsługiwany po 30 czerwca 2024 r. Jeśli jesteś istniejącym deweloperem zestawu QDK, zalecamy przejście do nowego zestawu Azure Quantum Development Kit (nowoczesnego zestawu QDK), aby kontynuować opracowywanie rozwiązań kwantowych. Aby uzyskać więcej informacji, zobacz Migrowanie Q# kodu do nowoczesnego zestawu QDK.

Poniżej przedstawiono kilka kluczowych pojęć, które należy zrozumieć przed rozpoczęciem:

  • Jeśli bity klasyczne przechowują pojedynczą wartość binarną, taką jak 0 lub 1, stan kubitu może znajdować się w superpozycji dwóch stanów kwantowych, 0 i 1. Każdy możliwy stan kwantowy ma skojarzona amplituda prawdopodobieństwa.
  • Czynność pomiaru kubitu generuje wynik binarny z pewnym prawdopodobieństwem i zmienia stan kubitu z superpozycji.
  • Wiele kubitów można splątać w taki sposób, że nie można ich opisać niezależnie od siebie. Oznacza to, że cokolwiek się dzieje z jednym kubitem w splątanej parze również dzieje się z drugim kubitem.

Z tego samouczka dowiesz się, jak wykonywać następujące czynności:

  • Tworzenie Q# operacji w celu zainicjowania kubitu do żądanego stanu.
  • Umieść kubit w superpozycji.
  • Splątanie pary kubitów.
  • Zmierz kubit i obserwuj wyniki.

Porada

Jeśli chcesz przyspieszyć podróż po obliczeniach kwantowych, zapoznaj się z kodem w usłudze Azure Quantum, unikatową funkcją witryny internetowej usługi Azure Quantum. W tym miejscu możesz uruchamiać wbudowane Q# przykłady lub własne Q# programy, generować nowy Q# kod z monitów, otwierać i uruchamiać kod w programie VS Code dla sieci Web za pomocą jednego kliknięcia i zadać Copilot wszelkie pytania dotyczące obliczeń kwantowych.

Wymagania wstępne

Aby uruchomić przykładowy kod w rozwiązaniu Copilot for Azure Quantum, potrzebne są następujące elementy:

  • Konto e-mail firmy Microsoft (MSA).

Aby uzyskać więcej informacji na temat rozwiązania Copilot, zobacz Eksplorowanie usługi Azure Quantum.

Inicjowanie kubitu do znanego stanu

Pierwszym krokiem Q# jest zdefiniowanie operacji, która zainicjuje kubit do znanego stanu. Można to wywołać, aby ustawić kubit na stan klasyczny, co oznacza, że w przypadku pomiaru zwraca Zero 100% czasu lub zwraca One 100% czasu. Pomiar kubitu zwraca Q# typ Result, który może mieć tylko wartość Zero lub One.

Otwórz narzędzie Copilot for Azure Quantum i skopiuj następujący kod do okna edytora kodu. Nie klikaj jeszcze przycisku Uruchom . W dalszej części samouczka uruchomisz kod.

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }
   }

W przykładzie kodu wprowadzono dwie standardowe operacje M i X, które przekształcają stan kubitu.

SetQubitState Operacja:

  1. Przyjmuje dwa parametry: typ o nazwie desired, który reprezentuje żądany stan kubitu, który ma znajdować się w (Zero lub One) i typ Qubit.Result
  2. Wykonuje operację pomiaru , Mktóra mierzy stan kubitu (Zero lub One) i porównuje wynik z wartością określoną w desiredelemecie .
  3. Jeśli miara nie jest zgodna z porównywaną wartością, uruchamia operację X , która przerzuca stan kubitu, gdzie prawdopodobieństwo zwracania Zero miary i One są odwrócone. W ten sposób SetQubitState zawsze umieszcza kubit docelowy w żądanym stanie.

Pisanie operacji testowej w celu przetestowania stanu dzwonka

Następnie, aby zademonstrować efekt SetQubitState operacji, utwórz kolejną operację o nazwie TestBellState. Ta operacja przydzieli dwa kubity, wywołaj polecenie SetQubitState , aby ustawić pierwszy kubit na znany stan, a następnie zmierzy kubity, aby zobaczyć wyniki.

Skopiuj następujący kod do okna edytora kodu poniżej SetQubitState operacji.

operation TestBellState() : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;
    let count = 1000;
    let initial = One;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2);           

        // Count the number of 'Ones' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

    // reset the qubits
    SetQubitState(Zero, q1);             
    SetQubitState(Zero, q2);
    

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

W kodzie count zmienne i initial są ustawione odpowiednio na 1000 i One . Inicjuje to pierwszy kubit i One mierzy każdy kubit 1000 razy.

TestBellStateOperacja:

  1. Ustawia zmienne dla licznika i początkowego stanu kubitu.
  2. Wywołuje instrukcję w use celu zainicjowania dwóch kubitów.
  3. Pętle dla count iteracji. Dla każdej pętli
    1. Wywołania SetQubitState ustawiają określoną initial wartość na pierwszym kubitie.
    2. Wywołaj ponownie polecenie SetQubitState , aby ustawić drugi kubit na Zero stan.
    3. M Używa operacji do mierzenia każdego kubitu.
    4. Przechowuje liczbę pomiarów dla każdego kubitu, który zwraca wartość One.
  4. Po zakończeniu pętli wywołuje ona ponownie polecenie SetQubitState resetowania kubitów do znanego stanu (Zero), aby umożliwić innym osobom przydzielanie kubitów w znanym stanie. Jest to wymagane przez instrukcję use.
  5. Na koniec używa Message funkcji do drukowania wyników w oknach danych wyjściowych Copilot przed zwróceniem wyników.

Uruchamianie kodu w rozwiązaniu Copilot for Azure Quantum

Przed przejściem do procedur superpozycji i splątania można przetestować kod do tego momentu, aby zobaczyć inicjowanie i pomiar kubitów.

Aby uruchomić kod jako autonomiczny program, kompilator w Copilot musi wiedzieć, Q#gdzie uruchomić program. Jest to wykonywane w Q# pliku przez dodanie bezpośrednio poprzedzającej @EntryPoint() operację, którą chcesz uruchomić najpierw. Na przykład w tym przypadku jest TestBellState to operacja.

Uwaga

@EntryPoint() program jest wymagany tylko w przypadku programów autonomicznych Q# . W przypadku uruchamiania Q# programu w notesach Jupyter Notebook lub wywoływania Q# programu z pliku hosta języka Python nie jest to wymagane i zgłasza błąd, jeśli zostanie uwzględniony.

Dodaj bezpośrednio przed operacją@EntryPoint(), a Q# program do tego punktu powinien teraz wyglądać następująco:TestBellState

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

    operation SetQubitState(desired : Result, target : Qubit) : Unit {
        if desired != M(target) {
            X(target);
        }
    }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
            
            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Skopiuj i wklej kompletny przykładowy kod w oknie Copilot for Azure Quantum code, ustaw slajd dla liczby strzałów na "1", a następnie kliknij przycisk Uruchom. Wyniki są wyświetlane w histogramie i w polach Wyniki .

Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0

Ponieważ kubity nie zostały jeszcze manipulowane, zachowały swoje wartości początkowe: pierwszy kubit zwraca One wartość za każdym razem, a drugi kubit zwraca wartość Zero.

Jeśli zmienisz wartość elementu initial na Zero i ponownie uruchomisz program, zwróć uwagę, że pierwszy kubit również jest zwracany Zero za każdym razem.

Q1 - Zeros: 1000
Q1 - Ones: 0
Q2 - Zeros: 1000
Q2 - Ones: 0

Umieszczanie kubitu w superpozycji

Obecnie kubity w programie są w stanie klasycznym, czyli są to 1 lub 0. Wiesz to, ponieważ program inicjuje kubity do znanego stanu i nie dodano żadnych procesów do manipulowania nimi. Przed splątaniem kubitów pierwszy kubit zostanie umieszczony w stanie superpozycji, w którym pomiar kubitu zwróci Zero ok. 50% czasu i One ok. 50% czasu. Koncepcyjnie kubit można traktować jako równy prawdopodobieństwo pomiaru wartości Zero lub One.

Aby umieścić kubit w superpozycji, Q# zapewnia operację H, lub Hadamard. X Przypomnij sobie operację z inicjowania kubitu do znanej procedury stanu wcześniej, która przerzuca kubit z zakresu od 0 do 1 (lub na odwrót); H operacja przerzuca kubit w połowie stanu równego prawdopodobieństwa Zero lub One. Po zmierzeniu kubit w superpozycji powinien zwracać mniej więcej taką samą liczbę Zero wyników i One .

Zmodyfikuj TestBellState kod w operacji, resetując wartość początkową i One wstawiając wiersz dla H operacji:

for test in 1..count {
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        H(q1);                // Add the H operation after initialization and before measurement

        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2); 
        ...

Teraz po uruchomieniu programu można zobaczyć wyniki pierwszego kubitu w superpozycji.

Q1 - Zeros: 523            // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0

Za każdym razem, gdy uruchamiasz program, wyniki pierwszego kubitu będą się nieznacznie różnić, ale będą zbliżone do 50% i 50% OneZero, podczas gdy wyniki drugiego kubitu pozostaną Zero cały czas.

Q1 - Zeros: 510           
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0

Inicjowanie pierwszego kubitu w celu Zero zwracania podobnych wyników.

Q1 - Zeros: 504           
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0

Uwaga

Przesuwając suwak w copilot dla usługi Azure Quantum i zwiększając liczbę zdjęć, możesz zobaczyć, jak wyniki superpozycji różnią się nieznacznie w rozkładzie strzałów.

Splątanie dwóch kubitów

Jak wspomniano wcześniej, splątane kubity są połączone tak, że nie można ich opisać niezależnie od siebie. Oznacza to, że jakakolwiek operacja dzieje się z jednym kubitem, dzieje się również z splątanym kubitem. Dzięki temu można znać wynikowy stan jednego kubitu bez mierzenia go, po prostu mierząc stan drugiego kubitu. (W tym przykładzie użyto dwóch kubitów; jednak można również splątać trzy lub więcej kubitów).

Aby włączyć splątanie, Q# zapewnia operację CNOT , która oznacza kontrolowaną notę. Wynikiem uruchomienia tej operacji na dwóch kubitach jest przerzucanie drugiego kubitu, jeśli pierwszy kubit to One.

Dodaj operację CNOT do programu bezpośrednio po H operacji. Pełny program powinien wyglądać następująco:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = Zero;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
        
            H(q1);            
            CNOT(q1, q2);      // Add the CNOT operation after the H operation

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Teraz po uruchomieniu programu powinien zostać wyświetlony następujący komunikat:

Q1 - Zeros: 502           // results will vary
Q1 - Ones: 498
Q2 - Zeros: 502
Q2 - Ones: 498

Zwróć uwagę, że statystyki pierwszego kubitu nie uległy zmianie (nadal istnieje prawdopodobieństwo ok. 50/50 wartości ZeroOne lub po pomiarze), ale wyniki pomiaru drugiego kubitu są zawsze takie same jak pomiar pierwszego kubitu, bez względu na to, ile razy uruchamiasz program. Operacja CNOT splątał dwa kubity, tak aby cokolwiek się z nimi stało, dzieje się z drugim.

Wymagania wstępne

Aby utworzyć i uruchomić przykładowy kod w lokalnym środowisku projektowym:

Tworzenie nowego Q# pliku

  1. Otwórz Visual Studio Code i wybierz pozycję Plik > nowy plik tekstowy, aby utworzyć nowy plik.
  2. Zapisz plik jako CreateBellStates.qs. Ten plik będzie zawierać Q# kod programu.

Inicjowanie kubitu do znanego stanu

Pierwszym krokiem Q# jest zdefiniowanie operacji, która zainicjuje kubit do znanego stanu. Może to być wywoływane w celu ustawienia kubitu na stan klasyczny, co oznacza, że zwraca Zero 100% czasu lub zwraca One 100% czasu. Zero i One to Q# wartości reprezentujące tylko dwa możliwe wyniki pomiaru kubitu.

Otwórz CreateBellStates.qs plik i skopiuj następujący kod:

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }
   }

W przykładzie kodu wprowadzono dwie standardowe operacje i MX, które przekształcają stan kubitu.

Operacja SetQubitState :

  1. Przyjmuje dwa parametry: typ Result, o nazwie desired, który reprezentuje żądany stan kubitu, który ma być w (Zero lub One) i typ Qubit.
  2. Wykonuje operację pomiaru , Mktóra mierzy stan kubitu (Zero lub One) i porównuje wynik z wartością określoną w desired.
  3. Jeśli pomiar nie jest zgodny z porównywaną wartością, uruchamia operację X , która przerzuca stan kubitu do miejsca, w którym prawdopodobieństwo zwracania Zero miary i One są odwrócone. W ten sposób SetQubitState zawsze umieszcza kubit docelowy w żądanym stanie.

Pisanie operacji testowej w celu przetestowania stanu Bell

Następnie, aby zademonstrować efekt SetQubitState operacji, utwórz kolejną operację o nazwie TestBellState. Ta operacja przydzieli dwa kubity, wywołaj metodę SetQubitState , aby ustawić pierwszy kubit do znanego stanu, a następnie zmierzy kubity, aby wyświetlić wyniki.

Dodaj następującą operację do CreateBellStates.qs pliku po SetQubitState operacji:

operation TestBellState() : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;
    let count = 1000;
    let initial = One;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2);           

        // Count the number of 'Ones' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

    // reset the qubits
    SetQubitState(Zero, q1);             
    SetQubitState(Zero, q2);
    

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

W kodzie count zmienne i initial są ustawione odpowiednio na 1000 i One . Spowoduje to zainicjowanie pierwszego kubitu do One i zmierzenie każdego kubitu 1000 razy.

Operacja TestBellState:

  1. Przyjmuje dwa parametry: count, liczbę razy do uruchomienia miary i initial, żądany stan do zainicjowania kubitu.
  2. Wywołuje instrukcję use w celu zainicjowania dwóch kubitów.
  3. Pętle dla count iteracji. Dla każdej pętli
    1. Wywołuje SetQubitState metodę ustawiania określonej initial wartości na pierwszym kubitie.
    2. Wywołania SetQubitState ponownie w celu ustawienia drugiego kubitu Zero na stan.
    3. M Używa operacji do mierzenia każdego kubitu.
    4. Przechowuje liczbę pomiarów dla każdego kubitu, który zwraca wartość One.
  4. Po zakończeniu pętli wywołuje SetQubitState ponownie polecenie w celu zresetowania kubitów do znanego stanu (Zero), aby umożliwić innym przydzielenie kubitów w znanym stanie. Jest to wymagane przez instrukcję use.
  5. Na koniec używa Message funkcji do drukowania komunikatu w konsoli przed zwróceniem wyników.

Uruchamianie kodu

Przed przejściem do procedur superpozycji i splątania przetestuj kod aż do tego momentu, aby zobaczyć inicjowanie i pomiar kubitów.

Odbywa się to w Q# pliku przez dodanie @EntryPoint() bezpośrednio poprzedzającej operację, którą chcesz uruchomić. Na przykład w tym przypadku jest TestBellState to operacja.

Uwaga

@EntryPoint() program jest wymagany tylko w przypadku programów autonomicznych Q# . W przypadku uruchamiania Q# programu w notesach Jupyter Notebook lub wywoływania Q# programu z pliku hosta języka Python nie jest to wymagane i w przypadku dołączeń zgłosi błąd.

Plik CreateBellStates.qs powinien teraz wyglądać następująco:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
            
            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Przed uruchomieniem programu należy ustawić profil docelowy na Wartość Nieograniczone. Wybierz pozycję Widok —> Paleta poleceń, wyszukaj pozycję QIR, wybierz pozycję Q#: Ustaw profil docelowy usługi Azure Quantum QIR, a następnie wybierz pozycję Q#: nieograniczone.

Aby uruchomić program, wybierz pozycję Uruchom Q# plik z listy rozwijanej ikona odtwarzania w prawym górnym rogu lub naciśnij klawisze Ctrl+F5. Program uruchamia operację lub funkcję oznaczoną atrybutem @EntryPoint() w symulatorze domyślnym.

Uwaga

Jeśli profil docelowy nie jest ustawiony na Wartość Nieograniczone, podczas uruchamiania programu zostanie wyświetlony błąd.

Dane wyjściowe są wyświetlane w konsoli debugowania.

Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0

Ponieważ kubity nie zostały jeszcze zmanipulowane, zachowały swoje początkowe wartości: pierwszy kubit jest zwracany One za każdym razem, a drugi kubit zwraca wartość Zero.

Jeśli zmienisz wartość initialZero na i ponownie uruchomisz program, należy zauważyć, że pierwszy kubit również jest zwracany Zero za każdym razem.

Q1 - Zeros: 1000
Q1 - Ones: 0
Q2 - Zeros: 1000
Q2 - Ones: 0

Porada

Pamiętaj, aby zapisać plik za każdym razem, gdy wprowadzasz zmianę w kodzie przed ponownym uruchomieniem.

Umieszczanie kubitu w superpozycji

Obecnie kubity w programie są w stanie klasycznym, czyli są 1 lub 0. Wiesz to, ponieważ program inicjuje kubity do znanego stanu i nie dodano żadnych procesów do manipulowania nimi. Przed splątaniem kubitów pierwszy kubit zostanie umieszczony w stanie superpozycji, w którym pomiar kubitu zwróci Zero 50% czasu i One 50% czasu. Koncepcyjnie kubit można traktować jako połowę między wartościami Zero i One.

Aby umieścić kubit w superpozycji, Q# zapewnia operację H, lub Hadamard. X Przypomnij sobie operację z inicjalizacji kubitu do znanej procedury stanu wcześniej, która przerzuciła kubit z Zero do One (lub odwrotnie); H operacja przerzuca kubit w połowie stanu równych prawdopodobieństwa Zero lub One. Po zmierzeniu kubit w superpozycji powinien zwracać mniej więcej taką samą liczbę Zero wyników i One .

Zmodyfikuj kod w operacji, TestBellState aby uwzględnić operację H :

    for test in 1..count {
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
            
            H(q1);                // Add the H operation after initialization and before measurement

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2); 
            ...

Teraz po uruchomieniu programu można zobaczyć wyniki pierwszego kubitu w superpozycji:

Q1 - Zeros: 523            // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0

Za każdym razem, gdy uruchamiasz program, wyniki dla pierwszego kubitu będą się nieznacznie różnić, ale będą zbliżone do 50% i 50% OneZero, podczas gdy wyniki drugiego kubitu pozostaną Zero cały czas.

Q1 - Zeros: 510           
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0

Inicjowanie pierwszego kubitu w celu Zero zwracania podobnych wyników.

Q1 - Zeros: 504           
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0

Splątanie dwóch kubitów

Jak wspomniano wcześniej, splątane kubity są połączone w taki sposób, że nie można ich opisać niezależnie od siebie. Oznacza to, że cokolwiek się dzieje z jednym kubitem, również dzieje się z splątanym kubitem. Dzięki temu można znać stan wynikowy jednego kubitu bez mierzenia go, po prostu mierząc stan drugiego kubitu. (W tym przykładzie użyto dwóch kubitów, ale istnieje również możliwość splątania trzech lub większej liczby kubitów).

Aby włączyć splątanie, Q# zapewnia operację CNOT , która oznacza Kontrolowane NIE. Wynikiem uruchomienia tej operacji na dwóch kubitach jest przerzucanie drugiego kubitu, jeśli pierwszy kubit to One.

Dodaj operację CNOT do programu natychmiast po H operacji. Pełny program powinien wyglądać następująco:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
        
            H(q1);            
            CNOT(q1, q2);      // Add the CNOT operation after the H operation

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Q1 - Zeros: 502           
Q1 - Ones: 498       // results will vary
Q2 - Zeros: 502
Q2 - Ones: 498

Statystyki dla pierwszego kubitu nie uległy zmianie (prawdopodobieństwo Zero 50/50 wartości lub One po pomiarze), ale wyniki pomiaru dla drugiego kubitu są zawsze takie same jak pomiar pierwszego kubitu. Operacja CNOT splątała dwa kubity, aby cokolwiek się z nimi stało, dzieje się z drugim.

Kreślenie histogramu częstotliwości

Zwizualizujmy rozkład wyników uzyskanych z wielokrotnego uruchamiania programu kwantowego. Histogram częstotliwości pomaga wizualizować rozkład prawdopodobieństwa tych wyników.

  1. Wybierz pozycję Widok —> Paleta poleceń lub naciśnij klawisze Ctrl+Shift+P i wpisz "histogram", który powinien wywołać Q#polecenie : Uruchom plik i pokaż opcję histogramu . Wybierz tę opcję, aby otworzyć okno histogramu Q# .

  2. Wprowadź liczbę zdjęć do wykonania programu, na przykład 100 zdjęć, a następnie naciśnij klawisz Enter. Histogram zostanie wyświetlony w oknie histogramu Q# .

  3. Każdy słupek na histogramie odpowiada możliwemu wynikowi, a jego wysokość reprezentuje liczbę obserwowanych wyników. W tym przypadku istnieje 50 różnych unikatowych wyników. Należy pamiętać, że dla każdego wyniku wyniki pomiaru dla pierwszego i drugiego kubitu są zawsze takie same.

    Zrzut ekranu przedstawiający okno histogramu Q# w Visual Studio Code.

    Porada

    Histogram można powiększyć za pomocą kółka przewijania myszy lub gestu klawiatury. Po powiększ wykres można przesuwać, naciskając klawisze "Alt" podczas przewijania.

  4. Kliknij pasek, aby wyświetlić procent tego wyniku.

  5. Kliknij ikonę ustawień w lewym górnym rogu, aby wyświetlić opcje. Możesz wyświetlić 10 pierwszych wyników, 25 pierwszych wyników lub wszystkie wyniki. Możesz również posortować wyniki od wysokiej do niskiej lub niskiej do wysokiej.

    Zrzut ekranu przedstawiający okno histogramu Q# w Visual Studio Code pokazujące sposób wyświetlania ustawień.

Następne kroki

Zapoznaj się z innymi Q# samouczkami: