Composition of QOperations
This note describes how to calculate composition of qoperations.
Composition
Composition is an operation in the time direction. To compute the tensor product, use compose_qoperations() in the quara.objects.operators module.
As a simple example, let’s look at how to compute the composition of the following State and Gate.
formula:
\((G_{z}, \rho_{z0})\)
quantum circuit diagram:
── \(\rho_{z0}\) ─ \(G_{z}\) ──
First, prepare State and Gate to be used for the operation. Note that the IDs of the ElementalSystems between QOperations to be calculated with composition must be same.
[1]:
from quara.objects.composite_system_typical import generate_composite_system
from quara.objects.qoperation_typical import generate_qoperation
# Prepare State and Gate
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
state = generate_qoperation(mode="state", name="z0", c_sys=c_sys)
gate = generate_qoperation(mode="gate", name="z", c_sys=c_sys)
print(f"vec of state: \n{state.vec}")
print(f"HS of gate: \n{gate.hs}")
vec of state:
[0.70710678 0. 0. 0.70710678]
HS of gate:
[[ 1. 0. 0. 0.]
[ 0. -1. 0. 0.]
[ 0. 0. -1. 0.]
[ 0. 0. 0. 1.]]
The composition of State and Gate can be written as follows. Note that the argument to compose_qoperations() specifies QOperations in the same order as the formula, not in the order on the quantum circuit.
[2]:
from quara.objects.operators import compose_qoperations
# Composition
result = compose_qoperations(gate, state)
# Result
print(result)
Type:
State
Dim:
2
Vec:
[0.70710678 0. 0. 0.70710678]
Composition of three or more QOperations
For three or more QOepration operations, add to the argument. Let’s look at how to compute the composition of the following State, and Gate.
formula:
\((G_{x}, G_{z}, \rho_{z0})\)
quantum circuit diagram:
── \(\rho_{z0}\) ─ \(G_{z}\) ─ \(G_{x}\) ──
[3]:
# Prepare State, POVM, and Gate
c_sys_0 = generate_composite_system("qubit", 1, ids_esys=[0])
state = generate_qoperation(mode="state", name="z0", c_sys=c_sys)
gate_0 = generate_qoperation(mode="gate", name="z", c_sys=c_sys)
gate_1 = generate_qoperation(mode="gate", name="x", c_sys=c_sys)
# Composition of three or more QOperations
result = compose_qoperations(gate_1, gate_0, state)
print(result)
Type:
State
Dim:
2
Vec:
[ 0.70710678 0. 0. -0.70710678]
It is also possible to specify QOperations as a list. For example, the following two expressions have the same meaning.
[4]:
# Specify by appending to the argument
result = compose_qoperations(gate_1, gate_0, state)
# Specify by list
result = compose_qoperations([gate_1, gate_0, state])
Supported operations
The compose_qoperations() supports the following combinations of QOperations.
Input |
Output |
|---|---|
(Gate, Gate) |
Gate |
(Gate, MProcess) |
MProcess |
(MProcess, Gate) |
MProcess |
(MProcess, MProcess) |
MProcess |
(Gate, State) |
State |
(MProcess, State) |
StateEnsemble |
(Mprocess, StateEnsemble) |
StateEnsemble |
(Povm, Gate) |
Povm |
(Povm, MProcess) |
Povm |
(Povm, State) |
MultinomialDistribution |
(Povm, StateEnsemble) |
MultinomialDistribution |
Examples
(Gate, Gate) -> Gate
[5]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
gate_0 = generate_qoperation(mode="gate", name="z", c_sys=c_sys)
gate_1 = generate_qoperation(mode="gate", name="x", c_sys=c_sys)
# Compose
result = compose_qoperations(gate_1, gate_0)
print(result) # Gate
Type:
Gate
Dim:
2
HS:
[[ 1. 0. 0. 0.]
[ 0. -1. 0. 0.]
[ 0. 0. 1. 0.]
[ 0. 0. 0. -1.]]
(Gate, MProcess) -> MProcess
[6]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
gate = generate_qoperation(mode="gate", name="z", c_sys=c_sys)
mprocess = generate_qoperation(mode="mprocess", name="x-type1", c_sys=c_sys)
# Compose
result = compose_qoperations(gate, mprocess)
print(result) # MProcess
Type:
MProcess
Dim:
2
HSs:
[array([[ 0.5, 0.5, 0. , 0. ],
[-0.5, -0.5, 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]]), array([[ 0.5, -0.5, 0. , 0. ],
[ 0.5, -0.5, 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]])]
ModeSampling:
False
(MProcess, Gate) -> MProcess
[7]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
mprocess = generate_qoperation(mode="mprocess", name="x-type1", c_sys=c_sys)
gate = generate_qoperation(mode="gate", name="z", c_sys=c_sys)
# Compose
result = compose_qoperations(mprocess, gate)
print(result) # MProcess
Type:
MProcess
Dim:
2
HSs:
[array([[ 0.5, -0.5, 0. , 0. ],
[ 0.5, -0.5, 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]]), array([[ 0.5, 0.5, 0. , 0. ],
[-0.5, -0.5, 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]])]
ModeSampling:
False
(Gate, State) -> State
[8]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
gate = generate_qoperation(mode="gate", name="z", c_sys=c_sys)
state = generate_qoperation(mode="state", name="z0", c_sys=c_sys)
# Compose
result = compose_qoperations(gate, state)
print(result) # State
Type:
State
Dim:
2
Vec:
[0.70710678 0. 0. 0.70710678]
(MProcess, State) -> StateEnsemble
[9]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
mprocess = generate_qoperation(mode="mprocess", name="x-type1", c_sys=c_sys)
state = generate_qoperation(mode="state", name="z0", c_sys=c_sys)
# Compose
result = compose_qoperations(mprocess, state)
print(result) # StateEnsemble
Type:
StateEnsemble
States:
states[0]: [0.70710678 0.70710678 0. 0. ]
states[1]: [ 0.70710678 -0.70710678 0. 0. ]
MultinomialDistribution:
shape = (2,)
ps = [0.5 0.5]
(MProcess, StateEnsemble) -> StateEnsemble
[10]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
mprocess = generate_qoperation(mode="mprocess", name="x-type1", c_sys=c_sys)
state_ensemble = generate_qoperation(mode="state_ensemble", name="z0", c_sys=c_sys)
# Compose
result = compose_qoperations(mprocess, state_ensemble)
print(result) # StateEnsemble
Type:
StateEnsemble
States:
states[0]: [0.70710678 0.70710678 0. 0. ]
states[1]: [ 0.70710678 -0.70710678 0. 0. ]
states[2]: [0. 0. 0. 0.]
states[3]: [0. 0. 0. 0.]
MultinomialDistribution:
shape = (2, 2)
ps = [0.5 0.5 0. 0. ]
(Povm, Gate) -> Povm
[11]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
povm = generate_qoperation(mode="povm", name="x", c_sys=c_sys)
gate = generate_qoperation(mode="gate", name="z", c_sys=c_sys)
# Compose
result = compose_qoperations(povm, gate)
print(result) # Povm
Type:
Povm
Dim:
2
Number of outcomes:
2
Vecs:
[[ 0.70710678 -0.70710678 0. 0. ]
[ 0.70710678 0.70710678 0. 0. ]]
(Povm, MProcess) -> Povm
[12]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
povm = generate_qoperation(mode="povm", name="x", c_sys=c_sys)
mprocess = generate_qoperation(mode="mprocess", name="x-type1", c_sys=c_sys)
# Compose
result = compose_qoperations(povm, mprocess)
print(result) # Povm
Type:
Povm
Dim:
2
Number of outcomes:
4
Vecs:
[[ 0.70710678 0.70710678 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0.70710678 -0.70710678 0. 0. ]]
(Povm, State) -> MultinomialDistribution
[13]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
povm = generate_qoperation(mode="povm", name="x", c_sys=c_sys)
state = generate_qoperation(mode="state", name="z0", c_sys=c_sys)
# Compose
result = compose_qoperations(povm, state)
print(type(result))
print(result) # MultinomialDistribution
<class 'quara.objects.multinomial_distribution.MultinomialDistribution'>
shape = (2,)
ps = [0.5 0.5]
(Povm, StateEnsemble) -> MultinomialDistribution
[14]:
# Prepare
c_sys = generate_composite_system("qubit", 1, ids_esys=[0])
povm = generate_qoperation(mode="povm", name="x", c_sys=c_sys)
state_ensemble = generate_qoperation(mode="state_ensemble", name="z0", c_sys=c_sys)
# Compose
result = compose_qoperations(povm, state_ensemble)
print(type(result))
print(result) # MultinomialDistribution
<class 'quara.objects.multinomial_distribution.MultinomialDistribution'>
shape = (2, 2)
ps = [0.5 0.5 0. 0. ]