0
$\begingroup$

In Qiskit, I need to define a custom gate or instruction that, once decomposed, turns into a series of basis gates, including measurements and classically controlled gates (this is the part that I can't get around).

I already tried using QuantumCircuit.to_gate(), but it does not work, maybe there is a way to it with the Instruction class?

Edit 1

I tried to do something like this:

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister

def mygate():
    qr = QuantumRegister(4)
    cr1 = ClassicalRegister(1)
    cr2 = ClassicalRegister(1)
    qc = QuantumCircuit(qr, cr1, cr2, name='mygate')
    qc.measure(qr[0], cr1[0])
    qc.measure(qr[1], cr2[0])
    qc.x(qr[-2]).c_if(cr1, 1)
    qc.x(qr[-1]).c_if(cr2, 1)

    return qc.to_instruction()


big = QuantumCircuit(5, 4)
big.append(mygate(), range(4), range(2))

But it does not work.

qiskit.exceptions.QiskitError: 'Cannot convert condition in circuit with multiple classical registers to instruction'
$\endgroup$
1
  • $\begingroup$ I'm sorry, I don't really understand the question - do you want to algorithmically decompose a custom gate? $\endgroup$
    – C. Kang
    Sep 17 '20 at 23:10
1
$\begingroup$

You need to convert a circuit into an instruction, not a gate. A gate is assumed to be invertible, which is not the case if you have measurements and classical conditionals. Therefore, you need to create a custom instruction. Here is a short tutorial for that:

First, create a circuit will all your gates and instructions, with measurements and conditionals. This will be the custom instruction:

from qiskit import *
from qiskit.circuit.library import *

qr = QuantumRegister(2)
cr = ClassicalRegister(2)
circuit = QuantumCircuit(qr, cr, name='my_inst')
circuit.h(qr[0])
circuit.cx(qr[0], qr[1])
circuit.measure(qr[1], cr[0])
circuit.append(XGate(), [qr[0]]).c_if(cr,2)
circuit.draw('text')
      ┌───┐         ┌───┐ 
q4_0: ┤ H ├──■──────┤ X ├─
      └───┘┌─┴─┐┌─┐ └─┬─┘ 
q4_1: ─────┤ X ├┤M├───┼───
           └───┘└╥┘┌──┴──┐
c4: 2/═══════════╩═╡ = 2 ╞
                 0 └─────┘

Then, you need to convert this circuit into an instruction:

my_inst = circuit.to_instruction()

This instruction can be append to another super circuit:

big_circuit = QuantumCircuit(5, 2)
big_circuit.h(range(5))
big_circuit.append(my_inst, range(2), range(2))
big_circuit.h(range(5))
big_circuit.draw('text')
     ┌───┐┌──────────┐┌───┐
q_0: ┤ H ├┤0         ├┤ H ├
     ├───┤│          │├───┤
q_1: ┤ H ├┤1         ├┤ H ├
     ├───┤│          │├───┤
q_2: ┤ H ├┤          ├┤ H ├
     ├───┤│          │├───┤
q_3: ┤ H ├┤  my_inst ├┤ H ├
     ├───┤│          │├───┤
q_4: ┤ H ├┤          ├┤ H ├
     └───┘│          │└───┘
c_0: ═════╡0         ╞═════
          │          │     
c_1: ═════╡1         ╞═════
          └──────────┘     

There it is. If you decompose the instructions in this circuit, you will see the internal operations:

big_circuit.decompose().draw('text')
     ┌──────────┐   ┌───┐                         ┌───┐ ┌──────────┐
q_0: ┤ U2(0,pi) ├───┤ H ├──────■──────────────────┤ X ├─┤ U2(0,pi) ├
     ├──────────┤   └───┘    ┌─┴─┐┌─┐┌──────────┐ └─┬─┘ └──────────┘
q_1: ┤ U2(0,pi) ├────────────┤ X ├┤M├┤ U2(0,pi) ├───┼───────────────
     ├──────────┤┌──────────┐└───┘└╥┘└──────────┘   │               
q_2: ┤ U2(0,pi) ├┤ U2(0,pi) ├──────╫────────────────┼───────────────
     ├──────────┤├──────────┤      ║                │               
q_3: ┤ U2(0,pi) ├┤ U2(0,pi) ├──────╫────────────────┼───────────────
     ├──────────┤├──────────┤      ║                │               
q_4: ┤ U2(0,pi) ├┤ U2(0,pi) ├──────╫────────────────┼───────────────
     └──────────┘└──────────┘      ║             ┌──┴──┐            
c: 2/══════════════════════════════╩═════════════╡ = 2 ╞════════════
                                   0             └─────┘            

If you want to decompose the circuit to a particular base, you can use the transpiler for that:

decomposed = transpile(big_circuit, basis_gates=['cx', 'u3'], optimization_level=0)
decomposed.draw('text', fold=-1)
     ┌───────────────┐┌───────────────┐                         ┌─────────────┐┌───────────────┐
q_0: ┤ U3(pi/2,0,pi) ├┤ U3(pi/2,0,pi) ├──■──────────────────────┤ U3(pi,0,pi) ├┤ U3(pi/2,0,pi) ├
     ├───────────────┤└───────────────┘┌─┴─┐┌─┐┌───────────────┐└──────┬──────┘└───────────────┘
q_1: ┤ U3(pi/2,0,pi) ├─────────────────┤ X ├┤M├┤ U3(pi/2,0,pi) ├───────┼────────────────────────
     ├───────────────┤┌───────────────┐└───┘└╥┘└───────────────┘       │                        
q_2: ┤ U3(pi/2,0,pi) ├┤ U3(pi/2,0,pi) ├──────╫─────────────────────────┼────────────────────────
     ├───────────────┤├───────────────┤      ║                         │                        
q_3: ┤ U3(pi/2,0,pi) ├┤ U3(pi/2,0,pi) ├──────╫─────────────────────────┼────────────────────────
     ├───────────────┤├───────────────┤      ║                         │                        
q_4: ┤ U3(pi/2,0,pi) ├┤ U3(pi/2,0,pi) ├──────╫─────────────────────────┼────────────────────────
     └───────────────┘└───────────────┘      ║                      ┌──┴──┐                     
c: 2/════════════════════════════════════════╩══════════════════════╡ = 2 ╞═════════════════════
                                             0                      └─────┘                     
$\endgroup$
4
  • $\begingroup$ Thanks for the reply, I updated my question with a slightly more complex example. $\endgroup$
    – DavideFrr
    Sep 18 '20 at 6:14
  • $\begingroup$ I see. The reason for Edit 1 failer is because registers get flatten as part of the conversion. Because classical conditional depends on the names of classical registers, converting a circuit with more than a classical register creates a condition on a partial register, which is not supported. Therefore that situation is not allowed. $\endgroup$
    – luciano
    Sep 18 '20 at 12:19
  • $\begingroup$ So there is no way to do it? $\endgroup$
    – DavideFrr
    Sep 19 '20 at 14:40
  • $\begingroup$ No. You can request the feature here github.com/Qiskit/qiskit-terra/issues/new/choose. $\endgroup$
    – luciano
    Sep 19 '20 at 17:42
0
$\begingroup$

I don't see a way to avoid the error you are getting as an Instruction can't handle multiple classical registers but here is a workaround.

def mygate():

  qr = QuantumRegister(4)
  cr1 = ClassicalRegister(1)
  cr2 = ClassicalRegister(1)

  qc = QuantumCircuit(qr, cr1, cr2, 
                      name='mygate')

  qc.measure(qr[0], cr1[0])
  qc.measure(qr[1], cr2[0])

  qc.x(qr[-2]).c_if(cr1, 1)
  qc.x(qr[-1]).c_if(cr2, 1)

  return qc



big = QuantumCircuit(5, 4)
big.compose(mygate(), 
            qubits=range(4), clbits=range(2), 
            inplace=True)
$\endgroup$
1
  • $\begingroup$ This will not create a custom instruction but will concatenate two circuits (big and mygate). The "encapsulation" of mygate happens at Python level, not at circuit level. Depending on your usecase, it's a possibility. $\endgroup$
    – luciano
    Sep 18 '20 at 17:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.