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

Use retworkx for CouplingMap #5183

Merged
merged 46 commits into from
Dec 4, 2020
Merged

Use retworkx for CouplingMap #5183

merged 46 commits into from
Dec 4, 2020

Conversation

This commit migrates Terra's CouplingMap class to us retworkx internally
instead of networkx providing >10x speed improvement for CouplingMap
operations.

Requires:

Qiskit/rustworkx#157
Qiskit/rustworkx#156
Qiskit/rustworkx#144
Qiskit/rustworkx#143
Qiskit/rustworkx#147
Qiskit/rustworkx#158
Qiskit/rustworkx#162
Qiskit/rustworkx#161

all be applied to the retworkx version installed.
@mtreinish mtreinish changed the title WIP: Use retworkx for CouplingMap Use retworkx for CouplingMap Oct 19, 2020
@mtreinish mtreinish removed the on hold Can not fix yet label Nov 12, 2020
@mtreinish
Copy link
Member Author

Ok, retworkx 0.6.0 was released this morning, so this should be good to merge now.

Copy link
Contributor

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor comments, but LGTM otherwise 👍

Comment on lines +113 to +114
graph.add_edges_from_no_data(
[(i, i + 1) for i in range(len(graph) - 1)])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference to extend_from_edge_list?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extend_from_edge_list() will add nodes to the graph if there is a node index in the edge tuple that doesn't exist. While add_edges_from_no_data() will error if there is an index in the edge tuple that doesn't exist.

https://retworkx.readthedocs.io/en/stable/stubs/retworkx.PyGraph.extend_from_edge_list.html#retworkx.PyGraph.extend_from_edge_list

Copy link
Contributor

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mtreinish
Copy link
Member Author

retworkx 0.7.0 was released this morning (and 0.7.1 a few minutes ago to fix an issue this PR uncovered with it around pickling) and added generator functions that can be used for CouplingMap.from_full() and CouplingMap.from_grid() which should significantly improve the performance of those constructors. I'll push a follow up to make that change after this merges.

@kdk kdk added this to To do in Transpiler via automation Dec 3, 2020
@mergify mergify bot merged commit d12e9c9 into Qiskit:master Dec 4, 2020
Transpiler automation moved this from To do to done Dec 4, 2020
@mtreinish mtreinish deleted the test-rx branch December 4, 2020 10:22
mtreinish added a commit to mtreinish/qiskit-core that referenced this pull request Dec 4, 2020
In Qiskit#5183 we switched the internal graph datastructures used for the
CouplingMap to be based on retworkx instead of networkx. That PR was
written against the 0.6.0 retworkx release and for the from_grid()
and from_full() constructors python had to be used since retworkx
was missing functions to generate graphs of those types. However, in the
recent 0.7.x retworkx release 2 new generators directed_grid_graph() [1]
and directed_mesh_graph() [2] were added. This commit switches the
implementation of from_grid() and from_full() to use these generators,
which significantly speeds up (and reduces the memory overhead) of the
constructor methods.

The only constructor which still relies on a Python loop is the
from_full() method when bidirection=False. This is because retworkx
doesn't offer a constructor that will build a graph like that. If in
a future release a generator is added we can remove that for loop too.

[1] https://retworkx.readthedocs.io/en/stable/stubs/retworkx.generators.directed_grid_graph.html
[2] https://retworkx.readthedocs.io/en/stable/stubs/retworkx.generators.directed_mesh_graph.html
mergify bot added a commit that referenced this pull request Dec 4, 2020
In #5183 we switched the internal graph datastructures used for the
CouplingMap to be based on retworkx instead of networkx. That PR was
written against the 0.6.0 retworkx release and for the from_grid()
and from_full() constructors python had to be used since retworkx
was missing functions to generate graphs of those types. However, in the
recent 0.7.x retworkx release 2 new generators directed_grid_graph() [1]
and directed_mesh_graph() [2] were added. This commit switches the
implementation of from_grid() and from_full() to use these generators,
which significantly speeds up (and reduces the memory overhead) of the
constructor methods.

The only constructor which still relies on a Python loop is the
from_full() method when bidirection=False. This is because retworkx
doesn't offer a constructor that will build a graph like that. If in
a future release a generator is added we can remove that for loop too.

[1] https://retworkx.readthedocs.io/en/stable/stubs/retworkx.generators.directed_grid_graph.html
[2] https://retworkx.readthedocs.io/en/stable/stubs/retworkx.generators.directed_mesh_graph.html

Co-authored-by: Luciano Bello <luciano.bello@ibm.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
mtreinish added a commit to mtreinish/qiskit-ignis that referenced this pull request Dec 7, 2020
The topological_code fitters module relies on networkx and has had a
hard dependency on it since it was first introduced in qiskit-community#211. However, it
was never added to the requirements list. This was never caught because
historically qiskit-terra (which is in the requirements list) has
required networkx too so installing qiskit-terra would install networkx.
But, in Qiskit/qiskit#5183 the dependency on networkx was removed
from terra. This commit corrects the issue so that we're properly
listing networkx as an ignis requirement moving forward. Longer term we
should migrate the topological codes fitter to use retworkx for better
performance and consistency with the rest of Qiskit. However, before we
can do that Qiskit/rustworkx#216 must be fixed first.
mtreinish added a commit to qiskit-community/qiskit-ignis that referenced this pull request Dec 7, 2020
The topological_code fitters module relies on networkx and has had a
hard dependency on it since it was first introduced in #211. However, it
was never added to the requirements list. This was never caught because
historically qiskit-terra (which is in the requirements list) has
required networkx too so installing qiskit-terra would install networkx.
But, in Qiskit/qiskit#5183 the dependency on networkx was removed
from terra. This commit corrects the issue so that we're properly
listing networkx as an ignis requirement moving forward. Longer term we
should migrate the topological codes fitter to use retworkx for better
performance and consistency with the rest of Qiskit. However, before we
can do that Qiskit/rustworkx#216 must be fixed first.
mtreinish added a commit to mtreinish/qiskit-core that referenced this pull request Dec 11, 2020
In Qiskit#5183 the inner graph object of the CouplingMap object was switched
to retworkx. While generally faster there are a few different edge cases
where retworkx performance can be worse than networkx. Namely, any place
where large lists are returned, for example lists of all nodes or edges
in a graph. In those cases the conversion from the Rust objects to the
Python objects can culmulatively be expensive. To avoid this conversion
overhead in every case retworkx has custom return types that are python
sequences but defer type conversion to __getitem__, meaning that the
return is fast but complete traversal can be slow, epsecially when done
multiple times. In such cases it's easier to cast the sequence to a
Python object such as a set or a list so the conversion is only done
once. However, in the CSPLayout pass the edges list returned from
retworkx was searched multiple times as part of the constraint function
which resulted in a large performance regression. This commit fixes this
by casting the local edges to a set(). This has 2 advantages, first it
avoids the multiple traversals of the graph which removes the conversion
overhead. The second advantage is that by using a set the lookups are
constant time instead of iterating over the full list every time. This
results in a performance improvement over the performance prior to Qiskit#5183
and the introduction of the regression.
kdk pushed a commit that referenced this pull request Dec 11, 2020
In #5183 the inner graph object of the CouplingMap object was switched
to retworkx. While generally faster there are a few different edge cases
where retworkx performance can be worse than networkx. Namely, any place
where large lists are returned, for example lists of all nodes or edges
in a graph. In those cases the conversion from the Rust objects to the
Python objects can culmulatively be expensive. To avoid this conversion
overhead in every case retworkx has custom return types that are python
sequences but defer type conversion to __getitem__, meaning that the
return is fast but complete traversal can be slow, epsecially when done
multiple times. In such cases it's easier to cast the sequence to a
Python object such as a set or a list so the conversion is only done
once. However, in the CSPLayout pass the edges list returned from
retworkx was searched multiple times as part of the constraint function
which resulted in a large performance regression. This commit fixes this
by casting the local edges to a set(). This has 2 advantages, first it
avoids the multiple traversals of the graph which removes the conversion
overhead. The second advantage is that by using a set the lookups are
constant time instead of iterating over the full list every time. This
results in a performance improvement over the performance prior to #5183
and the introduction of the regression.
mtreinish added a commit to mtreinish/qiskit-ignis that referenced this pull request Feb 5, 2021
The topological_code fitters module relies on networkx and has had a
hard dependency on it since it was first introduced in qiskit-community#211. However, it
was never added to the requirements list. This was never caught because
historically qiskit-terra (which is in the requirements list) has
required networkx too so installing qiskit-terra would install networkx.
But, in Qiskit/qiskit#5183 the dependency on networkx was removed
from terra. This commit corrects the issue so that we're properly
listing networkx as an ignis requirement moving forward. Longer term we
should migrate the topological codes fitter to use retworkx for better
performance and consistency with the rest of Qiskit. However, before we
can do that Qiskit/rustworkx#216 must be fixed first.

(cherry picked from commit 2775689)
@kdk kdk added the Changelog: None Do not include in changelog label Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: None Do not include in changelog performance
Projects
Transpiler
  
done
Development

Successfully merging this pull request may close these issues.

None yet

3 participants