Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support any two qubit gates #235

Draft
wants to merge 32 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c845d37
🔥 Remove assert in countGates
JoachimMarin Feb 13, 2023
d526398
✨ Preserve operation type for two qubit gates
JoachimMarin Feb 13, 2023
27b1b20
🚧 Generalize naming for two-qubit gates
JoachimMarin Feb 13, 2023
7002c93
🎨 Rename cnots to twoQubitGates
JoachimMarin Feb 13, 2023
03f4214
🎨 pre-commit fixes
pre-commit-ci[bot] Feb 13, 2023
5f49023
:sparkles: Case distinction for flipping gates
JoachimMarin Feb 20, 2023
4e8648a
🎨 pre-commit fixes
pre-commit-ci[bot] Feb 20, 2023
6d33c87
✨ Function for gate reversal cost
JoachimMarin Mar 4, 2023
3b05b62
:rewind: Assume cnot gates in distance table
JoachimMarin Mar 5, 2023
7b38085
:white_check_mark: Add direction reverse python tests
JoachimMarin Mar 5, 2023
e7127dd
:bulb: Add python test descriptions
JoachimMarin Mar 6, 2023
6dfbb94
🚨 Fix ruff warnings for python tests
JoachimMarin Mar 6, 2023
4016c86
Merge remote-tracking branch 'upstream/main' into support-any-two-qub…
JoachimMarin Mar 6, 2023
ff3929c
🚨 Fix missing return on unexpected enum value
JoachimMarin Mar 6, 2023
91b7969
✅ Remove InstructionSet import
JoachimMarin Mar 6, 2023
219eda2
✅ Use gate objects for python tests
JoachimMarin Mar 7, 2023
2bd795e
🩹 fix Python typing
burgholzer Mar 7, 2023
88a82ee
🩹 silence an external Qiskit warning from the tests
burgholzer Mar 7, 2023
90764c3
Merge remote-tracking branch 'origin/main' into support-any-two-qubit…
burgholzer Mar 7, 2023
f0f19e3
♻️ restructure tests
burgholzer Mar 7, 2023
e71fb87
🐛 Prevent reversals with swaps in exact mapper
JoachimMarin Mar 11, 2023
45deaab
Update include/Mapper.hpp
burgholzer Mar 11, 2023
e43c357
🚨 some `const`
burgholzer Mar 11, 2023
3c982bc
🚚 rename `insertFlippedGate` method
burgholzer Mar 11, 2023
80609be
♻️ refactor condition to simplify code
burgholzer Mar 11, 2023
44d81c8
⚡ add missing conditional skip statement
burgholzer Mar 11, 2023
31e73b3
🚸 add additional sanity check
burgholzer Mar 11, 2023
a33e1d1
🚸 add `const` version of the mapped circuit getter
burgholzer Mar 11, 2023
12ab7fa
♻️ simplify tests
burgholzer Mar 11, 2023
0aec519
🐛 fix coupling limit computation for directed architectures
burgholzer Mar 11, 2023
8897aa4
🧪 Add direction reverse tests for heuristic mapper
JoachimMarin Mar 14, 2023
34cc4bd
✨ Update heuristic algorithm for direction reverse
JoachimMarin Mar 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions include/Mapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,33 @@ class Mapper {
countGates(circuit.cbegin(), circuit.cend(), info);
}
/**
* @brief count number of elementary gates and cnots in circuit and save the
* results in `info.gates` and `info.cnots`
* @brief count number of elementary gates and controlled gates in circuit and
burgholzer marked this conversation as resolved.
Show resolved Hide resolved
* save the results in `info.gates` and `info.twoQubitGates`
*/
virtual void countGates(decltype(qcMapped.cbegin()) it,
const decltype(qcMapped.cend())& end,
MappingResults::CircuitInfo& info);

/**
* @brief inserts a two qubit operation op along edge.
* @param edge the edge in the coupling graph that controls on which physical
* qubits the operation will act. The logical and physical direction are the
* same.
* @param op the operation which is inserted
* @return total number of inserted operations
*/
std::size_t insertGate(const Edge& edge, qc::StandardOperation* op);

