Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7357cab
deprecated edge_map
1ucian0 Oct 23, 2020
2b35509
extending all the level
1ucian0 Oct 23, 2020
a591347
LayoutTransformation with coupling_map none
1ucian0 Oct 23, 2020
8679afa
deprecated dag.compose(..., edge_map=...)
1ucian0 Oct 23, 2020
eb235b1
Merge branch 'LayoutTransformation_cp_none' into 4911
1ucian0 Oct 23, 2020
205e924
Merge branch 'master' into LayoutTransformation_cp_none
1ucian0 Oct 23, 2020
d21412e
Merge branch 'master' into 4911
1ucian0 Oct 23, 2020
9445834
lint
1ucian0 Oct 23, 2020
82924fb
Merge branch 'LayoutTransformation_cp_none' into 4911
1ucian0 Oct 23, 2020
ae285ae
Merge branch '4911' of github.com:1ucian0/qiskit-terra into 4911
1ucian0 Oct 23, 2020
ac40ed7
Merge branch 'master' into 4911
1ucian0 Oct 28, 2020
30cba9d
Merge branch 'master' of github.com:Qiskit/qiskit-terra into 4911
1ucian0 Nov 2, 2020
8c75388
inital and trivial
1ucian0 Nov 3, 2020
a27b25b
no else
1ucian0 Nov 7, 2020
5618149
None instead of TRIVIAL
1ucian0 Nov 7, 2020
e0af3ab
conflict
1ucian0 Feb 10, 2021
0047bc6
Merge branch 'master' of github.com:Qiskit/qiskit-terra into 4911
1ucian0 Feb 16, 2021
c1d5872
Merge branch 'master' of github.com:Qiskit/qiskit-terra into 4911
1ucian0 Feb 22, 2021
3e4269f
remove param
1ucian0 Feb 22, 2021
67bf946
ApplyLayoutSwap
1ucian0 Feb 22, 2021
2f601d1
restore at the end
1ucian0 Feb 23, 2021
0b58ba6
apply layout swap and layout transformation
1ucian0 Feb 23, 2021
aaa9208
revert other levels
1ucian0 Feb 23, 2021
68cfe1d
docstring
1ucian0 Feb 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
SabreLayout
CSPLayout
ApplyLayout
ApplyLayoutSwap
Layout2qDistance
EnlargeWithAncilla
FullAncillaAllocation
Expand Down Expand Up @@ -130,6 +131,7 @@
from .layout import SabreLayout
from .layout import CSPLayout
from .layout import ApplyLayout
from .layout import ApplyLayoutSwaps
from .layout import Layout2qDistance
from .layout import EnlargeWithAncilla
from .layout import FullAncillaAllocation
Expand Down
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/layout/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .sabre_layout import SabreLayout
from .csp_layout import CSPLayout
from .apply_layout import ApplyLayout
from .apply_layout_swap import ApplyLayoutSwaps
from .layout_2q_distance import Layout2qDistance
from .enlarge_with_ancilla import EnlargeWithAncilla
from .full_ancilla_allocation import FullAncillaAllocation
2 changes: 1 addition & 1 deletion qiskit/transpiler/passes/layout/apply_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def run(self, dag):
Raises:
TranspilerError: if no layout is found in `property_set` or no full physical qubits.
"""
layout = self.property_set["layout"]
layout = self.property_set["layout_out"] = self.property_set["layout"]
if not layout:
raise TranspilerError(
"No 'layout' is found in property_set. Please run a Layout pass in advance.")
Expand Down
89 changes: 89 additions & 0 deletions qiskit/transpiler/passes/layout/apply_layout_swap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""TODO"""
from typing import Union

import numpy as np

from qiskit.transpiler import Layout, CouplingMap

from qiskit.circuit import QuantumRegister
from qiskit.dagcircuit import DAGCircuit
from qiskit.transpiler.basepasses import TransformationPass
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.transpiler.passes.routing.layout_transformation import LayoutTransformation
from qiskit.transpiler.passes.routing.algorithms import ApproximateTokenSwapper


class ApplyLayoutSwaps(TransformationPass):
"""TODO"""
def __init__(self, coupling_map: CouplingMap,
seed: Union[int, np.random.default_rng] = None,
trials: int = 4):
super().__init__()
self.coupling_map = coupling_map
self.seed = seed
self.trials = trials

