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

Port collect 2q blocks function from qiskit-terra #265

Closed
mtreinish opened this issue Mar 8, 2021 · 3 comments · Fixed by Qiskit/qiskit#6433 or #361
Closed

Port collect 2q blocks function from qiskit-terra #265

mtreinish opened this issue Mar 8, 2021 · 3 comments · Fixed by Qiskit/qiskit#6433 or #361
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@mtreinish
Copy link
Member

What is the expected enhancement?

In qiskit-terra there is a transpiler pass collect2q blocks which primarily consists of a graph traversal. Doing the actual graph traversal and search will be much faster in retworkx, so we should add a function that can be used in place of terra's python version. The terra function code is:

https://github.com/Qiskit/qiskit-terra/blob/b058856e2aee9c5819120dc9c95f1e2478c95f4e/qiskit/transpiler/passes/optimization/collect_2q_blocks.py#L55-L246

This is similar to collect_runs which already has a native retworkx version:

https://github.com/Qiskit/retworkx/blob/b1f973630cb352950fbdeabd4b4c60191a62a6e7/src/lib.rs#L1121-L1173

and will operate in a similar manner with a filter function argument except it will collect 2q blocks instead of 1q runs.

@mtreinish mtreinish added enhancement New feature or request good first issue Good for newcomers labels Mar 8, 2021
@mtreinish mtreinish changed the title Port collect 2q blocks function form qiskit-terra Port collect 2q blocks function from qiskit-terra Mar 8, 2021
@nahumsa
Copy link
Contributor

nahumsa commented Apr 2, 2021

I'll take a look on this issue.

@IvanIsCoding
Copy link
Collaborator

I'm working on it

@IvanIsCoding
Copy link
Collaborator

IvanIsCoding commented May 12, 2021

Giving an update on this after profiling the code and trying to convert it to Rust.

I am a bit concerned about porting all the Collect2qBlocks.run function to retworkx because it is very specific and it calls Python code very frequently. It won't generalize as collect_runs, because it has multiple conditions for handling cases and most of them mix checking DAG properties and quantum properties. So porting it might make it much harder to maintain the transpiler pass in qiskit-terra and the function in retworkx.

Nevertheless, I still think we can improve the performance by porting some core parts to Rust. Mainly about porting quantum_successors, quantum_predecessors, and some Python code that checks for elements in successors and predecessors.

I profiled the code with:

from random import randint
from qiskit import QuantumRegister, QuantumCircuit
from qiskit.dagcircuit import DAGCircuit
from qiskit.converters import circuit_to_dag
from qiskit.transpiler.passes.optimization import Collect2qBlocks

q = QuantumRegister(1000, 'q')
qc = QuantumCircuit(q)
for i in range(100000):
    a = randint(0, 999)
    b = randint(0, 999)
    if a == b:
        qc.h(a)
    else:
        if i % 2 == 0:
            qc.cz(a, b)
        else:
            qc.cx(a, b)

dag = circuit_to_dag(qc)

c2q = Collect2qBlocks()

for i in range(100):
	c2q.run(dag)

The results showed we spend around 10% of the computing time in quantum_predecessors, 7% of the time in quantum_successors, 7% in successors and 6% in predecessors.

I think the culprits are this and this check in predecessors/successors.

To address them, instead of rewriting the whole function I think we can:

  • add a filtered_sucessors/filtered_predecessors function in PyDiGraph to avoid having to convert all nodes into Python to then run a filter function
  • add a is_predecessors/is_sucessor function in PyDiGraph to avoid having to convert all nodes into Python to do a simple check

I will make a Draft PR with the additions and rewrite the function in qiskit-terra using those new functions. Hopefully that helps boost speed and make the code remain maintainable.

mtreinish added a commit that referenced this issue May 21, 2021
Related to #265

This PR adds two new functions to PyDiGraph: find_sucessors_by_edge and
find_predecessors_by_edge. These functions can be useful for speeding up routines that
want a subset of successors/predecessors that match a filter function.

With these new functions, it is possible to find the successors/predecessors of an node that
match a filter in O(e'), where e' is the number of edges connected to the node. Before, the
simplest way to achieve the same behavior was to get all edges for each successor/predecessor
and then filter, which was O(d * e'), where d is the number of distinct neighbors a node has.

These new functions will be immediately applicable to the quantum_successors and
quantum_predecessors methods in qiskit-terra's DAGCircuit class. They will consequently provide a
speed up to collect 2q blocks, which has quantum_successors and quantum_predecessors as its
most expensive steps during graph traversal.

* Add filtered_successors/filtered_predecessors

* Add release note

* Rename new functions for consistency

* Add test cases for new functions

* Release note updates from code review

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
mtreinish added a commit that referenced this issue Aug 4, 2021
This ports collect-2q-blocks to Rust. Is ports the rewritten version from
Qiskit/qiskit#6534 which is much simpler to maintain in Retworkx.

There's a 1.25x speed up for collect-2q-blocks  when using
collect_bicolor_runs

Closes #265

* Add collect_bicolor_runs

* Update src/lib.rs

Co-authored-by: georgios-ts <45130028+georgios-ts@users.noreply.github.com>

* Simplify block_list appends

* Call filter_fn only once

* Add test_collect_bicolor_runs

* Fix black

* Shorten ascii art to fix flake8 error

* Add more tests

* Add docstring

* Fix cargo fmt

* Remove grouping of single color chains

* Simplify code

* Use None instead of -1 to filter edges

* Update docstring

* Fix cargo fmt

* Use more accurate test cases

* Add new test case

* Use new PyO3 text signature

* Allocate with capacity

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

* Cargo fmt

Co-authored-by: georgios-ts <45130028+georgios-ts@users.noreply.github.com>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
3 participants