Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.23k stars 2.36k forks source link

Scheduling; physical circuits check #12419

Closed flowerthrower closed 5 months ago

flowerthrower commented 5 months ago

There is this stringent check on the naming of a quantum register during the scheduling process, leading to a TranspilerError.

MWE:

from qiskit import QuantumCircuit, transpile, QuantumRegister

qreg = QuantumRegister(2, 'node')
qc = QuantumCircuit(qreg)
qc.x(0)

qc = transpile(qc, scheduling_method="asap", basis_gates=['x'], instruction_durations=[('x', [0], 1, 's')])

TranspilerError: 'ASAP schedule runs on physical circuits only'

In our compiler tool, we make use of Qiskit as well as Tket optimization passes. However, Tket internally renames the registers as "node"s.

  1. Is there a way of easily manipulating the qreg name after initialisation (without accessing the private attribute _name)?
  2. Is this key-based check the best way of assessing physical circuits?
jakelishman commented 5 months ago

Mostly for historical reasons, and for lack of a more formal distinction in the type system, Qiskit's current specification of "physical circuit" requires a single quantum register spanning the entire circuit whose name is specifically q. This isn't unique to scheduling; it happens at several points during the transpiler.

We're not meaningfully able to change that within deprecation polices within Qiskit 1.x, though making more formal typing for physical circuits / registers is something we are interested in in general - it's more convenient for both us and users, but the change does risk quite serious disruption to the existing ecosystem.

There's no valid way to change the name of a register after creation; it's part of the hashing of registers, which are assumed to be immutable. The most immediate workaround for you (if there's no way to configure tket to leave the register names be) is likely to be to use the SetLayout and ApplyLayout transpiler passes to rewrite the DAG back in terms of Qiskit's names for physical qubits. Unfortunately, that's likely to disrupt the linking between the initial virtual qubits and the output physical qubits in QuantumCircuit.layout at the end of transpilation, though I suspect if you're already using a combination of tket and Qiskit, you've already lost that link.

As an example of using those two transpiler passes (I'll use an input QuantumCircuit and standalone PassManager to illustrate, but in general you can just insert the passes into your pipeline somewhere):

from qiskit.circuit import QuantumCircuit, QuantumRegister
from qiskit.transpiler import PassManager, Layout
from qiskit.transpiler.passes import SetLayout, ApplyLayout

tket_reg = QuantumRegister(3, "node")
# Or whatever the mapping is:
tket_to_physical = Layout({tket_qubit: i for i, tket_qubit in enumerate(tket_reg)})

# This assumes that the register is full width on the device.  If not,
# you'll want `FullAncillaAllocation` and `EnlargeWithAncilla` too.
pm = PassManager([
    SetLayout(tket_to_physical),
    ApplyLayout(),
])

circuit = QuantumCircuit(tket_reg)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)

physical = pm.run(circuit)
assert physical.qregs == [QuantumRegister(3, "q")]
flowerthrower commented 5 months ago

Thank you, @jakelishman, for your detailed answer; for now, your suggested trick works just fine. It's good to know the Qiskit team has this on their radar. I have also heard about the fantastic work you have been doing for the QuTiP project, and I am happy to see your continued quality work in Qiskit.