Skip to content

Commit

Permalink
Subgraph mapping (#52)
Browse files Browse the repository at this point in the history
* ⚡ only use SWAPs between qubits that are currently being considered
* ✨ allow only considering a subset of an architecture's qubits in exact mapping
* ✅ add tests for new feature

Signed-off-by: Lukas Burgholzer <[email protected]>
  • Loading branch information
burgholzer authored May 5, 2022
1 parent 610996c commit 7754650
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 7 deletions.
8 changes: 7 additions & 1 deletion include/configuration/Configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ struct Configuration {

bool verbose = false;

// map to particular subgraph of architecture (in exact mapper)
std::set<unsigned short> subgraph{};

// how to cluster the gates into layers
Layering layering = Layering::None;

Expand Down Expand Up @@ -67,7 +70,10 @@ struct Configuration {
config["method"] = ::toString(method);
config["calibration"] = calibration;
config["layering_strategy"] = ::toString(layering);
config["verbose"] = verbose;
if (!subgraph.empty()) {
config["subgraph"] = subgraph;
}
config["verbose"] = verbose;

if (method == Method::Heuristic) {
auto& heuristic = config["settings"];
Expand Down
2 changes: 1 addition & 1 deletion include/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ std::string printPi(std::vector<unsigned short>& pi);
/// \param current index of current qubit
/// \param visited visited qubits
/// \param cm coupling map of architecture
void dfs(unsigned short current, std::set<unsigned short>& visited, CouplingMap& rcm);
void dfs(unsigned short current, std::set<unsigned short>& visited, const CouplingMap& rcm);

/// Helper function returning correct 1D array index for 3D array
/// \param k first index
Expand Down
2 changes: 2 additions & 0 deletions mqt/qmap/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "heuristic/HeuristicMapper.hpp"
#include "nlohmann/json.hpp"
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"
#include "pybind11_json/pybind11_json.hpp"
#include "qiskit/QuantumCircuit.hpp"

Expand Down Expand Up @@ -182,6 +183,7 @@ PYBIND11_MODULE(pyqmap, m) {
.def_readwrite("swap_reduction", &Configuration::swapReduction)
.def_readwrite("swap_limit", &Configuration::swapLimit)
.def_readwrite("use_bdd", &Configuration::useBDD)
.def_readwrite("subgraph", &Configuration::subgraph)
.def("json", &Configuration::json)
.def("__repr__", &Configuration::toString);

Expand Down
11 changes: 9 additions & 2 deletions mqt/qmap/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
import pickle
from pathlib import Path
from typing import Union
from typing import Union, Optional, Set
from mqt.qmap.pyqmap import map, Method, InitialLayout, Layering, Arch, Encoding, CommanderGrouping, SwapReduction, Configuration, MappingResults


Expand All @@ -23,6 +23,7 @@ def compile(circ, arch: Union[str, Arch],
swap_limit: int = 0,
include_WCNF: bool = False,
use_subsets: bool = True,
subgraph: Optional[Set[int]] = None,
verbose: bool = False
) -> MappingResults:
"""Interface to the MQT QMAP tool for mapping quantum circuits
Expand All @@ -42,14 +43,17 @@ def compile(circ, arch: Union[str, Arch],
:param commander_grouping - Choose method of grouping in commander and bimander encoding (*halves* | fixed2 | fixed3 | logarithm)
:type commander_grouping: Union[str, CommanderGrouping]
:param use_bdd: Limit swaps per layer using BDDs, faster in some cases, but use with caution (default: False)
:type use_bdd: bool :param swap_reduction - Choose method of limiting the search space (none | *coupling_limit* | custom | increasing)
:type use_bdd: bool
:param swap_reduction - Choose method of limiting the search space (none | *coupling_limit* | custom | increasing)
:type swap_reduction: Union[str, SwapReduction]
:param swap_limit - Set a custom limit for max swaps per layer, for the increasing reduction strategy it sets the max swaps per layer
:type swap_limit: int
:param include_WCNF: Include WCNF file in the results (default: False)
:type include_WCNF: bool
:param use_subsets: Use qubit subsets, or consider all available physical qubits at once (default: True)
:type use_subsets: bool
:param subgraph: List of qubits to consider for mapping (in exact mapper), if None all qubits are considered
:type subgraph: Optional[List[int]]
:param use_teleportation: Use teleportation in addition to swaps
:param teleportation_fake: Assign qubits as ancillary for teleportation in the initial placement but don't actually use them (used for comparisons)
:param teleportation_seed: Fix a seed for the RNG in the initial ancilla placement (0 means the RNG will be seeded from /dev/urandom/ or similar)
Expand All @@ -59,6 +63,8 @@ def compile(circ, arch: Union[str, Arch],
:rtype: MappingResults
"""

if subgraph is None:
subgraph = set()
if type(circ) == str and Path(circ).suffix == '.pickle':
circ = pickle.load(open(circ, "rb"))

Expand All @@ -74,6 +80,7 @@ def compile(circ, arch: Union[str, Arch],
config.use_bdd = use_bdd
config.include_WCNF = include_WCNF
config.use_subsets = use_subsets
config.subgraph = subgraph
config.use_teleportation = use_teleportation
config.teleportation_fake = teleportation_fake
config.teleportation_seed = teleportation_seed
Expand Down
10 changes: 10 additions & 0 deletions src/Architecture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ unsigned long Architecture::minimumNumberOfSwaps(std::vector<unsigned short>& pe
// create selection of swap possibilities
std::set<std::pair<unsigned short, unsigned short>> possibleSwaps{};
for (const auto& edge: couplingMap) {
// only use SWAPs between qubits that are currently being considered
if (qubits.count(edge.first) == 0 || qubits.count(edge.second) == 0) {
continue;
}

if (!bidirectional() || (possibleSwaps.count(edge) == 0 && possibleSwaps.count({edge.second, edge.first}) == 0)) {
possibleSwaps.emplace(edge);
}
Expand Down Expand Up @@ -247,6 +252,11 @@ void Architecture::minimumNumberOfSwaps(std::vector<unsigned short>& permutation
// create selection of swap possibilities
std::set<std::pair<unsigned short, unsigned short>> possibleSwaps{};
for (const auto& edge: couplingMap) {
// only use SWAPs between qubits that are currently being considered
if (qubits.count(edge.first) == 0 || qubits.count(edge.second) == 0) {
continue;
}

if (!bidirectional() || (possibleSwaps.count(edge) == 0 && possibleSwaps.count({edge.second, edge.first}) == 0)) {
possibleSwaps.emplace(edge);
}
Expand Down
31 changes: 29 additions & 2 deletions src/exact/ExactMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,35 @@ void ExactMapper::map(const Configuration& settings) {

// 2) For all possibilities k (=m over n) to pick n qubits from m physical qubits
std::vector<unsigned short> qubitRange{};
for (unsigned short i = 0; i < architecture.getNqubits(); ++i) {
qubitRange.push_back(i);
if (!config.subgraph.empty()) {
const auto subgraphQubits = config.subgraph.size();
if (subgraphQubits < qc.getNqubits()) {
std::cerr << "The subgraph must contain at least as many qubits as the circuit has physical qubits." << std::endl;
return;
}

CouplingMap reducedCouplingMap = architecture.getCouplingMap();
for (const auto& edge: architecture.getCouplingMap()) {
if (!config.subgraph.count(edge.first) || !config.subgraph.count(edge.second)) {
reducedCouplingMap.erase(edge);
}
}

// check if the subgraph is connected
std::set<unsigned short> reachedQubits{};
reachedQubits.insert(*(config.subgraph.begin()));
dfs(*(config.subgraph.begin()), reachedQubits, reducedCouplingMap);
if (!(reachedQubits == config.subgraph)) {
std::cerr << "The subgraph is not connected." << std::endl;
return;
}
for (const auto& q: config.subgraph) {
qubitRange.emplace_back(q);
}
} else {
for (unsigned short i = 0; i < architecture.getNqubits(); ++i) {
qubitRange.push_back(i);
}
}
std::vector<QubitChoice> allPossibleQubitChoices{};
if (config.useSubsets) {
Expand Down
2 changes: 1 addition & 1 deletion src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ std::string printPi(std::vector<unsigned short>& pi) {
/// \param current index of current qubit
/// \param visited visited qubits
/// \param cm coupling map of architecture
void dfs(unsigned short current, std::set<unsigned short>& visited, CouplingMap& rcm) {
void dfs(unsigned short current, std::set<unsigned short>& visited, const CouplingMap& rcm) {
for (auto edge: rcm) {
if (edge.first == current) {
if (!visited.count(edge.second)) {
Expand Down
48 changes: 48 additions & 0 deletions test/test_exact.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,51 @@ TEST_F(ExactTest, WCNF) {
std::cout << wcnf << std::endl;
EXPECT_TRUE(!wcnf.empty());
}

TEST_F(ExactTest, MapToSubgraph) {
using namespace dd::literals;

qc.addQubitRegister(3U);
qc.x(0, 1_pc);
qc.x(1, 2_pc);
qc.x(2, 0_pc);

const auto connectedSubset = std::set<unsigned short>{0U, 1U, 2U};

settings.subgraph = connectedSubset;
IBMQ_London_mapper.map(settings);
const auto& results = IBMQ_London_mapper.getResults();
EXPECT_FALSE(results.timeout);
}

TEST_F(ExactTest, MapToSubgraphTooSmall) {
using namespace dd::literals;

qc.addQubitRegister(3U);
qc.x(0, 1_pc);
qc.x(1, 2_pc);
qc.x(2, 0_pc);

const auto tooSmallSubset = std::set<unsigned short>{0U, 1U};

settings.subgraph = tooSmallSubset;
IBMQ_London_mapper.map(settings);
const auto& results = IBMQ_London_mapper.getResults();
EXPECT_TRUE(results.timeout);
}

TEST_F(ExactTest, MapToSubgraphNotConnected) {
using namespace dd::literals;

qc.addQubitRegister(3U);
qc.x(0, 1_pc);
qc.x(1, 2_pc);
qc.x(2, 0_pc);

const auto nonConnectedSubset = std::set<unsigned short>{0U, 2U, 3U};

settings.subgraph = nonConnectedSubset;
IBMQ_London_mapper.map(settings);
const auto& results = IBMQ_London_mapper.getResults();
EXPECT_TRUE(results.timeout);
}

0 comments on commit 7754650

Please sign in to comment.