[2]:
from diskit import *
from qiskit import assemble, Aer, QuantumCircuit
from qiskit.visualization import plot_bloch_multivector
import warnings
warnings.filterwarnings("ignore")
Distributed Circuit for a CNOT gates¶
Define a Topology
[3]:
circuit_topo = Topology()
circuit_topo.create_qmap(2, [2, 3],"sys_cnot")
circuit_topo.qmap, circuit_topo.emap
[3]:
({'sys_cnot0': [Qubit(QuantumRegister(2, 'sys_cnot0'), 0),
Qubit(QuantumRegister(2, 'sys_cnot0'), 1)],
'sys_cnot1': [Qubit(QuantumRegister(3, 'sys_cnot1'), 0),
Qubit(QuantumRegister(3, 'sys_cnot1'), 1),
Qubit(QuantumRegister(3, 'sys_cnot1'), 2)]},
{'sys_cnot0': Qubit(QuantumRegister(1, 'com_sys_cnot0'), 0),
'sys_cnot1': Qubit(QuantumRegister(1, 'com_sys_cnot1'), 0)})
Get the registers
[3]:
qregs = circuit_topo.get_regs()
Define the monolithic Circuit
[4]:
qc = QuantumCircuit(*qregs)
qc.h(1)
qc.cx(0,2)
qc.draw('mpl')
[4]:
Create the remapper object based on topology defined
[5]:
remapper = CircuitRemapper(circuit_topo)
Convert the monolithic circuit to a Distributed circuit
[6]:
dist_circ = remapper.remap_circuit(qc)
dist_circ.draw(output='mpl')
[6]:
If there are consecutive gates with same control but with target on the same processor, we can do the distribution only once. Let’s look at the following example.
[7]:
qc2 = QuantumCircuit(*qregs)
qc2.h(1)
qc2.cx(0,2)
qc2.cx(0,4)
qc2.draw('mpl')
[7]:
[8]:
dist_circ2 = remapper.remap_circuit(qc2)
dist_circ2.draw(output='mpl')
[8]:
Let us check the validity of the working of the distributed version
First we check the output for monolithic circuit
[9]:
from qiskit.quantum_info import partial_trace
[10]:
sim = Aer.get_backend('aer_simulator')
[11]:
qc2_copy = qc2.copy()
qc2_copy.save_statevector()
qobj = assemble(qc2_copy)
state = sim.run(qobj).result().get_statevector()
state = partial_trace(state, [5,6]) ## Trace out the communication qubits
plot_bloch_multivector(state)
[11]:
Now We check output of the distributed circuit
[12]:
dqc2_copy = dist_circ2.copy()
dqc2_copy.save_statevector()
qobj = assemble(dqc2_copy)
state = sim.run(qobj).result().get_statevector()
state = partial_trace(state, [5,6]) ## Trace out the communication qubits
plot_bloch_multivector(state)
[12]:
As can be seen, the output of both circuits are equivalent
The case of higher order gates¶
In the case of gates with more than 2 qubits, we shall need to decompose the circuit to 2 and 1 qubit gates for the distribution to work
[13]:
qregs = circuit_topo.get_regs()
qc = QuantumCircuit(*qregs)
qc.ccx(0, 2, 4)
qc.draw('mpl')
[13]:
Trying to distribute the above circuit shall result in an error.
[15]:
dist_circ = remapper.remap_circuit(qc)
dist_circ.draw(output='mpl')
---------------------------------------------------------------------------
CircuitError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_23916\250667637.py in <module>
----> 1 dist_circ = remapper.remap_circuit(qc)
2 dist_circ.draw(output='mpl')
E:\distributed-qiskit\distributed_qiskit\circuit_remapper.py in remap_circuit(self, circuit, decompose, decompose_list)
221 if incompatible:
222 raise CircuitError(
--> 223 "The circuit contains incompatible gates, Please try decompose=True keyword argument.")
224
225 layers = self._circuit_to_layers(circuit=circuit)
CircuitError: 'The circuit contains incompatible gates, Please try decompose=True keyword argument.'
To bypass one needs to put decompose=True which shall iteratively perform decomposition until circuit is ready for distribution.
[16]:
dist_circ = remapper.remap_circuit(qc, decompose=True)
dist_circ.draw(output='mpl')
[16]: