Przejdź do głównej treści

Biblioteka Circuit

Wersje pakietów

Kod na tej stronie został opracowany przy użyciu poniższych wymagań. Zalecamy korzystanie z tych lub nowszych wersji.

qiskit[all]~=2.3.0

Qiskit SDK zawiera bibliotekę popularnych układów kwantowych, których możesz używać jako bloków konstrukcyjnych we własnych programach. Korzystanie z gotowych układów oszczędza czas poświęcany na research, pisanie kodu i debugowanie. Biblioteka zawiera popularne układy w obliczeniach kwantowych, układy trudne do symulowania klasycznie oraz układy przydatne do testowania wydajności sprzętu kwantowego.

Ta strona wymienia różne kategorie układów dostępnych w bibliotece. Pełna lista układów znajduje się w dokumentacji API biblioteki circuit.

Standardowe Gate'y

Biblioteka Circuit zawiera również standardowe bramki kwantowe. Niektóre z nich to bardziej podstawowe Gate'y (np. UGate), a inne to bramki wieloqubitowe, które zazwyczaj wymagają zbudowania z bramek jedno- i dwuqubitowych. Aby dodać zaimportowane Gate'y do swojego Circuit, użyj metody append; pierwszym argumentem jest Gate, a następnym argumentem jest lista Qubitów, na które ma zostać zastosowana.

Na przykład poniższy kod tworzy Circuit z bramką Hadamarda i bramką multi-controlled-X.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit import QuantumCircuit
from qiskit.circuit.library import HGate, MCXGate

mcx_gate = MCXGate(3)
hadamard_gate = HGate()

qc = QuantumCircuit(4)
qc.append(hadamard_gate, [0])
qc.append(mcx_gate, [0, 1, 2, 3])
qc.draw("mpl")

Output of the previous code cell

Zobacz Standard gates w dokumentacji API biblioteki circuit.

Nie wiesz, jak nazywa się twoja bramka? Zapytaj Qiskit Code Assistant.

Układy N-lokalne

Te układy przeplatają warstwy jednoQubitowych bramek rotacji z warstwami wieloQubitowych bramek splątujących.

Ta rodzina układów jest popularna w wariacyjnych algorytmach kwantowych, ponieważ może generować szeroki zakres stanów kwantowych. Algorytmy wariacyjne dostosowują parametry bramek, aby znaleźć stany o określonych właściwościach (np. stany reprezentujące dobre rozwiązanie problemu optymalizacyjnego). W tym celu wiele układów w bibliotece jest sparametryzowanych, co oznacza, że można je definiować bez ustalonych wartości.

Poniższy kod importuje Circuit n_local, w którym bramkami splątującymi są bramki dwuqubitowe. Ten Circuit przeplatają bloki sparametryzowanych jednoQubitowych bramek z blokami splątującymi złożonymi z bramek dwuqubitowych. Poniższy kod tworzy trzyQubitowy Circuit z jednoQubitowymi bramkami RX i dwuqubitowymi bramkami CZ.

from qiskit.circuit.library import n_local

two_local = n_local(3, "rx", "cz")
two_local.draw("mpl")

Output of the previous code cell

Obiekt podobny do listy zawierający parametry Circuit można uzyskać z atrybutu parameters.

two_local.parameters
ParameterView([ParameterVectorElement(θ[0]), ParameterVectorElement(θ[1]), ParameterVectorElement(θ[2]), ParameterVectorElement(θ[3]), ParameterVectorElement(θ[4]), ParameterVectorElement(θ[5]), ParameterVectorElement(θ[6]), ParameterVectorElement(θ[7]), ParameterVectorElement(θ[8]), ParameterVectorElement(θ[9]), ParameterVectorElement(θ[10]), ParameterVectorElement(θ[11])])

Możesz też przypisać te parametry do rzeczywistych wartości, używając słownika w postaci { Parameter: number }. Aby to zademonstrować, poniższy kod przypisuje każdy parametr w Circuit wartość 0.

bound_circuit = two_local.assign_parameters(
{p: 0 for p in two_local.parameters}
)
bound_circuit.decompose().draw("mpl")

Output of the previous code cell

Więcej informacji znajdziesz w N-local gates w dokumentacji API biblioteki circuit lub zapisz się na kurs Variational algorithm design w IBM Quantum Learning.

Układy kodowania danych

Te sparametryzowane układy kodują dane na stanach kwantowych w celu przetwarzania przez algorytmy kwantowego uczenia maszynowego. Niektóre układy obsługiwane przez Qiskit to:

  • Kodowanie amplitudowe, które koduje każdą liczbę jako amplitudę stanu bazowego. Może przechować 2n2^n liczb w jednym stanie, ale jego implementacja może być kosztowna.
  • Kodowanie bazowe, które koduje liczbę całkowitą kk poprzez przygotowanie odpowiadającego stanu bazowego k|k\rangle.
  • Kodowanie kątowe, które ustawia każdą liczbę w danych jako kąt obrotu w sparametryzowanym Circuit.

Najlepsze podejście zależy od specyfiki twojej aplikacji. Na obecnych komputerach kwantowych często jednak używamy układów kodowania kątowego, takich jak zz_feature_map.

from qiskit.circuit.library import zz_feature_map

