Skip to content

Commit

Permalink
Handle NPhasedX gates in decompose_cliffords_std() (#1431)
Browse files Browse the repository at this point in the history
  • Loading branch information
cqc-alec authored Jun 5, 2024
1 parent 5c8d7e4 commit 28556f3
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 38 deletions.
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.2@tket/stable")
self.requires("tket/1.3.3@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 @@ -13,6 +13,7 @@ Features:
Fixes:

* Allow barriers when dagger or transpose a circuit.
* Handle Clifford-angle ``NPhasedX`` gates in Clifford resynthesis.


1.28.0 (May 2024)
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.2"
version = "1.3.3"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
94 changes: 58 additions & 36 deletions tket/src/Transformations/Decomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1111,45 +1111,67 @@ Transform decompose_cliffords_std() {
BGL_FORALL_VERTICES(v, circ.dag, DAG) {
Op_ptr op = circ.get_Op_ptr_from_Vertex(v);
OpType type = op->get_type();
if (type != OpType::V && type != OpType::S && type != OpType::X &&
type != OpType::Z && is_single_qubit_unitary_type(type) &&
op->is_clifford()) {
std::vector<Expr> tk1_param_exprs = as_gate_ptr(op)->get_tk1_angles();
bool all_reduced = true;
bool all_roundable = true;
std::vector<int> iangles(3);
for (int i = 0; i < 3; i++) {
std::optional<double> reduced = eval_expr_mod(tk1_param_exprs[i], 4);
if (!reduced)
all_reduced = false;
else {
double angle = 2 * reduced.value(); // > 0
iangles[i] = int(angle + 0.5); // nearest integer
if (std::abs(angle - iangles[i]) >= EPS) {
all_roundable = false;
if (op->is_clifford()) {
if (type != OpType::V && type != OpType::S && type != OpType::X &&
type != OpType::Z && is_single_qubit_unitary_type(type)) {
std::vector<Expr> tk1_param_exprs = as_gate_ptr(op)->get_tk1_angles();
bool all_reduced = true;
bool all_roundable = true;
std::vector<int> iangles(3);
for (int i = 0; i < 3; i++) {
std::optional<double> reduced =
eval_expr_mod(tk1_param_exprs[i], 4);
if (!reduced)
all_reduced = false;
else {
double angle = 2 * reduced.value(); // > 0
iangles[i] = int(angle + 0.5); // nearest integer
if (std::abs(angle - iangles[i]) >= EPS) {
all_roundable = false;
}
iangles[i] %= 8; // 8 --> 0
}
}
if (!(all_reduced && all_roundable)) continue;
Circuit replacement =
clifford_from_tk1(iangles[0], iangles[1], iangles[2]);
Subcircuit sub = {
{circ.get_in_edges(v)}, {circ.get_all_out_edges(v)}, {v}};
bin.push_back(v);
circ.substitute(replacement, sub, Circuit::VertexDeletion::No);
circ.add_phase(tk1_param_exprs[3]);
success = true;
} else {
switch (type) {
case OpType::TK2: {
auto params = op->get_params();
TKET_ASSERT(params.size() == 3);
// TODO: Maybe handle TK2 gates natively within clifford_simp?
Circuit replacement =
CircPool::TK2_using_CX(params[0], params[1], params[2]);
decompose_cliffords_std().apply(replacement);
bin.push_back(v);
circ.substitute(replacement, v, Circuit::VertexDeletion::No);
success = true;
break;
}
case OpType::NPhasedX: {
auto params = op->get_params();
unsigned n = circ.n_out_edges(v);
Circuit replacement(n);
for (unsigned i = 0; i < n; i++) {
replacement.add_op<Qubit>(OpType::PhasedX, params, {Qubit(i)});
}
decompose_cliffords_std().apply(replacement);
bin.push_back(v);
circ.substitute(replacement, v, Circuit::VertexDeletion::No);
success = true;
break;
}
iangles[i] %= 8; // 8 --> 0
default:
break;
}
}
if (!(all_reduced && all_roundable)) continue;
Circuit replacement =
clifford_from_tk1(iangles[0], iangles[1], iangles[2]);
Subcircuit sub = {
{circ.get_in_edges(v)}, {circ.get_all_out_edges(v)}, {v}};
bin.push_back(v);
circ.substitute(replacement, sub, Circuit::VertexDeletion::No);
circ.add_phase(tk1_param_exprs[3]);
success = true;
} else if (type == OpType::TK2 && op->is_clifford()) {
auto params = op->get_params();
TKET_ASSERT(params.size() == 3);
// TODO: Maybe handle TK2 gates natively within clifford_simp?
Circuit replacement =
CircPool::TK2_using_CX(params[0], params[1], params[2]);
decompose_cliffords_std().apply(replacement);
bin.push_back(v);
circ.substitute(replacement, v, Circuit::VertexDeletion::No);
success = true;
}
}
circ.remove_vertices(
Expand Down
11 changes: 11 additions & 0 deletions tket/test/src/Passes/test_CliffordResynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ SCENARIO("SynthesiseCliffordResynthesis correctness") {
c.add_op<unsigned>(OpType::CY, {1, 0});
check_clifford_resynthesis(c);
}
GIVEN("A Clifford-angle NPhasedX on 1 qubit") {
// https://github.com/CQCL/tket/issues/1408
Circuit c(1);
c.add_op<unsigned>(OpType::NPhasedX, {0.5, 0.0}, {0});
check_clifford_resynthesis(c);
}
GIVEN("A Clifford-angle NPhasedX on 2 qubits") {
Circuit c(2);
c.add_op<unsigned>(OpType::NPhasedX, {0.5, 0.0}, {0, 1});
check_clifford_resynthesis(c);
}
}

} // namespace test_CliffordResynthesis
Expand Down

0 comments on commit 28556f3

Please sign in to comment.