Lumaktaw sa pangunahing nilalaman

Ang Operator class

Mga bersyon ng package

Ang code sa pahinang ito ay ginawa gamit ang mga sumusunod na requirements. Inirerekomenda naming gamitin ang mga bersyong ito o mas bago pa.

qiskit[all]~=2.3.0

Ipinapakita ng pahinang ito kung paano gamitin ang Operator class. Para sa pangkalahatang-ideya ng mga representasyon ng operator sa Qiskit, kabilang ang Operator class at iba pa, tingnan ang Overview of operator classes.

# Added by doQumentation β€” required packages for this notebook
!pip install -q numpy qiskit
import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import CXGate, RXGate, XGate
from qiskit.quantum_info import Operator, Pauli, process_fidelity

I-convert ang mga class sa Operators​

Maraming iba pang mga class sa Qiskit ang maaaring direktang i-convert sa isang Operator object gamit ang paraan ng pagsisimula ng operator. Halimbawa:

  • Mga Pauli object
  • Mga Gate at Instruction object
  • Mga QuantumCircuit object

Tandaan na ang huling punto ay nangangahulugang maaari mong gamitin ang Operator class bilang isang unitary simulator para makuha ang panghuling unitary matrix ng isang quantum circuit, nang hindi kailangang tumawag ng simulator backend. Kung ang circuit ay naglalaman ng anumang hindi sinusuportahang operasyon, magtataas ng exception. Ang hindi sinusuportahang mga operasyon ay: measure, reset, conditional operations, o isang gate na walang matrix definition o decomposition sa pamamagitan ng mga gate na may matrix definitions.

# Create an Operator from a Pauli object

pauliXX = Pauli("XX")
Operator(pauliXX)
Operator([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))
# Create an Operator for a Gate object
Operator(CXGate())
Operator([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))
# Create an operator from a parameterized Gate object
Operator(RXGate(np.pi / 2))
Operator([[0.70710678+0.j        , 0.        -0.70710678j],
[0. -0.70710678j, 0.70710678+0.j ]],
input_dims=(2,), output_dims=(2,))
# Create an operator from a QuantumCircuit object
circ = QuantumCircuit(10)
circ.h(0)
for j in range(1, 10):
circ.cx(j - 1, j)

# Convert circuit to an operator by implicit unitary simulation
Operator(circ)
Operator([[ 0.70710678+0.j,  0.70710678+0.j,  0.        +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
...,
[ 0. +0.j, 0. +0.j, 0. +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j]],
input_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2), output_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2))

Gamitin ang Operators sa mga circuit​

Ang mga unitary Operator ay maaaring direktang ipasok sa isang QuantumCircuit gamit ang QuantumCircuit.append na paraan. Kino-convert nito ang Operator sa isang UnitaryGate object, na idinaragdag sa circuit.

Kung ang operator ay hindi unitary, magtataas ng exception. Maaari itong suriin gamit ang Operator.is_unitary() na function, na nagbabalik ng True kung ang operator ay unitary at False kung hindi.

# Create an operator
XX = Operator(Pauli("XX"))

# Add to a circuit
circ = QuantumCircuit(2, 2)
circ.append(XX, [0, 1])
circ.measure([0, 1], [0, 1])
circ.draw("mpl")

Output of the previous code cell

Tandaan na sa halimbawa sa itaas, ang operator ay sinimulan mula sa isang Pauli object. Gayunpaman, ang Pauli object ay maaari ring direktang ipasok sa circuit mismo at ico-convert sa isang sequence ng single-qubit Pauli gates:

# Add to a circuit
circ2 = QuantumCircuit(2, 2)
circ2.append(Pauli("XX"), [0, 1])
circ2.measure([0, 1], [0, 1])
circ2.draw()
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œβ”€β”
q_0: ─0 β”œβ”€Mβ”œβ”€β”€β”€
β”‚ Pauli(XX) β”‚β””β•₯β”˜β”Œβ”€β”
q_1: ─1 β”œβ”€β•«β”€β”€Mβ”œ
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β•‘ β””β•₯β”˜
c: 2/═══════════════╩══╩═
0 1

Pagsamahin ang mga Operator​

Ang mga Operator ay maaaring pagsamahin gamit ang ilang pamamaraan.

Tensor product​

