Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix wire swap handling in the creation of a phase poly box [TKET-1653] #146

Merged
merged 3 commits into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions tket/src/Circuit/Circuit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1272,6 +1272,17 @@ class Circuit {
*/
void replace_SWAPs();

/**
* this function replaces an implicit wire swap between the two given qubits
* with three CX operations
*
* @param first qubits to add the wireswap on
* @param second qubits to add the wireswap on
*
* O(c)
*/
void replace_implicit_wire_swap(const Qubit first, const Qubit second);

// O(E+V+q)
Circuit dagger() const;

Expand Down
12 changes: 12 additions & 0 deletions tket/src/Circuit/macro_manipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,18 @@ void Circuit::replace_SWAPs() {
remove_vertices(bin, GraphRewiring::No, VertexDeletion::Yes);
}

void Circuit::replace_implicit_wire_swap(
const Qubit first, const Qubit second) {
add_op<UnitID>(OpType::CX, {first, second});
add_op<UnitID>(OpType::CX, {second, first});
Vertex cxvertex = add_op<UnitID>(OpType::CX, {first, second});
EdgeVec outs = get_all_out_edges(cxvertex);
Edge out1 = outs[0];
dag[out1].ports.first = 1;
Edge out2 = outs[1];
dag[out2].ports.first = 0;
}

// helper functions for the dagger and transpose
void Circuit::_handle_boundaries(Circuit& circ, vertex_map_t& vmap) const {
// Handle boundaries
Expand Down
45 changes: 41 additions & 4 deletions tket/src/Converters/PhasePoly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,55 @@ Circuit gray_synth(

PhasePolyBox::PhasePolyBox(const Circuit& circ)
: Box(OpType::PhasePolyBox), n_qubits_(circ.n_qubits()) {
if (circ.n_bits() != 0)
Circuit newcirc(circ);

// check for classical bits
if (newcirc.n_bits() != 0)
throw NotValid(
"Cannot construct phase polynomial from classical controlled "
"gates");

// check the gateset of the circuit
for (const Command& com : newcirc) {
OpType ot = com.get_op_ptr()->get_type();

switch (ot) {
case OpType::CX: {
break;
}
case OpType::Rz: {
break;
}
default: {
throw NotValid("Only CXs and Rzs allowed in Phase Polynomials");
}
}
}

// replace wireswaps with three CX
while (newcirc.has_implicit_wireswaps()) {
bool foundswap = false;

qubit_map_t perm = newcirc.implicit_qubit_permutation();
for (const std::pair<const Qubit, Qubit>& pair : perm) {
if (pair.first != pair.second) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it ever possible for the first and second qubits to be the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is the case when the wire is not involved in the permutation.

if (!foundswap) {
newcirc.replace_implicit_wire_swap(pair.first, pair.second);
foundswap = true;
}
}
}
}

// generate box
signature_ = op_signature_t(n_qubits_, EdgeType::Quantum);
unsigned i = 0;
for (const Qubit& qb : circ.all_qubits()) {
for (const Qubit& qb : newcirc.all_qubits()) {
qubit_indices_.insert({qb, i});
++i;
}
linear_transformation_ = MatrixXb::Identity(n_qubits_, n_qubits_);
for (const Command& com : circ) {
for (const Command& com : newcirc) {
OpType ot = com.get_op_ptr()->get_type();
unit_vector_t qbs = com.get_args();
if (ot == OpType::CX) {
Expand All @@ -180,7 +217,7 @@ PhasePolyBox::PhasePolyBox(const Circuit& circ)
else
pp_it->second += com.get_op_ptr()->get_params().at(0);
} else
throw NotImplemented("Only CXs and Rzs allowed in Phase Polynomials");
TKET_ASSERT(!"Only CXs and Rzs allowed in Phase Polynomials");
}
}

Expand Down
34 changes: 34 additions & 0 deletions tket/tests/test_PhasePolynomials.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,40 @@ SCENARIO("Test conversion of circuit to circuit with phase poly boxes") {
REQUIRE(test_statevector_comparison(circ, result));
}
}
SCENARIO("Phase polynomial synthesis without architecture") {
GIVEN("single SWAP circuit") {
Circuit circ(2);
circ.add_op<unsigned>(OpType::SWAP, {0, 1});
circ.replace_SWAPs();
PhasePolyBox ppbox(circ);
std::shared_ptr<Circuit> circptr = ppbox.to_circuit();
Circuit circ2 = *circptr;
REQUIRE(test_unitary_comparison(circ, circ2));
}
GIVEN("more SWAP circuit") {
Circuit circ(5);
circ.add_op<unsigned>(OpType::SWAP, {0, 1});
circ.add_op<unsigned>(OpType::SWAP, {0, 2});
circ.add_op<unsigned>(OpType::SWAP, {0, 3});
circ.replace_SWAPs();
PhasePolyBox ppbox(circ);
std::shared_ptr<Circuit> circptr = ppbox.to_circuit();
Circuit circ2 = *circptr;
REQUIRE(test_unitary_comparison(circ, circ2));
}
GIVEN("more SWAP circuit II") {
Circuit circ(5);
circ.add_op<unsigned>(OpType::SWAP, {0, 1});
circ.add_op<unsigned>(OpType::SWAP, {1, 2});
circ.add_op<unsigned>(OpType::SWAP, {2, 3});
circ.add_op<unsigned>(OpType::SWAP, {3, 4});
circ.replace_SWAPs();
PhasePolyBox ppbox(circ);
std::shared_ptr<Circuit> circptr = ppbox.to_circuit();
Circuit circ2 = *circptr;
REQUIRE(test_unitary_comparison(circ, circ2));
}
}

} // namespace test_PhasePolynomials
} // namespace tket