-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feature] [rv3] Generate random nearby placements (#232)
- Loading branch information
Showing
7 changed files
with
398 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright 2019-2022 Cambridge Quantum Computing | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include "NeighbourPlacements.hpp" | ||
|
||
#include <cstdlib> | ||
#include <string> | ||
|
||
#include "TokenSwapping/SwapListOptimiser.hpp" | ||
#include "Utils/TketLog.hpp" | ||
|
||
namespace tket { | ||
|
||
NeighbourPlacements::NeighbourPlacements( | ||
const Architecture& arc, const qubit_mapping_t& init_map) | ||
: arc_(arc), init_map_(init_map), u_to_node_(), rng_() { | ||
auto nodes = arc_.get_all_nodes_vec(); | ||
for (unsigned i = 0; i < nodes.size(); ++i) { | ||
u_to_node_.left.insert({i, nodes[i]}); | ||
} | ||
} | ||
|
||
NeighbourPlacements::ResultVec NeighbourPlacements::get( | ||
unsigned dist, unsigned n, bool optimise, unsigned seed, | ||
unsigned max_tries) { | ||
rng_.set_seed(seed); | ||
|
||
// define a comparison function for placements | ||
std::vector<Qubit> keys; | ||
for (auto [k, v] : init_map_) { | ||
keys.push_back(k); | ||
} | ||
auto map_compare = [&keys]( | ||
const qubit_mapping_t& a, const qubit_mapping_t& b) { | ||
for (auto k : keys) { | ||
if (a.at(k) < b.at(k)) { | ||
return true; | ||
} else if (a.at(k) > b.at(k)) { | ||
return false; | ||
} | ||
} | ||
return false; | ||
}; | ||
// set of all generated placement maps | ||
std::set<qubit_mapping_t, decltype(map_compare)> placements(map_compare); | ||
|
||
ResultVec resvec; | ||
for (unsigned i = 0; i < n; ++i) { | ||
unsigned n_unsuccessful = 0; | ||
while (n_unsuccessful < max_tries) { | ||
Result res = gen_result(dist, optimise, max_tries); | ||
if (!placements.contains(res.map)) { | ||
resvec.push_back(res); | ||
placements.insert(res.map); | ||
break; | ||
} | ||
++n_unsuccessful; | ||
} | ||
if (n_unsuccessful == max_tries) { | ||
tket_log()->warn( | ||
"Could not generate " + std::to_string(n) + " distinct placements"); | ||
} | ||
} | ||
return resvec; | ||
} | ||
|
||
NeighbourPlacements::Result NeighbourPlacements::gen_result( | ||
unsigned dist, bool optimise, unsigned max_tries) { | ||
SwapList swaps; | ||
tsa_internal::SwapListOptimiser optimiser; | ||
|
||
// it might be impossible to find `dist` non-trivial swaps | ||
unsigned n_unsuccessful = 0; | ||
|
||
while (swaps.size() < dist && n_unsuccessful < max_tries) { | ||
Swap new_swap = gen_swap(); | ||
|
||
if (optimise) { | ||
SwapList swaps_candidate = swaps; | ||
swaps_candidate.push_back(new_swap); | ||
optimiser.full_optimise(swaps_candidate); | ||
if (swaps_candidate.size() > swaps.size()) { | ||
swaps = std::move(swaps_candidate); | ||
n_unsuccessful = 0; | ||
} else { | ||
++n_unsuccessful; | ||
} | ||
} else { | ||
swaps.push_back(new_swap); | ||
} | ||
} | ||
|
||
if (n_unsuccessful == max_tries) { | ||
tket_log()->warn( | ||
"Unable to generate " + std::to_string(dist) + | ||
" swaps for given architecture"); | ||
} | ||
|
||
return convert_to_res(swaps.to_vector()); | ||
} | ||
|
||
Swap NeighbourPlacements::gen_swap() { | ||
auto edges = arc_.get_all_edges_vec(); | ||
unsigned m = edges.size(); | ||
auto [n1, n2] = edges[rng_.get_size_t(m - 1)]; | ||
Swap new_swap{u_to_node_.right.at(n1), u_to_node_.right.at(n2)}; | ||
return new_swap; | ||
} | ||
|
||
NeighbourPlacements::Result NeighbourPlacements::convert_to_res( | ||
const SwapVec& swaps) { | ||
NodeSwapVec node_swaps; | ||
for (auto [u1, u2] : swaps) { | ||
node_swaps.push_back({u_to_node_.left.at(u1), u_to_node_.left.at(u2)}); | ||
} | ||
|
||
qubit_bimap_t qubit_to_node; | ||
qubit_to_node.left.insert(init_map_.begin(), init_map_.end()); | ||
for (auto [n1, n2] : node_swaps) { | ||
const Qubit q1 = qubit_to_node.right.at(n1); | ||
const Qubit q2 = qubit_to_node.right.at(n2); | ||
qubit_to_node.left.erase(q1); | ||
qubit_to_node.left.erase(q2); | ||
qubit_to_node.left.insert({q1, n2}); | ||
qubit_to_node.left.insert({q2, n1}); | ||
} | ||
qubit_mapping_t map; | ||
for (auto [k, v] : qubit_to_node.left) { | ||
map.insert({k, v}); | ||
} | ||
return {map, node_swaps}; | ||
} | ||
|
||
} // namespace tket |
99 changes: 99 additions & 0 deletions
99
tket/src/Placement/include/Placement/NeighbourPlacements.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// Copyright 2019-2022 Cambridge Quantum Computing | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#pragma once | ||
|
||
#include <map> | ||
|
||
#include "Placement.hpp" | ||
#include "TokenSwapping/SwapFunctions.hpp" | ||
#include "Utils/BiMapHeaders.hpp" | ||
#include "Utils/RNG.hpp" | ||
|
||
namespace tket { | ||
|
||
/** | ||
* @brief Given a placement map generates `n` nearby placement maps. | ||
* | ||
* Based on an architecture and a placement map, generates random | ||
* placements that can be achieved with `m` swaps. | ||
* | ||
* Optionally uses token swapping optimisations to try to ensure | ||
* that the generated placements cannot be obtained in less than `m` | ||
* swaps, but this cannot be guaranteed. | ||
*/ | ||
class NeighbourPlacements { | ||
public: | ||
using SwapVec = std::vector<Swap>; | ||
using NodeSwap = std::pair<Node, Node>; | ||
using NodeSwapVec = std::vector<NodeSwap>; | ||
struct Result { | ||
qubit_mapping_t map; | ||
NodeSwapVec swaps; | ||
}; | ||
using ResultVec = std::vector<Result>; | ||
|
||
/** | ||
* @brief Construct a new Swap Placement object. | ||
* | ||
* @param arc The architecture defining the allowed swaps. | ||
* @param init_map The initial Qubit => Node map. | ||
*/ | ||
NeighbourPlacements(const Architecture& arc, const qubit_mapping_t& init_map); | ||
|
||
/** | ||
* @brief Generate `n` distinct placement maps using `dist` swaps for each map | ||
* | ||
* The sequences of swaps are generated randomly. Note that it cannot be | ||
* guaranteed that the generated placement cannot be obtained in less than | ||
* `dist` swaps. When optimise=true (default), we attempt to simplify | ||
* chains of swaps to make it more likely that `dist` swaps are indeed | ||
* necessary for the generated placement maps. | ||
* | ||
* If optimise=true, it is also possible that placements `dist` swaps away | ||
* do not exist. `max_tries` controls the number of attempts to generate | ||
* placements. | ||
* | ||
* If it is impossible (or very hard) to generate `n` distinct placement maps | ||
* of distance `dist` swaps away, then this method will raise a warning | ||
* and return fewer results and/or results with less than `dist` swaps. | ||
* | ||
* @param dist The number of swaps allowed on the architecture. | ||
* @param n The number of placement maps to generate (default n=1). | ||
* @param optimise Simplify the generated swap sequences (default true). | ||
* @param seed Seed for random number generator (default seed=5489). | ||
* @param max_tries Number of tries before aborting placement map generation | ||
* (default max_tries=10). | ||
* @return ResultVec A vector of the generated maps and swaps | ||
*/ | ||
ResultVec get( | ||
unsigned dist, unsigned n = 1, bool optimise = true, unsigned seed = 5489, | ||
unsigned max_tries = 10); | ||
|
||
private: | ||
// generate a single Result | ||
Result gen_result( | ||
unsigned dist, bool optimise = true, unsigned max_tries = 10); | ||
// generate a single swap | ||
Swap gen_swap(); | ||
// apply swap list to init_map and return new placement map | ||
Result convert_to_res(const SwapVec& swaps); | ||
|
||
Architecture arc_; | ||
qubit_mapping_t init_map_; | ||
boost::bimap<unsigned, Node> u_to_node_; | ||
RNG rng_; | ||
}; | ||
|
||
} // namespace tket |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.