Dalawang operator na AA at BB ay maaaring pagsamahin sa isang tensor product operator na AβŠ—BA\otimes B gamit ang Operator.tensor na function. Tandaan na kung parehong single-qubit operators ang AA at BB, ang A.tensor(B) = AβŠ—BA\otimes B ay magkakaroon ng mga subsystem na naka-index bilang matrix BB sa subsystem 0, at matrix AA sa subsystem 1.

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.tensor(B)
Operator([[ 0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j],
[ 0.+0.j, -0.+0.j, 0.+0.j, -1.+0.j],
[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, -1.+0.j, 0.+0.j, -0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))

Tensor expansion​

Ang isang malapit na kaugnay na operasyon ay ang Operator.expand, na kumikilos tulad ng isang tensor product ngunit sa kabaligtaran na pagkakasunud-sunod. Kaya, para sa dalawang operator na AA at BB, mayroon kang A.expand(B) = BβŠ—AB\otimes A kung saan ang mga subsystem ay naka-index bilang matrix AA sa subsystem 0, at matrix BB sa subsystem 1.

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.expand(B)
Operator([[ 0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j],
[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, -0.+0.j, -1.+0.j],
[ 0.+0.j, 0.+0.j, -1.+0.j, -0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))

Composition​

Maaari ka ring mag-compose ng dalawang operator na AA at BB para ipatupad ang matrix multiplication gamit ang Operator.compose na paraan. Ang A.compose(B) ay nagbabalik ng operator na may matrix B.AB.A:

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.compose(B)
Operator([[ 0.+0.j,  1.+0.j],
[-1.+0.j, 0.+0.j]],
input_dims=(2,), output_dims=(2,))

Maaari ka ring mag-compose sa kabaligtaran na pagkakasunud-sunod sa pamamagitan ng pag-apply ng BB sa harap ng AA gamit ang front kwarg ng compose: A.compose(B, front=True) = A.BA.B:

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.compose(B, front=True)
Operator([[ 0.+0.j, -1.+0.j],
[ 1.+0.j, 0.+0.j]],
input_dims=(2,), output_dims=(2,))

Subsystem composition​

Tandaan na ang nakaraang compose ay nangangailangan na ang kabuuang output dimension ng unang operator na AA ay katumbas ng kabuuang input dimension ng composed operator na BB (at gayundin, ang output dimension ng BB ay dapat katumbas ng input dimension ng AA kapag nag-compose gamit ang front=True).

Maaari ka ring mag-compose ng isang mas maliit na operator sa isang seleksyon ng mga subsystem sa isang mas malaking operator gamit ang qargs kwarg ng compose, may o walang front=True. Sa kasong ito, ang kaugnay na mga input at output dimension ng mga subsystem na ino-compose ay dapat magkatugma. Tandaan na ang mas maliit na operator ay palaging dapat na argument ng compose na paraan.

Halimbawa, para mag-compose ng isang two-qubit gate sa isang three-qubit operator:

# Compose XZ with a 3-qubit identity operator
op = Operator(np.eye(2**3))
XZ = Operator(Pauli("XZ"))
op.compose(XZ, qargs=[0, 2])
Operator([[ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
-1.+0.j],
[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, -1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j]],
input_dims=(2, 2, 2), output_dims=(2, 2, 2))
# Compose YX in front of the previous operator
op = Operator(np.eye(2**3))
YX = Operator(Pauli("YX"))
op.compose(YX, qargs=[0, 2], front=True)
Operator([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j],
[0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],
input_dims=(2, 2, 2), output_dims=(2, 2, 2))

Mga linear na kombinasyon​

Ang mga Operator ay maaari ring pagsamahin gamit ang mga karaniwang linear operator para sa karagdagan, pagbabawas, at scalar multiplication sa pamamagitan ng mga kumplikadong numero.

XX = Operator(Pauli("XX"))
YY = Operator(Pauli("YY"))
ZZ = Operator(Pauli("ZZ"))

op = 0.5 * (XX + YY - 3 * ZZ)
op
Operator([[-1.5+0.j,  0. +0.j,  0. +0.j,  0. +0.j],
[ 0. +0.j, 1.5+0.j, 1. +0.j, 0. +0.j],
[ 0. +0.j, 1. +0.j, 1.5+0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j, -1.5+0.j]],
input_dims=(2, 2), output_dims=(2, 2))

Ang isang mahalagang punto ay habang pinananatili ng tensor, expand, at compose ang unitary ng mga unitary operator, ang mga linear na kombinasyon ay hindi; kaya, ang pagdaragdag ng dalawang unitary operator ay, sa pangkalahatan, magreresulta sa isang non-unitary operator:

op.is_unitary()
False

Implicit na conversion sa mga Operator​

Tandaan na para sa lahat ng sumusunod na pamamaraan, kung ang pangalawang object ay hindi pa isang Operator object, ito ay awtomatikong kino-convert sa isa ng pamamaraan. Ibig sabihin, maaaring direktang ipasa ang mga matrix nang hindi muna ito tahasan na kino-convert sa isang Operator. Kung hindi posible ang conversion, magtataas ng exception.

# Compose with a matrix passed as a list
Operator(np.eye(2)).compose([[0, 1], [1, 0]])
Operator([[0.+0.j, 1.+0.j],
[1.+0.j, 0.+0.j]],
input_dims=(2,), output_dims=(2,))

Ikumpara ang mga Operator​

Ang mga Operator ay may equality method na maaaring gamitin para suriin kung ang dalawang operator ay halos magkapantay.

Operator(Pauli("X")) == Operator(XGate())
True

Tandaan na sinusuri nito ang bawat matrix element ng mga operator na halos magkapantay; dalawang unitary na may pagkakaiba ng global phase ay hindi itinuturing na magkapantay:

Operator(XGate()) == np.exp(1j * 0.5) * Operator(XGate())
False

Process fidelity​

Maaari ka ring ikumpara ang mga operator gamit ang process_fidelity na function mula sa Quantum Information module. Ito ay isang information-theoretic na dami para sa kung gaano kalapit ang dalawang quantum channel sa isa't isa, at sa kaso ng mga unitary operator, hindi ito nakasalalay sa global phase.

# Two operators which differ only by phase
op_a = Operator(XGate())
op_b = np.exp(1j * 0.5) * Operator(XGate())

# Compute process fidelity
F = process_fidelity(op_a, op_b)
print("Process fidelity =", F)
Process fidelity = 1.0

Tandaan na ang process fidelity ay karaniwang valid lamang bilang sukatan ng pagkakatulad kung ang mga input operator ay unitary (o CP sa kaso ng mga quantum channel), at magtataas ng exception kung ang mga input ay hindi CP.

Mga susunod na hakbang​

Mga rekomendasyon