Skip to content

Commit ae0dbcd

Browse files
authored
Merge pull request #8 from iic-jku/telefix
Fix for teleportation
2 parents 57c1176 + 4f8258a commit ae0dbcd

File tree

10 files changed

+157
-77
lines changed

10 files changed

+157
-77
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Params:
9191
layering – Circuit layering strategy to use (*individual_gates* | disjoint_qubits | odd_qubits | qubit_triangle)
9292
use_teleportation - Use teleportation in addition to swaps
9393
teleportation_fake - Assign qubits as ancillary for teleportation but don't actually use them
94-
teleportation_seed - Fix a seed for the initial ancilla placement (0 means no fixed seed)
94+
teleportationSeed - Fix a seed for the initial ancilla placement (0 means no fixed seed)
9595
save_mapped_circuit – Include .qasm string of the mapped circuit in result
9696
csv – Create CSV string for result
9797
statistics – Print statistics
@@ -106,7 +106,7 @@ def compile(circ, arch: Union[str, Arch],
106106
layering: LayeringStrategy = LayeringStrategy.individual_gates,
107107
use_teleportation: bool = False,
108108
teleportation_fake: bool = False,
109-
teleportation_seed: int = 0,
109+
teleportationSeed: int = 0,
110110
save_mapped_circuit: bool = False,
111111
csv: bool = False,
112112
statistics: bool = False,

apps/heuristic_app.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ int main(int argc, char** argv) {
104104
ms.verbose = vm.count("verbose") > 0;
105105

106106
if (vm.count("teleportation")) {
107-
ms.teleportation_qubits = std::min((arch.getNqubits() - qc.getNqubits()) & ~1u, 8u);
108-
ms.teleportation_seed = vm["teleportation"].as<unsigned long long int>();
109-
ms.teleportation_fake = vm.count("teleportation_fake") > 0;
107+
ms.teleportationQubits = std::min((arch.getNqubits() - qc.getNqubits()) & ~1u, 8u);
108+
ms.teleportationSeed = vm["teleportation"].as<unsigned long long int>();
109+
ms.teleportationFake = vm.count("teleportationFake") > 0;
110110
}
111111

112112
mapper.map(ms);

include/Architecture.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class Architecture {
5454

5555
public:
5656

57-
struct CalibrationData {
57+
struct CalibrationData {
5858
unsigned short qubit = 0;
5959
double t1 = 0.0; // [ms]
6060
double t2 = 0.0; // [ms]
@@ -105,6 +105,9 @@ class Architecture {
105105
CouplingMap& getCurrentTeleportations() {
106106
return current_teleportations;
107107
}
108+
std::vector<std::pair<short, short>>& getTeleportationQubits() {
109+
return teleportationQubits;
110+
}
108111

109112
const Matrix& getDistanceTable() const {
110113
return distanceTable;
@@ -175,6 +178,7 @@ class Architecture {
175178
CouplingMap current_teleportations = {};
176179
bool isBidirectional = true;
177180
Matrix distanceTable = {};
181+
std::vector<std::pair<short, short>> teleportationQubits{};
178182

179183
std::vector<CalibrationData> calibrationData = {};
180184
Matrix fidelityTable = {};

include/MappingResults.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ struct MappingResults {
9797
out << "\t\t\"singlequbitgates\": " << input_singlequbitgates << ",\n";
9898
out << "\t\t\"cnots\": " << input_cnots << ",\n";
9999
out << "\t\t\"layers\": " << input_layers << ",\n";
100-
out << "\t\t\"teleportation_qubits\": " << input_teleportation_qubits << "\n";
100+
out << "\t\t\"teleportationQubits\": " << input_teleportation_qubits << "\n";
101101
out << "\t},\n";
102102
out << "\t\"mapped_circuit\": {\n";
103103
out << "\t\t\"name\": \"" << output_name << "\",\n";
@@ -107,7 +107,7 @@ struct MappingResults {
107107
out << "\t\t\"cnots\": " << output_cnots << ",\n";
108108
out << "\t\t\"swaps\": " << output_swaps << ",\n";
109109
out << "\t\t\"teleportations\": " << output_teleportations << ",\n";
110-
out << "\t\t\"teleportation_qubits\": " << output_teleportation_qubits << ",\n";
110+
out << "\t\t\"teleportationQubits\": " << output_teleportation_qubits << ",\n";
111111
out << "\t\t\"teleportation_fake\": " << output_teleportation_fake << ",\n";
112112
out << "\t\t\"direction_reverse\": " << output_direction_reverse << "\n";
113113
out << "\t}";
@@ -156,7 +156,7 @@ struct MappingResults {
156156
mapped_circuit["cnots"] = output_cnots;
157157
mapped_circuit["swaps"] = output_swaps;
158158
mapped_circuit["teleportations"] = output_teleportations;
159-
mapped_circuit["teleportation_qubits"] = output_teleportation_qubits;
159+
mapped_circuit["teleportationQubits"] = output_teleportation_qubits;
160160
mapped_circuit["teleportation_fake"] = output_teleportation_fake;
161161
mapped_circuit["direction_reverse"] = output_direction_reverse;
162162

include/MappingSettings.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ struct MappingSettings {
7878

7979
bool lookahead = true;
8080
int nrLookaheads = 15;
81-
int teleportation_qubits = 0;
82-
unsigned long long teleportation_seed = 0;
83-
bool teleportation_fake = false;
81+
int teleportationQubits = 0;
82+
unsigned long long teleportationSeed = 0;
83+
bool teleportationFake = false;
8484
double firstLookaheadFactor = 0.75;
8585
double lookaheadFactor = 0.5;
8686

include/heuristic/HeuristicMapper.hpp

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,38 +49,61 @@ class HeuristicMapper: public Mapper {
4949

5050
if(arch.getCouplingMap().find(swap) != arch.getCouplingMap().end() || arch.getCouplingMap().find(Edge {swap.second, swap.first}) != arch.getCouplingMap().end()) {
5151
swaps.back().emplace_back(swap.first, swap.second, qc::SWAP);
52-
//std::clog << "SWAP " << swap.first << " <--> " << swap.second << "\n";
5352
} else {
54-
unsigned short middle_anc = std::numeric_limits<decltype(middle_anc)>::max();
55-
for(const auto& t : arch.getCurrentTeleportations()) {
56-
if (t.first == swap.first || t.first == swap.second) {
57-
middle_anc = t.second;
58-
break;
59-
} else if (t.second == swap.first || t.second == swap.second) {
60-
middle_anc = t.first;
61-
break;
62-
}
63-
}
53+
throw QMAPException("Something wrong in applySWAP.");
54+
}
55+
}
56+
57+
void applyTeleportation(const Edge& swap, Architecture& arch) {
58+
short q1 = qubits.at(swap.first);
59+
short q2 = qubits.at(swap.second);
60+
61+
qubits.at(swap.first) = q2;
62+
qubits.at(swap.second) = q1;
63+
64+
if (q1 != -1) {
65+
locations.at(q1) = swap.second;
66+
}
67+
if (q2 != -1) {
68+
locations.at(q2) = swap.first;
69+
}
6470

65-
if (middle_anc == std::numeric_limits<decltype(middle_anc)>::max()) {
66-
throw QMAPException("Teleportation between seemingly wrong qubits: " + std::to_string(swap.first) + " <--> " + std::to_string(swap.second));
67-
}
6871

69-
unsigned short source = std::numeric_limits<decltype(source)>::max();
70-
unsigned short target = std::numeric_limits<decltype(target)>::max();
71-
if(arch.getCouplingMap().find({swap.first, middle_anc}) != arch.getCouplingMap().end()
72-
|| arch.getCouplingMap().find({middle_anc, swap.first}) != arch.getCouplingMap().end()) {
73-
source = swap.first;
74-
target = swap.second;
75-
} else {
76-
source = swap.second;
77-
target = swap.first;
72+
unsigned short middle_anc = std::numeric_limits<decltype(middle_anc)>::max();
73+
for(const auto& qpair : arch.getTeleportationQubits()) {
74+
if (swap.first == qpair.first) {
75+
middle_anc = qpair.second;
76+
} else if (swap.first == qpair.second) {
77+
middle_anc = qpair.first;
78+
} else if (swap.second == qpair.first) {
79+
middle_anc = qpair.second;
80+
} else if (swap.second == qpair.second) {
81+
middle_anc = qpair.first;
7882
}
83+
}
7984

80-
swaps.back().emplace_back(source, middle_anc, target, qc::Teleportation);
81-
//std::clog << "TELE " << source << " -(" << middle_anc << ")-> " << target << "\n";
85+
if (middle_anc == std::numeric_limits<decltype(middle_anc)>::max()) {
86+
throw QMAPException("Teleportation between seemingly wrong qubits: " + std::to_string(swap.first) + " <--> " + std::to_string(swap.second));
8287
}
83-
}
88+
89+
unsigned short source = std::numeric_limits<decltype(source)>::max();
90+
unsigned short target = std::numeric_limits<decltype(target)>::max();
91+
if(arch.getCouplingMap().find({swap.first, middle_anc}) != arch.getCouplingMap().end()
92+
|| arch.getCouplingMap().find({middle_anc, swap.first}) != arch.getCouplingMap().end()) {
93+
source = swap.first;
94+
target = swap.second;
95+
} else {
96+
source = swap.second;
97+
target = swap.first;
98+
}
99+
100+
if (source == middle_anc || target == middle_anc) {
101+
std::clog << "FAIL: TELE " << source << " -(" << middle_anc << ")-> " << target << "\n";
102+
throw QMAPException("Overlap between source/target and middle ancillary in teleportation.");
103+
}
104+
105+
swaps.back().emplace_back(source, target, middle_anc, qc::Teleportation);
106+
}
84107

85108
void updateHeuristicCost(const Architecture& arch, const Gate& gate, bool admissibleHeuristic) {
86109
auto cost = arch.distance(locations.at(gate.control), locations.at(gate.target));

jkq/qmap/bindings.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ nl::json map(const py::object& circ, const py::object& arch, const nl::json& jso
7070
}
7171

7272
if (jsonConfig.contains("use_teleportation")) {
73-
ms.teleportation_qubits = std::min((architecture.getNqubits() - qc.getNqubits()) & ~1u, 8u);
74-
ms.teleportation_seed = jsonConfig["teleportation_seed"].get<unsigned long long>();
75-
ms.teleportation_fake = jsonConfig["teleportation_fake"].get<bool>();
73+
ms.teleportationQubits = std::min((architecture.getNqubits() - qc.getNqubits()) & ~1u, 8u);
74+
ms.teleportationSeed = jsonConfig["teleportationSeed"].get<unsigned long long>();
75+
ms.teleportationFake = jsonConfig["teleportation_fake"].get<bool>();
7676
}
7777

7878

src/Mapper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ void Mapper::initResults() {
1414
results.output_qubits = architecture.getNqubits();
1515
results.layeringStrategy = settings.layeringStrategy;
1616
results.initialLayoutStrategy = settings.initialLayoutStrategy;
17-
qcMapped.addQubitRegister(architecture.getNqubits());
17+
qcMapped.addQubitRegister(architecture.getNqubits()+settings.teleportationQubits);
1818
}
1919

2020
Mapper::Mapper(qc::QuantumComputation& quantumComputation, Architecture& arch): qc(quantumComputation), architecture(arch) {

src/heuristic/HeuristicMapper.cpp

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ void HeuristicMapper::map(const MappingSettings& ms) {
1919

2020
createLayers();
2121
if (ms.verbose) {
22-
std::clog << "Teleportation qubits: " << ms.teleportation_qubits << "\n";
22+
std::clog << "Teleportation qubits: " << ms.teleportationQubits << "\n";
2323
printLayering(std::clog);
2424
}
2525

@@ -182,31 +182,31 @@ void HeuristicMapper::initResults() {
182182
Mapper::initResults();
183183
results.method = Method::Heuristic;
184184

185-
results.seed = settings.teleportation_seed;
186-
results.input_teleportation_qubits = settings.teleportation_qubits;
187-
results.output_teleportation_qubits = settings.teleportation_qubits;
188-
results.output_teleportation_fake = settings.teleportation_fake;
185+
results.seed = settings.teleportationSeed;
186+
results.input_teleportation_qubits = settings.teleportationQubits;
187+
results.output_teleportation_qubits = settings.teleportationQubits;
188+
results.output_teleportation_fake = settings.teleportationFake;
189189
}
190190

191191
void HeuristicMapper::createInitialMapping() {
192192
if (layers.empty())
193193
return;
194194

195-
if (settings.teleportation_qubits > 0) {
195+
if (settings.teleportationQubits > 0) {
196196
std::mt19937_64 mt;
197-
if (settings.teleportation_seed == 0) {
197+
if (settings.teleportationSeed == 0) {
198198
std::array<std::mt19937_64::result_type, std::mt19937_64::state_size> random_data{};
199199
std::random_device rd;
200200
std::generate(std::begin(random_data), std::end(random_data), [&rd]() { return rd(); });
201201
std::seed_seq seeds(std::begin(random_data), std::end(random_data));
202202
mt.seed(seeds);
203203
} else {
204-
mt.seed(settings.teleportation_seed);
204+
mt.seed(settings.teleportationSeed);
205205
}
206206

207207
std::uniform_int_distribution<> dis(0, architecture.getNqubits() - 1);
208208

209-
for (int i = 0; i < settings.teleportation_qubits; i += 2) {
209+
for (int i = 0; i < settings.teleportationQubits; i += 2) {
210210
Edge e;
211211
do {
212212
auto it = std::begin(architecture.getCouplingMap());
@@ -217,12 +217,11 @@ void HeuristicMapper::createInitialMapping() {
217217
locations[qc.getNqubits() + i + 1] = e.second;
218218
qubits[e.first] = qc.getNqubits() + i;
219219
qubits[e.second] = qc.getNqubits() + i + 1;
220-
//std::clog << "initial teleportation pair: " << e.first << ", " << e.second << "\n";
221220
}
222221

223-
if (settings.teleportation_fake) {
224-
settings.teleportation_qubits = 0;
225-
results.output_teleportation_qubits = settings.teleportation_qubits;
222+
if (settings.teleportationFake) {
223+
settings.teleportationQubits = 0;
224+
results.output_teleportation_qubits = settings.teleportationQubits;
226225
}
227226
}
228227

@@ -300,21 +299,34 @@ void HeuristicMapper::mapUnmappedGates(long layer, HeuristicMapper::Node& node,
300299
possibleEdges.emplace(edge);
301300
}
302301
}
302+
std::pair<unsigned short, unsigned short> chosenEdge;
303303

304304
if (possibleEdges.empty()) {
305-
throw QMAPException("Could not map logical qubits to physical qubits. No suitable edge found.");
305+
double bestScore = std::numeric_limits<int>::max();
306+
307+
for(int i=0; i < architecture.getNqubits(); i++) {
308+
for (int j = i + 1; j < architecture.getNqubits(); j++) {
309+
if (qubits.at(i) == DEFAULT_POSITION && qubits.at(j) == DEFAULT_POSITION) {
310+
double dist = architecture.distance(i, j);
311+
if (dist < bestScore) {
312+
bestScore = dist;
313+
chosenEdge = std::make_pair(i, j);
314+
}
315+
}
316+
}
317+
}
318+
} else {
319+
chosenEdge = *possibleEdges.begin();
306320
}
307-
308321
// TODO: Consider fidelity here if available. The best available edge should be chosen
309-
auto& chosenEdge = *possibleEdges.begin();
310-
locations.at(gate.control) = chosenEdge.first;
311-
locations.at(gate.target) = chosenEdge.second;
312-
qubits.at(chosenEdge.first) = gate.control;
313-
qubits.at(chosenEdge.second) = gate.target;
314-
qc::QuantumComputation::findAndSWAP(gate.control, chosenEdge.first, qcMapped.initialLayout);
315-
qc::QuantumComputation::findAndSWAP(gate.target, chosenEdge.second, qcMapped.initialLayout);
316-
qc::QuantumComputation::findAndSWAP(gate.control, chosenEdge.first, qcMapped.outputPermutation);
317-
qc::QuantumComputation::findAndSWAP(gate.target, chosenEdge.second, qcMapped.outputPermutation);
322+
locations.at(gate.control) = chosenEdge.first;
323+
locations.at(gate.target) = chosenEdge.second;
324+
qubits.at(chosenEdge.first) = gate.control;
325+
qubits.at(chosenEdge.second) = gate.target;
326+
qc::QuantumComputation::findAndSWAP(gate.control, chosenEdge.first, qcMapped.initialLayout);
327+
qc::QuantumComputation::findAndSWAP(gate.target, chosenEdge.second, qcMapped.initialLayout);
328+
qc::QuantumComputation::findAndSWAP(gate.control, chosenEdge.first, qcMapped.outputPermutation);
329+
qc::QuantumComputation::findAndSWAP(gate.target, chosenEdge.second, qcMapped.outputPermutation);
318330
} else if (controlLocation == DEFAULT_POSITION) {
319331
mapToMinDistance(gate.target, gate.control);
320332
} else if (targetLocation == DEFAULT_POSITION) {
@@ -382,7 +394,9 @@ void HeuristicMapper::expandNode(const std::vector<unsigned short>& consideredQu
382394

383395
std::set<Edge> perms = architecture.getCouplingMap();
384396
architecture.getCurrentTeleportations().clear();
385-
for(int i = 0; i < settings.teleportation_qubits; i+=2) {
397+
architecture.getTeleportationQubits().clear();
398+
for(int i = 0; i < settings.teleportationQubits; i+=2) {
399+
architecture.getTeleportationQubits().emplace_back(node.locations[qc.getNqubits() + i], node.locations[qc.getNqubits() + i + 1]);
386400
Edge e;
387401
for(auto const& g : architecture.getCouplingMap()) {
388402
if(g.first == node.locations[qc.getNqubits() + i] && g.second != node.locations[qc.getNqubits() + i + 1]) {
@@ -434,14 +448,22 @@ void HeuristicMapper::expand_node_add_one_swap(const Edge &swap, Node& node, lon
434448

435449
Node new_node = Node(node.qubits, node.locations, node.swaps);
436450
new_node.nswaps++;
437-
if (architecture.bidirectional()) {
438-
new_node.costFixed = node.costFixed + COST_BIDIRECTIONAL_SWAP;
439-
} else {
440-
new_node.costFixed = node.costFixed + COST_UNIDIRECTIONAL_SWAP;
441-
}
442451

443452
new_node.swaps.emplace_back();
444-
new_node.applySWAP(swap, architecture);
453+
if(architecture.getCouplingMap().find(swap) != architecture.getCouplingMap().end() ||
454+
architecture.getCouplingMap().find(Edge {swap.second, swap.first}) != architecture.getCouplingMap().end()) {
455+
456+
if (architecture.bidirectional()) {
457+
new_node.costFixed = node.costFixed + COST_BIDIRECTIONAL_SWAP;
458+
} else {
459+
new_node.costFixed = node.costFixed + COST_UNIDIRECTIONAL_SWAP;
460+
}
461+
462+
new_node.applySWAP(swap, architecture);
463+
} else {
464+
new_node.costFixed = node.costFixed + COST_TELEPORTATION;
465+
new_node.applyTeleportation(swap, architecture);
466+
}
445467
new_node.costTotal = new_node.costFixed;
446468
new_node.done = true;
447469

0 commit comments

Comments
 (0)