This page was generated from the notebook examples/notebooks/1_Basics_of_circuit.ipynb.

Basic manipulation of circuits

The goal of this notebook is to explore main possibilities and manipulation of quantum circuits offered by MPQP.

Instantiation and display the circuit

We first import QCircuit, the class representing quantum circuits.

[1]:
from mpqp import QCircuit

The first argument taken by the constructor of QCircuit is either the number of qubits, or a list of Instruction.

One can instanciate an empty circuit by only giving its number of qubits. The number of classical bits is automatically handled by the class, and thus is optional. We can also attach to a circuit a given label.

[4]:
circ1 = QCircuit(3)
circ2 = QCircuit(5, nb_cbits=2, label="Example")

Then, one can add at the end of the circuit an instruction or list of instructions. For that, we add the right imports.

[2]:
from mpqp.gates import *
from mpqp.measures import BasisMeasure
from mpqp import Barrier
[5]:
circ2.add(CNOT(2,3))
circ2.add([H(0), T(1), CNOT(0,1), S(4)])

As previously stated, we can also instantiate and initialize the circuit with a list of Instruction (gates or measurements).

[6]:
circ3 = QCircuit(
    [
        H(0),
        X(1),
        CNOT(1, 2),
        Barrier(),
        Y(2),
        Z(0),
        CZ(1, 0),
        BasisMeasure([0, 1, 2], shots=1024),
    ]
)

We can then print the circuit directly as a string, or use pretty_print for more detailed information on the circuit.

[6]:
print(circ2)
     ┌───┐
q_0: ┤ H ├──■──
     ├───┤┌─┴─┐
q_1: ┤ T ├┤ X ├
     └───┘└───┘
q_2: ──■───────
     ┌─┴─┐
q_3: ┤ X ├─────
     ├───┤
q_4: ┤ S ├─────
     └───┘
c: 2/══════════

[7]:
circ3.pretty_print()
QCircuit : Size (Qubits,Cbits) = (3, 3), Nb instructions = 8
     ┌───┐      ░ ┌───┐   ┌─┐
q_0: ┤ H ├──────░─┤ Z ├─■─┤M├───
     ├───┤      ░ └───┘ │ └╥┘┌─┐
q_1: ┤ X ├──■───░───────■──╫─┤M├
     └───┘┌─┴─┐ ░ ┌───┐┌─┐ ║ └╥┘
q_2: ─────┤ X ├─░─┤ Y ├┤M├─╫──╫─
          └───┘ ░ └───┘└╥┘ ║  ║
c: 3/═══════════════════╩══╩══╩═
                        2  0  1

We can also use the method display to render the circuit in different formats. The default one uses matplotlib, but other options can be given in parameters (the same as the qiskit display function).

[8]:
circ3.display()
c:\Users\Henri\anaconda3\lib\site-packages\mpqp\core\circuit.py:294: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.
  fig.show()
[8]:
../_images/notebooks_1_Basics_of_circuit_14_1.png
[9]:
circ3.display("latex")
[9]:
../_images/notebooks_1_Basics_of_circuit_15_0.png

Retrieve circuit properties

One can also retrieve different properties of the circuit, including the depth, the size (quantum and classical bits), counting (specific) gates and retrieving the attached measurements.

[10]:
circ3.depth()
[10]:
4
[11]:
circ3.size()
[11]:
(3, 3)
[12]:
circ3.count_gates(X)
[12]:
1
[13]:
circ3.get_measurements()
[13]:
[BasisMeasure([0, 1, 2], shots=1024)]

Combination of circuits

We also allow combinations of circuits.

[7]:
circ1 = QCircuit([H(0), S(1), CNOT(0,1)])
circ2 = QCircuit([X(0)])
print(circ1)
print('-------------')
print(circ2)
     ┌───┐
q_0: ┤ H ├──■──
     ├───┤┌─┴─┐
q_1: ┤ S ├┤ X ├
     └───┘└───┘
-------------
   ┌───┐
q: ┤ X ├
   └───┘

One can append a circuit to another, consisting in concatenating the circuit horizontally at the right of the first one. For more simplicity, the + realized the same operation. When the size does not match, we automatically adjust the size of the resulting circuit.

