Skip to content

Commit

Permalink
[feature] auto_rebase_pass function for attempting automatic rebase p…
Browse files Browse the repository at this point in the history
…asses
  • Loading branch information
ss2165 committed Feb 14, 2022
1 parent 51a3ae8 commit ddabf5e
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 1 deletion.
6 changes: 6 additions & 0 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ API changes:
* The deprecated ``Backend.compile_circuit`` method is removed. (Use
``get_compiled_circuit`` instead.)


Minor new features:

* New ``pytket.passes.auto_rebase_pass`` which attempts to construct a rebase pass given a target gate set from known decompositions.
* ``RebaseCustom`` takes one allowed gateset parameter rather than separate single qubit and multiqubit gatesets.

0.19.0 (February 2022)
----------------------

Expand Down
1 change: 1 addition & 0 deletions pytket/pytket/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
from pytket._tket.passes import * # type: ignore

from .script import compilation_pass_from_script, compilation_pass_grammar
from .auto_rebase import auto_rebase_pass
71 changes: 71 additions & 0 deletions pytket/pytket/passes/auto_rebase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright 2019-2022 Cambridge Quantum Computing
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Union, Callable, Dict, FrozenSet, TYPE_CHECKING
from pytket.circuit import Circuit, OpType, pool # type: ignore
from pytket.passes import RebaseCustom # type: ignore

if TYPE_CHECKING:
from sympy import Expr # type: ignore


class NoAutoRebase(Exception):
"""Automatic rebase could not be found"""


_CX_CIRCS: Dict[OpType, Callable[[], "Circuit"]] = {
OpType.CX: pool.CX,
OpType.ZZMax: pool.CX_using_ZZMax,
OpType.XXPhase: pool.CX_using_XXPhase_0,
OpType.ECR: pool.CX_using_ECR,
OpType.CZ: lambda: Circuit(2).H(1).CZ(0, 1).H(1),
}

Param = Union[str, "Expr"]

_tk1_circs: Dict[FrozenSet[OpType], Callable[[Param, Param, Param], "Circuit"]] = {
frozenset({OpType.TK1}): pool.tk1_to_tk1,
frozenset({OpType.PhasedX, OpType.Rz}): pool.tk1_to_PhasedXRz,
frozenset({OpType.Rx, OpType.Rz}): pool.tk1_to_rzrx,
frozenset({OpType.Rz, OpType.H}): pool.tk1_to_rzh,
frozenset({OpType.Rz, OpType.SX}): pool.tk1_to_rzsx,
}


def auto_rebase_pass(gateset: FrozenSet[OpType]) -> RebaseCustom:
"""Attempt to generate a rebase pass automatically for the given target
gateset.
Checks if there are known existing decompositions from CX
to target gateset and TK1 to target gateset and uses thsoe to construct a
CustomRebase.
Raises an error if known decompositions can be found, in which case try
using RebaseCustom with your own decompositions.
:param gateset: Set of supported OpTypes, target gate set
:type gateset: FrozenSet[OpType]
:raises NoAutoRebase: No suitable CX or TK1 decomposition found.
:return: Rebase pass.
:rtype: RebaseCustom
"""
if any((matching := k) in gateset for k in _CX_CIRCS):
cx_circ = _CX_CIRCS[matching]()
else:
raise NoAutoRebase("No known decomposition from CX to available gateset.")

if any((matching := k).issubset(gateset) for k in _tk1_circs):
tk1_func = _tk1_circs[matching]
else:
raise NoAutoRebase("No known decomposition from TK1 to available gateset.")

return RebaseCustom(set(gateset), cx_circ, tk1_func)
53 changes: 52 additions & 1 deletion pytket/tests/transform_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@

from pathlib import Path
from pytket.circuit import Circuit, OpType, PauliExpBox # type: ignore
from pytket.circuit import pool # type: ignore
from pytket.pauli import Pauli # type: ignore
from pytket.passes import RemoveRedundancies, KAKDecomposition, ThreeQubitSquash, CommuteThroughMultis, PauliSquash, FullPeepholeOptimise, GlobalisePhasedX # type: ignore
from pytket.passes import RemoveRedundancies, KAKDecomposition, ThreeQubitSquash, CommuteThroughMultis, PauliSquash, FullPeepholeOptimise, GlobalisePhasedX, RebaseCustom # type: ignore
from pytket.passes import auto_rebase_pass
from pytket.passes.auto_rebase import _CX_CIRCS, NoAutoRebase
from pytket.predicates import CompilationUnit # type: ignore
from pytket.transform import Transform, CXConfigType, PauliSynthStrat # type: ignore
from pytket.qasm import circuit_from_qasm
Expand Down Expand Up @@ -729,6 +732,54 @@ def test_full_peephole_optimise() -> None:
assert n_cx1 < n_cz


def test_auto_rebase() -> None:
pass_params = [
({OpType.CX, OpType.Rz, OpType.Rx}, pool.CX(), pool.tk1_to_rzrx),
(
{OpType.CZ, OpType.Rz, OpType.SX, OpType.ZZPhase},
_CX_CIRCS[OpType.CZ](),
pool.tk1_to_rzsx,
),
(
{OpType.ZZMax, OpType.T, OpType.Rz, OpType.H},
pool.CX_using_ZZMax(),
pool.tk1_to_rzh,
),
(
{OpType.XXPhase, OpType.T, OpType.Rz, OpType.H},
pool.CX_using_XXPhase_0(),
pool.tk1_to_rzh,
),
(
{OpType.ECR, OpType.PhasedX, OpType.Rz, OpType.CnX},
pool.CX_using_ECR(),
pool.tk1_to_PhasedXRz,
),
(
{OpType.CX, OpType.TK1, OpType.U3, OpType.CnX},
pool.CX(),
pool.tk1_to_tk1,
),
]

circ = get_test_circuit()

for gateset, cx_circ, tk1_func in pass_params:
rebase = auto_rebase_pass(frozenset(gateset))
assert rebase.to_dict() == RebaseCustom(gateset, cx_circ, tk1_func).to_dict()

c2 = circ.copy()
assert rebase.apply(c2)

with pytest.raises(NoAutoRebase) as cx_err:
_ = auto_rebase_pass(frozenset({OpType.ZZPhase, OpType.TK1}))
assert "CX" in str(cx_err.value)

with pytest.raises(NoAutoRebase) as cx_err:
_ = auto_rebase_pass(frozenset({OpType.CX, OpType.H, OpType.T}))
assert "TK1" in str(cx_err.value)


if __name__ == "__main__":
test_remove_redundancies()
test_reduce_singles()
Expand Down

0 comments on commit ddabf5e

Please sign in to comment.