Skip to content

Commit

Permalink
Modify and fix CliffordResynthesis pass (#1476)
Browse files Browse the repository at this point in the history
  • Loading branch information
cqc-alec authored Jul 2, 2024
1 parent 2017ae4 commit 3df27b8
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 16 deletions.
4 changes: 2 additions & 2 deletions pytket/binders/passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,8 @@ PYBIND11_MODULE(passes, m) {

m.def(
"CliffordResynthesis", &gen_clifford_resynthesis_pass,
"An optimisation pass that resynhesises all Clifford subcircuits and "
"then applies some rewrite rules to simplify them further."
"An optimisation pass that resynthesises Clifford subcircuits, trying "
"to reduce the 2-qubit gate count as much as possible."
"\n\n:param transform: optional user-provided resynthesis method to "
"apply to all Clifford subcircuits (a function taking a Clifford "
"circuit as an argument and returning an equivalent circuit); if not "
Expand Down
2 changes: 1 addition & 1 deletion pytket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def package(self):
cmake.install()

def requirements(self):
self.requires("tket/1.3.12@tket/stable")
self.requires("tket/1.3.13@tket/stable")
self.requires("tklog/0.3.3@tket/stable")
self.requires("tkrng/0.3.3@tket/stable")
self.requires("tkassert/0.3.4@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 @@ -9,6 +9,7 @@ Unreleased
* Add `PauliSynthStrat.Greedy` strategy to `TermSequenceBox`.
* Update version requirements on dependencies, removing all upper bounds (in
particular allowing compatibility with numpy 2.0).
* Fix bug in `CliffordResynthesis()` pass.

1.29.2 (June 2024)
------------------
Expand Down
2 changes: 1 addition & 1 deletion pytket/pytket/_tket/passes.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def CliffordPushThroughMeasures() -> BasePass:
"""
def CliffordResynthesis(transform: typing.Callable[[pytket._tket.circuit.Circuit], pytket._tket.circuit.Circuit] | None = None, allow_swaps: bool = True) -> BasePass:
"""
An optimisation pass that resynhesises all Clifford subcircuits and then applies some rewrite rules to simplify them further.
An optimisation pass that resynthesises Clifford subcircuits, trying to reduce the 2-qubit gate count as much as possible.
:param transform: optional user-provided resynthesis method to apply to all Clifford subcircuits (a function taking a Clifford circuit as an argument and returning an equivalent circuit); if not provided, a default resynthesis method is applied
:param allow_swaps: whether the rewriting may introduce wire swaps (only relevant to the default resynthesis method used when the `transform` argument is not provided)
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.12"
version = "1.3.13"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
53 changes: 43 additions & 10 deletions tket/src/Transformations/CliffordResynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

#include "tket/Transformations/CliffordResynthesis.hpp"

#include <algorithm>
#include <vector>

#include "tket/Circuit/Circuit.hpp"
#include "tket/Circuit/DAGDefs.hpp"
#include "tket/Clifford/UnitaryTableau.hpp"
#include "tket/Converters/Converters.hpp"
#include "tket/Transformations/BasicOptimisation.hpp"
Expand All @@ -27,19 +31,20 @@ namespace tket {
namespace Transforms {

static Circuit resynthesised_circuit(
Circuit &circ,
const Circuit &circ,
std::optional<std::function<Circuit(const Circuit &)>> transform = nullptr,
bool allow_swaps = true) {
if (transform.has_value()) {
return (*transform)(circ);
} else {
Circuit circ1(circ);
// Ensure all recognized Clifford gates are Clifford types:
decompose_multi_qubits_CX().apply(circ);
decompose_cliffords_std().apply(circ);
remove_redundancies().apply(circ);
decompose_multi_qubits_CX().apply(circ1);
decompose_cliffords_std().apply(circ1);
remove_redundancies().apply(circ1);

// Convert to tableau and back:
const UnitaryTableau tab = circuit_to_unitary_tableau(circ);
const UnitaryTableau tab = circuit_to_unitary_tableau(circ1);
Circuit newcirc = unitary_tableau_to_circuit(tab);

// Simplify:
Expand All @@ -49,18 +54,46 @@ static Circuit resynthesised_circuit(
}
}

// Returns the two-qubit-gate reduction resulting from resynthesising the given
// (convex, connected) vertex set using the given transform.
static int n_2q_reduction(
const Circuit &circ, const VertexSet &verts,
std::optional<std::function<Circuit(const Circuit &)>> transform,
bool allow_swaps) {
Subcircuit subcircuit = circ.make_subcircuit(verts);
const Circuit subc = circ.subcircuit(subcircuit);
Circuit newsubc = resynthesised_circuit(subc, transform, allow_swaps);
return int(subc.count_n_qubit_gates(2)) - int(newsubc.count_n_qubit_gates(2));
}

static bool resynthesise_cliffords(
Circuit &circ,
std::optional<std::function<Circuit(const Circuit &)>> transform = nullptr,
bool allow_swaps = true) {
bool changed = false;
for (const VertexSet &verts :
circ.get_subcircuits([](Op_ptr op) { return op->is_clifford(); })) {
while (true) {
std::vector<VertexSet> subcircuits =
circ.get_subcircuits([](Op_ptr op) { return op->is_clifford(); });
if (subcircuits.empty()) {
break;
}
// Pick the one that reduces the 2q gate count the most.
VertexSet verts = *std::max_element(
subcircuits.begin(), subcircuits.end(),
[&circ, &transform, &allow_swaps](
const VertexSet &A, const VertexSet &B) {
return n_2q_reduction(circ, A, transform, allow_swaps) <
n_2q_reduction(circ, B, transform, allow_swaps);
});
Subcircuit subcircuit = circ.make_subcircuit(verts);
Circuit subc = circ.subcircuit(subcircuit);
const Circuit subc = circ.subcircuit(subcircuit);
Circuit newsubc = resynthesised_circuit(subc, transform, allow_swaps);
circ.substitute(newsubc, subcircuit);
changed = true;
if (newsubc.count_n_qubit_gates(2) < subc.count_n_qubit_gates(2)) {
circ.substitute(newsubc, subcircuit);
changed = true;
} else {
break;
}
}
return changed;
}
Expand Down
26 changes: 25 additions & 1 deletion tket/test/src/Passes/test_CliffordResynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <catch2/catch_test_macros.hpp>
#include <vector>

#include "../testutil.hpp"
#include "tket/Circuit/Circuit.hpp"
Expand All @@ -23,7 +25,7 @@
namespace tket {
namespace test_CliffordResynthesis {

void check_clifford_resynthesis(const Circuit& c) {
void check_clifford_resynthesis(const Circuit &c) {
Circuit c0 = c;
CompilationUnit cu(c0);
gen_clifford_resynthesis_pass()->apply(cu);
Expand Down Expand Up @@ -120,6 +122,28 @@ SCENARIO("SynthesiseCliffordResynthesis correctness") {
c.add_op<unsigned>(OpType::NPhasedX, {0.5, 0.0}, {0, 1});
check_clifford_resynthesis(c);
}

GIVEN("A troublesome circuit (3)") {
// https://github.com/CQCL/tket/issues/1468
Circuit c0(6);
c0.add_op<unsigned>(OpType::XXPhase, 0.5, {1, 4});
c0.add_op<unsigned>(OpType::XXPhase, 1.5, {2, 3});
c0.add_op<unsigned>(OpType::XXPhase, 2.5, {1, 3});
c0.add_op<unsigned>(OpType::YYPhase, 0.5, {4, 5});
c0.add_op<unsigned>(OpType::YYPhase, 1.5, {4, 2});
c0.add_op<unsigned>(OpType::YYPhase, 2.5, {3, 1});
c0.add_op<unsigned>(OpType::ZZPhase, 0.5, {0, 3});
c0.add_op<unsigned>(OpType::ZZPhase, 1.5, {4, 1});
c0.add_op<unsigned>(OpType::ZZPhase, 2.5, {0, 5});
CompilationUnit cu(c0);
gen_clifford_resynthesis_pass()->apply(cu);
Circuit c1 = cu.get_circ_ref();
std::vector<Command> cmds = c1.get_commands();
CHECK(std::all_of(cmds.begin(), cmds.end(), [](const Command &cmd) {
return cmd.get_op_ptr()->is_clifford();
}));
CHECK(c1.count_n_qubit_gates(2) <= c0.count_n_qubit_gates(2));
}
}

} // namespace test_CliffordResynthesis
Expand Down

0 comments on commit 3df27b8

Please sign in to comment.