In [1]:
import numpy as np
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit import Aer, execute
from qiskit.quantum_info import Pauli, state_fidelity, basis_state, process_fidelity
In [2]:
q0 = QuantumRegister(2, 'q0')
c0 = ClassicalRegister(2, 'c0')
q1 = QuantumRegister(2, 'q1')
c1 = ClassicalRegister(2, 'c1')
q_test = QuantumRegister(2, 'q0')
The name is optional. If not given Qiskit will name it $qi$ where $i$ is an interger which will count from 0. The name and size can be returned using the following:
In [3]:
print(q0.name)
print(q0.size)
You can test if the register are the same or different.
In [4]:
q0==q0
Out[4]:
In [5]:
q0==q_test
Out[5]:
In [6]:
q0==q1
Out[6]:
In [7]:
circ = QuantumCircuit(q0, q1)
circ.x(q0[1])
circ.x(q1[0])
circ.draw()
Out[7]:
is the same as
In [8]:
circ2 = QuantumCircuit()
circ2.add_register(q0)
circ2.add_register(q1)
circ2.x(q0[1])
circ2.x(q1[0])
circ2.draw()
Out[8]:
In [9]:
from copy import deepcopy
q3 = QuantumRegister(2, 'q3')
circ3 = deepcopy(circ)
circ3.add_register(q3)
circ3.draw()
Out[9]:
TODO: CHECK AFTER UPDATE THAT THIS IS CORRECT
In [10]:
meas = QuantumCircuit(q0, q1, c0, c1)
meas.measure(q0, c0)
meas.measure(q1, c1)
qc = circ + meas
qc.draw()
Out[10]:
In [11]:
meas2 = QuantumCircuit()
meas2.add_register(q0)
meas2.add_register(q1)
meas2.add_register(c0)
meas2.add_register(c1)
meas2.measure(q0, c0)
meas2.measure(q1, c1)
qc2 = circ2 + meas2
qc2.draw()
Out[11]:
It even works when the circuits have different registers. Let's start by making two new circuits:
In [12]:
circ4 = QuantumCircuit(q1)
circ4.x(q1)
circ4.draw()
Out[12]:
In [13]:
circ5 = QuantumCircuit(q3)
circ5.h(q3)
circ5.draw()
Out[13]:
The new register is added to the circuit:
In [14]:
(circ4+circ5).draw()
Out[14]:
We have also overloaded +=
to the QuantumCircuit
object:
In [15]:
circ4 += circ5
circ4.draw()
Out[15]:
In [16]:
circ.draw()
Out[16]:
qubit register $Q_0$ is prepared in the state $|10\rangle$ and $Q_1$ is in the state $|01\rangle$ giving a total state $|0110\rangle$ ($Q1\otimes Q0$).
That is the four qubit statevector of length 16 with the 6th element (int('0110',2)=6
) being one. Note the element count starts from zero.
In [17]:
backend_sim = Aer.get_backend('statevector_simulator')
result = execute(circ, backend_sim).result()
state = result.get_statevector(circ)
print(state)
To check the fidelity of this state with the basis_state
in Qiskit Terra you can use:
In [19]:
state_fidelity(basis_state('0110', 4), state)
Out[19]:
We can also use Qiskit Terra to make the unitary operator representing the circuit (provided there are no measurements). This will be a $16\otimes16$ matrix equal to $I\otimes X\otimes X\otimes I$. To check this is correct we can use the Pauli
class and the process_fidelity
function.
In [20]:
backend_sim = Aer.get_backend('unitary_simulator')
result = execute(circ, backend_sim).result()
unitary = result.get_unitary(circ)
process_fidelity(Pauli(label='IXXI').to_matrix(), unitary)
Out[20]:
To map the information of the quantum state to the classial world we have to use the example with measurements qc
:
In [21]:
qc.draw()
Out[21]:
This will map the quantum state to the classical world and since the state has no superpositions it will be deterministic and equal to '01 10'
. Here a space is used to separate the registers.
In [22]:
backend_sim = Aer.get_backend('qasm_simulator')
result = execute(qc, backend_sim).result()
counts = result.get_counts(qc)
print(counts)
To show that it does not matter how you add the registers we run the same as above on the second example circuit:
In [23]:
backend_sim = Aer.get_backend('statevector_simulator')
result = execute(circ2, backend_sim).result()
states = result.get_statevector(circ2)
backend_sim = Aer.get_backend('qasm_simulator')
result = execute(qc2, backend_sim).result()
counts = result.get_counts(qc2)
backend_sim = Aer.get_backend('unitary_simulator')
result = execute(circ2, backend_sim).result()
unitary = result.get_unitary(circ2)
In [24]:
print(counts)
In [25]:
state_fidelity(basis_state('0110', 4), state)
Out[25]:
In [26]:
process_fidelity(Pauli(label='IXXI').to_matrix(), unitary)
Out[26]:
In [27]:
q = QuantumRegister(6)
circuit = QuantumCircuit(q)
circuit.h(q[0])
circuit.ccx(q[0], q[1], q[2])
circuit.cx(q[1], q[3])
circuit.x(q)
circuit.h(q[2])
circuit.h(q[3])
circuit.draw()
Out[27]:
In [28]:
# total number of operations in the circuit. no unrolling is done.
circuit.size()
Out[28]:
In [29]:
# depth of circuit (number of ops on the critical path)
circuit.depth()
Out[29]:
In [30]:
# number of qubits in the circuit
circuit.width()
Out[30]:
In [32]:
# a breakdown of operations by type
circuit.count_ops()
Out[32]:
In [33]:
# number of unentangled subcircuits in this circuit.
# each subcircuit can in principle be executed on a different quantum processor!
circuit.num_tensor_factors()
Out[33]:
One useful application of this is that you can easily compare your original circuit with the circuit after it goes through transpilation.
Add an example of this after release and stabilization of transpile API.
In [ ]: