@@ -256,25 +256,27 @@ void ExactMapper::map(const Configuration& settings) {
256256 for (std::size_t i = 0U ; i < layers.size (); ++i) {
257257 if (i == 0U ) {
258258 qcMapped.initialLayout .clear ();
259- qcMapped.outputPermutation .clear ();
260259
261260 // no swaps but initial permutation
262261 for (const auto & [physical, logical] : *swapsIterator) {
263262 locations.at (logical) = static_cast <std::int16_t >(physical);
264263 qubits.at (physical) = static_cast <std::int16_t >(logical);
265264 qcMapped.initialLayout [static_cast <qc::Qubit>(physical)] =
266265 static_cast <qc::Qubit>(logical);
267- qcMapped.outputPermutation [static_cast <qc::Qubit>(physical)] =
268- static_cast <qc::Qubit>(logical);
269266 }
270267
271268 // place remaining architecture qubits
272269 placeRemainingArchitectureQubits ();
273270
274271 if (settings.verbose ) {
272+ std::cout << " Qubits: " ;
275273 for (auto q = 0U ; q < architecture.getNqubits (); ++q) {
276274 std::cout << qubits.at (q) << " " ;
277275 }
276+ std::cout << " Locations: " ;
277+ for (std::size_t q = 0 ; q < qc.getNqubits (); ++q) {
278+ std::cout << locations.at (q) << " " ;
279+ }
278280 std::cout << std::endl;
279281 }
280282 ++swapsIterator;
@@ -341,19 +343,23 @@ void ExactMapper::map(const Configuration& settings) {
341343 // apply swaps before layer
342344 for (auto it = (*swapsIterator).rbegin (); it != (*swapsIterator).rend ();
343345 ++it) {
344- auto & swap = *it;
345- qcMapped.swap (swap.first , swap.second );
346- std::swap (qcMapped.outputPermutation .at (swap.first ),
347- qcMapped.outputPermutation .at (swap.second ));
348- std::swap (qubits.at (swap.first ), qubits.at (swap.second ));
349- std::swap (
350- locations.at (static_cast <std::size_t >(qubits.at (swap.first ))),
351- locations.at (static_cast <std::size_t >(qubits.at (swap.second ))));
346+ const auto & [q0, q1] = *it;
347+ const auto logical0 = static_cast <qc::Qubit>(qubits.at (q0));
348+ const auto logical1 = static_cast <qc::Qubit>(qubits.at (q1));
349+ qcMapped.swap (q0, q1);
350+ std::swap (qubits.at (q0), qubits.at (q1));
351+ locations.at (logical0) = static_cast <std::int16_t >(q1);
352+ locations.at (logical1) = static_cast <std::int16_t >(q0);
352353
353354 if (settings.verbose ) {
355+ std::cout << " Qubits: " ;
354356 for (auto q = 0U ; q < architecture.getNqubits (); ++q) {
355357 std::cout << qubits.at (q) << " " ;
356358 }
359+ std::cout << " Locations: " ;
360+ for (std::size_t q = 0 ; q < qc.getNqubits (); ++q) {
361+ std::cout << locations.at (q) << " " ;
362+ }
357363 std::cout << std::endl;
358364 }
359365 }
@@ -363,6 +369,13 @@ void ExactMapper::map(const Configuration& settings) {
363369 }
364370 }
365371
372+ // set output permutation
373+ qcMapped.outputPermutation .clear ();
374+ for (qc::Qubit logical = 0 ; logical < qc.getNqubits (); ++logical) {
375+ const auto physical = static_cast <qc::Qubit>(locations.at (logical));
376+ qcMapped.outputPermutation [physical] = logical;
377+ }
378+
366379 // 9) apply post mapping optimizations
367380 postMappingOptimizations (config);
368381
@@ -783,22 +796,51 @@ number of variables: (|L|-1) * m!
783796 assert (choiceResults.output .directionReverse == 0U );
784797 // swaps
785798 for (std::size_t k = 1 ; k < reducedLayerIndices.size (); ++k) {
786- auto & i = x[k - 1 ];
787- auto & j = x[k];
788-
789- for (const auto qubit : qubitChoice) {
790- for (std::size_t q = 0 ; q < qc.getNqubits (); ++q) {
791- if (m->getBoolValue (i[physicalQubitIndex[qubit]][q], lb.get ())) {
792- // logical qubit q was mapped to physical qubit Q
793- for (const auto otherQubit : qubitChoice) {
794- // and has been assigned to physical qubit P going forward
795- if (m->getBoolValue (j[physicalQubitIndex[otherQubit]][q],
796- lb.get ())) {
797- pi[physicalQubitIndex[qubit]] = otherQubit;
799+ if (qubitChoice.size () == qc.getNqubits ()) {
800+ // When as many qubits of the architecture are being considered
801+ // as in the circuit, the assignment of the logical to the physical
802+ // qubits is a bijection. Hence, we the assignment matrices X can be
803+ // used to directly infer the permutation of the qubits in each layer.
804+ auto & oldAssignment = x[k - 1 ];
805+ auto & newAssignment = x[k];
806+ for (const auto physicalQubit : qubitChoice) {
807+ for (std::size_t logicalQubit = 0 ; logicalQubit < qc.getNqubits ();
808+ ++logicalQubit) {
809+ if (const auto oldIndex = physicalQubitIndex[physicalQubit];
810+ m->getBoolValue (oldAssignment[oldIndex][logicalQubit],
811+ lb.get ())) {
812+ for (const auto newPhysicalQubit : qubitChoice) {
813+ if (const auto newIndex = physicalQubitIndex[newPhysicalQubit];
814+ m->getBoolValue (newAssignment[newIndex][logicalQubit],
815+ lb.get ())) {
816+ pi[oldIndex] = newPhysicalQubit;
817+ break ;
818+ }
798819 }
820+ break ;
799821 }
800822 }
801823 }
824+ } else {
825+ // When more qubits of the architecture are being considered than are in
826+ // the circuit, the assignment of the logical to the physical qubits
827+ // cannot be a bijection. Hence, the permutation variables y have to be
828+ // used to infer the permutation of the qubits in each layer. This is
829+ // mainly because the additional qubits movement cannot be inferred
830+ // from the assignment matrices X.
831+ piCount = 0 ;
832+ internalPiCount = 0 ;
833+ // sort the permutation of the qubits to start fresh
834+ std::sort (pi.begin (), pi.end ());
835+ do {
836+ if (skippedPi.count (piCount) == 0 || !config.enableSwapLimits ) {
837+ if (m->getBoolValue (y[k - 1 ][internalPiCount], lb.get ())) {
838+ break ;
839+ }
840+ ++internalPiCount;
841+ }
842+ ++piCount;
843+ } while (std::next_permutation (pi.begin (), pi.end ()));
802844 }
803845
804846 architecture.minimumNumberOfSwaps (pi, swaps.at (k));
0 commit comments