74 maxVirtualExtent = val;
76 if (nrQubits == 0)
return;
78 const double untruncatedMaxExtent = std::pow(physExtent, nrQubits / 2);
80 static_cast<IndexType>(untruncatedMaxExtent);
82 if (untruncatedMaxExtent >= std::numeric_limits<IndexType>::max() ||
83 std::isnan(untruncatedMaxExtent) || std::isinf(untruncatedMaxExtent))
84 maxVirtualExtentLimit = std::numeric_limits<IndexType>::max() - 1;
85 else if (untruncatedMaxExtent < 2)
86 maxVirtualExtentLimit = 2;
88 maxVirtualExtent = maxVirtualExtent == 0
89 ? maxVirtualExtentLimit
90 : std::min(maxVirtualExtent, maxVirtualExtentLimit);
92 bondCost.resize(nrQubits - 1);
93 maxBondDim.resize(nrQubits - 1);
94 currentBondDim.assign(nrQubits - 1, 1.0);
98 for (
IndexType i = 0; i < static_cast<IndexType>(nrQubits); ++i) {
99 double maxExtent1 = std::pow((
double)physExtent, (
double)i + 1.);
101 std::pow((
double)physExtent, (
double)nrQubits - i - 1.);
103 if (maxExtent1 >= (
double)std::numeric_limits<size_t>::max() ||
104 std::isnan(maxExtent1) || std::isinf(maxExtent1))
105 maxExtent1 = (double)std::numeric_limits<size_t>::max() - 1;
106 else if (maxExtent1 < 1)
109 if (maxExtent2 > (
double)std::numeric_limits<size_t>::max() ||
110 std::isnan(maxExtent2) || std::isinf(maxExtent2))
111 maxExtent2 = (double)std::numeric_limits<size_t>::max() - 1;
112 else if (maxExtent2 < 1)
115 size_t maxRightExtent = (size_t)std::min<double>(
116 {maxExtent1, maxExtent2, (double)maxVirtualExtent});
117 if (maxRightExtent < 2) maxRightExtent = 2;
119 if (i <
static_cast<IndexType>(nrQubits) - 1) {
120 maxBondDim[i] =
static_cast<double>(maxRightExtent);
121 const double maxRightExtentD =
static_cast<double>(maxRightExtent);
122 bondCost[i] = maxRightExtentD * maxRightExtentD * maxRightExtentD;
267 long long int currentGateIndex,
int lookaheadDepth,
268 int lookaheadDepthWithHeuristic,
double currentCost,
double& bestCost,
269 bool useSameDummy =
false) {
270 if (currentGateIndex >=
static_cast<long long int>(upcomingGates.size())) {
271 if (currentCost < bestCost) bestCost = currentCost;
276 while (currentGateIndex <
277 static_cast<long long int>(upcomingGates.size()) &&
278 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
281 if (currentGateIndex >=
static_cast<long long int>(upcomingGates.size())) {
282 if (currentCost < bestCost) bestCost = currentCost;
286 const auto& op = upcomingGates[currentGateIndex];
287 const auto qbits = op->AffectedQubits();
289 assert(qbits.size() >= 2);
300 if (realq1 > realq2) std::swap(realq1, realq2);
305 if (realq2 - realq1 > 1)
314 if (currentCost >= bestCost)
return;
316 if (lookaheadDepth <= 0) {
317 if (currentCost < bestCost) bestCost = currentCost;
324 while (currentGateIndex <
325 static_cast<long long int>(upcomingGates.size()) &&
326 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
329 if (currentGateIndex >=
330 static_cast<long long int>(upcomingGates.size())) {
331 if (currentCost < bestCost) bestCost = currentCost;
336 lookaheadDepth - 1, lookaheadDepthWithHeuristic,
337 currentCost, bestCost);
340 dummySim.maxVirtualExtent = maxVirtualExtent;
341 dummySim.maxBondDim = maxBondDim;
342 dummySim.currentBondDim = currentBondDim;
343 dummySim.bondCost = bondCost;
344 dummySim.qubitsMap = qubitsMap;
345 dummySim.qubitsMapInv.resize(qubitsMap.size());
346 for (
size_t i = 0; i < qubitsMap.size(); ++i)
347 dummySim.qubitsMapInv[qubitsMap[i]] =
static_cast<IndexType>(i);
349 dummySim.setTotalSwappingCost(0);
351 if (realq2 - realq1 > 1)
352 dummySim.SwapQubitsToPosition(qubit1, qubit2, meetPosition);
354 dummySim.ApplyGate(op);
357 currentCost += dummySim.getTotalSwappingCost();
360 if (currentCost >= bestCost)
return;
363 if (lookaheadDepth <= 0) {
364 if (currentCost < bestCost) bestCost = currentCost;
371 while (currentGateIndex <
372 static_cast<long long int>(upcomingGates.size()) &&
373 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
376 if (currentGateIndex >=
377 static_cast<long long int>(upcomingGates.size())) {
378 if (currentCost < bestCost) bestCost = currentCost;
382 dummySim.FindBestMeetingPosition(
383 upcomingGates, currentGateIndex, lookaheadDepth - 1,
384 lookaheadDepthWithHeuristic, currentCost, bestCost);
393 long long int currentGateIndex,
int lookaheadDepth,
394 int lookaheadDepthWithHeuristic,
double currentCost,
double& bestCost) {
395 const auto& op = upcomingGates[currentGateIndex];
396 const auto qbits = op->AffectedQubits();
398 assert(qbits.size() >= 2);
406 if (realq1 > realq2) std::swap(realq1, realq2);
408 if (lookaheadDepth <= 0) {
410 ? ComputeHeuristicMeetPosition(realq1, realq2)
413 lookaheadDepthWithHeuristic, currentCost,
418 if (realq2 - realq1 <= 1) {
420 realq1, upcomingGates, currentGateIndex, lookaheadDepth,
421 lookaheadDepthWithHeuristic, currentCost, bestCost,
422 lookaheadDepth <= lookaheadDepthWithHeuristic);
429 if (lookaheadDepth <= lookaheadDepthWithHeuristic) {
430 bestPosition = ComputeHeuristicMeetPosition(realq1, realq2);
432 lookaheadDepth, lookaheadDepthWithHeuristic,
433 currentCost, bestCost,
true);
435 for (
IndexType m = realq1; m < realq2; ++m) {
436 const double oldCost = bestCost;
438 lookaheadDepth, lookaheadDepthWithHeuristic,
439 currentCost, bestCost);
441 if (bestCost < oldCost) bestPosition = m;
450 int nrShuffles = 0,
int nrSwaps = 0) {
453 if (layers.empty() || nrQubits <= 2)
return qubitsMap;
457 [&,
this](
const std::vector<IndexType>& candidateMap) ->
double {
458 auto saveQubitsMap = qubitsMap;
459 auto saveQubitsMapInv = qubitsMapInv;
460 auto saveCurrentBondDim = currentBondDim;
461 auto saveTotalSwappingCost = totalSwappingCost;
462 auto saveBondCost = bondCost;
466 for (
const auto& layer : layers)
469 qubitsMap = std::move(saveQubitsMap);
470 qubitsMapInv = std::move(saveQubitsMapInv);
471 currentBondDim = std::move(saveCurrentBondDim);
472 totalSwappingCost = saveTotalSwappingCost;
473 bondCost = std::move(saveBondCost);
478 auto evaluateCostBounded = [&,
this](
479 const std::vector<IndexType>& candidateMap,
480 double bound) ->
double {
481 auto saveQubitsMap = qubitsMap;
482 auto saveQubitsMapInv = qubitsMapInv;
483 auto saveCurrentBondDim = currentBondDim;
484 auto saveTotalSwappingCost = totalSwappingCost;
485 auto saveBondCost = bondCost;
489 for (
const auto& layer : layers) {
494 qubitsMap = std::move(saveQubitsMap);
495 qubitsMapInv = std::move(saveQubitsMapInv);
496 currentBondDim = std::move(saveCurrentBondDim);
497 totalSwappingCost = saveTotalSwappingCost;
498 bondCost = std::move(saveBondCost);
504 qubitsMap = std::move(saveQubitsMap);
505 qubitsMapInv = std::move(saveQubitsMapInv);
506 currentBondDim = std::move(saveCurrentBondDim);
507 totalSwappingCost = saveTotalSwappingCost;
508 bondCost = std::move(saveBondCost);
518 std::vector<std::vector<QubitPair>> layerPairs;
520 for (
size_t li = 0; li < layers.size(); ++li) {
521 const auto& layer = layers[li];
522 std::vector<QubitPair> lp;
523 for (
const auto& op : layer->GetOperations()) {
524 auto qbits = op->AffectedQubits();
525 if (qbits.size() >= 2) {
526 if (qbits[0] > qbits[1]) std::swap(qbits[0], qbits[1]);
528 lp.push_back({
static_cast<IndexType>(qbits[0]),
532 if (!lp.empty()) layerPairs.push_back(std::move(lp));
534 if (layerPairs.empty())
return qubitsMap;
544 auto buildChain = [&](
const std::vector<std::vector<QubitPair>>& orderedLP)
545 -> std::vector<long long int> {
546 std::vector<std::deque<IndexType>> groups;
547 std::vector<int> qubitGroup(nrQubits, -1);
548 std::unordered_set<IndexType> placedQubits;
550 for (
const auto& lp : orderedLP) {
551 for (
const auto& p : lp) {
552 const int g1 = qubitGroup[p.q1];
553 const int g2 = qubitGroup[p.q2];
555 if (g1 < 0 && g2 < 0) {
557 const int gIdx =
static_cast<int>(groups.size());
558 groups.push_back({p.q1, p.q2});
559 qubitGroup[p.q1] = gIdx;
560 qubitGroup[p.q2] = gIdx;
561 placedQubits.insert(p.q1);
562 placedQubits.insert(p.q2);
563 }
else if (g1 >= 0 && g2 < 0) {
565 auto& grp = groups[g1];
567 for (
size_t i = 0; i < grp.size(); ++i)
568 if (grp[i] == p.q1) {
573 if (idx + 1 <= grp.size() - idx)
574 grp.push_front(p.q2);
577 qubitGroup[p.q2] = g1;
578 placedQubits.insert(p.q2);
579 }
else if (g1 < 0 && g2 >= 0) {
581 auto& grp = groups[g2];
583 for (
size_t i = 0; i < grp.size(); ++i)
584 if (grp[i] == p.q2) {
588 if (idx + 1 <= grp.size() - idx)
589 grp.push_front(p.q1);
592 qubitGroup[p.q1] = g2;
593 placedQubits.insert(p.q1);
594 }
else if (g1 != g2) {
596 auto& grpA = groups[g1];
597 auto& grpB = groups[g2];
598 size_t idxA = 0, idxB = 0;
599 for (
size_t i = 0; i < grpA.size(); ++i)
600 if (grpA[i] == p.q1) {
604 for (
size_t i = 0; i < grpB.size(); ++i)
605 if (grpB[i] == p.q2) {
611 const size_t distAB = grpA.size() + idxB - idxA;
612 const size_t distBA = grpB.size() + idxA - idxB;
615 if (distAB <= distBA) {
616 for (
const auto q : grpB) grpA.push_back(q);
620 for (
const auto q : grpA) grpB.push_back(q);
624 for (
const auto q : groups[mergedGroup])
625 qubitGroup[q] = mergedGroup;
629 if (placedQubits.size() ==
static_cast<size_t>(nrQubits))
633 if (placedQubits.size() ==
static_cast<size_t>(nrQubits))
638 std::vector<IndexType> chain;
639 chain.reserve(nrQubits);
640 for (
const auto& grp : groups)
641 for (
const auto q : grp) chain.push_back(q);
645 if (qubitGroup[q] < 0) chain.push_back(q);
647 assert(chain.size() ==
static_cast<size_t>(nrQubits));
650 std::vector<long long int> result(nrQubits);
651 for (
size_t i = 0; i < chain.size(); ++i)
652 result[chain[i]] =
static_cast<long long int>(i);
657 auto optMap = buildChain(layerPairs);
658 if (layers.size() <= 2)
return optMap;
659 auto optCost = evaluateCost(optMap);
661 std::vector<long long int> qubitsMap(nrQubits);
662 std::iota(qubitsMap.begin(), qubitsMap.end(), 0);
663 double tryCost = evaluateCostBounded(qubitsMap, optCost);
664 if (tryCost < optCost) {
671 std::mt19937 rng(42);
672 for (
int i = 0; i < nrShuffles; ++i) {
673 std::shuffle(qubitsMap.begin(), qubitsMap.end(), rng);
674 tryCost = evaluateCostBounded(qubitsMap, optCost);
675 if (tryCost < optCost) {
682 std::uniform_int_distribution<IndexType> qubitDist(0, nrQubits - 1);
683 std::uniform_int_distribution<int> nrSwapsDist(
684 1, std::min<int>(3,
static_cast<int>(nrQubits) / 2));
686 const int maxNoImprove = std::max(nrShuffles,
static_cast<int>(nrQubits));
687 const int maxTotalShuffles = maxNoImprove * 3;
688 int noImproveCount = 0;
690 for (
int s = 0; s < maxTotalShuffles && noImproveCount < maxNoImprove; ++s) {
691 auto tryMap = optMap;
692 const int nrSwaps = nrSwapsDist(rng);
693 for (
int sw = 0; sw < nrSwaps; ++sw) {
696 while (b == a) b = qubitDist(rng);
697 std::swap(tryMap[a], tryMap[b]);
700 auto cost = evaluateCostBounded(tryMap, optCost);
701 if (cost < optCost) {
713 auto candidate = optMap;
714 bool improved =
true;
715 for (
int improvementCount = 0; improved && improvementCount < nrSwaps;
716 ++improvementCount) {
718 for (
IndexType i = 0; i < nrQubits; ++i) {
719 for (
IndexType j = i + 1; j < nrQubits; ++j) {
721 std::swap(candidate[i], candidate[j]);
722 auto cost = evaluateCostBounded(candidate, optCost);
723 if (cost < optCost) {
729 std::swap(candidate[i], candidate[j]);
804 if (realq1 > realq2) {
805 std::swap(realq1, realq2);
806 std::swap(qubit1, qubit2);
809 if (realq2 - realq1 <= 1)
return;
811 assert(meetPosition >= realq1 && meetPosition < realq2);
816 while (movingReal < meetPosition) {
818 const IndexType toInv = qubitsMapInv[toReal];
820 qubitsMap[toInv] = movingReal;
821 qubitsMapInv[movingReal] = toInv;
823 qubitsMap[qubit1] = toReal;
824 qubitsMapInv[toReal] = qubit1;
826 totalSwappingCost += bondCost[movingReal];
827 growBondDimension(movingReal,
true);
835 while (movingReal > meetPosition + 1) {
837 const IndexType toInv = qubitsMapInv[toReal];
839 qubitsMap[toInv] = movingReal;
840 qubitsMapInv[movingReal] = toInv;
842 qubitsMap[qubit2] = toReal;
843 qubitsMapInv[toReal] = qubit2;
845 totalSwappingCost += bondCost[toReal];
846 growBondDimension(toReal,
true);
851 assert(abs(qubitsMap[qubit1] - qubitsMap[qubit2]) == 1);