Skip to content

Commit

Permalink
add rigetti agave and aspen (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasberent authored Jun 5, 2022
1 parent bfb94c0 commit 09a9e51
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 42 deletions.
99 changes: 62 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,45 +94,59 @@ Architectures that are available per default (either as strings or under `qmap.A
- `IBMQ_Bogota` (5 qubit, undirected linear chain layout)
- `IBMQ_Casablanca` (7 qubit, undirected H-shape layout)
- `IBMQ_Tokyo` (20 qubit, undirected brick-like layout)
- `Rigetti_Agave` (8 qubit, undirected ring layout)
- `Rigetti_Aspen` (16 qubit, undirected dumbbell layout)

Whether the heuristic (*default*) or the exact mapper is used can be controlled by passing `method="heuristic"` or `method="exact"` to the `compile` function.

There are several configuration options that can be passed to the `compile` function:

- The heuristic mapper offers the `initial_layout` option, which allows to choose one of the following strategies for choosing an initial layout:
- `identity`: map logical qubit q_i to physical qubit Q_i,
- `static`: determine fixed initial layout statically at the start of mapping,
- `dynamic` (*default*): determine initial layout on demand during the mapping (this is the only one compatible with teleportation).

- Both, the exact and the heuristic mapper also offer the `layering` option, which allows to choose one of the following strategies for partitioning the circuit:
- `individual_gates` (*default*): consider each gate separately,
- `disjoint_qubits`: consider gates acting on disjoint qubits as a layer,
- `odd_gates`: group pairs of gates. (Note that this strategy was only tested for IBM QX4 with the exact mapping tool and may not work on different architectures)
- `qubit_triangle`: add gates to a layer, as long as no more than three qubits are involved. (Note that this strategy only works if the architecture's coupling map contains a triangle, e.g. IBM QX4, and was only tested using the exact
mapping tool)
- The exact mapper offers the `encoding` option, which allows to choose a different encoding for at-most-one and exactly-one constraints:
- `naive` (*default*): use naive encoding for constraints
- `commander`: use commander encoding for at-most-one and exactly-one constraints
- `bimander`: use bimander encoding for at-most-one and commander for exactly-one constraints
As the commander encoding can use different strategies to group the variables, there are different `commander_grouping` options:
- `halves` (*default*): each group contains half of the total variables
- `logarithm`: each group contains at most log2 of the total variables
- `fixed2`: each group contains exactly two variables
- `fixed3`: each group contains exactly three variables
- Per default, the exact mapper searches for a suitable mapping by considering every possible (connected) subset of qubits instead of the whole architecture at once. This can be disabled by setting `use_subsets=False`.
- The exact mapper also offers the `swap_reduction` option to enable limiting the number of swaps considered per layer (as proposed
- The heuristic mapper offers the `initial_layout` option, which allows to choose one of the following strategies for
choosing an initial layout:
- `identity`: map logical qubit q_i to physical qubit Q_i,
- `static`: determine fixed initial layout statically at the start of mapping,
- `dynamic` (*default*): determine initial layout on demand during the mapping (this is the only one compatible with
teleportation).

- Both, the exact and the heuristic mapper also offer the `layering` option, which allows to choose one of the following
strategies for partitioning the circuit:
- `individual_gates` (*default*): consider each gate separately,
- `disjoint_qubits`: consider gates acting on disjoint qubits as a layer,
- `odd_gates`: group pairs of gates. (Note that this strategy was only tested for IBM QX4 with the exact mapping tool
and may not work on different architectures)
- `qubit_triangle`: add gates to a layer, as long as no more than three qubits are involved. (Note that this strategy
only works if the architecture's coupling map contains a triangle, e.g. IBM QX4, and was only tested using the exact
mapping tool)
- The exact mapper offers the `encoding` option, which allows to choose a different encoding for at-most-one and
exactly-one constraints:
- `naive` (*default*): use naive encoding for constraints
- `commander`: use commander encoding for at-most-one and exactly-one constraints
- `bimander`: use bimander encoding for at-most-one and commander for exactly-one constraints
As the commander encoding can use different strategies to group the variables, there are
different `commander_grouping` options:
- `halves` (*default*): each group contains half of the total variables
- `logarithm`: each group contains at most log2 of the total variables
- `fixed2`: each group contains exactly two variables
- `fixed3`: each group contains exactly three variables
- Per default, the exact mapper searches for a suitable mapping by considering every possible (connected) subset of
qubits instead of the whole architecture at once. This can be disabled by setting `use_subsets=False`.
- The exact mapper also offers the `swap_reduction` option to enable limiting the number of swaps considered per layer (
as proposed
in [[4]](https://www.cda.cit.tum.de/files/eda/2022_aspdac_limiting_search_space_optimal_quantum_circuit_mapping.pdf)
, which offers the following options:
- `none`: consider whole search space
- `coupling_limit` (*default*): calculate the max swaps per layer based on the longest path of current choice of qubits, or if `use_subsets` is disabled considers the whole architecture
- `increasing`: start with 0 swaps and geometrically increase the number of swaps per layer
- `custom`: set a custom limit, needs the `swap_limit` option to set the limit
Using the `use_bdd` option, the mapping utilizes BDDs instead of simply removing the permutations from the core routine. This option is not generally advised, as it is more resource intensive in most cases, but is something to try in
- `none`: consider whole search space
- `coupling_limit` (*default*): calculate the max swaps per layer based on the longest path of current choice of
qubits, or if `use_subsets` is disabled considers the whole architecture
- `increasing`: start with 0 swaps and geometrically increase the number of swaps per layer
- `custom`: set a custom limit, needs the `swap_limit` option to set the limit
Using the `use_bdd` option, the mapping utilizes BDDs instead of simply removing the permutations from the core
routine. This option is not generally advised, as it is more resource intensive in most cases, but is something to try
in
cases of timeout.
### Command-line Executable
Expand Down Expand Up @@ -209,25 +223,36 @@ Internally the MQT QMAP library works in the following way
### Configure, Build, and Install
To start off, clone this repository using
```shell
git clone --recurse-submodules -j8 https://github.com/cda-tum/qmap
```
Note the `--recurse-submodules` flag. It is required to also clone all the required submodules.
If you happen to forget passing the flag on your initial clone, you can initialize all the submodules by executing `git submodule update --init --recursive` in the main project directory.
Our projects use CMake as the main build configuration tool. Building a project using CMake is a two-stage process. First, CMake needs to be *configured* by calling
Note the `--recurse-submodules` flag. It is required to also clone all the required submodules.
If you happen to forget passing the flag on your initial clone, you can initialize all the submodules by
executing `git submodule update --init --recursive` in the main project directory.
Our projects use CMake as the main build configuration tool. Building a project using CMake is a two-stage process.
First, CMake needs to be *configured* by calling
```shell
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
```
This tells CMake to search the current directory `.` (passed via `-S`) for a *CMakeLists.txt* file and process it into a directory `build` (passed via `-B`).
This tells CMake to search the current directory `.` (passed via `-S`) for a *CMakeLists.txt* file and process it into a
directory `build` (passed via `-B`).
The flag `-DCMAKE_BUILD_TYPE=Release` tells CMake to configure a *Release* build (as opposed to, e.g., a *Debug* build).
After configuring with CMake, the project can be built by calling
```shell
cmake --build build --config Release
```
This tries to build the project in the `build` directory (passed via `--build`).
Some operating systems and developer environments explicitly require a configuration to be set, which is why the `--config` flag is also passed to the build command. The flag `--parallel <NUMBER_OF_THREADS>` may be added to trigger a parallel build.
Some operating systems and developer environments explicitly require a configuration to be set, which is why
the `--config` flag is also passed to the build command. The flag `--parallel <NUMBER_OF_THREADS>` may be added to
trigger a parallel build.
Building the project this way generates
- the heuristic library `libqmap_heuristic_lib.a` (Unix) / `qmap_heuristic_lib.lib` (Windows) in the `build/src` directory
Expand Down
16 changes: 14 additions & 2 deletions include/configuration/AvailableArchitecture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ enum class AvailableArchitecture {
IBMQ_London,
IBMQ_Bogota,
IBMQ_Casablanca,
IBMQ_Tokyo
IBMQ_Tokyo,
Rigetti_Agave,
Rigetti_Aspen
};

[[maybe_unused]] static std::string toString(const AvailableArchitecture architecture) {
Expand All @@ -35,6 +37,10 @@ enum class AvailableArchitecture {
return "IBMQ_Casablanca";
case AvailableArchitecture::IBMQ_Tokyo:
return "IBMQ_Tokyo";
case AvailableArchitecture::Rigetti_Agave:
return "Rigetti_Agave";
case AvailableArchitecture::Rigetti_Aspen:
return "Rigetti_Aspen";
}
return " ";
}
Expand All @@ -54,6 +60,10 @@ enum class AvailableArchitecture {
return AvailableArchitecture::IBMQ_Casablanca;
} else if (architecture == "IBMQ_Tokyo" || architecture == "6") {
return AvailableArchitecture::IBMQ_Tokyo;
} else if (architecture == "Rigetti_Agave" || architecture == "7") {
return AvailableArchitecture::Rigetti_Agave;
} else if (architecture == "Rigetti_Aspen" || architecture == "8") {
return AvailableArchitecture::Rigetti_Aspen;
} else {
throw std::invalid_argument("Invalid architecture value: " + architecture);
}
Expand All @@ -67,7 +77,9 @@ enum class AvailableArchitecture {
{AvailableArchitecture::IBMQ_London, "5\n0 1\n1 0\n1 2\n2 1\n1 3\n3 1\n3 4\n4 3"},
{AvailableArchitecture::IBMQ_Bogota, "5\n0 1\n1 0\n1 2\n2 1\n2 3\n3 2\n3 4\n4 3"},
{AvailableArchitecture::IBMQ_Casablanca, "7\n0 1\n1 0\n1 2\n2 1\n1 3\n3 1\n3 5\n5 3\n5 4\n4 5\n5 6\n6 5"},
{AvailableArchitecture::IBMQ_Tokyo, "20\n0 1\n1 0\n1 2\n2 1\n2 3\n3 2\n3 4\n4 3\n5 6\n6 5\n6 7\n7 6\n7 8\n8 7\n8 9\n9 8\n10 11\n11 10\n11 12\n12 11\n12 13\n13 12\n13 14\n14 13\n15 16\n16 15\n16 17\n17 16\n17 18\n18 17\n18 19\n19 18\n0 5\n5 0\n5 10\n10 5\n10 15\n15 10\n1 6\n6 1\n6 11\n11 6\n11 16\n16 11\n2 7\n7 2\n7 12\n12 7\n12 17\n17 12\n3 8\n8 3\n8 13\n13 8\n13 18\n18 13\n4 9\n9 4\n9 14\n14 9\n14 19\n19 14\n5 11\n11 5\n11 17\n17 11\n1 7\n7 1\n7 13\n13 7\n13 9\n9 13\n3 9\n9 3\n2 6\n6 2\n6 10\n10 6\n4 8\n8 4\n8 12\n12 8\n12 16\n16 12\n14 18\n18 14"}};
{AvailableArchitecture::IBMQ_Tokyo, "20\n0 1\n1 0\n1 2\n2 1\n2 3\n3 2\n3 4\n4 3\n5 6\n6 5\n6 7\n7 6\n7 8\n8 7\n8 9\n9 8\n10 11\n11 10\n11 12\n12 11\n12 13\n13 12\n13 14\n14 13\n15 16\n16 15\n16 17\n17 16\n17 18\n18 17\n18 19\n19 18\n0 5\n5 0\n5 10\n10 5\n10 15\n15 10\n1 6\n6 1\n6 11\n11 6\n11 16\n16 11\n2 7\n7 2\n7 12\n12 7\n12 17\n17 12\n3 8\n8 3\n8 13\n13 8\n13 18\n18 13\n4 9\n9 4\n9 14\n14 9\n14 19\n19 14\n5 11\n11 5\n11 17\n17 11\n1 7\n7 1\n7 13\n13 7\n13 9\n9 13\n3 9\n9 3\n2 6\n6 2\n6 10\n10 6\n4 8\n8 4\n8 12\n12 8\n12 16\n16 12\n14 18\n18 14"},
{AvailableArchitecture::Rigetti_Agave, "8\n1 0\n0 1\n0 7\n7 0\n7 6\n6 7\n6 5\n5 6\n5 4\n4 5\n4 3\n3 4\n3 2\n2 3\n2 1\n1 2"},
{AvailableArchitecture::Rigetti_Aspen, "16\n0 1\n1 0\n1 14\n14 1\n14 15\n15 14\n15 0\n0 15\n0 7\n7 0\n7 6\n6 7\n6 5\n5 6\n5 4\n4 5\n4 3\n3 4\n3 2\n2 3\n2 1\n1 2\n14 13\n13 14\n13 12\n12 13\n12 11\n11 12\n11 10\n10 11\n10 9\n9 10\n9 8\n8 9\n8 15\n15 8"}};
return architectureMap.at(architecture);
}

Expand Down
8 changes: 5 additions & 3 deletions mqt/qmap/bindings.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of MQT QMAP library which is released under the MIT license.
* See file README.md or go to http://iic.jku.at/eda/research/quantum/ for more information.
*/
* This file is part of MQT QMAP library which is released under the MIT license.
* See file README.md or go to http://iic.jku.at/eda/research/quantum/ for more information.
*/

#ifdef Z3_FOUND
#include "exact/ExactMapper.hpp"
Expand Down Expand Up @@ -111,6 +111,8 @@ PYBIND11_MODULE(pyqmap, m) {
.value("IBMQ_London", AvailableArchitecture::IBMQ_London)
.value("IBMQ_Bogota", AvailableArchitecture::IBMQ_Bogota)
.value("IBMQ_Tokyo", AvailableArchitecture::IBMQ_Tokyo)
.value("Rigetti_Agave", AvailableArchitecture::Rigetti_Agave)
.value("Rigetti_Aspen", AvailableArchitecture::Rigetti_Aspen)
.export_values()
.def(py::init([](const std::string& str) -> AvailableArchitecture { return architectureFromString(str); }));

Expand Down
15 changes: 15 additions & 0 deletions test/test_exact.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,3 +456,18 @@ TEST_F(ExactTest, MapToSubgraphNotConnected) {
const auto& results = IBMQ_London_mapper->getResults();
EXPECT_TRUE(results.timeout);
}
TEST_F(ExactTest, CommanderEncodingRigettiArch) {
Architecture aspen;
aspen.loadCouplingMap(AvailableArchitecture::Rigetti_Aspen);
Architecture agave;
agave.loadCouplingMap(AvailableArchitecture::Rigetti_Agave);

auto aspenMapper = ExactMapper(qc, aspen);
auto agaveMapper = ExactMapper(qc, agave);
aspenMapper.map(settings);
agaveMapper.map(settings);
aspenMapper.printResult(std::cout);
agaveMapper.printResult(std::cout);

SUCCEED() << "Mapping successful";
}

0 comments on commit 09a9e51

Please sign in to comment.