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

General routing #3762

Merged
merged 30 commits into from
Feb 24, 2020
Merged

General routing #3762

merged 30 commits into from
Feb 24, 2020

Conversation

eddieschoute
Copy link
Contributor

Summary

From #2860 the question arose if I could submit a PR for the Token Swapping algorithm separately and this pull request does that.
The algorithm allows for a partial permutation to be implemented through a Swap circuit that attempts to minimize circuit size.

Details and comments

This implements the Token Swapping approximation algorithm
@ajavadia
Copy link
Member

There is a qiskit.transpiler.passes.routing directory now so it would be better if this was there rather than in the transpiler namespace.

This pass just calls the ApproximateTokenSwapper code to compute which
swaps needs to be performed and appends that to the circuit.
@eddieschoute
Copy link
Contributor Author

@ajavadia Do you want to algorithm (currently in transpiler.routing.general.py) also in the passes directory? I put the Pass in the top-level of the pass directory as you had suggested since routing seems to have a different definition within the Qiskit project, i.e., it means to map and route a whole circuit.

I implemented the code as a pass as well but I haven't tested it yet.

@ajavadia
Copy link
Member

what about creating a directory for transpiler.algorithms? It just seems transpiler.routing and transpiler.passes.routing might lead to confusion. @kdk @1ucian0 thoughts?

@1ucian0
Copy link
Member

1ucian0 commented Jan 29, 2020

what about creating a directory for transpiler.algorithms? It just seems transpiler.routing and transpiler.passes.routing might lead to confusion.

For me it is clear that everything in transpiler.passes is a pass and can be used in a pass manager and everything out cannot. So, in principle, I don't see the problem.

However, if this pass is the only one using these algorithms, why not having them together?

@eddieschoute
Copy link
Contributor Author

I think the issue is that the functionality is useful outside of a pass as well. Therefore it may be odd to put it inside a pass only. I leave it up to you where to put it :)

@1ucian0
Copy link
Member

1ucian0 commented Jan 29, 2020

It is useful for transpiler or in general?

@ajavadia
Copy link
Member

It is useful for transpiler or in general?

It's useful in multiple transpiler passes.

I leave it up to you where to put it :)

It doesn't matter that much honestly. Just leave it as is.

Copy link
Member

@ajavadia ajavadia left a comment

Choose a reason for hiding this comment

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

I tried running the pass. I think the DAGCircuit.extend_back() method is buggy, which is preventing the pass from working at the moment. Is this what you find too?

It has this line which just seems wrong as it adds an entry with always the same key/value.

edge_map.update([(qbit, qbit) for qbit in qreg if qbit not in edge_map])

qiskit/transpiler/passes/layout_transform.py Outdated Show resolved Hide resolved
qiskit/transpiler/passes/layout_transform.py Outdated Show resolved Hide resolved
qiskit/transpiler/passes/layout_transform.py Outdated Show resolved Hide resolved
Copy link
Contributor

@itoko itoko left a comment

Choose a reason for hiding this comment

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

Thank you for preparing this PR, @eddieschoute !

I think from_layout/to_layout (or start_layout/goal_layout?) is less confusing than initial_layout/final_layout that they are reserved as layout at the beginning/end of the circuit.
Since LayoutTransformation pass appends swaps at the end of circuit, the starting layout is often the "final_layout". To avoid confusion, I recommend to use the other terms.

I also think "from_layout" and "to_layout" can be taken in run time i.e. within run() so that this pass can cooperate with the other passes. In many cases, the "from_layout" (in this pass, the layout at the end of the circuit) is given after running a routing pass. I think we should be able to get the "from_layout" (or "to_layout") from property_set in run(). (I know this is impossible for now.)

To this make possible, I think all of the routing passes should set property_set["final_layout"]. It would be useful for other passes (I have one concrete example in my mind). Thoughts? @ajavadia , @1ucian0 , @kdk

(+1 to create a directory for transpiler.algorithms)

Co-Authored-By: Ali Javadi-Abhari <[email protected]>
@eddieschoute
Copy link
Contributor Author

While you work on #3769, is there an alternative way of adding the Swaps to the end of the DAG?

I think from_layout and to_layout sound good. I would've preferred to put them as arguments in the run() but that wasn't feasible.

Copy link
Member

@ajavadia ajavadia left a comment

Choose a reason for hiding this comment

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

I tested this on top of PR #3772 and it seems to work (Suggested a couple more bug fixes inline)

qiskit/transpiler/passes/layout_transform.py Outdated Show resolved Hide resolved
qiskit/transpiler/passes/layout_transform.py Outdated Show resolved Hide resolved
@itoko
Copy link
Contributor

itoko commented Jan 31, 2020

While I work on #1803, I've used apply_operation_back to append swap gates (on physical qubits) to the end of the dag.

new_dag.apply_operation_back(SwapGate(), [pqubit_a, pqubit_b])