def run(self, dag):
"""Run the ApplyLayout pass on `dag`.

Args:
dag (DAGCircuit): DAG to map.

Returns:
DAGCircuit: A mapped DAG (with physical qubits).

Raises:
TranspilerError: if no layout is found in `property_set` or no full physical qubits.
"""
layout = self.property_set["layout"]
if not layout:
raise TranspilerError(
"No 'layout' is found in property_set. Please run a Layout pass in advance.")
if len(layout) != (1 + max(layout.get_physical_bits())):
raise TranspilerError(
"The 'layout' must be full (with ancilla).")

if self.coupling_map:
graph = self.coupling_map.graph.to_undirected()
else:
coupling_map = CouplingMap.from_full(len(layout))
graph = coupling_map.graph

token_swapper = ApproximateTokenSwapper(graph, self.seed)

q = QuantumRegister(len(layout), 'q')

new_dag = DAGCircuit()
new_dag.add_qreg(q)
new_dag.metadata = dag.metadata
new_dag._global_phase = dag._global_phase
for creg in dag.cregs.values():
new_dag.add_creg(creg)

trivial_layout = Layout.generate_trivial_layout(*dag.qregs.values())
# Find the permutation from trivial layout to property_set['layout'].
permutation = {pqubit: layout.get_virtual_bits()[vqubit]
for vqubit, pqubit in trivial_layout.get_virtual_bits().items()}
perm_circ = token_swapper.permutation_circuit(permutation, self.trials)

qubits = [dag.qubits[i[0]] for i in sorted(perm_circ.inputmap.items(), key=lambda x: x[0])]
new_dag.compose(perm_circ.circuit, qubits=qubits)

for node in dag.topological_op_nodes():
if node.type == 'op':
qargs = [q[layout[qarg]] for qarg in node.qargs]
new_dag.apply_operation_back(node.op, qargs, node.cargs)

return new_dag
4 changes: 2 additions & 2 deletions qiskit/transpiler/passes/routing/basic_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ def run(self, dag):
raise TranspilerError('The layout does not match the amount of qubits in the DAG')

canonical_register = dag.qregs['q']
trivial_layout = Layout.generate_trivial_layout(canonical_register)
current_layout = trivial_layout.copy()
current_layout = Layout.generate_trivial_layout(canonical_register)

for layer in dag.serial_layers():
subdag = layer['graph']
Expand Down Expand Up @@ -95,5 +94,6 @@ def run(self, dag):

order = current_layout.reorder_bits(new_dag.qubits)
new_dag.compose(subdag, qubits=order)
self.property_set['layout_out'] = current_layout

return new_dag
35 changes: 22 additions & 13 deletions qiskit/transpiler/passes/routing/layout_transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class LayoutTransformation(TransformationPass):

def __init__(self, coupling_map: CouplingMap,
from_layout: Union[Layout, str],
to_layout: Union[Layout, str],
to_layout: Union[Layout, str] = None,
seed: Union[int, np.random.default_rng] = None,
trials=4):
trials: int = 4):
"""LayoutTransformation initializer.

Args:
Expand All @@ -42,10 +42,12 @@ def __init__(self, coupling_map: CouplingMap,
from_layout (Union[Layout, str]):
The starting layout of qubits onto physical qubits.
If the type is str, look up `property_set` when this pass runs.
If None, it will map to the trivial layout.

to_layout (Union[Layout, str]):
The final layout of qubits on physical qubits.
If the type is str, look up `property_set` when this pass runs.
if None, use trivial.

seed (Union[int, np.random.default_rng]):
Seed to use for random trials.
Expand All @@ -61,7 +63,7 @@ def __init__(self, coupling_map: CouplingMap,
graph = coupling_map.graph.to_undirected()
else:
self.coupling_map = CouplingMap.from_full(len(to_layout))
graph = self.coupling_map.graph.to_undirected()
graph = self.coupling_map.graph
self.token_swapper = ApproximateTokenSwapper(graph, seed)
self.trials = trials

Expand All @@ -86,24 +88,31 @@ def run(self, dag):

from_layout = self.from_layout
if isinstance(from_layout, str):
try:
from_layout = self.property_set[from_layout]
except Exception:
raise TranspilerError('No {} (from_layout) in property_set.'.format(from_layout))
if self.property_set[from_layout] is None:
raise TranspilerError('No property_set["{}"] (from_layout).'.format(from_layout))
from_layout = self.property_set[from_layout]

to_layout = self.to_layout
if isinstance(to_layout, str):
try:
to_layout = self.property_set[to_layout]
except Exception:

if to_layout is None:
to_layout = Layout.generate_trivial_layout(*dag.qregs.values())
elif isinstance(to_layout, str):
to_layout = self.property_set[to_layout]
if to_layout is None:
raise TranspilerError('No {} (to_layout) in property_set.'.format(to_layout))
else:
raise TranspilerError('to_layout parameter should be a Layout, a string, or None.')

# Find the permutation between the initial physical qubits and final physical qubits.
permutation = {pqubit: to_layout.get_virtual_bits()[vqubit]
for vqubit, pqubit in from_layout.get_virtual_bits().items()}
permutation = {pqubit: self.property_set['layout'][vqubit] for vqubit, pqubit in
from_layout.get_virtual_bits().items()}

perm_circ = self.token_swapper.permutation_circuit(permutation, self.trials)

qubits = [dag.qubits[i[0]] for i in sorted(perm_circ.inputmap.items(), key=lambda x: x[0])]
dag.compose(perm_circ.circuit, qubits=qubits)

# Reset the layout to trivial
self.property_set["layout"] = Layout.generate_trivial_layout(*dag.qregs.values())

return dag
5 changes: 4 additions & 1 deletion qiskit/transpiler/passmanager_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def __init__(self,
scheduling_method=None,
instruction_durations=None,
backend_properties=None,
seed_transpiler=None):
seed_transpiler=None,
restore_layout=None):
"""Initialize a PassManagerConfig object

