tket
Loading...
Searching...
No Matches
PauliPartition.cpp
Go to the documentation of this file.
1// Copyright Quantinuum
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
17#include <numeric>
18#include <tkassert/Assert.hpp>
19
22
23namespace tket {
24
26 const std::list<SpPauliString>& strings, PauliPartitionStrat strat) {
27 pac_graph = {};
28 for (const SpPauliString& tensor : strings) {
29 PauliACVertex new_vert = boost::add_vertex(tensor, pac_graph);
30 BGL_FORALL_VERTICES(v, pac_graph, PauliACGraph) {
31 if (v != new_vert) {
32 switch (strat) {
34 bool conflict = !tensor.conflicting_qubits(pac_graph[v]).empty();
35 if (conflict) boost::add_edge(new_vert, v, pac_graph);
36 break;
37 }
39 if (!tensor.commutes_with(pac_graph[v])) {
40 boost::add_edge(new_vert, v, pac_graph);
41 }
42 break;
43 }
44 default: {
46 }
47 }
48 }
49 }
50 }
51}
52
53// Consider templatising this and putting it into the graph routines.
54// The purpose is to take a boost graph and convert it
55// into our format, ready for graph colouring.
56// Surely an insignificant overhead unless the graph is tiny.
57// MAYBE consider changing our graph colouring routines,
58// by templatising/converting to boost-style.
59class AbstractGraphData {
60 public:
61 // All the conversion work is done inside the constructor.
62 explicit AbstractGraphData(const PauliACGraph& pac_graph);
63
64 // Return the ID of the string (and also assign a new ID if the string
65 // was not seen before); the eventual IDs will form an interval {0,1,2,...,n}.
66 std::size_t get_vertex_id(const SpPauliString& pauli_string);
67
68 typedef
69 // KEY: the Pauli string present in a vertex
70 // VALUE: an integer label for that vertex.
71 // The labels will be a contiguous interval {0,1,2,...,m}.
72 std::map<SpPauliString, std::size_t>
73 VertexMap;
74
75 const graphs::AdjacencyData& get_adjacency_data() const;
76
77 const VertexMap& get_vertex_map() const;
78
79 private:
80 graphs::AdjacencyData m_adjacency_data;
81 VertexMap m_vertex_map;
82};
83
84std::size_t AbstractGraphData::get_vertex_id(
85 const SpPauliString& pauli_string) {
86 const auto citer = m_vertex_map.find(pauli_string);
87 if (citer != m_vertex_map.cend()) {
88 return citer->second;
89 }
90 // Haven't seen this vertex before!
91 const auto new_id = m_vertex_map.size();
92 m_vertex_map[pauli_string] = new_id;
93 return new_id;
94}
95
96const AbstractGraphData::VertexMap& AbstractGraphData::get_vertex_map() const {
97 return m_vertex_map;
98}
99
100const graphs::AdjacencyData& AbstractGraphData::get_adjacency_data() const {
101 return m_adjacency_data;
102}
103
104AbstractGraphData::AbstractGraphData(const PauliACGraph& pac_graph)
105 : m_adjacency_data(boost::num_vertices(pac_graph)) {
106 const auto vertex_iterators = boost::vertices(pac_graph);
107 for (auto v_iter = vertex_iterators.first; v_iter != vertex_iterators.second;
108 ++v_iter) {
109 // NOTE: on Windows, *v_iter appears to be of type uint64,
110 // but presumably this is an internal Boost implementation detail
111 // and we cannot rely on this.
112 // (It might even be that the Boost vertex IDs are contiguous,
113 // just like ours, in which case this conversion
114 // is unnecessary - but again, we cannot rely on this).
115 const auto this_vertex_id = get_vertex_id(pac_graph[*v_iter]);
116 const auto neighbour_iterators =
117 boost::adjacent_vertices(*v_iter, pac_graph);
118
119 for (auto n_iter = neighbour_iterators.first;
120 n_iter != neighbour_iterators.second; ++n_iter) {
121 m_adjacency_data.add_edge(
122 this_vertex_id, get_vertex_id(pac_graph[*n_iter]));
123 }
124 }
125}
126
127static std::map<unsigned, std::list<SpPauliString>>
128get_partitioned_paulis_for_exhaustive_method(const PauliACGraph& pac_graph) {
129 const AbstractGraphData data(pac_graph);
130 const graphs::GraphColouringResult colouring =
131 graphs::GraphColouringRoutines ::get_colouring(data.get_adjacency_data());
132
133 TKET_ASSERT(data.get_vertex_map().size() == colouring.colours.size());
134
135 std::map<unsigned, std::list<SpPauliString>> colour_map;
136
137 for (const auto& entry : data.get_vertex_map()) {
138 const SpPauliString& vertex = entry.first;
139 const std::size_t id = entry.second;
140 TKET_ASSERT(id < colouring.colours.size());
141
142 // "id" is the index of this vertex.
143 const std::size_t colour = colouring.colours[id];
144 TKET_ASSERT(colour < colouring.number_of_colours);
145
146 colour_map[colour].push_back(vertex);
147 }
148 if (!colour_map.empty()) {
149 TKET_ASSERT(colour_map.size() == 1 + colour_map.crbegin()->first);
150 TKET_ASSERT(colour_map.cbegin()->first == 0);
151 }
152 return colour_map;
153}
154
155static std::map<unsigned, std::list<SpPauliString>>
156get_partitioned_paulis_for_largest_first_method(const PauliACGraph& pac_graph) {
157 std::vector<unsigned> order_vec(boost::num_vertices(pac_graph));
158 std::iota(order_vec.begin(), order_vec.end(), 0);
159
160 std::sort(order_vec.begin(), order_vec.end(), [&](unsigned i, unsigned j) {
161 return (boost::out_degree(i, pac_graph) > boost::out_degree(j, pac_graph));
162 });
163
164 /* Some boost machinery */
165 std::vector<unsigned> colour_vec(boost::num_vertices(pac_graph));
166 boost::iterator_property_map<
167 unsigned*,
168 boost::property_map<PauliACGraph, boost::vertex_index_t>::const_type>
169 colour_prop_map(
170 &colour_vec.front(), boost::get(boost::vertex_index, pac_graph));
171 boost::sequential_vertex_coloring(
172 pac_graph,
173 boost::make_iterator_property_map(
174 order_vec.begin(), boost::identity_property_map()),
175 colour_prop_map);
176
177 std::map<unsigned, std::list<SpPauliString>> colour_map;
178 BGL_FORALL_VERTICES(v, pac_graph, PauliACGraph) {
179 unsigned v_colour = colour_prop_map[v];
180 colour_map[v_colour].push_back(pac_graph[v]);
181 }
182 return colour_map;
183}
184
185std::map<unsigned, std::list<SpPauliString>>
187 switch (method) {
189 return get_partitioned_paulis_for_largest_first_method(pac_graph);
190
192 return get_partitioned_paulis_for_exhaustive_method(pac_graph);
193
195 throw std::logic_error(
196 "Lazy graph colouring should never reach this point");
197
198 default: {
199 throw std::logic_error("Unknown graph colouring method");
200 }
201 }
202}
203
204static std::list<std::list<SpPauliString>>
205get_term_sequence_for_lazy_colouring_method(
206 const std::list<SpPauliString>& strings, PauliPartitionStrat strat) {
207 std::list<std::list<SpPauliString>> terms;
208 for (const SpPauliString& qpt : strings) {
209 if (terms.empty()) {
210 terms.push_back({qpt});
211 continue;
212 }
213
214 bool found_bin = false;
215 for (std::list<SpPauliString>& qpt_list : terms) {
216 bool viable_bin = true;
217 for (const SpPauliString& qpt2 : qpt_list) {
218 switch (strat) {
220 bool conflict = !qpt.conflicting_qubits(qpt2).empty();
221 if (conflict) viable_bin = false;
222 break;
223 }
225 if (!qpt.commutes_with(qpt2)) viable_bin = false;
226 break;
227 }
228 default: {
229 throw UnknownPauliPartitionStrat();
230 }
231 }
232
233 if (viable_bin == false) break;
234 }
235 if (viable_bin) {
236 qpt_list.push_back(qpt);
237 found_bin = true;
238 break;
239 }
240 }
241
242 if (found_bin == false) {
243 terms.push_back({qpt});
244 }
245 }
246 return terms;
247}
248
249static std::list<std::list<SpPauliString>>
250get_term_sequence_with_constructed_dependency_graph(
251 const std::list<SpPauliString>& strings, PauliPartitionStrat strat,
252 GraphColourMethod method) {
253 std::list<std::list<SpPauliString>> terms;
254 PauliPartitionerGraph pp(strings, strat);
255 std::map<unsigned, std::list<SpPauliString>> colour_map =
256 pp.partition_paulis(method);
257
258 for (const std::pair<const unsigned, std::list<SpPauliString>>& colour_pair :
259 colour_map) {
260 terms.push_back(colour_pair.second);
261 }
262 return terms;
263}
264
265std::list<std::list<SpPauliString>> term_sequence(
266 const std::list<SpPauliString>& strings, PauliPartitionStrat strat,
267 GraphColourMethod method) {
268 switch (method) {
270 return get_term_sequence_for_lazy_colouring_method(strings, strat);
271
273 // Deliberate fall through
275 return get_term_sequence_with_constructed_dependency_graph(
276 strings, strat, method);
277 default:
278 throw std::logic_error("term_sequence : unknown graph colouring method");
279 }
280}
281
282} // namespace tket
PauliPartitionerGraph(const std::list< SpPauliString > &strings, PauliPartitionStrat strat)
std::map< unsigned, std::list< SpPauliString > > partition_paulis(GraphColourMethod method) const
PauliTensor<PauliContainer, CoeffType>
Data for an undirected graph.
const Transform id
Identity transform (does nothing, returns false)
Definition Transform.hpp:87
detail::vertex< T > vertex
Definition Utils.hpp:34
Defines tket::DeviceCharacterisation, used in NoiseAwarePlacement and in commute_SQ_gates_through_SWA...
Definition Path.cpp:22
PauliPartitionStrat
A choice of strategies to partition Pauli tensors into sets.
@ CommutingSets
Sets of mutually commuting tensors; requires O(n^2) CXs for diagonalisation.
@ NonConflictingSets
Sets of tensors with no conflicting Paulis; requires no CXs for diagonalisation.
GraphColourMethod
A choice of methods to perform graph colouring for Pauli partitioning.
@ LargestFirst
Builds the graph and then greedily colours by iterating through the vertices, with the highest degree...
@ Lazy
Lazy: does not build the graph before performing the colouring; partitions while iterating through th...
@ Exhaustive
Builds the graph, then colours it using the minimum possible number of colours.
boost::graph_traits< PauliACGraph >::vertex_descriptor PauliACVertex
boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, SpPauliString > PauliACGraph
A PauliACGraph is a graph where each vertex is a Pauli tensor, and an edge corresponds to anticommuti...
PauliTensor< QubitPauliMap, no_coeff_t > SpPauliString
std::list< std::list< SpPauliString > > term_sequence(const std::list< SpPauliString > &strings, PauliPartitionStrat strat, GraphColourMethod method)
Partitions a QubitOperator into lists of mutually commuting gadgets.