0
$\begingroup$

Give the following input: $$ A: 1110 \\ B: 0111 \\ \text{indicator}: 0 \text{ or } 1 $$ How do I copy the value of A or B to target qubits if indicator is 0 or 1 respectively?

In the image below, the indicator=0 so the value of the copy_of_a_or_b qubits should resemble a_input qubits:

enter image description here

How can I do this in Qiskit?

$\endgroup$
0
$\begingroup$

It seems you are looking for a classical operation called multiplexer. It is possible to build such operation with Qiskit's uniformly controlled gates (UCGate). More info in here.

However, this way might not be the easier way. After reading Cryoris' answer, here is my version of your example (which piggyback on Cryoris' great answer):

Let's set your current circuit:

from qiskit import *

a_input = QuantumRegister(4, name='a')
b_input = QuantumRegister(4, name='b')

inputs = QuantumCircuit(a_input, b_input)

inputs.initialize('1110', a_input)
inputs.initialize('0111', b_input)

inputs.draw('mpl')

enter image description here

(side note, if your run inputs.decompose().draw('mpl') you will notice that the order of the $X$ gates are going to be "in reverse". That's because Qiskit endianness.)

Now, time to create the multiplexer. This scales up the Cryoris' answer:

from qiskit.circuit.library import CXGate

indicator = QuantumRegister(1, name='indicator')
a_or_b = QuantumRegister(4, name='aORb')

multiplexer = QuantumCircuit(a_input, b_input, indicator, a_or_b)
for i in range(4):
    # If indicator is 0, copy from A
    multiplexer.append(CXGate().control(1, ctrl_state='0'), [indicator, a_input[i], a_or_b[i]])
    
multiplexer.barrier(a_input, b_input)

for i in range(4):
    # If indicator is 1, copy from B
    multiplexer.append(CXGate().control(1, ctrl_state='1'), [indicator, b_input[i], a_or_b[i]])

multiplexer.draw('mpl')

enter image description here

The register a_or_b needs to be measured:

output = ClassicalRegister(4, name='output')
measure = QuantumCircuit(a_or_b)
measure.measure_all(a_or_b)

The composed result:

circuit = inputs + multiplexer + measure
circuit.draw('mpl')

enter image description here

Finally, we need to "set" the indicator qubit. Once circuit for each possibility:

indicator0 = QuantumCircuit(indicator)
indicator0.initialize('0', indicator)

indicator1 = QuantumCircuit(indicator)
indicator1.initialize('1', indicator)

Time to test how it works:

job = execute(indicator0 + circuit, backend=BasicAer.get_backend('qasm_simulator'))
job.result().get_counts().keys()
dict_keys(['1110'])
job = execute(indicator1 + circuit, backend=BasicAer.get_backend('qasm_simulator'))
job.result().get_counts().keys()
dict_keys(['0111'])
$\endgroup$
1
  • $\begingroup$ Thanks. the structure and approach you took to answer the question is very good. Very helpful for indiviaudal stepping into quantum programming such as myself. Much appreciated. Didn't realise how much I took for granted in classical programming until I started learning quantum computing $\endgroup$ Dec 3 '20 at 20:31
1
$\begingroup$

"Copying" a bit value from one qubit to another in this sense means applying a $CX$ gate where the source qubit is the control. If you additionally want to control this operation on an indicator qubit you can add another control. Then you have a $CCX$ or Toffoli. If you use an "ordinary" or closed control, the bit value will be copied if the indicator is 1. If you sandwich the control with two $X$ gates however -- an open control -- it will copy when the indicator is 0. In your case you could just apply two $CCX$ gates per bit where once you use an open control on the indicator and once a closed control on the indicator.

In circuits (for only one bit, for several qubits just repeat this operation):

>>> from qiskit import QuantumCircuit, QuantumRegister
>>> from qiskit.circuit.library import XGate
>>> qr_a, qr_b, qr_i, qr_t = QuantumRegister(1, 'a'), QuantumRegister(1, 'b'), QuantumRegister(1, 'indicator'), QuantumRegister(1, 'target')
>>> circuit = QuantumCircuit(qr_a, qr_b, qr_i, qr_t)
>>> open_ccx = XGate().control(2, ctrl_state='01')
>>> closed_ccx = XGate().control(2)  # per default ctrl_state='00'
>>> circuit.append(open_ccx, [qr_a, qr_i, qr_t])  # copy A if indicator is 0
>>> circuit.append(closed_ccx, [qr_b, qr_i, qr_t])  # copy B if indicator is 1
>>> circuit.draw()

        a_0: ──■───────
               │
        b_0: ──┼────■──
               │    │
indicator_0: ──o────■──
             ┌─┴─┐┌─┴─┐
   target_0: ┤ X ├┤ X ├
             └───┘└───┘

And now the nicer solution by using a blockwise control. Since Qiskit can control arbitrary operations we can just define our custom copy operation consisting of 4 $CX$ gates and then control this, once open and once closed. Like so:

>>> qr_a, qr_b, qr_i, qr_t = QuantumRegister(4, 'a'), QuantumRegister(4, 'b'), QuantumRegister(1, 'indicator'), QuantumRegister(4, 'target')
>>> circuit = QuantumCircuit(qr_a, qr_b, qr_i, qr_t)
>>> copy = QuantumCircuit(8)  # circuit to copy 4 bits
>>> copy.cx(range(4), range(4, 8))
>>> open_copy = copy.control(1, ctrl_state='0')
>>> closed_copy = copy.control(1, ctrl_state='1')
>>> circuit.append(open_copy, qr_i[:] + qr_a[:] + qr_t[:])
>>> circuit.append(closed_copy, qr_i[:] + qr_b[:] + qr_t[:])

Hope that helps!

$\endgroup$
1
  • $\begingroup$ Thanks @Cryoris, will give it a try and report back. much appreciated $\endgroup$ Dec 3 '20 at 16:56

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.