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

Update Noise Aware Placement for Circuits with only single qubit gates #1165

Merged
merged 7 commits into from
Dec 8, 2023
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
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.71@tket/stable")
self.requires("tket/1.2.72@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
7 changes: 3 additions & 4 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ Deprecations:

Fixes:

* Fix `PauliFrameRandomisation.sample_circuits`.

Fixes:

* Ensure that squashing long sequences of gates via unitary multiplication does
not produce non-unitary results due to rounding errors.
* Fix `PauliFrameRandomisation.sample_circuits`.
* For `Circuit` with no 2-qubit gates, `NoiseAwarePlacement` now assigns `Qubit` to `Node` in `Architecture`
with lowest reported error rates.


1.22.0 (November 2023)
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.71"
version = "1.2.72"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
29 changes: 29 additions & 0 deletions tket/src/Placement/NoiseAwarePlacement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,35 @@ std::vector<std::map<Qubit, Node>> NoiseAwarePlacement::get_all_placement_maps(
const Circuit& circ_, unsigned matches) const {
std::vector<WeightedEdge> weighted_pattern_edges =
this->default_pattern_weighting(circ_);

if (weighted_pattern_edges.empty()) {
// => there are no two-qubit gates in the input circuit
// in this case, as this method is "noise-aware", assign
// qubits in the circuit to the lowest-error architecture nodes
std::vector<std::pair<gate_error_t, Node>> all_node_errors;
for (const Node& node : this->architecture_.nodes()) {
all_node_errors.push_back(
{this->characterisation_.get_error(node), node});
}
// make sure all_node_errors goes from best->worst error rates
// N.B. `get_error` returns "0", i.e. no error, if the `Node` passed
// is not held in the characterisation
std::sort(
all_node_errors.begin(), all_node_errors.end(),
[](const auto& lhs, const auto& rhs) {
// Compare based on the float values in descending order
return lhs.first < rhs.first;
});
std::vector<Qubit> circ_qubits = circ_.all_qubits();
TKET_ASSERT(all_node_errors.size() >= circ_qubits.size());
std::map<Qubit, Node> placement_map;
// assign circuit qubits to Node with best error rate
for (std::size_t i = 0; i < circ_qubits.size(); i++) {
placement_map.insert({circ_qubits[i], all_node_errors[i].second});
}
return {placement_map};
}

std::vector<boost::bimap<Qubit, Node>> placement_maps =
this->get_all_weighted_subgraph_monomorphisms(
circ_, weighted_pattern_edges, true);
Expand Down
40 changes: 33 additions & 7 deletions tket/test/src/Placement/test_NoiseAwarePlacement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ SCENARIO("Base NoiseAwarePlacement class") {
Circuit circuit(1);
NoiseAwarePlacement placement(architecture);
placement.place(circuit);
REQUIRE(circuit.all_qubits()[0] == Qubit(Placement::unplaced_reg(), 0));
REQUIRE(circuit.all_qubits()[0] == Node(0));
}
GIVEN(
"Two qubit unconnected circuit, two qubit Architecture, "
Expand All @@ -51,8 +51,8 @@ SCENARIO("Base NoiseAwarePlacement class") {
Circuit circuit(2);
NoiseAwarePlacement placement(architecture);
placement.place(circuit);
REQUIRE(circuit.all_qubits()[0] == Qubit(Placement::unplaced_reg(), 0));
REQUIRE(circuit.all_qubits()[1] == Qubit(Placement::unplaced_reg(), 1));
REQUIRE(circuit.all_qubits()[0] == Node(0));
REQUIRE(circuit.all_qubits()[1] == Node(1));
}
GIVEN(
"Three qubit unconnected circuit, two qubit Architecture, "
Expand Down Expand Up @@ -231,8 +231,8 @@ SCENARIO("Base NoiseAwarePlacement class") {
circuit.add_op<unsigned>(OpType::CX, {1, 2});
circuit.add_op<unsigned>(OpType::CX, {2, 3});
circuit.add_op<unsigned>(OpType::CX, {0, 3});
// In this case there are many valid placements, it happens to return this
// one
// In this case there are many valid placements, it happens to return
// this one
NoiseAwarePlacement placement(architecture);
std::map<Qubit, Node> map = placement.get_placement_map(circuit);
REQUIRE(map[Qubit(0)] == Node(3));
Expand Down Expand Up @@ -276,8 +276,8 @@ SCENARIO("Base NoiseAwarePlacement class") {
DeviceCharacterisation characterisation_link_node(
op_node_errors, op_link_errors);

// Here the difference in single qubit error rates makes this placement (or
// a rotation of) best
// Here the difference in single qubit error rates makes this placement
// (or a rotation of) best
placement.set_characterisation(characterisation_link_node);
map = placement.get_placement_map(circuit);

Expand Down Expand Up @@ -408,5 +408,31 @@ SCENARIO("Base NoiseAwarePlacement class") {
REQUIRE(map[Qubit(4)] == Node(1));
REQUIRE(map[Qubit(5)] == Node(2));
}
GIVEN(
"A circuit with only single-qubit gates, assigns Qubits to Nodes with "
"lowest single qubit error rates.") {
std::vector<std::pair<unsigned, unsigned>> edges = {
{0, 1}, {1, 2}, {0, 2}, {2, 3}};
Architecture architecture(edges);
Circuit circuit(3);
circuit.add_op<unsigned>(OpType::H, {0});
circuit.add_op<unsigned>(OpType::H, {1});
circuit.add_op<unsigned>(OpType::H, {2});

avg_node_errors_t op_node_errors;
op_node_errors[Node(0)] = 0.25;
op_node_errors[Node(1)] = 0.01;
op_node_errors[Node(2)] = 0.01;
op_node_errors[Node(3)] = 0.05;

DeviceCharacterisation characterisation(op_node_errors, {}, {});
NoiseAwarePlacement placement(architecture);
placement.set_characterisation(characterisation);

std::map<Qubit, Node> placement_map = placement.get_placement_map(circuit);
REQUIRE(placement_map[Qubit(0)] == Node(1));
REQUIRE(placement_map[Qubit(1)] == Node(2));
REQUIRE(placement_map[Qubit(2)] == Node(3));
}
}
} // namespace tket
Loading