/**
* @brief inserts a two qubit operation op along a direction reversed edge.
* @param edge the edge in the coupling graph that controls on which physical
* qubits the operation will act. The logical direction of the operation is
* the reverse of the physical direction.
* @param op the operation which is inserted
* @return total number of inserted operations
*/
std::size_t insertFlippedGate(const Edge& edge, qc::StandardOperation* op);
burgholzer marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief performs optimizations on the circuit before mapping
*
Expand Down
16 changes: 8 additions & 8 deletions include/MappingResults.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct MappingResults {
std::uint16_t qubits = 0;
std::size_t gates = 0;
std::size_t singleQubitGates = 0;
std::size_t cnots = 0;
std::size_t twoQubitGates = 0;
std::size_t layers = 0;

// info in output circuit
Expand Down Expand Up @@ -62,14 +62,14 @@ struct MappingResults {
circuit["qubits"] = input.qubits;
circuit["gates"] = input.gates;
circuit["single_qubit_gates"] = input.singleQubitGates;
circuit["cnots"] = input.cnots;
circuit["cnots"] = input.twoQubitGates;

auto& mappedCirc = resultJSON["mapped_circuit"];
mappedCirc["name"] = output.name;
mappedCirc["qubits"] = output.qubits;
mappedCirc["gates"] = output.gates;
mappedCirc["single_qubit_gates"] = output.singleQubitGates;
mappedCirc["cnots"] = output.cnots;
mappedCirc["cnots"] = output.twoQubitGates;
if (!mappedCircuit.empty()) {
mappedCirc["qasm"] = mappedCircuit;
}
Expand Down Expand Up @@ -100,11 +100,11 @@ struct MappingResults {
virtual std::string csv() {
std::stringstream ss{};
ss << input.name << ";" << input.qubits << ";" << input.gates << ";"
<< input.singleQubitGates << ";" << input.cnots << ";" << architecture
<< ";" << output.name << ";" << output.qubits << ";" << output.gates
<< ";" << output.singleQubitGates << ";" << output.cnots << ";"
<< output.swaps << ";" << output.directionReverse << ";"
<< output.teleportations << ";";
<< input.singleQubitGates << ";" << input.twoQubitGates << ";"
<< architecture << ";" << output.name << ";" << output.qubits << ";"
<< output.gates << ";" << output.singleQubitGates << ";"
<< output.twoQubitGates << ";" << output.swaps << ";"
<< output.directionReverse << ";" << output.teleportations << ";";
if (timeout) {
ss << "TO";
} else {
Expand Down
3 changes: 2 additions & 1 deletion mqt/qmap/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ PYBIND11_MODULE(pyqmap, m) {
.def_readwrite("gates", &MappingResults::CircuitInfo::gates)
.def_readwrite("single_qubit_gates",
&MappingResults::CircuitInfo::singleQubitGates)
.def_readwrite("cnots", &MappingResults::CircuitInfo::cnots)
.def_readwrite("two_qubit_gates",
&MappingResults::CircuitInfo::twoQubitGates)
.def_readwrite("layers", &MappingResults::CircuitInfo::layers)
.def_readwrite("swaps", &MappingResults::CircuitInfo::swaps)
.def_readwrite("direction_reverse",
Expand Down
49 changes: 45 additions & 4 deletions src/Mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,18 +280,17 @@ void Mapper::countGates(decltype(qcMapped.cbegin()) it,
if (g->getType() == qc::SWAP) {
if (architecture.bidirectional()) {
info.gates += GATES_OF_BIDIRECTIONAL_SWAP;
info.cnots += GATES_OF_BIDIRECTIONAL_SWAP;
info.twoQubitGates += GATES_OF_BIDIRECTIONAL_SWAP;
} else {
info.gates += GATES_OF_UNIDIRECTIONAL_SWAP;
info.cnots += GATES_OF_BIDIRECTIONAL_SWAP;
info.twoQubitGates += GATES_OF_BIDIRECTIONAL_SWAP;
info.singleQubitGates += GATES_OF_DIRECTION_REVERSE;
}
} else if (g->getControls().empty()) {
++info.singleQubitGates;
++info.gates;
} else {
assert(g->getType() == qc::X);
++info.cnots;
++info.twoQubitGates;
++info.gates;
}
continue;
Expand All @@ -303,3 +302,45 @@ void Mapper::countGates(decltype(qcMapped.cbegin()) it,
}
}
}
std::size_t Mapper::insertGate(const Edge& edge, qc::StandardOperation* op) {
qcMapped.emplace_back<qc::StandardOperation>(
qcMapped.getNqubits(), qc::Control{static_cast<qc::Qubit>(edge.first)},
edge.second, op->getType(), op->getParameter().at(0),
op->getParameter().at(1), op->getParameter().at(2));
burgholzer marked this conversation as resolved.
Show resolved Hide resolved
return 1;
}

std::size_t Mapper::insertFlippedGate(const Edge& edge,
qc::StandardOperation* op) {
int swapType = -1;
switch (op->getType()) {
case qc::X:
burgholzer marked this conversation as resolved.
Show resolved Hide resolved
swapType = 1;
break;
case qc::Z:
burgholzer marked this conversation as resolved.
Show resolved Hide resolved
swapType = 0;
break;
default:
swapType = -1;
}
burgholzer marked this conversation as resolved.
Show resolved Hide resolved

if (swapType == 0) {
// no additional gates required to reverse direction
return insertGate(edge, op);
}
if (swapType == 1) {
// four hadamard gates to reverse direction
qcMapped.h(edge.first);
qcMapped.h(edge.second);
auto tmp = insertGate(edge, op);
qcMapped.h(edge.first);
qcMapped.h(edge.second);
return tmp + 4;
}

// in all other cases, swap gates are used to reverse direction
qcMapped.swap(edge.first, edge.second);
auto tmp = insertGate(edge, op);
qcMapped.swap(edge.second, edge.first);
burgholzer marked this conversation as resolved.
Show resolved Hide resolved
return 2 + tmp;
}
Fixed Show fixed Hide fixed
47 changes: 21 additions & 26 deletions src/exact/ExactMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,38 +275,33 @@ void ExactMapper::map(const Configuration& settings) {
op->getParameter().at(0), op->getParameter().at(1),
op->getParameter().at(2));
} else {
const Edge cnot = {locations.at(static_cast<std::size_t>(gate.control)),
locations.at(gate.target)};
const Edge controlledGate = {
locations.at(static_cast<std::size_t>(gate.control)),
locations.at(gate.target)};

if (architecture.getCouplingMap().find(cnot) ==
if (architecture.getCouplingMap().find(controlledGate) ==
architecture.getCouplingMap().end()) {
const Edge reverse = {cnot.second, cnot.first};
const Edge reverse = {controlledGate.second, controlledGate.first};
if (architecture.getCouplingMap().find(reverse) ==
architecture.getCouplingMap().end()) {
throw QMAPException(
"Invalid CNOT: " + std::to_string(reverse.first) + "-" +
std::to_string(reverse.second));
throw QMAPException("Invalid controlled gate " + op->getName() +
": " + std::to_string(reverse.first) + "-" +
std::to_string(reverse.second));
}
if (settings.verbose) {
std::cout
<< i
<< ": Added (direction-reversed) cnot with control and target: "
<< cnot.first << " " << cnot.second << std::endl;
std::cout << i << ": Added (direction-reversed) controlled gate "
<< op->getName()
<< " with control and target: " << controlledGate.first
<< " " << controlledGate.second << std::endl;
}
qcMapped.h(reverse.first);
qcMapped.h(reverse.second);
qcMapped.x(reverse.second,
qc::Control{static_cast<qc::Qubit>(reverse.first)});
qcMapped.h(reverse.second);
qcMapped.h(reverse.first);
insertFlippedGate(reverse, op);
} else {
if (settings.verbose) {
std::cout << i
<< ": Added cnot with control and target: " << cnot.first
<< " " << cnot.second << std::endl;
std::cout << i << ": Added controlled gate " << op->getName()
<< " with control and target: " << controlledGate.first
<< " " << controlledGate.second << std::endl;
}
qcMapped.x(cnot.second,
qc::Control{static_cast<qc::Qubit>(cnot.first)});
insertGate(controlledGate, op);
}
}
}
Expand Down Expand Up @@ -354,7 +349,7 @@ void ExactMapper::map(const Configuration& settings) {

// 10) re-count gates
results.output.singleQubitGates = 0U;
results.output.cnots = 0U;
results.output.twoQubitGates = 0U;
results.output.gates = 0U;
countGates(qcMapped, results.output);

Expand Down Expand Up @@ -762,9 +757,9 @@ number of variables: (|L|-1) * m!
// quickly determine cost
choiceResults.output.singleQubitGates =
choiceResults.input.singleQubitGates;
choiceResults.output.cnots = choiceResults.input.cnots;
choiceResults.output.gates =
choiceResults.output.singleQubitGates + choiceResults.output.cnots;
choiceResults.output.twoQubitGates = choiceResults.input.twoQubitGates;
choiceResults.output.gates = choiceResults.output.singleQubitGates +
choiceResults.output.twoQubitGates;
assert(choiceResults.output.swaps == 0U);
assert(choiceResults.output.directionReverse == 0U);
// swaps
Expand Down
25 changes: 8 additions & 17 deletions src/heuristic/HeuristicMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,31 +94,22 @@ void HeuristicMapper::map(const Configuration& configuration) {
gateidx++;
}
} else {
const Edge cnot = {
const Edge controlledGate = {
locations.at(static_cast<std::uint16_t>(gate.control)),
locations.at(gate.target)};
if (architecture.getCouplingMap().find(cnot) ==
if (architecture.getCouplingMap().find(controlledGate) ==
architecture.getCouplingMap().end()) {
const Edge reverse = {cnot.second, cnot.first};
const Edge reverse = {controlledGate.second, controlledGate.first};
if (architecture.getCouplingMap().find(reverse) ==
architecture.getCouplingMap().end()) {
throw QMAPException(
"Invalid CNOT: " + std::to_string(reverse.first) + "-" +
std::to_string(reverse.second));
throw QMAPException("Invalid controlled gate " + op->getName() +
": " + std::to_string(reverse.first) + "-" +
std::to_string(reverse.second));
}
qcMapped.h(reverse.first);
qcMapped.h(reverse.second);
qcMapped.x(reverse.second,
qc::Control{static_cast<qc::Qubit>(reverse.first)});
qcMapped.h(reverse.second);
qcMapped.h(reverse.first);

gateidx += insertFlippedGate(reverse, op);
results.output.directionReverse++;
gateidx += 5;
} else {
qcMapped.x(cnot.second,
qc::Control{static_cast<qc::Qubit>(cnot.first)});
gateidx++;
gateidx += insertGate(controlledGate, op);
}
}
}
Expand Down