Skip to content

Commit

Permalink
Add pass to remove Phase gates (#1735)
Browse files Browse the repository at this point in the history
  • Loading branch information
cqc-alec authored Jan 10, 2025
1 parent ba51191 commit 75d584f
Show file tree
Hide file tree
Showing 15 changed files with 95 additions and 4 deletions.
5 changes: 5 additions & 0 deletions pytket/binders/passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,11 @@ PYBIND11_MODULE(passes, m) {
m.def(
"RemoveBarriers", &RemoveBarriers,
"A pass to remove all barrier instructions from the circuit.");
m.def(
"RemovePhaseOps", &RemovePhaseOps,
"A pass to remove all Phase operations from the circuit. This includes "
"conditional Phase operations, but not Phase operations inside "
"CircBoxes, QControlBoxes or other nested structures.");
m.def(
"ZXGraphlikeOptimisation", &ZXGraphlikeOptimisation,
"Attempt to optimise the circuit by simplifying in ZX calculus and "
Expand Down
2 changes: 1 addition & 1 deletion pytket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def requirements(self):
self.requires("pybind11_json/0.2.15")
self.requires("symengine/0.13.0")
self.requires("tkassert/0.3.4@tket/stable")
self.requires("tket/1.3.60@tket/stable")
self.requires("tket/1.3.61@tket/stable")
self.requires("tklog/0.3.3@tket/stable")
self.requires("tkrng/0.3.3@tket/stable")
self.requires("tktokenswap/0.3.9@tket/stable")
Expand Down
7 changes: 7 additions & 0 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

Unreleased
----------

Features:

* Add `RemovePhaseOps` pass.

1.38.0 (January 2025)
---------------------

Expand Down
2 changes: 1 addition & 1 deletion pytket/pytket/_tket/circuit.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2574,7 +2574,7 @@ class Circuit:
@property
def wasm_uid(self) -> str | None:
"""
:return: the unique wasm uid of the circuit
:return: the unique WASM UID of the circuit, or `None` if the circuit has none
"""
class ClBitVar:
"""
Expand Down
6 changes: 5 additions & 1 deletion pytket/pytket/_tket/passes.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import pytket._tket.transform
import pytket._tket.unit_id
import sympy
import typing
__all__ = ['AASRouting', 'Audit', 'AutoRebase', 'AutoSquash', 'BasePass', 'CNotSynthType', 'CXMappingPass', 'CliffordPushThroughMeasures', 'CliffordResynthesis', 'CliffordSimp', 'CnXPairwiseDecomposition', 'CommuteThroughMultis', 'ComposePhasePolyBoxes', 'ContextSimp', 'CustomPass', 'CustomRoutingPass', 'DecomposeArbitrarilyControlledGates', 'DecomposeBoxes', 'DecomposeClassicalExp', 'DecomposeMultiQubitsCX', 'DecomposeSingleQubitsTK1', 'DecomposeSwapsToCXs', 'DecomposeSwapsToCircuit', 'DecomposeTK2', 'Default', 'DefaultMappingPass', 'DelayMeasures', 'EulerAngleReduction', 'FlattenRegisters', 'FlattenRelabelRegistersPass', 'FullMappingPass', 'FullPeepholeOptimise', 'GlobalisePhasedX', 'GreedyPauliSimp', 'GuidedPauliSimp', 'HamPath', 'KAKDecomposition', 'NaivePlacementPass', 'NormaliseTK2', 'OptimisePhaseGadgets', 'PauliExponentials', 'PauliSimp', 'PauliSquash', 'PeepholeOptimise2Q', 'PlacementPass', 'RebaseCustom', 'RebaseTket', 'Rec', 'RemoveBarriers', 'RemoveDiscarded', 'RemoveImplicitQubitPermutation', 'RemoveRedundancies', 'RenameQubitsPass', 'RepeatPass', 'RepeatUntilSatisfiedPass', 'RepeatWithMetricPass', 'RoundAngles', 'RoutingPass', 'SWAP', 'SafetyMode', 'SequencePass', 'SimplifyInitial', 'SimplifyMeasured', 'SquashCustom', 'SquashRzPhasedX', 'SquashTK1', 'SynthesiseTK', 'SynthesiseTket', 'SynthesiseUMD', 'ThreeQubitSquash', 'ZXGraphlikeOptimisation', 'ZZPhaseToRz']
__all__ = ['AASRouting', 'Audit', 'AutoRebase', 'AutoSquash', 'BasePass', 'CNotSynthType', 'CXMappingPass', 'CliffordPushThroughMeasures', 'CliffordResynthesis', 'CliffordSimp', 'CnXPairwiseDecomposition', 'CommuteThroughMultis', 'ComposePhasePolyBoxes', 'ContextSimp', 'CustomPass', 'CustomRoutingPass', 'DecomposeArbitrarilyControlledGates', 'DecomposeBoxes', 'DecomposeClassicalExp', 'DecomposeMultiQubitsCX', 'DecomposeSingleQubitsTK1', 'DecomposeSwapsToCXs', 'DecomposeSwapsToCircuit', 'DecomposeTK2', 'Default', 'DefaultMappingPass', 'DelayMeasures', 'EulerAngleReduction', 'FlattenRegisters', 'FlattenRelabelRegistersPass', 'FullMappingPass', 'FullPeepholeOptimise', 'GlobalisePhasedX', 'GreedyPauliSimp', 'GuidedPauliSimp', 'HamPath', 'KAKDecomposition', 'NaivePlacementPass', 'NormaliseTK2', 'OptimisePhaseGadgets', 'PauliExponentials', 'PauliSimp', 'PauliSquash', 'PeepholeOptimise2Q', 'PlacementPass', 'RebaseCustom', 'RebaseTket', 'Rec', 'RemoveBarriers', 'RemoveDiscarded', 'RemoveImplicitQubitPermutation', 'RemovePhaseOps', 'RemoveRedundancies', 'RenameQubitsPass', 'RepeatPass', 'RepeatUntilSatisfiedPass', 'RepeatWithMetricPass', 'RoundAngles', 'RoutingPass', 'SWAP', 'SafetyMode', 'SequencePass', 'SimplifyInitial', 'SimplifyMeasured', 'SquashCustom', 'SquashRzPhasedX', 'SquashTK1', 'SynthesiseTK', 'SynthesiseTket', 'SynthesiseUMD', 'ThreeQubitSquash', 'ZXGraphlikeOptimisation', 'ZZPhaseToRz']
class BasePass:
"""
Base class for passes.
Expand Down Expand Up @@ -618,6 +618,10 @@ def RemoveImplicitQubitPermutation() -> BasePass:
Note that if the circuit contains measurements, they may become mid-circuit measurements in the transformed circuit.
"""
def RemovePhaseOps() -> BasePass:
"""
A pass to remove all Phase operations from the circuit. This includes conditional Phase operations, but not Phase operations inside CircBoxes, QControlBoxes or other nested structures.
"""
def RemoveRedundancies() -> BasePass:
"""
Removes gate-inverse pairs, merges rotations, removes identity rotations, and removes redundant gates before measurement. Does not add any new gate types.
Expand Down
6 changes: 6 additions & 0 deletions pytket/pytket/passes/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
RebaseTket,
RemoveBarriers,
RemoveDiscarded,
RemovePhaseOps,
RemoveRedundancies,
RepeatPass,
SequencePass,
Expand Down Expand Up @@ -85,6 +86,7 @@
| rebase_tket
| remove_barriers
| remove_discarded
| remove_phase_ops
| remove_redundancies
| simplify_initial
| simplify_initial_no_classical
Expand Down Expand Up @@ -127,6 +129,7 @@
rebase_tket: "RebaseTket"
remove_barriers: "RemoveBarriers"
remove_discarded: "RemoveDiscarded"
remove_phase_ops: "RemovePhaseOps"
remove_redundancies: "RemoveRedundancies"
simplify_initial: "SimplifyInitial"
simplify_initial_no_classical: "SimplifyInitialNoClassical"
Expand Down Expand Up @@ -286,6 +289,9 @@ def remove_barriers(self, t: list) -> BasePass:
def remove_discarded(self, t: list) -> BasePass:
return RemoveDiscarded()

def remove_phase_ops(self, t: list) -> BasePass:
return RemovePhaseOps()

def remove_redundancies(self, t: list) -> BasePass:
return RemoveRedundancies()

Expand Down
1 change: 1 addition & 0 deletions pytket/tests/passes_serialisation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ def nonparam_predicate_dict(name: str) -> Dict[str, Any]:
"DecomposeSingleQubitsTK1",
"RebaseTket",
"RebaseUFR",
"RemovePhaseOps",
"RemoveRedundancies",
"SynthesiseTK",
"SynthesiseTket",
Expand Down
10 changes: 10 additions & 0 deletions pytket/tests/predicates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
RemoveBarriers,
RemoveDiscarded,
RemoveImplicitQubitPermutation,
RemovePhaseOps,
RemoveRedundancies,
RenameQubitsPass,
RepeatPass,
Expand Down Expand Up @@ -496,6 +497,15 @@ def test_remove_barriers() -> None:
assert cmd.op.type == OpType.CX


def test_remove_phase_ops() -> None:
circ = Circuit(2, 2).H(0).H(1).measure_all()
circ0 = circ.copy()
circ.Phase(0.0)
circ.Phase(0.1, condition_bits=[Bit(0), Bit(1)], condition_value=3)
assert RemovePhaseOps().apply(circ)
assert circ == circ0


def test_user_defined_swap_decomp() -> None:
circ = Circuit(2)
circ.SWAP(0, 1)
Expand Down
2 changes: 2 additions & 0 deletions schemas/compiler_pass_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"RemoveDiscarded",
"SimplifyMeasured",
"RemoveBarriers",
"RemovePhaseOps",
"DecomposeBridges",
"KAKDecomposition",
"ThreeQubitSquash",
Expand Down Expand Up @@ -948,6 +949,7 @@
"RemoveDiscarded",
"SimplifyMeasured",
"RemoveBarriers",
"RemovePhaseOps",
"DecomposeBridges"
]
}
Expand Down
2 changes: 1 addition & 1 deletion tket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

class TketConan(ConanFile):
name = "tket"
version = "1.3.60"
version = "1.3.61"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
3 changes: 3 additions & 0 deletions tket/include/tket/Predicates/PassLibrary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,7 @@ const PassPtr &RemoveImplicitQubitPermutation();
*/
const PassPtr &ZXGraphlikeOptimisation();

/** Remove all \ref OpType::Phase (including conditionals) from the circuit. */
const PassPtr &RemovePhaseOps();

} // namespace tket
2 changes: 2 additions & 0 deletions tket/src/Predicates/CompilerPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,8 @@ PassPtr deserialise(
pp = SimplifyMeasured();
} else if (passname == "RemoveBarriers") {
pp = RemoveBarriers();
} else if (passname == "RemovePhaseOps") {
pp = RemovePhaseOps();
} else if (passname == "ComposePhasePolyBoxes") {
pp = ComposePhasePolyBoxes(content.at("min_size").get<unsigned>());
} else if (passname == "RebaseCustom") {
Expand Down
31 changes: 31 additions & 0 deletions tket/src/Predicates/PassLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <memory>

#include "tket/Converters/Converters.hpp"
#include "tket/OpType/OpType.hpp"
#include "tket/Predicates/CompilationUnit.hpp"
#include "tket/Predicates/CompilerPass.hpp"
#include "tket/Predicates/Predicates.hpp"
Expand Down Expand Up @@ -512,4 +513,34 @@ const PassPtr &ZXGraphlikeOptimisation() {
return pp;
}

const PassPtr &RemovePhaseOps() {
static const PassPtr pp([]() {
Transform t = Transform([](Circuit &circ) {
VertexList phases;
BGL_FORALL_VERTICES(v, circ.dag, DAG) {
Op_ptr op = circ.get_Op_ptr_from_Vertex(v);
OpType optype = op->get_type();
bool conditional = optype == OpType::Conditional;
if (conditional) {
const Conditional &cond = static_cast<const Conditional &>(*op);
op = cond.get_op();
optype = op->get_type();
}
if (optype == OpType::Phase) {
phases.push_back(v);
}
}
circ.remove_vertices(
phases, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::Yes);
return !phases.empty();
});
const PredicatePtrMap no_precons;
PostConditions postcons = {{}, {}, Guarantee::Preserve};
nlohmann::json j;
j["name"] = "RemovePhaseOps";
return std::make_shared<StandardPass>(no_precons, t, postcons, j);
}());
return pp;
}

} // namespace tket
19 changes: 19 additions & 0 deletions tket/test/src/test_CompilerPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,25 @@ SCENARIO("RemoveBarriers pass") {
}
}

SCENARIO("RemovePhaseOps pass") {
GIVEN("A circuit containing Phase ops") {
Circuit circ(1, 1), circ0(1, 1);
circ.add_op<unsigned>(OpType::Phase, 0.1, {});
circ.add_op<unsigned>(OpType::H, {0});
circ0.add_op<unsigned>(OpType::H, {0});
circ.add_measure(0, 0);
circ0.add_measure(0, 0);
circ.add_conditional_gate<unsigned>(OpType::Phase, {0.2}, {}, {0}, 1);
circ.add_op<unsigned>(OpType::Phase, 0.3, {});
CompilationUnit cu(circ);
REQUIRE(RemovePhaseOps()->apply(cu));
const Circuit& circ1 = cu.get_circ_ref();
REQUIRE(circ1 == circ0);
CompilationUnit cu0(circ0);
REQUIRE_FALSE(RemovePhaseOps()->apply(cu0));
}
}

SCENARIO("gen_placement_pass test") {
GIVEN("A simple circuit and device and base Placement.") {
Circuit circ(4);
Expand Down
1 change: 1 addition & 0 deletions tket/test/src/test_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,7 @@ SCENARIO("Test compiler pass serializations") {
COMPPASSJSONTEST(SimplifyMeasured, SimplifyMeasured())
COMPPASSJSONTEST(ZZPhaseToRz, ZZPhaseToRz())
COMPPASSJSONTEST(RemoveBarriers, RemoveBarriers())
COMPPASSJSONTEST(RemovePhaseOps, RemovePhaseOps())
COMPPASSJSONTEST(ComposePhasePolyBoxes, ComposePhasePolyBoxes())
COMPPASSJSONTEST(DecomposeBridges, DecomposeBridges())
COMPPASSJSONTEST(
Expand Down

0 comments on commit 75d584f

Please sign in to comment.