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;
261 long long int currentGateIndex,
int lookaheadDepth,
262 int lookaheadDepthWithHeuristic,
double currentCost,
double& bestCost,
263 bool useSameDummy =
false) {
264 if (currentGateIndex >=
static_cast<long long int>(upcomingGates.size())) {
265 if (currentCost < bestCost) bestCost = currentCost;
270 while (currentGateIndex <
271 static_cast<long long int>(upcomingGates.size()) &&
272 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
275 if (currentGateIndex >=
static_cast<long long int>(upcomingGates.size())) {
276 if (currentCost < bestCost) bestCost = currentCost;
280 const auto& op = upcomingGates[currentGateIndex];
281 const auto qbits = op->AffectedQubits();
283 assert(qbits.size() >= 2);
294 if (realq1 > realq2) std::swap(realq1, realq2);
299 if (realq2 - realq1 > 1)
308 if (currentCost >= bestCost)
return;
310 if (lookaheadDepth <= 0) {
311 if (currentCost < bestCost) bestCost = currentCost;
318 while (currentGateIndex <
319 static_cast<long long int>(upcomingGates.size()) &&
320 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
323 if (currentGateIndex >=
324 static_cast<long long int>(upcomingGates.size())) {
325 if (currentCost < bestCost) bestCost = currentCost;
330 lookaheadDepth - 1, lookaheadDepthWithHeuristic,
331 currentCost, bestCost);
334 dummySim.maxVirtualExtent = maxVirtualExtent;
335 dummySim.maxBondDim = maxBondDim;
336 dummySim.currentBondDim = currentBondDim;
337 dummySim.bondCost = bondCost;
338 dummySim.qubitsMap = qubitsMap;
339 dummySim.qubitsMapInv.resize(qubitsMap.size());
340 for (
size_t i = 0; i < qubitsMap.size(); ++i)
341 dummySim.qubitsMapInv[qubitsMap[i]] =
static_cast<IndexType>(i);
343 dummySim.setTotalSwappingCost(0);
345 if (realq2 - realq1 > 1)
346 dummySim.SwapQubitsToPosition(qubit1, qubit2, meetPosition);
348 dummySim.ApplyGate(op);
351 currentCost += dummySim.getTotalSwappingCost();
354 if (currentCost >= bestCost)
return;
357 if (lookaheadDepth <= 0) {
358 if (currentCost < bestCost) bestCost = currentCost;
365 while (currentGateIndex <
366 static_cast<long long int>(upcomingGates.size()) &&
367 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
370 if (currentGateIndex >=
371 static_cast<long long int>(upcomingGates.size())) {
372 if (currentCost < bestCost) bestCost = currentCost;
376 dummySim.FindBestMeetingPosition(
377 upcomingGates, currentGateIndex, lookaheadDepth - 1,
378 lookaheadDepthWithHeuristic, currentCost, bestCost);
387 long long int currentGateIndex,
int lookaheadDepth,
388 int lookaheadDepthWithHeuristic,
double currentCost,
double& bestCost) {
389 const auto& op = upcomingGates[currentGateIndex];
390 const auto qbits = op->AffectedQubits();
392 assert(qbits.size() >= 2);
400 if (realq1 > realq2) std::swap(realq1, realq2);
402 if (lookaheadDepth <= 0) {
404 ? ComputeHeuristicMeetPosition(realq1, realq2)
407 lookaheadDepthWithHeuristic, currentCost,
412 if (realq2 - realq1 <= 1) {
414 realq1, upcomingGates, currentGateIndex, lookaheadDepth,
415 lookaheadDepthWithHeuristic, currentCost, bestCost,
416 lookaheadDepth <= lookaheadDepthWithHeuristic);
423 if (lookaheadDepth <= lookaheadDepthWithHeuristic) {
424 bestPosition = ComputeHeuristicMeetPosition(realq1, realq2);
426 lookaheadDepth, lookaheadDepthWithHeuristic,
427 currentCost, bestCost,
true);
429 for (
IndexType m = realq1; m < realq2; ++m) {
430 const double oldCost = bestCost;
432 lookaheadDepth, lookaheadDepthWithHeuristic,
433 currentCost, bestCost);
435 if (bestCost < oldCost) bestPosition = m;
444 int nrShuffles = 25,
int nrSwaps = 10) {
447 if (layers.empty() || nrQubits <= 2)
return qubitsMap;
451 [&,
this](
const std::vector<IndexType>& candidateMap) ->
double {
452 auto saveQubitsMap = qubitsMap;
453 auto saveQubitsMapInv = qubitsMapInv;
454 auto saveCurrentBondDim = currentBondDim;
455 auto saveTotalSwappingCost = totalSwappingCost;
456 auto saveBondCost = bondCost;
460 for (
const auto& layer : layers)
463 qubitsMap = std::move(saveQubitsMap);
464 qubitsMapInv = std::move(saveQubitsMapInv);
465 currentBondDim = std::move(saveCurrentBondDim);
466 totalSwappingCost = saveTotalSwappingCost;
467 bondCost = std::move(saveBondCost);
472 auto evaluateCostBounded = [&,
this](
473 const std::vector<IndexType>& candidateMap,
474 double bound) ->
double {
475 auto saveQubitsMap = qubitsMap;
476 auto saveQubitsMapInv = qubitsMapInv;
477 auto saveCurrentBondDim = currentBondDim;
478 auto saveTotalSwappingCost = totalSwappingCost;
479 auto saveBondCost = bondCost;
483 for (
const auto& layer : layers) {
488 qubitsMap = std::move(saveQubitsMap);
489 qubitsMapInv = std::move(saveQubitsMapInv);
490 currentBondDim = std::move(saveCurrentBondDim);
491 totalSwappingCost = saveTotalSwappingCost;
492 bondCost = std::move(saveBondCost);
498 qubitsMap = std::move(saveQubitsMap);
499 qubitsMapInv = std::move(saveQubitsMapInv);
500 currentBondDim = std::move(saveCurrentBondDim);
501 totalSwappingCost = saveTotalSwappingCost;
502 bondCost = std::move(saveBondCost);
512 std::vector<std::vector<QubitPair>> layerPairs;
514 for (
size_t li = 0; li < layers.size(); ++li) {
515 const auto& layer = layers[li];
516 std::vector<QubitPair> lp;
517 for (
const auto& op : layer->GetOperations()) {
518 auto qbits = op->AffectedQubits();
519 if (qbits.size() >= 2) {
520 if (qbits[0] > qbits[1]) std::swap(qbits[0], qbits[1]);
522 lp.push_back({
static_cast<IndexType>(qbits[0]),
526 if (!lp.empty()) layerPairs.push_back(std::move(lp));
528 if (layerPairs.empty())
return qubitsMap;
538 auto buildChain = [&](
const std::vector<std::vector<QubitPair>>& orderedLP)
539 -> std::vector<long long int> {
540 std::vector<std::deque<IndexType>> groups;
541 std::vector<int> qubitGroup(nrQubits, -1);
542 std::unordered_set<IndexType> placedQubits;
544 for (
const auto& lp : orderedLP) {
545 for (
const auto& p : lp) {
546 const int g1 = qubitGroup[p.q1];
547 const int g2 = qubitGroup[p.q2];
549 if (g1 < 0 && g2 < 0) {
551 const int gIdx =
static_cast<int>(groups.size());
552 groups.push_back({p.q1, p.q2});
553 qubitGroup[p.q1] = gIdx;
554 qubitGroup[p.q2] = gIdx;
555 placedQubits.insert(p.q1);
556 placedQubits.insert(p.q2);
557 }
else if (g1 >= 0 && g2 < 0) {
559 auto& grp = groups[g1];
561 for (
size_t i = 0; i < grp.size(); ++i)
562 if (grp[i] == p.q1) {
567 if (idx + 1 <= grp.size() - idx)
568 grp.push_front(p.q2);
571 qubitGroup[p.q2] = g1;
572 placedQubits.insert(p.q2);
573 }
else if (g1 < 0 && g2 >= 0) {
575 auto& grp = groups[g2];
577 for (
size_t i = 0; i < grp.size(); ++i)
578 if (grp[i] == p.q2) {
582 if (idx + 1 <= grp.size() - idx)
583 grp.push_front(p.q1);
586 qubitGroup[p.q1] = g2;
587 placedQubits.insert(p.q1);
588 }
else if (g1 != g2) {
590 auto& grpA = groups[g1];
591 auto& grpB = groups[g2];
592 size_t idxA = 0, idxB = 0;
593 for (
size_t i = 0; i < grpA.size(); ++i)
594 if (grpA[i] == p.q1) {
598 for (
size_t i = 0; i < grpB.size(); ++i)
599 if (grpB[i] == p.q2) {
605 const size_t distAB = grpA.size() + idxB - idxA;
606 const size_t distBA = grpB.size() + idxA - idxB;
609 if (distAB <= distBA) {
610 for (
const auto q : grpB) grpA.push_back(q);
614 for (
const auto q : grpA) grpB.push_back(q);
618 for (
const auto q : groups[mergedGroup])
619 qubitGroup[q] = mergedGroup;
623 if (placedQubits.size() ==
static_cast<size_t>(nrQubits))
627 if (placedQubits.size() ==
static_cast<size_t>(nrQubits))
632 std::vector<IndexType> chain;
633 chain.reserve(nrQubits);
634 for (
const auto& grp : groups)
635 for (
const auto q : grp) chain.push_back(q);
639 if (qubitGroup[q] < 0) chain.push_back(q);
641 assert(chain.size() ==
static_cast<size_t>(nrQubits));
644 std::vector<long long int> result(nrQubits);
645 for (
size_t i = 0; i < chain.size(); ++i)
646 result[chain[i]] =
static_cast<long long int>(i);
651 auto optMap = buildChain(layerPairs);
652 if (layers.size() <= 2)
return optMap;
653 auto optCost = evaluateCost(optMap);
655 std::vector<long long int> qubitsMap(nrQubits);
656 std::iota(qubitsMap.begin(), qubitsMap.end(), 0);
657 double tryCost = evaluateCostBounded(qubitsMap, optCost);
658 if (tryCost < optCost) {
665 std::mt19937 rng(42);
666 for (
int i = 0; i < nrShuffles; ++i) {
667 std::shuffle(qubitsMap.begin(), qubitsMap.end(), rng);
668 tryCost = evaluateCostBounded(qubitsMap, optCost);
669 if (tryCost < optCost) {
676 std::uniform_int_distribution<IndexType> qubitDist(0, nrQubits - 1);
677 std::uniform_int_distribution<int> nrSwapsDist(
678 1, std::min<int>(3,
static_cast<int>(nrQubits) / 2));
680 const int maxNoImprove = std::max(nrShuffles,
static_cast<int>(nrQubits));
681 const int maxTotalShuffles = maxNoImprove * 3;
682 int noImproveCount = 0;
684 for (
int s = 0; s < maxTotalShuffles && noImproveCount < maxNoImprove; ++s) {
685 auto tryMap = optMap;
686 const int nrSwaps = nrSwapsDist(rng);
687 for (
int sw = 0; sw < nrSwaps; ++sw) {
690 while (b == a) b = qubitDist(rng);
691 std::swap(tryMap[a], tryMap[b]);
694 auto cost = evaluateCostBounded(tryMap, optCost);
695 if (cost < optCost) {
707 auto candidate = optMap;
708 bool improved =
true;
709 for (
int improvementCount = 0; improved && improvementCount < nrSwaps;
710 ++improvementCount) {
712 for (
IndexType i = 0; i < nrQubits; ++i) {
713 for (
IndexType j = i + 1; j < nrQubits; ++j) {
715 std::swap(candidate[i], candidate[j]);
716 auto cost = evaluateCostBounded(candidate, optCost);
717 if (cost < optCost) {
723 std::swap(candidate[i], candidate[j]);
798 if (realq1 > realq2) {
799 std::swap(realq1, realq2);
800 std::swap(qubit1, qubit2);
803 if (realq2 - realq1 <= 1)
return;
805 assert(meetPosition >= realq1 && meetPosition < realq2);
810 while (movingReal < meetPosition) {
812 const IndexType toInv = qubitsMapInv[toReal];
814 qubitsMap[toInv] = movingReal;
815 qubitsMapInv[movingReal] = toInv;
817 qubitsMap[qubit1] = toReal;
818 qubitsMapInv[toReal] = qubit1;
820 totalSwappingCost += bondCost[movingReal];
821 growBondDimension(movingReal,
true);
829 while (movingReal > meetPosition + 1) {
831 const IndexType toInv = qubitsMapInv[toReal];
833 qubitsMap[toInv] = movingReal;
834 qubitsMapInv[movingReal] = toInv;
836 qubitsMap[qubit2] = toReal;
837 qubitsMapInv[toReal] = qubit2;
839 totalSwappingCost += bondCost[toReal];
840 growBondDimension(toReal,
true);
845 assert(abs(qubitsMap[qubit1] - qubitsMap[qubit2]) == 1);