features = [0.2, 0.4, 0.8]
feature_map = zz_feature_map(feature_dimension=len(features))

encoded = feature_map.assign_parameters(features)
encoded.draw("mpl")

Output of the previous code cell

Zobacz Data encoding circuits w dokumentacji API biblioteki circuit.

Układy ewolucji czasowej

Te układy symulują ewolucję stanu kwantowego w czasie. Używaj układów ewolucji czasowej do badania efektów fizycznych, takich jak transfer ciepła lub przejścia fazowe w układzie. Układy ewolucji czasowej są również podstawowym blokiem konstrukcyjnym dla chemicznych funkcji falowych (takich jak unitarne stany próbne sprzężonych klastrów) oraz algorytmu QAOA stosowanego do problemów optymalizacyjnych.

from qiskit.circuit.library import PauliEvolutionGate
from qiskit.circuit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp

# Prepare an initial state with a Hadamard on the middle qubit
state = QuantumCircuit(3)
state.h(1)

hamiltonian = SparsePauliOp(["ZZI", "IZZ"])
evolution = PauliEvolutionGate(hamiltonian, time=1)

# Evolve state by appending the evolution gate
state.compose(evolution, inplace=True)

state.draw("mpl")

Output of the previous code cell

Przeczytaj dokumentację API PauliEvolutionGate.

Układy do testowania wydajności i teorii złożoności

Układy do testowania wydajności pozwalają nam ocenić, jak dobrze naprawdę działa nasz sprzęt, a układy z teorii złożoności pomagają zrozumieć, jak trudne są problemy, które chcemy rozwiązać.

Na przykład test „quantum volume" mierzy, jak dokładnie komputer kwantowy wykonuje pewien typ losowego układu kwantowego. Wynik komputera kwantowego rośnie wraz z rozmiarem układu, który może niezawodnie wykonać. Uwzględnia to wszystkie aspekty komputera, w tym liczbę Qubitów, wierność instrukcji, połączenia między Qubitami oraz stos oprogramowania obsługujący Transpiler i przetwarzanie wyników. Więcej o quantum volume możesz przeczytać w oryginalnej pracy o quantum volume.

Poniższy kod pokazuje przykład układu quantum volume zbudowanego w Qiskit, działającego na czterech Qubitach (bloki unitary to losowe bramki dwuqubitowe).

from qiskit.circuit.library import quantum_volume

quantum_volume(4).draw("mpl")

Output of the previous code cell

Biblioteka Circuit zawiera również układy uważane za trudne do symulowania klasycznie, takie jak układy iqp (instantaneous quantum polynomial). Te układy otaczają pewne bramki diagonalne (w bazie obliczeniowej) blokami bramek Hadamarda.

Inne układy to grover_operator stosowany w algorytmie Grovera oraz Circuit fourier_checking dla problemu sprawdzania Fouriera. Zobacz te układy w sekcji Particular quantum circuits w dokumentacji API biblioteki circuit.

Układy arytmetyczne

Operacje arytmetyczne to klasyczne funkcje, takie jak dodawanie liczb całkowitych i operacje bitowe. Mogą być przydatne w algorytmach takich jak estymacja amplitudy do zastosowań finansowych oraz w algorytmach takich jak algorytm HHL, który rozwiązuje układy równań liniowych.

Jako przykład spróbujmy dodać dwie trzycyfrowe liczby binarne, używając układu „ripple-carry" do wykonania dodawania w miejscu (FullAdderGate). Ten dodawacz sumuje dwie liczby (nazwiemy je „A" i „B") i zapisuje wynik w rejestrze, który przechowywał B. W poniższym przykładzie A=2 i B=3.

from qiskit.circuit.library import FullAdderGate
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister

adder = FullAdderGate(3) # Adder of 3-bit numbers

# Create the number A=2
reg_a = QuantumRegister(3, "a")
number_a = QuantumCircuit(reg_a)
number_a.initialize(2) # Number 2; |010>

# Create the number B=3
reg_b = QuantumRegister(3, "b")
number_b = QuantumCircuit(reg_b)
number_b.initialize(3) # Number 3; |011>

# Create a circuit to hold everything, including a classical register for
# the result
qregs = [
QuantumRegister(1, "cin"),
QuantumRegister(3, "a"),
QuantumRegister(3, "b"),
QuantumRegister(1, "cout"),
]
reg_result = ClassicalRegister(3)
circuit = QuantumCircuit(*qregs, reg_result)

# Compose number initializers with the adder. Adder stores the result to
# register B, so we'll measure those qubits.
circuit = (
circuit.compose(number_a, qubits=reg_a)
.compose(number_b, qubits=reg_b)
.compose(adder)
)
circuit.measure(reg_b, reg_result)
circuit.draw("mpl")

Output of the previous code cell

Symulacja układu pokazuje, że dla wszystkich 1024 strzałów daje wynik 5 (tj. jest mierzony z prawdopodobieństwem 1.0).

from qiskit.primitives import StatevectorSampler

result = StatevectorSampler().run([circuit]).result()

print(f"Count data:\n {result[0].data.c0.get_int_counts()}")
Count data:
{5: 1024}

Zobacz Arithmetic w dokumentacji API biblioteki circuit.

Kolejne kroki

Zalecenia