Qualtran icon indicating copy to clipboard operation
Qualtran copied to clipboard

Issue with And bloqs when round-tripping to Cirq and back.

Open wjhuggins opened this issue 9 months ago • 7 comments

I'm doing something a little strange, but I think that what I'm trying to do is supposed to work.

Basically, I'm taking an Add bloq and converting it to a Cirq circuit with some decomposition rules that stop Cirq from decomposing the And bloqs (which are also instances of GateWithRegisters). Then I'm going back from the Cirq circuit to a composite bloq.

I would expect this to work without errors, but there is some issue with the soquets corresponding to the target registers not being properly freed. I tried to figure it out on my own but I don't understand the magic that happens under the hood well enough.

I'm including a minimal (not) working example below.

from qualtran import QUInt
from qualtran.bloqs.arithmetic import Add
from qualtran.bloqs.mcmt import And
import numpy as np
import cirq

def test_self_contained_adder_issue():
    adder_bloq = Add(a_dtype=QUInt(4), b_dtype=QUInt(4))

    a_qubits = np.asarray([cirq.LineQubit(i * 3 + 0) for i in range(4)])
    b_qubits = np.asarray([cirq.LineQubit(i * 3 + 1) for i in range(4)])

    adder_op, _ = adder_bloq.as_cirq_op(
        qubit_manager=cirq.SimpleQubitManager(), a=b_qubits, b=a_qubits
    )
    circuit = cirq.Circuit(adder_op)

    def is_and_or_short(op):

        if len(op.qubits) <= 2:
            return True

        if isinstance(op.gate, And):
            return True

        return False

    circuit = cirq.Circuit(cirq.decompose(circuit, keep=is_and_or_short))

    cbloq = cirq_optree_to_cbloq(
        circuit.all_operations(),
    )

wjhuggins avatar Apr 16 '25 18:04 wjhuggins

The following leads to an error

CompositeBloq.from_cirq_circuit(adder_bloq.decompose_bloq().to_cirq_circuit())

but if you instead specify the input / output registers correct, then it works. So for example:

cbloq = cirq_optree_to_cbloq(adder_bloq.decompose_bloq().to_cirq_circuit(), signature=adder_bloq.signature, in_quregs=get_named_qubits(adder_bloq.signature.lefts()), out_quregs=get_named_qubits(adder_bloq.signature.rights())

@mpharrigan We should probably update the CompositeBloq.from_cirq_circuit so it also accepts optional parameters for signature, in_quregs and out_quregs and forwards it to the cirq_optree_to_cbloq method so users don't need to call the function and can directly call the static method on CompositeBloq.

tanujkhattar avatar Apr 16 '25 20:04 tanujkhattar

why does the conversion fail without the additional arguments? Add has only thru registers, so presumably the signature, in_quregs, and out_quregs arguments aren't carrying any special information.

Would it be possible to raise a more helpful error message in these cases?

mpharrigan avatar Apr 29 '25 16:04 mpharrigan

I see that if signature is None it uses circuit.all_qubits() to figure out the signature, which must include all the ancillae

mpharrigan avatar Apr 29 '25 16:04 mpharrigan

which must include all the ancillae

The word "must" could mean different things here. Should this be interpreted as "it needs to (but it doesn't)" or "it seems to (but it shouldn't)"?

daxfohl avatar Jun 10 '25 17:06 daxfohl

it uses all_qubits to deduce a signature that includes registers for qubits that only exist internally as ancillae (local q-variables), and shouldn't be included in the signature

mpharrigan avatar Jun 10 '25 17:06 mpharrigan

Okay, so is it that cirq's all_qubits includes ancillae by default, and needs a flag to exclude them? Or is it that the conversion from qualtran format to cirq format preemptively materialize all the ancilla qubits into regular qubits, so that cirq would have no way to tell the difference, in which case the fix would need to be on the qualtran side?

daxfohl avatar Jun 10 '25 17:06 daxfohl

There is actual information lost when converting to Cirq that cannot be automatically recovered. The most concise form of the data that needs to be recovered is indeed the signature, in_quregs, and out_quregs arguments that one can provide to Qualtran to finish the round trip

mpharrigan avatar Jun 10 '25 18:06 mpharrigan