Args:
Expand All @@ -50,6 +51,7 @@ def __init__(self,
qubit coherence times, etc.
seed_transpiler (int): Sets random seed for the stochastic parts of
the transpiler.
restore_layout (str): `trivial`, `initial`, or None
"""
self.initial_layout = initial_layout
self.basis_gates = basis_gates
Expand All @@ -61,3 +63,4 @@ def __init__(self,
self.instruction_durations = instruction_durations
self.backend_properties = backend_properties
self.seed_transpiler = seed_transpiler
self.restore_layout = restore_layout
11 changes: 9 additions & 2 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@
from qiskit.transpiler.passes import LookaheadSwap
from qiskit.transpiler.passes import StochasticSwap
from qiskit.transpiler.passes import SabreSwap
from qiskit.transpiler.passes import LayoutTransformation
from qiskit.transpiler.passes import FullAncillaAllocation
from qiskit.transpiler.passes import EnlargeWithAncilla
from qiskit.transpiler.passes import FixedPoint
from qiskit.transpiler.passes import Depth
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
from qiskit.transpiler.passes import ApplyLayout
from qiskit.transpiler.passes import ApplyLayoutSwaps
from qiskit.transpiler.passes import CheckCXDirection
from qiskit.transpiler.passes import Layout2qDistance
from qiskit.transpiler.passes import Collect2qBlocks
Expand Down Expand Up @@ -90,6 +91,7 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
instruction_durations = pass_manager_config.instruction_durations
seed_transpiler = pass_manager_config.seed_transpiler
backend_properties = pass_manager_config.backend_properties
restore_layout = pass_manager_config.restore_layout

# 1. Use trivial layout if no layout given
_given_layout = SetLayout(initial_layout)
Expand Down Expand Up @@ -118,7 +120,7 @@ def _not_perfect_yet(property_set):
property_set['trivial_layout_score'] != 0

# 3. Extend dag/layout with ancillas using the full coupling map
_embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()]
_embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla()]

# 4. Decompose so only 1-qubit and 2-qubit gates remain
_unroll3q = Unroll3qOrMore()
Expand All @@ -144,6 +146,9 @@ def _swap_condition(property_set):
else:
raise TranspilerError("Invalid routing method %s." % routing_method)

_restore_layout = [LayoutTransformation(coupling_map, 'layout_out', None,
seed=seed_transpiler, trials=4)]

# 6. Unroll to the basis
if translation_method == 'unroller':
_unroll = [Unroller(basis_gates)]
Expand Down Expand Up @@ -197,9 +202,11 @@ def _opt_control(property_set):
pm1.append(_choose_layout_and_score, condition=_choose_layout_condition)
pm1.append(_improve_layout, condition=_not_perfect_yet)
pm1.append(_embed)
pm1.append(ApplyLayoutSwaps(coupling_map, seed=seed_transpiler, trials=4))
pm1.append(_unroll3q)
pm1.append(_swap_check)
pm1.append(_swap, condition=_swap_condition)
pm1.append(_restore_layout)
pm1.append(_unroll)
if coupling_map and not coupling_map.is_symmetric:
pm1.append(_direction_check)
Expand Down