Skip to content

Commit

Permalink
fix: Handle classical control in PhasedXFrontier (#1338)
Browse files Browse the repository at this point in the history
  • Loading branch information
lmondada authored Apr 15, 2024
1 parent 46961c7 commit e5c5e5c
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 2 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.2.114@tket/stable")
self.requires("tket/1.2.115@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
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.2.114"
version = "1.2.115"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
33 changes: 33 additions & 0 deletions tket/include/tket/Transformations/PhasedXFrontier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#pragma once

#include <cmath>
#include <optional>
#include <set>

#include "SingleQubitSquash.hpp"
Expand Down Expand Up @@ -289,13 +290,45 @@ class PhasedXFrontier {

// squasher to squash gates
SingleQubitSquash squasher_;

// Access class attributes for testing
friend class PhasedXFrontierTester;
};

/**
* @brief Whether all elements of `vec` are std::nullopt.
*/
bool all_nullopt(const OptVertexVec& vec);

/**
* @brief Testing class for the PhasedXFrontier class.
*
* Gives access to current interval start and end vertices.
*/
class PhasedXFrontierTester {
public:
PhasedXFrontierTester(PhasedXFrontier& frontier, Circuit& circ);

/**
* @brief Get the start of the interval on qubit `i`.
*
* @param i The qubit index.
* @return Vertex The gate before the current interval on qubit `i`.
*/
Vertex get_interval_start(unsigned i);
/**
* @brief Get the end of the interval on qubit `i`.
*
* @param i The qubit index.
* @return Vertex The gate after the current interval on qubit `i`.
*/
Vertex get_interval_end(unsigned i);

private:
PhasedXFrontier const& frontier_;
Circuit const& circ_;
};

} // namespace Transforms

} // namespace tket
21 changes: 21 additions & 0 deletions tket/src/Transformations/PhasedXFrontier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ Edge PhasedXFrontier::get_interval_start(Edge e) const {

bool PhasedXFrontier::is_interval_boundary(Op_ptr op) {
OpType type = op->get_type();
if (type == OpType::Conditional) {
// We currently split intervals on Conditional gates even if they
// are single-qubit gates, as there is no simple way to guarantee that
// classically controlled gates are space-like separated without making
// additional assumptions or walking the DAG.
return true;
}
return is_gate_type(type) && as_gate_ptr(op)->n_qubits() > 1 &&
type != OpType::NPhasedX;
}
Expand Down Expand Up @@ -437,6 +444,20 @@ bool all_nullopt(const OptVertexVec& vec) {
return true;
}

Vertex PhasedXFrontierTester::get_interval_start(unsigned i) {
auto edge = frontier_.intervals_[i].first;
return circ_.source(edge);
}

Vertex PhasedXFrontierTester::get_interval_end(unsigned i) {
auto edge = frontier_.intervals_[i].second;
return circ_.target(edge);
}

PhasedXFrontierTester::PhasedXFrontierTester(
PhasedXFrontier& frontier, Circuit& circ)
: frontier_(frontier), circ_(circ) {}

} // namespace Transforms

} // namespace tket
54 changes: 54 additions & 0 deletions tket/test/src/test_PhasedXFrontier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,5 +297,59 @@ SCENARIO("PhasedXFrontier: Squashing PhasedX") {
}
}

SCENARIO("PhasedXFrontier: Compute intervals") {
GIVEN("A simple circuit") {
Circuit c(2, 1);
c.add_op<unsigned>(OpType::PhasedX, {0.4, 0.3}, {0});
c.add_op<unsigned>(OpType::PhasedX, {0.4, 0.3}, {1});
auto first_cx = c.add_op<unsigned>(OpType::CX, {0, 1});
c.add_op<unsigned>(OpType::PhasedX, {0.4, 0.3}, {0});
auto ctrl_phasedx = c.add_conditional_gate<unsigned>(
OpType::PhasedX, {0.4, 0.3}, {0}, {0}, 1);
c.add_op<unsigned>(OpType::PhasedX, {0.4, 0.3}, {1});
auto ctrl_cx =
c.add_conditional_gate<unsigned>(OpType::CX, {}, {0, 1}, {0}, 1);

Transforms::PhasedXFrontier frontier(c);
Transforms::PhasedXFrontierTester frontier_tester(frontier, c);

THEN("Initial intervals: [input, first_cx] and [input, first_cx]") {
auto inputs = c.all_inputs();
REQUIRE(frontier_tester.get_interval_start(0) == inputs[0]);
REQUIRE(frontier_tester.get_interval_start(1) == inputs[1]);
REQUIRE(frontier_tester.get_interval_end(0) == first_cx);
REQUIRE(frontier_tester.get_interval_end(1) == first_cx);
}

// Move frontier forward
frontier.next_multiqb(first_cx);
THEN("Second intervals: [first_cx, ctrl_phasedx] and [first_cx, ctrl_cx]") {
REQUIRE(frontier_tester.get_interval_start(0) == first_cx);
REQUIRE(frontier_tester.get_interval_start(1) == first_cx);
REQUIRE(frontier_tester.get_interval_end(0) == ctrl_phasedx);
REQUIRE(frontier_tester.get_interval_end(1) == ctrl_cx);
}

// Move frontier forward
frontier.next_multiqb(ctrl_phasedx);
THEN("Third intervals: [ctrl_phasedx, ctrl_cx] and [first_cx, ctrl_cx]") {
REQUIRE(frontier_tester.get_interval_start(0) == ctrl_phasedx);
REQUIRE(frontier_tester.get_interval_start(1) == first_cx);
REQUIRE(frontier_tester.get_interval_end(0) == ctrl_cx);
REQUIRE(frontier_tester.get_interval_end(1) == ctrl_cx);
}

// Move frontier forward
frontier.next_multiqb(ctrl_cx);
THEN("Final intervals: [ctrl_cx, output] and [ctrl_cx, output]") {
auto outputs = c.all_outputs();
REQUIRE(frontier_tester.get_interval_start(0) == ctrl_cx);
REQUIRE(frontier_tester.get_interval_start(1) == ctrl_cx);
REQUIRE(frontier_tester.get_interval_end(0) == outputs[0]);
REQUIRE(frontier_tester.get_interval_end(1) == outputs[1]);
}
}
}

} // namespace test_PhasedXFrontier
} // namespace tket

0 comments on commit e5c5e5c

Please sign in to comment.