How about to use it?
It works well for routing passes that return circuits with physical qubits. I think it should work for the LayoutTransformation pass as well.
(You've already use it within util.circuit())

Sorry, I confused. Is input/output dagcircuit of the LayoutTransformation pass virtual or physical? Both are virtual? Agnostic?

Excuse me for my unclear message, I meant something like

def __init__(self, coupling_map, from_layout: Union(str, Layout), to_layout):
    self.from_layout = from_layout
    ...

def run(dag):
    from_layout = self.from_layout
    if isinstance(from_layout, str)
        from_layout = self.propertye_set[from_layout]
    ...

(Because it's not allowed to take any arguments other than dag in run().)

@eddieschoute
Copy link
Contributor Author

I'm not quite sure what you mean but I think the situation that makes most sense is when you have a DagCircuit that somehow respects the physical constraints and you wish to move the virtual qubits to different physical qubits (the to_layout) than what they were before (the from_layout).

They were only used in comments
@eddieschoute
Copy link
Contributor Author

I'm running into this linter error

test/randomized/test_transpiler_equivalence.py:1:0: R0401: Cyclic import (qiskit -> qiskit.execute -> qiskit.compiler.transpile -> qiskit.transpiler.transpile_circuit -> qiskit.transpiler.preset_passmanagers -> qiskit.transpiler.preset_passmanagers.level2 -> qiskit.transpiler.passes -> qiskit.transpiler.passes.routing -> qiskit.transpiler.passes.routing.layout_transformation -> qiskit.transpiler.routing.util) (cyclic-import)

but I don't see how that is cyclic. I only import types from the same module (through the init). Any suggestions?

Co-Authored-By: Kevin Krsulich <[email protected]>
@eddieschoute
Copy link
Contributor Author

Running into a cyclic import again it seems...

@ajavadia ajavadia mentioned this pull request Feb 11, 2020
@itoko
Copy link
Contributor

itoko commented Feb 12, 2020

@eddieschoute I succeeded to reproduce cyclic import in my environment and found a workaround, it can be resolved by moving transpiler/routing directory to transpiler/passes/routing/algorithms. I know we need further discussion on the right place for algorithms used in more than routing.
I have several ideas to improve APIs around LayoutTransformation pass.
For example, I'd like to put all the files in the transpiler/routing into one file and name it token_swapper.py at the point of this PR.
If you don't mind, I'd like to apply those tweaks directly to your branch. (If you don't like them, you can revert them.) Are you OK with it?

@eddieschoute
Copy link
Contributor Author

That's fine with me. The util functions I factored out of my previous PR #2860 but within this PR do not serve a purpose that is shared across multiple files. Just note that it is in #2860 so would likely need to be factored back out for that PR. So I'm not sure it's worth combining them into one file now.

@itoko
Copy link
Contributor

itoko commented Feb 12, 2020

OK. Regarding file changes, I had second thought, to make my tweak minimal, I'll leave the two files types.py and util.py as separated files. I'll apply other tweaks to your branch.

@itoko
Copy link
Contributor

itoko commented Feb 13, 2020

@eddieschoute I've done with my API tweaks. Can you check if they make sense to you?

@eddieschoute
Copy link
Contributor Author

I think they make sense. One nitpick I have is that we call the file token_swapper. I think for anyone outside the project they would not know what it does without reading the docs. It's why I chose the routing folder structure. Should we choose to rename the class to GeneralRouting or something similar instead?

@itoko
Copy link
Contributor

itoko commented Feb 19, 2020

Good. It's better to make the names more user-friendly. I don't stick the name token_swapper.
GeneralRouting might be too general. I prefer including the term "permutation/permuter" (GraphNodePermuter or something like that), or "partial routing" if you want to use the term "routing". The term routing usually means complete mapping onto physical circuit while the token swapping algorithm does permutation of nodes (= physical qubits) on coupling graph (i.e. partial mapping that changes layout, not always complete mapping of whole circuit).

Copy link
Member

@ajavadia ajavadia left a comment

Choose a reason for hiding this comment

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

Looks good. Please remove the WIP if it is ready.

@eddieschoute eddieschoute changed the title [WIP] General routing General routing Feb 19, 2020
Co-Authored-By: Ali Javadi-Abhari <[email protected]>
Copy link
Member

@ajavadia ajavadia left a comment

Choose a reason for hiding this comment

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

Ok thanks I think this is good to go

@mergify mergify bot merged commit 346f8d4 into Qiskit:master Feb 24, 2020
faisaldebouni pushed a commit to faisaldebouni/qiskit-terra that referenced this pull request Aug 5, 2020
* Add files for implementing general routing

This implements the Token Swapping approximation algorithm

* Implement LayoutTransform pass

This pass just calls the ApproximateTokenSwapper code to compute which
swaps needs to be performed and appends that to the circuit.

* Restructure case+break (lint)

* Change indentation (lint)

* Fix some bugs suggested by Ali

Co-Authored-By: Ali Javadi-Abhari <[email protected]>

* Bugfixes in the LayoutTransformation pass

Co-Authored-By: Ali Javadi-Abhari <[email protected]>

* Moving LayoutTransformation to passes folder

Also add init imports

* Removed unused imports

They were only used in comments

* Resolve circular import (lint)

Co-Authored-By: Kevin Krsulich <[email protected]>

* Use relative import

Co-Authored-By: Kevin Krsulich <[email protected]>

* Fix references to Swap with relative import

* Add seed to ApproximateTokenSwapper and its pass

* Fix bug assuming dag.qubits() order is given

Added basic test for pass
Some types added

* Reformat imports for test

* Keep things DRY ;)

* Add doc for test

* move directory to avoid cyclic import

* rename general.py to token_swapper.py

* decrease graph size to make the test faster

* expose PermutationCircuit

* rename to from/to_layout

* remove unused function

* allow string layouts

* allow string layouts

* fix test

* lint

* Doc grammar

Co-Authored-By: Ali Javadi-Abhari <[email protected]>

Co-authored-by: Ali Javadi-Abhari <[email protected]>
Co-authored-by: Kevin Krsulich <[email protected]>
Co-authored-by: itoko <[email protected]>
Co-authored-by: Matthew Treinish <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants