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

VF2 Layout : The layout allocation as a subgraph isomorphism problem #6620

Merged
merged 44 commits into from
Nov 2, 2021

Conversation

1ucian0
Copy link
Member

@1ucian0 1ucian0 commented Jun 22, 2021

On hold, depends on Qiskit/rustworkx#368 and Qiskit/rustworkx#375

Exploring alternatives with @czachow on how to improve CSPLayout, we start reading more about subgraph isomorphism problem, in particular VF2. In this way, we noticed that, when VF2 finds an isomorphism a subgraph of G and H, also finds the mapping m that pairs the nodes in H with nodes in G. That mapping is they layout. @mtreinish and @georgios-ts wrote a is_subgraph_isomorphic for retworkx some time ago using VF2 and they just need to expose m. This pass uses m to construct a matching subgraph, like CSPLayout but much faster.

Features

This pass has the following features:

  • Handles direction: because retworkx supports digraph_vf2_mapping and graph_vf2_mapping.
  • Introduces non-determinism by shuffling the coupling map nodes labels. In this way, if there are many isomorphic subgraphs, will get a random one. That can be deactivated with seed=-1.
  • The parameter id_order is passed to the underling *graph_vf2_mapping call. If None activates id_order only if the problem is small (a subgraph to find with less than 300 edges).
  • It works very much like CSPLayout, but faster.

Performance

In order to illustrate the performance advantage, I used timeit in the following example:

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.transpiler import CouplingMap
from qiskit.transpiler.passes import VF2Layout, CSPLayout
from qiskit.converters import circuit_to_dag
from qiskit.test.mock import FakeTenerife
from timeit import timeit

def run_pass(qc, pass_):
    dag = circuit_to_dag(qc)
    return timeit(lambda: pass_.run(dag), number=100)

tenerife_cm = FakeTenerife().configuration().coupling_map

qr = QuantumRegister(3, "qr")
circuit = QuantumCircuit(qr)
circuit.cx(qr[1], qr[0])  # qr1 -> qr0
circuit.cx(qr[0], qr[2])  # qr0 -> qr2
circuit.cx(qr[1], qr[2])  # qr1 -> qr2

print('Tenerife:')
print('VF2Layout:', run_pass(circuit, VF2Layout(CouplingMap(tenerife_cm))))
print('CSPLayout:', run_pass(circuit, CSPLayout(CouplingMap(tenerife_cm), time_limit=None, call_limit=None)))

The result for this small case is noticible:

Tenerife:
VF2Layout: 0.00985708399999985
CSPLayout: 0.015390594999999951

With the example from #5694 (where a trivial layout in Manhattan makes CSP timeout in level 2 and 3), the difference is huge:

import numpy
from qiskit.circuit.library import GraphState
from qiskit.test.mock import FakeManhattan


backend = FakeManhattan()
config = backend.configuration()
manhattan_cm = FakeManhattan().configuration().coupling_map

rows = [x[0] for x in manhattan_cm]
cols = [x[1] for x in manhattan_cm]

A = numpy.zeros((65, 65))
A[rows, cols] = 1

circuit = GraphState(A).decompose()

print('Manhattan:')
print('VF2Layout:', run_pass(circuit, VF2Layout(CouplingMap(manhattan_cm))))
print('CSPLayout:', run_pass(circuit, CSPLayout(CouplingMap(manhattan_cm), time_limit=None, call_limit=None)))
Manhattan:
VF2Layout: 0.16880208799999963
CSPLayout: 60499.96817250001

Things to add

Noise awareness

Since this is so fast, probably would be better to add noise awareness a la #5075. For that, several possible solutions can be found and then calculate the fidelity. This can be done by a fidelity scoring pass (to add later)

@1ucian0 1ucian0 requested a review from a team as a code owner June 22, 2021 11:29
@1ucian0 1ucian0 marked this pull request as draft June 22, 2021 11:29
@1ucian0 1ucian0 added the on hold Can not fix yet label Jun 22, 2021
@mtreinish mtreinish added this to the 0.19 milestone Jun 22, 2021
@mtreinish
Copy link
Member

