1
$\begingroup$

Suppose I have a QuantumCircuit with three classical bits, and I would like to apply the X operation conditionally if the first two bits are 0b11 or 0b00. Is there a better approach to do so than the two approaches I have listed down below?

Approach I: Each branch implemented separately

circuit = QuantumCircuit(1)
c_registers = [Clbit() for _ in range(3)]
circuit.add_bits(c_registers)

with circuit.if_test((c_registers[0], 0)) as _:
    with circuit.if_test((c_registers[1], 0)) as _:
        circuit.x(0)

with circuit.if_test((c_registers[0], 1)) as _:
    with circuit.if_test((c_registers[1], 1)) as _:
        circuit.x(0)

Approach II: Create ClassicalRegister and ignore last bit

circuit = QuantumCircuit(1, 3)
c_reg = circuit.cregs[0]

# Ignoring the last bit by having same branch for `0` and `1`.
with circuit.if_test((c_reg, 0b110)):
        circuit.x(0)

with circuit.if_test((c_reg, 0b111)):
        circuit.x(0)

with circuit.if_test((c_reg, 0b000)):
        circuit.x(0)

with circuit.if_test((c_reg, 0b001)):
        circuit.x(0)

It would have been neat to have something as follows:

## Approach III: List of conditions

circuit = QuantumCircuit(1)
c_registers = [Clbit() for _ in range(3)]
circuit.add_bits(c_registers)

with circuit.if_test([(c_registers[0], 1), (c_registers[1], 1)]) as _:
        circuit.x(0)

If there are no other approaches, I believe that the best approach would be to use write functionality to create the branches for the first trees methodically.

def apply_if_cond(circuit: QuantumCircuit, regs: list[Clbit], bits: int, gate: Gate, pos: list[int]):
    """
    Conditional operator on circuit

    Inputs:
        - circuit: Circuit on which operation is applied
        - regs: Classical registers on which condition is applied
        - bits: Integer representing the condition
        - gate: Gate to be applied conditionally
        - pos: Qubit positions on which the Gate is to be applied on
    """
    if len(regs) == 0:
        circuit.append(gate, pos)
        return

    bit = bits & 1
    bits = bits // 2
    with circuit.if_test((regs[0], bit)) as _:
        apply_if_cond(circuit, regs[1:], bits, gate, pos)

circuit = QuantumCircuit(1)
c_registers = [Clbit() for _ in range(3)]
circuit.add_bits(c_registers)

apply_regs = [c_registers[0], c_registers[1]]
apply_if_cond(circuit, apply_regs, 0b00, XGate(), [0])
apply_if_cond(circuit, apply_regs, 0b11, XGate(), [0])
```
$\endgroup$

2 Answers 2

2
$\begingroup$

Qiskit allows you to add the same classical bits to more than one register. So, you can add to the circuit one more classical register that contains these two bits:

circuit = QuantumCircuit(1)
c_registers = [Clbit() for _ in range(3)]
circuit.add_bits(c_registers)

# Add a new ClassicalRegister:
cr = ClassicalRegister(bits=c_registers[0:2])
circuit.add_register(cr)

with circuit.if_test((cr, 0)) as _:
    circuit.x(0)

with circuit.if_test((cr, 3)) as _:
    circuit.x(0)

Another option is to use the newly added SwitchCaseOp1, 2

circuit = QuantumCircuit(1)
c_registers = ClassicalRegister(bits=[Clbit() for _ in range(3)])
circuit.add_register(c_registers)

with circuit.switch(c_registers) as case:
    with case(0, 1, 6, 7):
        circuit.x(0)

Note, however, that none of IBM backends currently support the switch-case operation.


If OpenQasm is an option, you should go with OpenQasm 3.0 which supports bitwise operations and boolean operations3.

$\endgroup$
1
  • 2
    $\begingroup$ +1 Honestly, I think that using SwichCaseOp is a really good way to do this. Better than my idea/answer $\endgroup$ Commented Jul 9, 2023 at 17:16
0
$\begingroup$

We can do this in QASM (I perfer doing it like this):

qc = QuantumCircuit.from_qasm_str("""
OPENQASM 2.0;
include "qelib1.inc";

qreg q[3];
creg c[3];

x q[0];
x q[1];

measure q[0] -> c[0];
measure q[1] -> c[1];

if (c == 3) x q[0];
if (c == 0) x q[0];


measure q[0] -> c[0];
measure q[1] -> c[1];
measure q[2] -> c[2];
""")

For more information about QASM 2.0 : https://arxiv.org/pdf/1707.03429.pdf

Edit after the comments

This method can be perfectly done is Qiskit. We can do this perfectly if we dont measure the third qubit:

cr = ClassicalRegister(3)
qr = QuantumRegister(3)
qc : QuantumCircuit = QuantumCircuit(cr,qr)

qc.x(range(3))
qc.measure([qr[0],qr[1]],[cr[0],cr[1]])

with qc.if_test((cr,0b11)):
    qc.x(0)

qc.measure(qr,cr)
$\endgroup$
6
  • $\begingroup$ I believe this is also possible using ClassicalRegister, how do I do something like c[0] == 1 and c[1] == 1 and ignore c[2]? That is what I desire :) $\endgroup$
    – Zee
    Commented Jul 9, 2023 at 15:23
  • $\begingroup$ Honestly, I was trying and I don't have any good solutions. Also by the answer in the link i belive there is no option nowadays. Nevertheless, in next qiskit versions, we can do it for sure. Link : quantumcomputing.stackexchange.com/questions/32530/… $\endgroup$ Commented Jul 9, 2023 at 15:34
  • $\begingroup$ So the best option, for me, is using QASM. In this way we can say if (c==3) that means: if(c[0]==1 and c[1]==1) and with the method from_qasm_simulator you get the QuantumCircuit required $\endgroup$ Commented Jul 9, 2023 at 15:37
  • $\begingroup$ @Zeeshanahmed I have made some changes, it's the same but in qiskit and if_test $\endgroup$ Commented Jul 9, 2023 at 15:56
  • $\begingroup$ If you are dealing with 3 bit register, if (c==3) implies if (c[0] == 1 and c[1] == 1 and c[2] == 0) there is no way of skipping c[2] == 0 in QASM either. The nested if condition is the best solution I guess :3 $\endgroup$
    – Zee
    Commented Jul 9, 2023 at 16:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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