Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CalibrationBuilder scales superlinearly #7178

Closed
ewinston opened this issue Oct 25, 2021 · 3 comments · Fixed by #7187
Closed

CalibrationBuilder scales superlinearly #7178

ewinston opened this issue Oct 25, 2021 · 3 comments · Fixed by #7187
Assignees
Labels
type: enhancement It's working, but needs polishing
Milestone

Comments

@ewinston
Copy link
Contributor

ewinston commented Oct 25, 2021

What is the expected enhancement?

For a random circuit of equal width and depth the CalibrationBuilder pass scales like n_qubits^3 whereas one might expect scaling like n_qubits^2 if it was proportional to the number of gates. This slow down seems to be in retrieving the qubits associated with a dag node.

This test was run without actual calibrations so only part of the pass code is actually profiled.

image

image

This is qiskit-terra version 0.19.0.dev0+637acc0.

@ewinston ewinston added the type: enhancement It's working, but needs polishing label Oct 25, 2021
@jakelishman
Copy link
Member

The obvious culprit I assume are these lines:

        for node in dag.gate_nodes():
            qubits = list(dag.qubits.index(q) for q in node.qargs)

That looks pretty cubic to me - "for op in circuit: for qubit in op: for bit in dag: if qubit == bit: ...". I don't know off the top of my head if DAGCircuit gained the benefits of #6621 - I assume probably not, because keeping it updated would be a bit gross. The simplest solution is probably just to do a little bit of

qubit_map = {q: i for i, q in enumerate(dag.qubits)}
for node in dag.gate_nodes():
    qubits = [qubit_map[q] for q in node.qargs]

in the transpiler pass manually, which should drop it back down to quadratic complexity.

There's also an easy win in Bit.__eq__:

def __eq__(self, other):
    if (self._register, self._index) == (None, None):
        return self is other
    # ... else handle old-style bits ...

The if check is a bit inefficient here: if self._register is None and self._index is None should be faster, because it avoids creation of temporary tuples, and avoids a call to Register.__eq__.

@jakelishman jakelishman self-assigned this Oct 26, 2021
@mtreinish
Copy link
Member

Yeah, it was a follow up for #6621 to add an equivalent method for DAGCircuit #6621 (comment) just adding the dict comprehension to get the indices is the best way to do this. That's what we've been doing in other transpiler passes while we wait for an equivalent to #6621 for DAGCircuit.

@jakelishman
Copy link
Member

The change to the pass is in #7187. I changed my mind about the Bit speedups - in theory, the only times that _register won't be None (and hence not even have an __eq__ should) be rare, since it's deprecated behaviour, so it shouldn't matter. I'll look again tomorrow to see if it actually does or not.

@mergify mergify bot closed this as completed in #7187 Oct 26, 2021
@kdk kdk added this to the 0.19 milestone Nov 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement It's working, but needs polishing
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants