Skip to content

Commit

Permalink
Add only_reduce parameter to GreedyPauliSimp (#1669)
Browse files Browse the repository at this point in the history
* add timeout

* add timeout to serialisation

* Update changelog.rst

* bump library

* Update transform.cpp

* Update test_GreedyPauli.cpp

* update stubs

* fix serialisation

* Update test_GreedyPauli.cpp

* optionally relabel classical expressions when renaming units

* Update predicates_test.py

* update flattenrelabelregisters

* reformat, add false to rename_units again

* bump library

* Update passes_serialisation_test.py

* bump library version

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* add logic to allow only returning the transformed circuit if it has fewer two qubit gates

* add only_reduce argument

* bump library

* Update PassGenerators.cpp

* Update PassGenerators.cpp

* update json

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update test_GreedyPauli.cpp

* Update PassGenerators.cpp

* condense code

* Update passes.pyi

* Update PassGenerators.cpp

* Update predicates_test.py

* Update changelog.rst
  • Loading branch information
sjdilkes authored Nov 11, 2024
1 parent fbc3ebc commit d6d5801
Show file tree
Hide file tree
Showing 12 changed files with 53 additions and 15 deletions.
6 changes: 4 additions & 2 deletions pytket/binders/passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -961,11 +961,13 @@ PYBIND11_MODULE(passes, m) {
"implement 2-qubit rotations using ZZPhase gates when deemed "
"optimal. Defaults to False."
"\n:param timeout: Sets maximum out of time spent finding solution."
"\n:param only_reduce: Only returns modified circuit if it has "
"fewer two-qubit gates."
"\n:return: a pass to perform the simplification",
py::arg("discount_rate") = 0.7, py::arg("depth_weight") = 0.3,
py::arg("max_lookahead") = 500, py::arg("max_tqe_candidates") = 500,
py::arg("seed") = 0, py::arg("allow_zzphase") = false,
py::arg("timeout") = 100);
py::arg("timeout") = 100, py::arg("only_reduce") = false);
m.def(
"PauliSquash", &PauliSquash,
"Applies :py:meth:`PauliSimp` followed by "
Expand Down Expand Up @@ -1038,7 +1040,7 @@ PYBIND11_MODULE(passes, m) {

m.def(
"CnXPairwiseDecomposition", &CnXPairwiseDecomposition,
"Decompose CnX gates to 2-qubit gates and single qubit gates. "
"Decompose CnX gates to 2-qubit gates `fand single qubit gates. "
"For every two CnX gates, reorder their control qubits to improve "
"the chance of gate cancellation");

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.14")
self.requires("symengine/0.12.0")
self.requires("tkassert/0.3.4@tket/stable")
self.requires("tket/1.3.42@tket/stable")
self.requires("tket/1.3.43@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
1 change: 1 addition & 0 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Features:
* Add `custom_deserialisation` argument to `BasePass` and `SequencePass`
`from_dict` method to support construction of `CustomPass` from json.
* Add `timeout` argument to `GreedyPauliSimp`.
* Add `only_reduce` argument to `GreedyPauliSimp`.
* Add option to not relabel `ClassicalExpBox` when calling `rename_units`
and `flatten_registers`

Expand Down
5 changes: 3 additions & 2 deletions pytket/pytket/_tket/passes.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ def CliffordSimp(allow_swaps: bool = True) -> BasePass:
"""
def CnXPairwiseDecomposition() -> BasePass:
"""
Decompose CnX gates to 2-qubit gates and single qubit gates. For every two CnX gates, reorder their control qubits to improve the chance of gate cancellation
Decompose CnX gates to 2-qubit gates `fand single qubit gates. For every two CnX gates, reorder their control qubits to improve the chance of gate cancellation
"""
def CommuteThroughMultis() -> BasePass:
"""
Expand Down Expand Up @@ -445,7 +445,7 @@ def GlobalisePhasedX(squash: bool = True) -> BasePass:
It is not recommended to use this pass with symbolic expressions, as in certain cases a blow-up in symbolic expression sizes may occur.
"""
def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_lookahead: int = 500, max_tqe_candidates: int = 500, seed: int = 0, allow_zzphase: bool = False, timeout: int = 100) -> BasePass:
def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_lookahead: int = 500, max_tqe_candidates: int = 500, seed: int = 0, allow_zzphase: bool = False, timeout: int = 100, only_reduce: bool = False) -> BasePass:
"""
Construct a pass that converts a circuit into a graph of Pauli gadgets to account for commutation and phase folding, and resynthesises them using a greedy algorithm adapted from arxiv.org/abs/2103.08602. The method for synthesising the final Clifford operator is adapted from arxiv.org/abs/2305.10966.
Expand All @@ -456,6 +456,7 @@ def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_l
:param seed: Unsigned integer seed used for sampling candidates and tie breaking. Default to 0.
:param allow_zzphase: If set to True, allows the algorithm to implement 2-qubit rotations using ZZPhase gates when deemed optimal. Defaults to False.
:param timeout: Sets maximum out of time spent finding solution.
:param only_reduce: Only returns modified circuit if it has fewer two-qubit gates.
:return: a pass to perform the simplification
"""
def GuidedPauliSimp(strat: pytket._tket.transform.PauliSynthStrat = pytket._tket.transform.PauliSynthStrat.Sets, cx_config: pytket._tket.circuit.CXConfigType = pytket._tket.circuit.CXConfigType.Snake) -> BasePass:
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 @@ -297,6 +297,7 @@ def nonparam_predicate_dict(name: str) -> Dict[str, Any]:
"seed": 2,
"allow_zzphase": True,
"timeout": 5000,
"only_reduce": False,
}
),
# lists must be sorted by OpType value
Expand Down
2 changes: 1 addition & 1 deletion pytket/tests/predicates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,7 @@ def test_greedy_pauli_synth() -> None:
).SWAP(regb[1], rega[0])
d = circ.copy()
pss = GreedyPauliSimp(0.5, 0.5)
assert not GreedyPauliSimp(0.5, 0.5, timeout=0).apply(d)
assert not GreedyPauliSimp(0.5, 0.5, timeout=0, only_reduce=False).apply(d)
assert pss.apply(d)
assert np.allclose(circ.get_unitary(), d.get_unitary())
assert d.name == "test"
Expand Down
9 changes: 7 additions & 2 deletions schemas/compiler_pass_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@
"timeout": {
"type": "number",
"definition": "parameter controlling the maximum runtime of \"GreedyPauliSimp\""
},
"only_reduce": {
"type": "boolean",
"definition": "parameter controlling whether \"GreedyPauliSimp\" can return circuits with more two qubit gates"
}
},
"required": [
Expand Down Expand Up @@ -909,9 +913,10 @@
"max_tqe_candidates",
"seed",
"allow_zzphase",
"timeout"
"timeout",
"only_reduce"
],
"maxProperties": 8
"maxProperties": 9
}
},
{
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.42"
version = "1.3.43"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
4 changes: 3 additions & 1 deletion tket/include/tket/Predicates/PassGenerators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,14 @@ PassPtr gen_special_UCC_synthesis(
* @param seed
* @param allow_zzphase
* @param timeout
* @param only_reduce
* @return PassPtr
*/
PassPtr gen_greedy_pauli_simp(
double discount_rate = 0.7, double depth_weight = 0.3,
unsigned max_lookahead = 500, unsigned max_tqe_candidates = 500,
unsigned seed = 0, bool allow_zzphase = false, unsigned timeout = 100);
unsigned seed = 0, bool allow_zzphase = false, unsigned timeout = 100,
bool only_reduce = false);

/**
* Generate a pass to simplify the circuit where it acts on known basis states.
Expand Down
3 changes: 2 additions & 1 deletion tket/src/Predicates/CompilerPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,10 @@ PassPtr deserialise(
unsigned seed = content.at("seed").get<unsigned>();
bool allow_zzphase = content.at("allow_zzphase").get<bool>();
unsigned timeout = content.at("timeout").get<unsigned>();
bool only_reduce = content.at("only_reduce").get<bool>();
pp = gen_greedy_pauli_simp(
discount_rate, depth_weight, max_lookahead, max_tqe_candidates, seed,
allow_zzphase, timeout);
allow_zzphase, timeout, only_reduce);

} else if (passname == "PauliSimp") {
// SEQUENCE PASS - DESERIALIZABLE ONLY
Expand Down
23 changes: 19 additions & 4 deletions tket/src/Predicates/PassGenerators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1018,10 +1018,24 @@ PassPtr gen_synthesise_pauli_graph(
PassPtr gen_greedy_pauli_simp(
double discount_rate, double depth_weight, unsigned max_lookahead,
unsigned max_tqe_candidates, unsigned seed, bool allow_zzphase,
unsigned timeout) {
Transform t = Transforms::greedy_pauli_optimisation(
discount_rate, depth_weight, max_lookahead, max_tqe_candidates, seed,
allow_zzphase, timeout);
unsigned timeout, bool only_reduce) {
Transform t =
Transform([discount_rate, depth_weight, max_lookahead, max_tqe_candidates,
seed, allow_zzphase, timeout, only_reduce](Circuit& circ) {
Transform gpo = Transforms::greedy_pauli_optimisation(
discount_rate, depth_weight, max_lookahead, max_tqe_candidates,
seed, allow_zzphase, timeout);
if (only_reduce) {
Circuit gpo_circ = circ;
if (gpo.apply(gpo_circ) &&
gpo_circ.count_n_qubit_gates(2) < circ.count_n_qubit_gates(2)) {
circ = gpo_circ;
return true;
}
return false;
}
return gpo.apply(circ);
});
OpTypeSet ins = {
OpType::Z,
OpType::X,
Expand Down Expand Up @@ -1071,6 +1085,7 @@ PassPtr gen_greedy_pauli_simp(
j["seed"] = seed;
j["allow_zzphase"] = allow_zzphase;
j["timeout"] = timeout;
j["only_reduce"] = only_reduce;

return std::make_shared<StandardPass>(precons, t, postcon, j);
}
Expand Down
10 changes: 10 additions & 0 deletions tket/test/src/test_GreedyPauli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "tket/Gate/SymTable.hpp"
#include "tket/Ops/ClassicalOps.hpp"
#include "tket/Predicates/PassGenerators.hpp"
#include "tket/Predicates/PassLibrary.hpp"
#include "tket/Transformations/GreedyPauliOptimisation.hpp"
#include "tket/Utils/Expression.hpp"

Expand Down Expand Up @@ -749,6 +750,15 @@ SCENARIO("Test GreedyPauliSimp pass construction") {
CHECK(gen_greedy_pauli_simp(0.3, 0.5)->apply(cu));
REQUIRE(test_unitary_comparison(c, cu.get_circ_ref(), true));
}
GIVEN("Preserving a circuit with only_reduce set to true.") {
Circuit c(4);
c.add_op<unsigned>(OpType::CX, {0, 1});
c.add_op<unsigned>(OpType::CX, {1, 2});
c.add_op<unsigned>(OpType::CX, {2, 3});
CompilationUnit cu(c);
REQUIRE(!gen_greedy_pauli_simp(0.3, 0.5, 500, 500, 0, false, 100, true)
->apply(cu));
}
}
} // namespace test_GreedyPauliSimp
} // namespace tket

0 comments on commit d6d5801

Please sign in to comment.