[8]:
appended = circ1 + circ2
print(appended)
     ┌───┐     ┌───┐
q_0: ┤ H ├──■──┤ X ├
     ├───┤┌─┴─┐└───┘
q_1: ┤ S ├┤ X ├─────
     └───┘└───┘

One can also take the tensor product of two circuits using the method tensor, or the symbol @, which will concatenate the second circuit vertically under the first.

[9]:
tensored = circ1 @ circ2
print(tensored)
     ┌───┐
q_0: ┤ H ├──■──
     ├───┤┌─┴─┐
q_1: ┤ S ├┤ X ├
     ├───┤└───┘
q_2: ┤ X ├─────
     └───┘

Translating the circuit

MPQP is a multi-platform quantum programming library and handles for the user the translation of circuits. We allow the user to use a function to export the circuit in different objects specific to each SDK using the method to_other_language.

[10]:
from mpqp import Language

circ3.to_other_language(Language.QISKIT)
[10]:
<qiskit.circuit.quantumcircuit.QuantumCircuit at 0x2186bf40a90>
[11]:
circ3.to_other_language(Language.MY_QLM)
[11]:
Circuit(ops=[Op(gate='H', qbits=[0], type=0, cbits=None, formula=None, remap=None), Op(gate='X', qbits=[1], type=0, cbits=None, formula=None, remap=None), Op(gate='CNOT', qbits=[1, 2], type=0, cbits=None, formula=None, remap=None), Op(gate='Y', qbits=[2], type=0, cbits=None, formula=None, remap=None), Op(gate='Z', qbits=[0], type=0, cbits=None, formula=None, remap=None), Op(gate='CSIGN', qbits=[1, 0], type=0, cbits=None, formula=None, remap=None)], name=None, gateDic={'X': GateDefinition(name='X', arity=1, matrix=Matrix(nRows=2, nCols=2, data=[ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='X', parameters=[]), nbctrls=None, circuit_implementation=None), 'Y': GateDefinition(name='Y', arity=1, matrix=Matrix(nRows=2, nCols=2, data=[ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=-0.0, im=-1.0), ComplexNumber(re=0.0, im=1.0), ComplexNumber(re=0.0, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='Y', parameters=[]), nbctrls=None, circuit_implementation=None), 'Z': GateDefinition(name='Z', arity=1, matrix=Matrix(nRows=2, nCols=2, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=-1.0, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='Z', parameters=[]), nbctrls=None, circuit_implementation=None), 'H': GateDefinition(name='H', arity=1, matrix=Matrix(nRows=2, nCols=2, data=[ComplexNumber(re=0.7071067811865475, im=0.0), ComplexNumber(re=0.7071067811865475, im=0.0), ComplexNumber(re=0.7071067811865475, im=0.0), ComplexNumber(re=-0.7071067811865475, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='H', parameters=[]), nbctrls=None, circuit_implementation=None), 'CNOT': GateDefinition(name='CNOT', arity=2, matrix=Matrix(nRows=4, nCols=4, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0)]), is_ctrl=True, is_dag=None, is_trans=None, is_conj=None, subgate='X', syntax=GSyntax(name='CNOT', parameters=[]), nbctrls=1, circuit_implementation=None), 'CSIGN': GateDefinition(name='CSIGN', arity=2, matrix=Matrix(nRows=4, nCols=4, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=-1.0, im=0.0)]), is_ctrl=True, is_dag=None, is_trans=None, is_conj=None, subgate='Z', syntax=GSyntax(name='CSIGN', parameters=[]), nbctrls=1, circuit_implementation=None), 'ISWAP': GateDefinition(name='ISWAP', arity=2, matrix=Matrix(nRows=4, nCols=4, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=1.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=1.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='ISWAP', parameters=[]), nbctrls=None, circuit_implementation=None), 'SQRTSWAP': GateDefinition(name='SQRTSWAP', arity=2, matrix=Matrix(nRows=4, nCols=4, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.5, im=0.5), ComplexNumber(re=0.5, im=-0.5), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.5, im=-0.5), ComplexNumber(re=0.5, im=0.5), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='SQRTSWAP', parameters=[]), nbctrls=None, circuit_implementation=None), 'I': GateDefinition(name='I', arity=1, matrix=Matrix(nRows=2, nCols=2, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='I', parameters=[]), nbctrls=None, circuit_implementation=None), 'SWAP': GateDefinition(name='SWAP', arity=2, matrix=Matrix(nRows=4, nCols=4, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='SWAP', parameters=[]), nbctrls=None, circuit_implementation=None), 'CCNOT': GateDefinition(name='CCNOT', arity=3, matrix=Matrix(nRows=8, nCols=8, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0)]), is_ctrl=True, is_dag=None, is_trans=None, is_conj=None, subgate='CNOT', syntax=GSyntax(name='CCNOT', parameters=[]), nbctrls=1, circuit_implementation=None), 'S': GateDefinition(name='S', arity=1, matrix=Matrix(nRows=2, nCols=2, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=1.0)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='S', parameters=[]), nbctrls=None, circuit_implementation=None), 'T': GateDefinition(name='T', arity=1, matrix=Matrix(nRows=2, nCols=2, data=[ComplexNumber(re=1.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.0, im=0.0), ComplexNumber(re=0.7071067811865476, im=0.7071067811865476)]), is_ctrl=False, is_dag=None, is_trans=None, is_conj=None, subgate=None, syntax=GSyntax(name='T', parameters=[]), nbctrls=None, circuit_implementation=None)}, nbqbits=3, nbcbits=0, _gate_set=GateSet(gate_signatures={'X': GateSignature(name='X', parameters=[], arity=1, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_x at 0x000002186CACCA00>, circuit_generator=None), 'Y': GateSignature(name='Y', parameters=[], arity=1, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_y at 0x000002186CACCAD0>, circuit_generator=None), 'Z': GateSignature(name='Z', parameters=[], arity=1, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_z at 0x000002186CACCBA0>, circuit_generator=None), 'H': GateSignature(name='H', parameters=[], arity=1, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_h at 0x000002186CACC930>, circuit_generator=None), 'CNOT': GateSignature(name='CNOT', parameters=[], arity=2, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_cnot at 0x000002186CACCEE0>, circuit_generator=None), 'CSIGN': GateSignature(name='CSIGN', parameters=[], arity=2, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_csign at 0x000002186CAD7040>, circuit_generator=None), 'ISWAP': GateSignature(name='ISWAP', parameters=[], arity=2, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_iswap at 0x000002186CAD72B0>, circuit_generator=None), 'SQRTSWAP': GateSignature(name='SQRTSWAP', parameters=[], arity=2, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_sqrtswap at 0x000002186CAD71E0>, circuit_generator=None), 'I': GateSignature(name='I', parameters=[], arity=1, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_i at 0x000002186CACCC70>, circuit_generator=None), 'SWAP': GateSignature(name='SWAP', parameters=[], arity=2, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_swap at 0x000002186CAD7110>, circuit_generator=None), 'CCNOT': GateSignature(name='CCNOT', parameters=[], arity=3, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_ccnot at 0x000002186CAD7380>, circuit_generator=None), 'S': GateSignature(name='S', parameters=[], arity=1, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_s at 0x000002186CACCD40>, circuit_generator=None), 'T': GateSignature(name='T', parameters=[], arity=1, nb_args=0, arg_types=[], arity_generator=None, matrix_generator=<cyfunction gen_t at 0x000002186CACCE10>, circuit_generator=None), 'PH': GateSignature(name='PH', parameters=[1], arity=1, nb_args=1, arg_types=[<class 'float'>], arity_generator=None, matrix_generator=<cyfunction gen_ph at 0x000002186CACC450>, circuit_generator=None), 'RZ': GateSignature(name='RZ', parameters=[1], arity=1, nb_args=1, arg_types=[<class 'float'>], arity_generator=None, matrix_generator=<cyfunction gen_rz at 0x000002186CACC520>, circuit_generator=None), 'RX': GateSignature(name='RX', parameters=[1], arity=1, nb_args=1, arg_types=[<class 'float'>], arity_generator=None, matrix_generator=<cyfunction gen_rx at 0x000002186CACC6C0>, circuit_generator=None), 'RY': GateSignature(name='RY', parameters=[1], arity=1, nb_args=1, arg_types=[<class 'float'>], arity_generator=None, matrix_generator=<cyfunction gen_ry at 0x000002186CACC5F0>, circuit_generator=None), 'U': AbstractGate(name='U', parameters=[1, 1, 1], arity=1, nb_args=3, arg_types=[<class 'float'>, <class 'float'>, <class 'float'>], arity_generator=None, matrix_generator=<function gen_U at 0x000002186CD04040>, circuit_generator=None, dag_func=None), 'U1': AbstractGate(name='U1', parameters=[1], arity=1, nb_args=1, arg_types=[<class 'float'>], arity_generator=None, matrix_generator=<function gen_u1 at 0x000002186CDC6670>, circuit_generator=None, dag_func=None), 'U2': AbstractGate(name='U2', parameters=[1, 1], arity=1, nb_args=2, arg_types=[<class 'float'>, <class 'float'>], arity_generator=None, matrix_generator=<function gen_u2 at 0x000002186CDC6700>, circuit_generator=None, dag_func=None), 'U3': AbstractGate(name='U3', parameters=[1, 1, 1], arity=1, nb_args=3, arg_types=[<class 'float'>, <class 'float'>, <class 'float'>], arity_generator=None, matrix_generator=<function gen_U at 0x000002186CD04040>, circuit_generator=None, dag_func=None)}), has_matrices=True, var_dic={}, qregs=[], ancilla_map=None, _serialized_gate_set=b"\x80\x04\x95?\x06\x00\x00\x00\x00\x00\x00\x8c\x11qat.core.gate_set\x94\x8c\x07GateSet\x94\x93\x94)\x81\x94}\x94\x8c\x0fgate_signatures\x94}\x94(\x8c\x01X\x94h\x00\x8c\rGateSignature\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94h\x07\x8c\nparameters\x94]\x94\x8c\x05arity\x94K\x01\x8c\x07nb_args\x94K\x00\x8c\targ_types\x94]\x94\x8c\x0farity_generator\x94N\x8c\x10matrix_generator\x94\x8c$qat.core.circuit_builder.matrix_util\x94\x8c\x05gen_x\x94\x93\x94\x8c\x11circuit_generator\x94Nub\x8c\x01Y\x94h\t)\x81\x94}\x94(h\x0ch\x19h\r]\x94h\x0fK\x01h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x05gen_y\x94\x93\x94h\x18Nub\x8c\x01Z\x94h\t)\x81\x94}\x94(h\x0ch h\r]\x94h\x0fK\x01h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x05gen_z\x94\x93\x94h\x18Nub\x8c\x01H\x94h\t)\x81\x94}\x94(h\x0ch'h\r]\x94h\x0fK\x01h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x05gen_h\x94\x93\x94h\x18Nub\x8c\x04CNOT\x94h\t)\x81\x94}\x94(h\x0ch.h\r]\x94h\x0fK\x02h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x08gen_cnot\x94\x93\x94h\x18Nub\x8c\x05CSIGN\x94h\t)\x81\x94}\x94(h\x0ch5h\r]\x94h\x0fK\x02h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\tgen_csign\x94\x93\x94h\x18Nub\x8c\x05ISWAP\x94h\t)\x81\x94}\x94(h\x0ch<h\r]\x94h\x0fK\x02h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\tgen_iswap\x94\x93\x94h\x18Nub\x8c\x08SQRTSWAP\x94h\t)\x81\x94}\x94(h\x0chCh\r]\x94h\x0fK\x02h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x0cgen_sqrtswap\x94\x93\x94h\x18Nub\x8c\x01I\x94h\t)\x81\x94}\x94(h\x0chJh\r]\x94h\x0fK\x01h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x05gen_i\x94\x93\x94h\x18Nub\x8c\x04SWAP\x94h\t)\x81\x94}\x94(h\x0chQh\r]\x94h\x0fK\x02h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x08gen_swap\x94\x93\x94h\x18Nub\x8c\x05CCNOT\x94h\t)\x81\x94}\x94(h\x0chXh\r]\x94h\x0fK\x03h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\tgen_ccnot\x94\x93\x94h\x18Nub\x8c\x01S\x94h\t)\x81\x94}\x94(h\x0ch_h\r]\x94h\x0fK\x01h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x05gen_s\x94\x93\x94h\x18Nub\x8c\x01T\x94h\t)\x81\x94}\x94(h\x0chfh\r]\x94h\x0fK\x01h\x10K\x00h\x11]\x94h\x13Nh\x14h\x15\x8c\x05gen_t\x94\x93\x94h\x18Nub\x8c\x02PH\x94h\t)\x81\x94}\x94(h\x0chmh\r]\x94K\x01ah\x0fK\x01h\x10K\x01h\x11]\x94\x8c\ndill._dill\x94\x8c\n_load_type\x94\x93\x94\x8c\x05float\x94\x85\x94R\x94ah\x13Nh\x14h\x15\x8c\x06gen_ph\x94\x93\x94h\x18Nub\x8c\x02RZ\x94h\t)\x81\x94}\x94(h\x0chzh\r]\x94K\x01ah\x0fK\x01h\x10K\x01h\x11]\x94hwah\x13Nh\x14h\x15\x8c\x06gen_rz\x94\x93\x94h\x18Nub\x8c\x02RX\x94h\t)\x81\x94}\x94(h\x0ch\x81h\r]\x94K\x01ah\x0fK\x01h\x10K\x01h\x11]\x94hwah\x13Nh\x14h\x15\x8c\x06gen_rx\x94\x93\x94h\x18Nub\x8c\x02RY\x94h\t)\x81\x94}\x94(h\x0ch\x88h\r]\x94K\x01ah\x0fK\x01h\x10K\x01h\x11]\x94hwah\x13Nh\x14h\x15\x8c\x06gen_ry\x94\x93\x94h\x18Nub\x8c\x01U\x94\x8c\x14qat.lang.AQASM.gates\x94\x8c\x0cAbstractGate\x94\x93\x94)\x81\x94}\x94(h\x0ch\x8fh\r]\x94(K\x01K\x01K\x01eh\x0fK\x01h\x10K\x03h\x11]\x94(hwhwhweh\x13Nh\x14\x8c qat.interop.openqasm.qasm_parser\x94\x8c\x05gen_U\x94\x93\x94h\x18N\x8c\x08dag_func\x94Nub\x8c\x02U1\x94h\x92)\x81\x94}\x94(h\x0ch\x9bh\r]\x94K\x01ah\x0fK\x01h\x10K\x01h\x11]\x94hwah\x13Nh\x14h\x97\x8c\x06gen_u1\x94\x93\x94h\x18Nh\x9aNub\x8c\x02U2\x94h\x92)\x81\x94}\x94(h\x0ch\xa2h\r]\x94(K\x01K\x01eh\x0fK\x01h\x10K\x02h\x11]\x94(hwhweh\x13Nh\x14h\x97\x8c\x06gen_u2\x94\x93\x94h\x18Nh\x9aNub\x8c\x02U3\x94h\x92)\x81\x94}\x94(h\x0ch\xa9h\r]\x94(K\x01K\x01K\x01eh\x0fK\x01h\x10K\x03h\x11]\x94(hwhwhweh\x13Nh\x14h\x99h\x18Nh\x9aNubusb.")
[12]:
circ3.to_other_language(Language.BRAKET)
c:\Users\JulienCalisto\Documents\MPQP_main_repo\mpqp\.venv\lib\site-packages\mpqp\qasm\qasm_to_braket.py:80: UnsupportedBraketFeaturesWarning:
This program uses OpenQASM language features that may not be supported on QPUs or on-demand simulators.
  warnings.warn(

[12]:
Circuit('instructions': [Instruction('operator': H('qubit_count': 1), 'target': QubitSet([Qubit(0)]), 'control': QubitSet([]), 'control_state': (), 'power': 1), Instruction('operator': X('qubit_count': 1), 'target': QubitSet([Qubit(1)]), 'control': QubitSet([]), 'control_state': (), 'power': 1), Instruction('operator': CNot('qubit_count': 2), 'target': QubitSet([Qubit(1), Qubit(2)]), 'control': QubitSet([]), 'control_state': (), 'power': 1), Instruction('operator': Y('qubit_count': 1), 'target': QubitSet([Qubit(2)]), 'control': QubitSet([]), 'control_state': (), 'power': 1), Instruction('operator': Z('qubit_count': 1), 'target': QubitSet([Qubit(0)]), 'control': QubitSet([]), 'control_state': (), 'power': 1), Instruction('operator': CZ('qubit_count': 2), 'target': QubitSet([Qubit(1), Qubit(0)]), 'control': QubitSet([]), 'control_state': (), 'power': 1)])
[13]:
circ3.to_other_language(Language.CIRQ)
[13]:
q_0: ───H───Z───@───M('c_0')───
                │
q_1: ───X───@───@───M('c_1')───
            │
q_2: ───────X───Y───M('c_2')───

Since we use OpenQASM as a common standard for circuit translation, we also provide for the user a way to retrive the code of the circuit in OpenQASM 2.0 and 3.0.

[21]:
print(circ3.to_qasm2())
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[3];
h q[0];
x q[1];
cx q[1],q[2];
barrier q[0],q[1],q[2];
y q[2];
z q[0];
cz q[1],q[0];
measure q[0] -> c[0];
measure q[1] -> c[1];
measure q[2] -> c[2];

[22]:
print(circ3.to_qasm3())
OPENQASM 3.0;
include "stdgates.inc";

qubit[3] q;
bit[3] c;
h q[0];
x q[1];
cx q[1],q[2];
barrier q[0],q[1],q[2];
y q[2];
z q[0];
cz q[1],q[0];
c[0] = measure q[0];
c[1] = measure q[1];
c[2] = measure q[2];

Parametrized circuit

We allow the use and manipulation of symbolic variable to parametrize gates.

We first declare symbolic variables using symbols (yes, we indeed use sympy!).

[ ]:
from sympy import symbols

theta, k = symbols("θ k")

We can then use these variables to instantiate and add ParametrizedGate to the circuit.

[ ]:
param_circ = QCircuit(
    [Rx(theta, 0), CNOT(1,2), X(2), Rk(k,1), H(0), CRk(k, 0, 2),
    BasisMeasure(list(range(3)), shots=1000)]
)

One can observe, in the print below, that 3 gates depend on variables.

[ ]:
print(param_circ)
     ┌───────┐       ┌───┐                              ┌─┐
q_0: ┤ Rx(θ) ├───────┤ H ├─────────■────────────────────┤M├───
     └───────┘┌──────┴───┴───────┐ │                 ┌─┐└╥┘
q_1: ────■────┤ P(2**(1 - k)*pi) ├─┼─────────────────┤M├─╫────
       ┌─┴─┐  └──────┬───┬───────┘ │P(2**(1 - k)*pi) └╥┘ ║ ┌─┐
q_2: ──┤ X ├─────────┤ X ├─────────■──────────────────╫──╫─┤M├
       └───┘         └───┘                            ║  ║ └╥┘
c: 3/═════════════════════════════════════════════════╩══╩══╩═
                                                      1  0  2

If we want to attribute values to the parameters, one can use the method subs as follows. This will return a new circuit with the gates’ parameters given in subs. One can also choose to substitute symbolic variable with real and complex numbers when call the run function (at execution).

[ ]:
import numpy as np
print(param_circ.subs({theta: np.pi/3, k:2}))
     ┌─────────┐  ┌───┐               ┌─┐
q_0: ┤ Rx(π/3) ├──┤ H ├────■──────────┤M├───
     └─────────┘┌─┴───┴──┐ │       ┌─┐└╥┘
q_1: ─────■─────┤ P(π/2) ├─┼───────┤M├─╫────
        ┌─┴─┐   └─┬───┬──┘ │P(π/2) └╥┘ ║ ┌─┐
q_2: ───┤ X ├─────┤ X ├────■────────╫──╫─┤M├
        └───┘     └───┘             ║  ║ └╥┘
c: 3/═══════════════════════════════╩══╩══╩═
                                    1  0  2

One can also retrieve the set of variables in the circuit by calling the variables() method.

[ ]:
param_circ.variables()
{k, θ}