| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | // Copyright 2019-2022 Cambridge Quantum Computing | |||
| 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 | ||||
| 15 | #pragma once | |||
| 16 | ||||
| 17 | #include <algorithm> | |||
| 18 | #include <boost/iterator/transform_iterator.hpp> | |||
| 19 | #include <boost/range/iterator_range_core.hpp> | |||
| 20 | #include <map> | |||
| 21 | #include <set> | |||
| 22 | #include <type_traits> | |||
| 23 | #include <utility> | |||
| 24 | ||||
| 25 | #include "Utils/BiMapHeaders.hpp" | |||
| 26 | #include "Utils/GraphHeaders.hpp" | |||
| 27 | ||||
| 28 | // Implemetation details of `Graphs/Utils.hpp` | |||
| 29 | namespace tket::graphs::utils { | |||
| 30 | ||||
| 31 | // ::detail includes all internal implementation-specific details | |||
| 32 | namespace detail { | |||
| 33 | ||||
| 34 | // Type synonyms for many often-used BGL types | |||
| 35 | template <typename T> | |||
| 36 | using vertex = | |||
| 37 | typename boost::graph_traits<std::remove_reference_t<T>>::vertex_descriptor; | |||
| 38 | template <typename T> | |||
| 39 | using edge = | |||
| 40 | typename boost::graph_traits<std::remove_reference_t<T>>::edge_descriptor; | |||
| 41 | template <typename T> | |||
| 42 | using vertex_index_pmap = typename boost::property_map< | |||
| 43 | std::remove_reference_t<T>, boost::vertex_index_t>::type; | |||
| 44 | template <typename T> | |||
| 45 | using vertex_index = | |||
| 46 | typename boost::property_traits<vertex_index_pmap<T>>::value_type; | |||
| 47 | ||||
| 48 | /* Compile-time boolean flag to check if boost graph type is | |||
| 49 | * directed or undirected graph | |||
| 50 | * | |||
| 51 | * Template Argument Graph is the boost type of the graph to be checked | |||
| 52 | * the second (directedness tag) should be left to default to be inferred | |||
| 53 | * by the compiler ("SFINAE") | |||
| 54 | * | |||
| 55 | * This is available in the public interface as is_directed<Graph> (see | |||
| 56 | * `Utils.hpp`) | |||
| 57 | */ | |||
| 58 | template < | |||
| 59 | typename Graph, typename directed_category = typename boost::graph_traits< | |||
| 60 | std::remove_reference_t<Graph>>::directed_category> | |||
| 61 | struct is_directed_struct { | |||
| 62 | static const bool value = true; | |||
| 63 | }; | |||
| 64 | template <typename Graph> | |||
| 65 | struct is_directed_struct<Graph, boost::undirected_tag> { | |||
| 66 | static const bool value = false; | |||
| 67 | }; | |||
| 68 | ||||
| 69 | /* Compile-time boolean used in template specialisations | |||
| 70 | * and graph_utils_helper_with_map to infer whether the Graph type supports | |||
| 71 | * integer indexing | |||
| 72 | * | |||
| 73 | * has_integral_index<Graph, PMap> is true iff | |||
| 74 | * either the vertex_descriptor of Graph are integers (i.e. VertexList = vecS) | |||
| 75 | * or an explicit property map PMap is provided with integral values | |||
| 76 | * | |||
| 77 | * Template argument Graph is the boost type of the graph to be checked | |||
| 78 | * PMap is the optional property map to provide integral index values | |||
| 79 | * The third argument should always be left to default, used for type inference | |||
| 80 | * ("SFINAE") | |||
| 81 | */ | |||
| 82 | template <typename Graph, typename PMap = void, typename = void> | |||
| 83 | struct has_integral_index_struct { | |||
| 84 | static const bool value = false; | |||
| 85 | }; | |||
| 86 | template <typename Graph> | |||
| 87 | struct has_integral_index_struct< | |||
| 88 | Graph, void, std::enable_if_t<std::is_integral_v<vertex<Graph>>>> { | |||
| 89 | static const bool value = true; | |||
| 90 | }; | |||
| 91 | template <typename Graph, typename PMap> | |||
| 92 | struct has_integral_index_struct< | |||
| 93 | Graph, PMap, | |||
| 94 | std::enable_if_t<std::is_integral_v<typename PMap::mapped_type>>> { | |||
| 95 | static const bool value = true; | |||
| 96 | }; | |||
| 97 | template <typename Graph, typename PMap = void> | |||
| 98 | constexpr bool has_integral_index = | |||
| 99 | has_integral_index_struct<Graph, PMap>::value; | |||
| 100 | ||||
| 101 | // less than comparison using key as compared values | |||
| 102 | template <typename V, typename Func> | |||
| 103 | 932 | auto lt_with_key(const Func& key) { | ||
| 104 | 34733 | return [&key](const V& v1, const V& v2) { return key(v1) < key(v2); }; | ||
| 105 | } | |||
| 106 | ||||
| 107 | /* This class, along with their inherited classes and template specialisations | |||
| 108 | * below implement the graphs::utils helper functions, defined further below. | |||
| 109 | * | |||
| 110 | * CLASS HIERARCHY | |||
| 111 | * --------------- | |||
| 112 | * +---------------------+ +---------------------------+ | |||
| 113 | * Base classes: | graph_utils_base | | graph_utils_base_with_ind | | |||
| 114 | * +---------------------+ +---------------------------+ | |||
| 115 | * | | | | | |||
| 116 | * v v v v | |||
| 117 | * Container-specific +---------+ +---------+ +---------+ +---------+ | |||
| 118 | * classes | _helper | | _helper | | _helper | | _helper | | |||
| 119 | * (pmap / indexable) | YES/NO | | NO/NO | | YES/YES | | NO/YES | | |||
| 120 | * +---------+ +---------+ +---------+ +---------+ | |||
| 121 | * | | | | | | | | | |||
| 122 | * | | | | +-------+ | | | | | |||
| 123 | * Child class to be used | | | +->| _impl |<--+ | | | | |||
| 124 | * in utils | +------------>| |<--------------+ | | |||
| 125 | * | | +-------+ | | | |||
| 126 | * v v v v | |||
| 127 | * Container-specific +---------+ +---------+ +---------+ +---------+ | |||
| 128 | * classes with added | _helper | | _helper | | _helper | | _helper | | |||
| 129 | * support for maps |_with_map| |_with_map| |_with_map| |_with_map| | |||
| 130 | * (pmap / indexable) | YES/NO | | NO/NO | | YES/YES | | NO/YES | | |||
| 131 | * +---------+ +---------+ +---------+ +---------+ | |||
| 132 | * | | | | | |||
| 133 | * | | +---------+ | | | |||
| 134 | * Child class to be used | +->| _impl |<----+ | | |||
| 135 | * in utils with map support +------------>|_with_map|<---------------+ | |||
| 136 | * +---------+ | |||
| 137 | * | |||
| 138 | * graph_utils_base and graph_utils_base_with_ind implement the functionality | |||
| 139 | * that is shared among all vertex container types (i.e. most of the code logic) | |||
| 140 | * | |||
| 141 | * Impl must be a subclass of this and must implement | |||
| 142 | * - on_remove_vertex: event handler when vertex is removed | |||
| 143 | */ | |||
| 144 | template <typename Graph, typename Impl> | |||
| 145 | class graph_utils_base { | |||
| 146 | public: | |||
| 147 | 1120 | explicit graph_utils_base(Graph& g) : graph(g) {} | ||
| 148 | ||||
| 149 | 1084 | void remove_vertex(vertex<Graph> v) { | ||
| 150 | 1084 | remove_vertex_handler(v); | ||
| 151 | 1084 | boost::remove_vertex(v, graph); | ||
| 152 | 1084 | } | ||
| 153 | ||||
| 154 | 52 | void remove_edge(edge<Graph> e, bool remove_unused_vertices = false) { | ||
| 155 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | auto [u, v] = get_vertex_pair(e); | |
| 156 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | boost::remove_edge(e, graph); | |
| 157 | ||||
| 158 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 1 times.
|
2/2✓ Decision 'true' taken 51 times.
✓ Decision 'false' taken 1 times.
|
52 | if (remove_unused_vertices) { |
| 159 |
3/4✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 37 times.
|
2/2✓ Decision 'true' taken 14 times.
✓ Decision 'false' taken 37 times.
|
51 | if (boost::degree(u, graph) == 0) { |
| 160 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | remove_vertex(u); | |
| 161 | } | |||
| 162 |
3/4✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 49 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 49 times.
|
51 | if (boost::degree(v, graph) == 0) { |
| 163 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | remove_vertex(v); | |
| 164 | } | |||
| 165 | } | |||
| 166 | 52 | } | ||
| 167 | ||||
| 168 | protected: | |||
| 169 | ✗ | virtual void remove_vertex_handler(vertex<Graph> v) { | ||
| 170 | ✗ | Impl* impl = static_cast<Impl*>(this); | ||
| 171 | ✗ | impl->on_remove_vertex(v); | ||
| 172 | } | |||
| 173 | ||||
| 174 | /* returns source and target in an order in which they can be | |||
| 175 | * safely deleted if necessary | |||
| 176 | */ | |||
| 177 | 52 | std::pair<vertex<Graph>, vertex<Graph>> get_vertex_pair(edge<Graph> e) { | ||
| 178 | 52 | vertex<Graph> u = boost::source(e, graph); | ||
| 179 | 52 | vertex<Graph> v = boost::target(e, graph); | ||
| 180 | ||||
| 181 | 52 | return in_delete_order(u, v); | ||
| 182 | } | |||
| 183 | ||||
| 184 | ✗ | virtual std::pair<vertex<Graph>, vertex<Graph>> in_delete_order( | ||
| 185 | vertex<Graph> u, vertex<Graph> v) { | |||
| 186 | ✗ | return {u, v}; | ||
| 187 | } | |||
| 188 | ||||
| 189 | Graph& graph; | |||
| 190 | }; | |||
| 191 | ||||
| 192 | /* small adjustments to graph_utils_helper for integral vertex indices. | |||
| 193 | * Unlike the general case, here indices get shifted when vertices are deleted | |||
| 194 | * so that the vertex indices remain contiguous | |||
| 195 | * | |||
| 196 | * Impl must be a subclass of this and must implement | |||
| 197 | * - to_index: return index of vertex v | |||
| 198 | * - typename index_type: type of index returned by to_index | |||
| 199 | * - on_index_change: event handler when indices are shifted | |||
| 200 | * - on_remove_vertex: event handler when vertex is removed, after all | |||
| 201 | * indices were updated | |||
| 202 | */ | |||
| 203 | template <typename Graph, typename Impl> | |||
| 204 | class graph_utils_base_with_ind : public graph_utils_base<Graph, Impl> { | |||
| 205 | private: | |||
| 206 | using Base = graph_utils_base<Graph, Impl>; | |||
| 207 | ||||
| 208 | public: | |||
| 209 | 1120 | explicit graph_utils_base_with_ind(Graph& g) : Base(g) {} | ||
| 210 | ||||
| 211 | protected: | |||
| 212 | using Base::graph; | |||
| 213 | 1084 | void remove_vertex_handler(vertex<Graph> v) override { | ||
| 214 | 1084 | Impl* impl = static_cast<Impl*>(this); | ||
| 215 | using index_type = typename Impl::index_type; | |||
| 216 | ||||
| 217 |
7/12✓ Branch 1 taken 1084 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1084 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 80117 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 80117 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 81201 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 80117 times.
✓ Branch 18 taken 1084 times.
|
0/1? Decision couldn't be analyzed.
|
81201 | for (vertex<Graph> u : boost::make_iterator_range(boost::vertices(graph))) { |
| 218 |
2/2✓ Branch 2 taken 74502 times.
✓ Branch 3 taken 5615 times.
|
2/2✓ Decision 'true' taken 74502 times.
✓ Decision 'false' taken 5615 times.
|
80117 | if (impl->to_index(u) > impl->to_index(v)) { |
| 219 | 74502 | index_type new_ind = impl->to_index(u) - 1; | ||
| 220 |
1/2✓ Branch 1 taken 74494 times.
✗ Branch 2 not taken.
|
74502 | impl->on_index_change(u, new_ind); | |
| 221 | } | |||
| 222 | } | |||
| 223 | 1084 | impl->on_remove_vertex(v); | ||
| 224 | 1084 | } | ||
| 225 | ||||
| 226 | 52 | std::pair<vertex<Graph>, vertex<Graph>> in_delete_order( | ||
| 227 | vertex<Graph> u, vertex<Graph> v) override { | |||
| 228 | 52 | Impl* impl = static_cast<Impl*>(this); | ||
| 229 | ||||
| 230 | // return larger index first | |||
| 231 |
2/2✓ Branch 2 taken 39 times.
✓ Branch 3 taken 13 times.
|
2/2✓ Decision 'true' taken 39 times.
✓ Decision 'false' taken 13 times.
|
52 | if (impl->to_index(u) < impl->to_index(v)) { |
| 232 | 39 | return {v, u}; | ||
| 233 | } else { | |||
| 234 | 13 | return {u, v}; | ||
| 235 | } | |||
| 236 | } | |||
| 237 | }; | |||
| 238 | ||||
| 239 | /* The classes graph_utils_helper and graph_utils_helper_with_map provide | |||
| 240 | * the container-specific implementation bits. | |||
| 241 | * The Derived template type is the child class that inherits from this class | |||
| 242 | * -> see Curiously Recurring Template Pattern (CRTP) | |||
| 243 | * The Indexable boolean template is true iff Graph support integer vertex | |||
| 244 | * indexing (see has_integral_index). It should be left to default and infered | |||
| 245 | * by compiler | |||
| 246 | * | |||
| 247 | * We distinguish four cases for template specialisations, given by the four | |||
| 248 | * combinations of two variables: | |||
| 249 | * | |||
| 250 | * a) whether an explicit property map is provided or not | |||
| 251 | * b) whether the graph is indexable, i.e. either it has an intrinsic | |||
| 252 | * vertex_index property (case VertexList == vecS) or the property map has | |||
| 253 | * integral values | |||
| 254 | * | |||
| 255 | * Case 1: explicit property map, not indexable | |||
| 256 | */ | |||
| 257 | template < | |||
| 258 | typename Derived, typename Graph, typename PMap = void, | |||
| 259 | bool Indexable = has_integral_index<Graph, PMap>> | |||
| 260 | class graph_utils_helper : public graph_utils_base<Graph, Derived> { | |||
| 261 | private: | |||
| 262 | using Base = graph_utils_base<Graph, Derived>; | |||
| 263 | ||||
| 264 | public: | |||
| 265 | graph_utils_helper(Graph& g, PMap& p) : Base(g), pmap(p) {} | |||
| 266 | ||||
| 267 | void on_remove_vertex(vertex<Graph> v) { pmap.erase(v); } | |||
| 268 | ||||
| 269 | private: | |||
| 270 | PMap& pmap; | |||
| 271 | }; | |||
| 272 | ||||
| 273 | // Case 2: no explicit property, not indexable | |||
| 274 | template <typename Derived, typename Graph> | |||
| 275 | class graph_utils_helper<Derived, Graph, void, false> | |||
| 276 | : public graph_utils_base<Graph, Derived> { | |||
| 277 | private: | |||
| 278 | using Base = graph_utils_base<Graph, Derived>; | |||
| 279 | ||||
| 280 | public: | |||
| 281 | explicit graph_utils_helper(Graph& g) : Base(g) {} | |||
| 282 | void on_remove_vertex(vertex<Graph>) {} | |||
| 283 | }; | |||
| 284 | ||||
| 285 | // Case 3: explicit property, indexable | |||
| 286 | // in this case we must ensure that we update the property map | |||
| 287 | // when vertices are removed and indices get shifted | |||
| 288 | template <typename Derived, typename Graph, typename PMap> | |||
| 289 | class graph_utils_helper<Derived, Graph, PMap, true> | |||
| 290 | : public graph_utils_base_with_ind<Graph, Derived> { | |||
| 291 | private: | |||
| 292 | using Base = graph_utils_base_with_ind<Graph, Derived>; | |||
| 293 | ||||
| 294 | public: | |||
| 295 | using index_type = typename PMap::mapped_type; | |||
| 296 | graph_utils_helper(Graph& g, PMap& p) : Base(g), pmap(p), new_pmap(p) { | |||
| 297 | static_assert( | |||
| 298 | !std::is_integral_v<vertex<Graph>>, | |||
| 299 | "Ambiguous vertex index: you cannot provide an explicit " | |||
| 300 | "index property map if vertex descriptors are integrals."); | |||
| 301 | } | |||
| 302 | ||||
| 303 | index_type to_index(vertex<Graph> v) { return pmap[v]; } | |||
| 304 | ||||
| 305 | void on_index_change(vertex<Graph> v, index_type new_ind) { | |||
| 306 | new_pmap[v] = new_ind; | |||
| 307 | } | |||
| 308 | void on_remove_vertex(vertex<Graph> v) { | |||
| 309 | new_pmap.erase(v); | |||
| 310 | pmap = new_pmap; | |||
| 311 | } | |||
| 312 | ||||
| 313 | private: | |||
| 314 | PMap& pmap; | |||
| 315 | PMap new_pmap; | |||
| 316 | }; | |||
| 317 | ||||
| 318 | // Case 4: no explicit property, indexable | |||
| 319 | // boost automatically shifts indices, so there is not much to do | |||
| 320 | template <typename Derived, typename Graph> | |||
| 321 | class graph_utils_helper<Derived, Graph, void, true> | |||
| 322 | : public graph_utils_base_with_ind<Graph, Derived> { | |||
| 323 | private: | |||
| 324 | using Base = graph_utils_base_with_ind<Graph, Derived>; | |||
| 325 | ||||
| 326 | public: | |||
| 327 | using index_type = vertex_index<Graph>; | |||
| 328 | 1120 | explicit graph_utils_helper(Graph& g) : Base(g) {} | ||
| 329 | ||||
| 330 | 309334 | index_type to_index(vertex<Graph> v) { return v; } | ||
| 331 | 74502 | void on_index_change(vertex<Graph>, index_type) {} | ||
| 332 | 1084 | void on_remove_vertex(vertex<Graph>) {} | ||
| 333 | }; | |||
| 334 | ||||
| 335 | /* Now come the same 4 cases with the additional support of an external map | |||
| 336 | * with vertrex indices as keys | |||
| 337 | */ | |||
| 338 | // Case 1-2: not indexable | |||
| 339 | template < | |||
| 340 | typename Derived, typename Graph, typename Map, typename PMap = void, | |||
| 341 | bool Indexable = has_integral_index<Graph, PMap>> | |||
| 342 | class graph_utils_helper_with_map | |||
| 343 | : public graph_utils_helper<Derived, Graph, PMap> { | |||
| 344 | private: | |||
| 345 | using Base = graph_utils_helper<Derived, Graph, PMap>; | |||
| 346 | ||||
| 347 | public: | |||
| 348 | graph_utils_helper_with_map(Graph& g, Map& m) : Base(g), map(m) {} | |||
| 349 | ||||
| 350 | void on_remove_vertex(vertex<Graph> v) { | |||
| 351 | map.erase(v); | |||
| 352 | Base::on_remove_vertex(v); | |||
| 353 | } | |||
| 354 | ||||
| 355 | private: | |||
| 356 | Map& map; | |||
| 357 | }; | |||
| 358 | ||||
| 359 | // Case 3: explicit property, indexable | |||
| 360 | template <typename Derived, typename Graph, typename Map, typename PMap> | |||
| 361 | class graph_utils_helper_with_map<Derived, Graph, Map, PMap, true> | |||
| 362 | : public graph_utils_helper<Derived, Graph, PMap> { | |||
| 363 | private: | |||
| 364 | using Base = graph_utils_helper<Derived, Graph, PMap>; | |||
| 365 | ||||
| 366 | public: | |||
| 367 | using index_type = typename Base::index_type; | |||
| 368 | graph_utils_helper_with_map(Graph& g, Map& m, PMap& p) | |||
| 369 | : Base(g, p), map(m), new_map(m) {} | |||
| 370 | ||||
| 371 | void on_index_change(vertex<Graph> v, index_type new_ind) { | |||
| 372 | if (new_map.count(new_ind)) { | |||
| 373 | new_map.erase(new_ind); | |||
| 374 | } | |||
| 375 | new_map.insert({new_ind, new_map[Base::to_index(v)]}); | |||
| 376 | Base::on_index_change(v, new_ind); | |||
| 377 | } | |||
| 378 | void on_remove_vertex(vertex<Graph> v) { | |||
| 379 | auto max_ind = std::max_element(std::begin(new_map), std::end(new_map)); | |||
| 380 | new_map.erase(max_ind); | |||
| 381 | map.clear(); | |||
| 382 | for (auto& p : new_map) { | |||
| 383 | map.insert(p); | |||
| 384 | } | |||
| 385 | ||||
| 386 | Base::on_remove_vertex(v); | |||
| 387 | } | |||
| 388 | ||||
| 389 | private: | |||
| 390 | Map& map; | |||
| 391 | Map new_map; | |||
| 392 | }; | |||
| 393 | ||||
| 394 | // Case 4: no explicit property, indexable | |||
| 395 | template <typename Derived, typename Graph, typename Map> | |||
| 396 | class graph_utils_helper_with_map<Derived, Graph, Map, void, true> | |||
| 397 | : public graph_utils_helper<Derived, Graph, void> { | |||
| 398 | private: | |||
| 399 | using Base = graph_utils_helper<Derived, Graph, void>; | |||
| 400 | using StdMap = std::map<typename Map::key_type, typename Map::mapped_type>; | |||
| 401 | ||||
| 402 | 80048 | static typename StdMap::value_type transformer_it( | ||
| 403 | typename Map::value_type& elem) { | |||
| 404 | 80048 | return std::make_pair(elem.first, elem.second); | ||
| 405 | } | |||
| 406 | 1069 | auto map_begin_it(Map& m) { | ||
| 407 | 1069 | return boost::make_transform_iterator(m.begin(), &transformer_it); | ||
| 408 | } | |||
| 409 | 1069 | auto map_end_it(Map& m) { | ||
| 410 | 1069 | return boost::make_transform_iterator(m.end(), &transformer_it); | ||
| 411 | } | |||
| 412 | ||||
| 413 | public: | |||
| 414 | using index_type = typename Base::index_type; | |||
| 415 | 1069 | graph_utils_helper_with_map(Graph& g, Map& m) | ||
| 416 | 1069 | : Base(g), map(m), new_map(map_begin_it(m), map_end_it(m)) {} | ||
| 417 | 74494 | void on_index_change(vertex<Graph> v, index_type new_ind) { | ||
| 418 |
1/2✓ Branch 1 taken 74494 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 74494 times.
✗ Decision 'false' not taken.
|
74494 | if (new_map.count(new_ind)) { |
| 419 | 74494 | new_map.erase(new_ind); | ||
| 420 | } | |||
| 421 |
2/4✓ Branch 2 taken 74494 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 74494 times.
✗ Branch 7 not taken.
|
74494 | new_map.insert({new_ind, new_map[Base::to_index(v)]}); | |
| 422 | 74494 | Base::on_index_change(v, new_ind); | ||
| 423 | 74494 | } | ||
| 424 | 1068 | void on_remove_vertex(vertex<Graph> v) { | ||
| 425 |
1/2✓ Branch 3 taken 1068 times.
✗ Branch 4 not taken.
|
1068 | auto max_ind = std::max_element(std::begin(new_map), std::end(new_map)); | |
| 426 |
1/2✓ Branch 1 taken 1068 times.
✗ Branch 2 not taken.
|
1068 | new_map.erase(max_ind); | |
| 427 | 1068 | map.clear(); | ||
| 428 |
2/2✓ Branch 4 taken 78976 times.
✓ Branch 5 taken 1068 times.
|
2/2✓ Decision 'true' taken 78976 times.
✓ Decision 'false' taken 1068 times.
|
80044 | for (auto& p : new_map) { |
| 429 |
2/4✓ Branch 1 taken 78976 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 78976 times.
✗ Branch 5 not taken.
|
78976 | map.insert(p); | |
| 430 | } | |||
| 431 | ||||
| 432 | 1068 | Base::on_remove_vertex(v); | ||
| 433 | 1068 | } | ||
| 434 | ||||
| 435 | protected: | |||
| 436 | Map& map; | |||
| 437 | StdMap new_map; | |||
| 438 | }; | |||
| 439 | ||||
| 440 | // The above implementions are accessed through the following helper classes, | |||
| 441 | // making template args nicer | |||
| 442 | template <typename Graph, typename PMap = void> | |||
| 443 | class graph_utils_impl | |||
| 444 | : public graph_utils_helper<graph_utils_impl<Graph, PMap>, Graph, PMap> { | |||
| 445 | private: | |||
| 446 | using Base = graph_utils_helper<graph_utils_impl<Graph, PMap>, Graph, PMap>; | |||
| 447 | ||||
| 448 | public: | |||
| 449 | using Base::Base; | |||
| 450 | }; | |||
| 451 | template <typename Graph, typename Map, typename PMap = void> | |||
| 452 | class graph_utils_impl_with_map | |||
| 453 | : public graph_utils_helper_with_map< | |||
| 454 | graph_utils_impl_with_map<Graph, Map, PMap>, Graph, Map, PMap> { | |||
| 455 | private: | |||
| 456 | using Base = graph_utils_helper_with_map< | |||
| 457 | graph_utils_impl_with_map<Graph, Map, PMap>, Graph, Map, PMap>; | |||
| 458 | ||||
| 459 | public: | |||
| 460 | using Base::Base; | |||
| 461 | }; | |||
| 462 | ||||
| 463 | } // namespace detail | |||
| 464 | } // namespace tket::graphs::utils | |||
| 465 |