65 maxVirtualExtent = val;
67 if (nrQubits == 0)
return;
69 const double untruncatedMaxExtent = std::pow(physExtent, nrQubits / 2);
71 static_cast<IndexType>(untruncatedMaxExtent);
73 if (untruncatedMaxExtent >= std::numeric_limits<IndexType>::max() ||
74 std::isnan(untruncatedMaxExtent) || std::isinf(untruncatedMaxExtent))
75 maxVirtualExtentLimit = std::numeric_limits<IndexType>::max() - 1;
76 else if (untruncatedMaxExtent < 2)
77 maxVirtualExtentLimit = 2;
79 maxVirtualExtent = maxVirtualExtent == 0
80 ? maxVirtualExtentLimit
81 : std::min(maxVirtualExtent, maxVirtualExtentLimit);
83 bondCost.resize(nrQubits - 1);
84 maxBondDim.resize(nrQubits - 1);
85 currentBondDim.assign(nrQubits - 1, 1.0);
89 for (
IndexType i = 0; i < static_cast<IndexType>(nrQubits); ++i) {
90 double maxExtent1 = std::pow((
double)physExtent, (
double)i + 1.);
92 std::pow((
double)physExtent, (
double)nrQubits - i - 1.);
94 if (maxExtent1 >= (
double)std::numeric_limits<size_t>::max() ||
95 std::isnan(maxExtent1) || std::isinf(maxExtent1))
96 maxExtent1 = (double)std::numeric_limits<size_t>::max() - 1;
97 else if (maxExtent1 < 1)
100 if (maxExtent2 > (
double)std::numeric_limits<size_t>::max() ||
101 std::isnan(maxExtent2) || std::isinf(maxExtent2))
102 maxExtent2 = (
double)std::numeric_limits<size_t>::max() - 1;
103 else if (maxExtent2 < 1)
106 size_t maxRightExtent = (size_t)std::min<double>(
107 {maxExtent1, maxExtent2, (double)maxVirtualExtent});
108 if (maxRightExtent < 2) maxRightExtent = 2;
110 if (i <
static_cast<IndexType>(nrQubits) - 1) {
111 maxBondDim[i] =
static_cast<double>(maxRightExtent);
112 const double maxRightExtentD =
static_cast<double>(maxRightExtent);
113 bondCost[i] = maxRightExtentD * maxRightExtentD * maxRightExtentD;
225 long long int currentGateIndex,
int lookaheadDepth,
226 int lookaheadDepthWithHeuristic,
double currentCost,
double& bestCost,
227 bool useSameDummy =
false) {
228 if (currentGateIndex >=
static_cast<long long int>(upcomingGates.size())) {
229 if (currentCost < bestCost) bestCost = currentCost;
234 while (currentGateIndex <
235 static_cast<long long int>(upcomingGates.size()) &&
236 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
239 if (currentGateIndex >=
static_cast<long long int>(upcomingGates.size())) {
240 if (currentCost < bestCost) bestCost = currentCost;
244 const auto& op = upcomingGates[currentGateIndex];
245 const auto qbits = op->AffectedQubits();
247 assert(qbits.size() >= 2);
258 if (realq1 > realq2) std::swap(realq1, realq2);
263 if (realq2 - realq1 > 1)
272 if (currentCost >= bestCost)
return;
274 if (lookaheadDepth <= 0) {
275 if (currentCost < bestCost) bestCost = currentCost;
282 while (currentGateIndex <
283 static_cast<long long int>(upcomingGates.size()) &&
284 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
287 if (currentGateIndex >=
288 static_cast<long long int>(upcomingGates.size())) {
289 if (currentCost < bestCost) bestCost = currentCost;
294 lookaheadDepth - 1, lookaheadDepthWithHeuristic,
295 currentCost, bestCost);
298 dummySim.maxVirtualExtent = maxVirtualExtent;
299 dummySim.maxBondDim = maxBondDim;
300 dummySim.currentBondDim = currentBondDim;
301 dummySim.bondCost = bondCost;
302 dummySim.qubitsMap = qubitsMap;
303 dummySim.qubitsMapInv.resize(qubitsMap.size());
304 for (
size_t i = 0; i < qubitsMap.size(); ++i)
305 dummySim.qubitsMapInv[qubitsMap[i]] =
static_cast<IndexType>(i);
307 dummySim.setTotalSwappingCost(0);
309 if (realq2 - realq1 > 1)
310 dummySim.SwapQubitsToPosition(qubit1, qubit2, meetPosition);
312 dummySim.ApplyGate(op);
315 currentCost += dummySim.getTotalSwappingCost();
318 if (currentCost >= bestCost)
return;
321 if (lookaheadDepth <= 0) {
322 if (currentCost < bestCost) bestCost = currentCost;
329 while (currentGateIndex <
330 static_cast<long long int>(upcomingGates.size()) &&
331 upcomingGates[currentGateIndex]->AffectedQubits().size() < 2)
334 if (currentGateIndex >=
335 static_cast<long long int>(upcomingGates.size())) {
336 if (currentCost < bestCost) bestCost = currentCost;
340 dummySim.FindBestMeetingPosition(
341 upcomingGates, currentGateIndex, lookaheadDepth - 1,
342 lookaheadDepthWithHeuristic, currentCost, bestCost);
351 long long int currentGateIndex,
int lookaheadDepth,
352 int lookaheadDepthWithHeuristic,
double currentCost,
double& bestCost) {
353 const auto& op = upcomingGates[currentGateIndex];
354 const auto qbits = op->AffectedQubits();
356 assert(qbits.size() >= 2);
364 if (realq1 > realq2) std::swap(realq1, realq2);
366 if (lookaheadDepth <= 0) {
368 ? ComputeHeuristicMeetPosition(realq1, realq2)
371 lookaheadDepthWithHeuristic, currentCost,
376 if (realq2 - realq1 <= 1) {
378 realq1, upcomingGates, currentGateIndex, lookaheadDepth,
379 lookaheadDepthWithHeuristic, currentCost, bestCost,
380 lookaheadDepth <= lookaheadDepthWithHeuristic);
387 if (lookaheadDepth <= lookaheadDepthWithHeuristic) {
388 bestPosition = ComputeHeuristicMeetPosition(realq1, realq2);
390 lookaheadDepth, lookaheadDepthWithHeuristic,
391 currentCost, bestCost,
true);
393 for (
IndexType m = realq1; m < realq2; ++m) {
394 const double oldCost = bestCost;
396 lookaheadDepth, lookaheadDepthWithHeuristic,
397 currentCost, bestCost);
399 if (bestCost < oldCost) bestPosition = m;
408 int nrShuffles = 25) {
411 if (layers.empty() || nrQubits <= 2)
return qubitsMap;
415 [&,
this](
const std::vector<IndexType>& candidateMap) ->
double {
416 auto saveQubitsMap = qubitsMap;
417 auto saveQubitsMapInv = qubitsMapInv;
418 auto saveCurrentBondDim = currentBondDim;
419 auto saveTotalSwappingCost = totalSwappingCost;
420 auto saveBondCost = bondCost;
424 for (
const auto& layer : layers)
427 qubitsMap = std::move(saveQubitsMap);
428 qubitsMapInv = std::move(saveQubitsMapInv);
429 currentBondDim = std::move(saveCurrentBondDim);
430 totalSwappingCost = saveTotalSwappingCost;
431 bondCost = std::move(saveBondCost);
436 auto evaluateCostBounded = [&,
this](
437 const std::vector<IndexType>& candidateMap,
438 double bound) ->
double {
439 auto saveQubitsMap = qubitsMap;
440 auto saveQubitsMapInv = qubitsMapInv;
441 auto saveCurrentBondDim = currentBondDim;
442 auto saveTotalSwappingCost = totalSwappingCost;
443 auto saveBondCost = bondCost;
447 for (
const auto& layer : layers) {
452 qubitsMap = std::move(saveQubitsMap);
453 qubitsMapInv = std::move(saveQubitsMapInv);
454 currentBondDim = std::move(saveCurrentBondDim);
455 totalSwappingCost = saveTotalSwappingCost;
456 bondCost = std::move(saveBondCost);
462 qubitsMap = std::move(saveQubitsMap);
463 qubitsMapInv = std::move(saveQubitsMapInv);
464 currentBondDim = std::move(saveCurrentBondDim);
465 totalSwappingCost = saveTotalSwappingCost;
466 bondCost = std::move(saveBondCost);
476 std::vector<std::vector<QubitPair>> layerPairs;
478 for (
size_t li = 0; li < layers.size(); ++li) {
479 const auto& layer = layers[li];
480 std::vector<QubitPair> lp;
481 for (
const auto& op : layer->GetOperations()) {
482 auto qbits = op->AffectedQubits();
483 if (qbits.size() >= 2) {
484 if (qbits[0] > qbits[1]) std::swap(qbits[0], qbits[1]);
486 lp.push_back({
static_cast<IndexType>(qbits[0]),
490 if (!lp.empty()) layerPairs.push_back(std::move(lp));
492 if (layerPairs.empty())
return qubitsMap;
502 auto buildChain = [&](
const std::vector<std::vector<QubitPair>>& orderedLP)
503 -> std::vector<long long int> {
504 std::vector<std::deque<IndexType>> groups;
505 std::vector<int> qubitGroup(nrQubits, -1);
506 std::unordered_set<IndexType> placedQubits;
508 for (
const auto& lp : orderedLP) {
509 for (
const auto& p : lp) {
510 const int g1 = qubitGroup[p.q1];
511 const int g2 = qubitGroup[p.q2];
513 if (g1 < 0 && g2 < 0) {
515 const int gIdx =
static_cast<int>(groups.size());
516 groups.push_back({p.q1, p.q2});
517 qubitGroup[p.q1] = gIdx;
518 qubitGroup[p.q2] = gIdx;
519 placedQubits.insert(p.q1);
520 placedQubits.insert(p.q2);
521 }
else if (g1 >= 0 && g2 < 0) {
523 auto& grp = groups[g1];
525 for (
size_t i = 0; i < grp.size(); ++i)
526 if (grp[i] == p.q1) {
531 if (idx + 1 <= grp.size() - idx)
532 grp.push_front(p.q2);
535 qubitGroup[p.q2] = g1;
536 placedQubits.insert(p.q2);
537 }
else if (g1 < 0 && g2 >= 0) {
539 auto& grp = groups[g2];
541 for (
size_t i = 0; i < grp.size(); ++i)
542 if (grp[i] == p.q2) {
546 if (idx + 1 <= grp.size() - idx)
547 grp.push_front(p.q1);
550 qubitGroup[p.q1] = g2;
551 placedQubits.insert(p.q1);
552 }
else if (g1 != g2) {
554 auto& grpA = groups[g1];
555 auto& grpB = groups[g2];
556 size_t idxA = 0, idxB = 0;
557 for (
size_t i = 0; i < grpA.size(); ++i)
558 if (grpA[i] == p.q1) {
562 for (
size_t i = 0; i < grpB.size(); ++i)
563 if (grpB[i] == p.q2) {
569 const size_t distAB = grpA.size() + idxB - idxA;
570 const size_t distBA = grpB.size() + idxA - idxB;
573 if (distAB <= distBA) {
574 for (
const auto q : grpB) grpA.push_back(q);
578 for (
const auto q : grpA) grpB.push_back(q);
582 for (
const auto q : groups[mergedGroup])
583 qubitGroup[q] = mergedGroup;
587 if (placedQubits.size() ==
static_cast<size_t>(nrQubits))
591 if (placedQubits.size() ==
static_cast<size_t>(nrQubits))
596 std::vector<IndexType> chain;
597 chain.reserve(nrQubits);
598 for (
const auto& grp : groups)
599 for (
const auto q : grp) chain.push_back(q);
603 if (qubitGroup[q] < 0) chain.push_back(q);
605 assert(chain.size() ==
static_cast<size_t>(nrQubits));
608 std::vector<long long int> result(nrQubits);
609 for (
size_t i = 0; i < chain.size(); ++i)
610 result[chain[i]] =
static_cast<long long int>(i);
615 auto optMap = buildChain(layerPairs);
616 if (layers.size() <= 2)
return optMap;
617 auto optCost = evaluateCost(optMap);
619 std::vector<long long int> qubitsMap(nrQubits);
620 std::iota(qubitsMap.begin(), qubitsMap.end(), 0);
621 double tryCost = evaluateCostBounded(qubitsMap, optCost);
622 if (tryCost < optCost) {
629 std::mt19937 rng(42);
630 for (
int i = 0; i < nrShuffles; ++i) {
631 std::shuffle(qubitsMap.begin(), qubitsMap.end(), rng);
632 tryCost = evaluateCostBounded(qubitsMap, optCost);
633 if (tryCost < optCost) {
640 std::uniform_int_distribution<IndexType> qubitDist(0, nrQubits - 1);
641 std::uniform_int_distribution<int> nrSwapsDist(
642 1, std::min<int>(3,
static_cast<int>(nrQubits) / 2));
644 const int maxNoImprove = std::max(nrShuffles,
static_cast<int>(nrQubits));
645 const int maxTotalShuffles = maxNoImprove * 3;
646 int noImproveCount = 0;
648 for (
int s = 0; s < maxTotalShuffles && noImproveCount < maxNoImprove; ++s) {
649 auto tryMap = optMap;
650 const int nrSwaps = nrSwapsDist(rng);
651 for (
int sw = 0; sw < nrSwaps; ++sw) {
654 while (b == a) b = qubitDist(rng);
655 std::swap(tryMap[a], tryMap[b]);
658 auto cost = evaluateCostBounded(tryMap, optCost);
659 if (cost < optCost) {
671 auto candidate = optMap;
672 bool improved =
true;
675 for (
IndexType i = 0; i < nrQubits; ++i) {
676 for (
IndexType j = i + 1; j < nrQubits; ++j) {
678 std::swap(candidate[i], candidate[j]);
679 auto cost = evaluateCostBounded(candidate, optCost);
680 if (cost < optCost) {
686 std::swap(candidate[i], candidate[j]);
761 if (realq1 > realq2) {
762 std::swap(realq1, realq2);
763 std::swap(qubit1, qubit2);
766 if (realq2 - realq1 <= 1)
return;
768 assert(meetPosition >= realq1 && meetPosition < realq2);
773 while (movingReal < meetPosition) {
775 const IndexType toInv = qubitsMapInv[toReal];
777 qubitsMap[toInv] = movingReal;
778 qubitsMapInv[movingReal] = toInv;
780 qubitsMap[qubit1] = toReal;
781 qubitsMapInv[toReal] = qubit1;
783 totalSwappingCost += bondCost[movingReal];
784 growBondDimension(movingReal,
true);
792 while (movingReal > meetPosition + 1) {
794 const IndexType toInv = qubitsMapInv[toReal];
796 qubitsMap[toInv] = movingReal;
797 qubitsMapInv[movingReal] = toInv;
799 qubitsMap[qubit2] = toReal;
800 qubitsMapInv[toReal] = qubit2;
802 totalSwappingCost += bondCost[toReal];
803 growBondDimension(toReal,
true);
808 assert(abs(qubitsMap[qubit1] - qubitsMap[qubit2]) == 1);