If you update the retworkx line in the requirements.txt file to:

retworkx @ git+https://github.com/mtreinish/retworkx@vf2-mapping

Then you can run the tests in CI. See: https://github.com/Qiskit/qiskit-terra/pull/6302/files#diff-4d7c51b1efe9043e44439a949dfd92e5827321b34082903477fd04876edb7552 for where I'm doing that on another PR that depends on an in progress retworkx commit.

@mtreinish mtreinish added the Changelog: New Feature Include in the "Added" section of the changelog label Jun 22, 2021
@1ucian0 1ucian0 changed the title VF2 initial commit VF2 Layout : The layout allocation as a subgraph isomorphism problem Jun 22, 2021
@1ucian0 1ucian0 marked this pull request as ready for review June 23, 2021 11:36
@georgios-ts
Copy link
Contributor

Hi @1ucian0, i'm afraid we need to tweak a bit is_subgraph_isomorphic function to find layouts since it currently works for the induced subgraph case. What this means is the following will return False:

import retworkx as rx

ga = rx.PyGraph()
ga.add_nodes_from([0, 1, 2])
ga.add_edges_from_no_data([
    (0, 1), (1, 2), (2, 0)
])

gb = rx.PyGraph()
gb.add_nodes_from([0, 1, 2])
gb.add_edges_from_no_data([
    (0, 1), (1, 2)
])

rx.is_subgraph_isomorphic(ga, gb)
---
False

because the edge (0, 2) does not exist in the second graph.
Sorry for the confusion, i should have document this better in the first place. Good news, it shouldn't be a big change and i will try to push a PR asap

@1ucian0
Copy link
Member Author

1ucian0 commented Jun 24, 2021

Hi @1ucian0, i'm afraid we need to tweak a bit is_subgraph_isomorphic function to find layouts since it currently works for the induced subgraph case.

Adding a layout version of the same situation as a test... Once Qiskit/rustworkx#372 is merged, I can add the related adjustment here. Thanks!

1ucian0 and others added 5 commits October 28, 2021 14:40
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
mtreinish
mtreinish previously approved these changes Oct 29, 2021
Copy link
Member

@mtreinish mtreinish left a comment

Choose a reason for hiding this comment

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

This LGTM now, thanks for the updates. Before merging though I have 1 question inline about the docs and some nits in the tests (nothing blocking there though).

qiskit/transpiler/passes/layout/vf2_layout.py Outdated Show resolved Hide resolved
test/python/transpiler/test_vf2_layout.py Outdated Show resolved Hide resolved
test/python/transpiler/test_vf2_layout.py Outdated Show resolved Hide resolved
test/python/transpiler/test_vf2_layout.py Show resolved Hide resolved
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
@1ucian0
Copy link
Member Author

1ucian0 commented Nov 2, 2021

Per #7155 I'm wondering if we want to mention here that this only takes into account 2q gates.

oh gosh. Indeed. Actually, this unveiled that most of the tests were doing nothing, as they graph gate is >2q. Fixed in b7eb52c .

Nothing layout/routing related works for >2q right now, but when #5885 merges the transpiler can potentially know that it has a 3q basis gate and this pass won't be compatible with that ever (can't represent a >2q link as a graph).

I guess it's a problem for later. For now, the pass only works with 2q. Anything >2q, raises.

Copy link
Member

@mtreinish mtreinish left a comment

Choose a reason for hiding this comment

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

I just realized the docstrings need to be updated here, because the rendered docs would contain no detail on how the pass worked. I left a suggestion inline on how to fix it (hopefuilly I got the spacing right in the github editor). After that's fixed I think this is ready.

qiskit/transpiler/passes/layout/vf2_layout.py Outdated Show resolved Hide resolved
This commit updates the vf2layout docstrings to include details
on how the pass works and the user expectations when using it.
Previously this information was set in the module docstring which
doesn't get rendered in the compiled documentation. This commit
just moves these details to the class docstring and expands on it slightly.
mtreinish
mtreinish previously approved these changes Nov 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants