18#ifndef __EXECUTION_COST_H_
19#define __EXECUTION_COST_H_
87 throw std::out_of_range(
"Invalid index for CircuitInfo field");
130 throw std::out_of_range(
"Invalid index for ExecutionInfo field");
142 const double opOrder = exp2(nrQubits);
145 for (
const auto& op : *circuit) {
146 const auto affectedQubits = op->AffectedQubits();
149 cost += opOrder * affectedQubits.size();
151 cost += 2. * opOrder * affectedQubits.size();
154 if (affectedQubits.size() == 1)
156 else if (affectedQubits.size() == 2)
158 else if (affectedQubits.size() == 3)
159 cost += 16 * opOrder;
164 const double twoQubitOpOrder = pow(maxBondDim, 3);
165 const double oneQubitOpOrder = pow(maxBondDim, 2);
168 for (
const auto& op : *circuit) {
169 const auto affectedQubits = op->AffectedQubits();
184 cost += twoQubitOpOrder * affectedQubits.size() * nrQubits / 2.;
187 if (affectedQubits.size() == 1)
188 cost += oneQubitOpOrder;
189 else if (affectedQubits.size() == 2)
192 cost += twoQubitOpOrder * nrQubits / 3.;
193 else if (affectedQubits.size() == 3)
196 cost += twoQubitOpOrder * nrQubits * 2;
201 const double measOrder = pow(nrQubits, 2);
202 const double opOrder =
static_cast<double>(nrQubits);
205 for (
const auto& op : *circuit) {
206 const auto affectedQubits = op->AffectedQubits();
210 cost += measOrder * affectedQubits.size();
213 cost += opOrder * affectedQubits.size();
218 double doublingCost = 1;
220 for (
const auto& op : *circuit) {
221 if (op->IsBranching()) doublingCost *= 2;
223 const auto affectedQubits = op->AffectedQubits();
227 cost += doublingCost * affectedQubits.size();
230 if (affectedQubits.size() == 1)
231 cost += doublingCost;
232 else if (affectedQubits.size() == 2)
233 cost += doublingCost * 2;
234 else if (affectedQubits.size() == 3)
235 cost += doublingCost * 4;
244 return std::numeric_limits<double>::infinity();
249 size_t nrQubitsSampled,
size_t samples,
253 const bool hasMeasurementsInTheMiddle = circuit->HasOpsAfterMeasurements();
254 const std::vector<bool> executedOps =
255 circuit->ExecuteNonMeasurements(
nullptr, dummyState);
257 const size_t dif = circuit->size() - executedOps.size();
261 circuit, nrQubitsSampled, samples);
264 const double opOrder = exp2(nrQubits);
267 for (
size_t i = 0; i < circuit->size(); ++i) {
268 if (i >= dif && !executedOps[i - dif])
continue;
270 const auto& op = (*circuit)[i];
271 const auto affectedQubits = op->AffectedQubits();
274 cost += opOrder * affectedQubits.size();
276 cost += 2. * opOrder * affectedQubits.size();
279 if (affectedQubits.size() == 1)
281 else if (affectedQubits.size() == 2)
283 else if (affectedQubits.size() == 3)
284 cost += 16 * opOrder;
294 if (hasMeasurementsInTheMiddle) {
295 double samplingCost = 0;
296 for (
size_t i = dif; i < circuit->size(); ++i) {
297 if (executedOps[i - dif])
continue;
299 const auto& op = (*circuit)[i];
300 const auto affectedQubits = op->AffectedQubits();
303 samplingCost += opOrder * affectedQubits.size();
305 samplingCost += 2. * opOrder * affectedQubits.size();
308 if (affectedQubits.size() == 1)
309 samplingCost += opOrder;
310 else if (affectedQubits.size() == 2)
311 samplingCost += 4 * opOrder;
312 else if (affectedQubits.size() == 3)
313 samplingCost += 16 * opOrder;
317 samplingCost += opOrder * nrQubitsSampled;
319 return cost + samplingCost * samples;
323 return cost + 30 * opOrder + samples * nrQubits;
325 const double oneQubitOpOrder = maxBondDim * maxBondDim;
326 const double twoQubitOpOrder = oneQubitOpOrder * maxBondDim;
329 for (
size_t i = 0; i < circuit->size(); ++i) {
330 if (i >= dif && !executedOps[i - dif])
continue;
332 const auto& op = (*circuit)[i];
333 const auto affectedQubits = op->AffectedQubits();
348 cost += twoQubitOpOrder * affectedQubits.size() * nrQubits / 2.;
351 if (affectedQubits.size() == 1)
352 cost += oneQubitOpOrder;
353 else if (affectedQubits.size() == 2)
356 cost += twoQubitOpOrder * nrQubits / 3.;
357 else if (affectedQubits.size() == 3)
360 cost += twoQubitOpOrder * nrQubits * 2;
364 if (hasMeasurementsInTheMiddle) {
365 double samplingCost = 0;
366 for (
size_t i = dif; i < circuit->size(); ++i) {
367 if (executedOps[i - dif])
continue;
369 const auto& op = (*circuit)[i];
370 const auto affectedQubits = op->AffectedQubits();
376 twoQubitOpOrder * affectedQubits.size() * nrQubits / 2.;
379 if (affectedQubits.size() == 1)
380 samplingCost += oneQubitOpOrder;
381 else if (affectedQubits.size() == 2)
384 samplingCost += twoQubitOpOrder * nrQubits / 3.;
385 else if (affectedQubits.size() == 3)
389 twoQubitOpOrder * nrQubits * 2;
393 samplingCost += twoQubitOpOrder * nrQubits * nrQubits;
395 return cost + samplingCost * samples;
405 return cost + samples * twoQubitOpOrder * nrQubits * nrQubits;
407 const double measOrder = pow(nrQubits, 2);
408 const double opOrder =
static_cast<double>(nrQubits);
411 for (
size_t i = 0; i < circuit->size(); ++i) {
412 if (i >= dif && !executedOps[i - dif])
continue;
414 const auto& op = (*circuit)[i];
415 const auto affectedQubits = op->AffectedQubits();
419 cost += measOrder * affectedQubits.size();
422 cost += opOrder * affectedQubits.size();
425 if (hasMeasurementsInTheMiddle) {
426 double samplingCost = 0;
427 for (
size_t i = dif; i < circuit->size(); ++i) {
428 if (executedOps[i - dif])
continue;
430 const auto& op = (*circuit)[i];
431 const auto affectedQubits = op->AffectedQubits();
436 samplingCost += measOrder * affectedQubits.size();
439 samplingCost += opOrder * affectedQubits.size();
442 samplingCost += measOrder * nrQubitsSampled;
444 return cost + samplingCost * samples;
454 return cost + samples * measOrder * nrQubitsSampled;
457 double doublingCost = 1;
458 for (
size_t i = 0; i < circuit->size(); ++i) {
459 if (i >= dif && !executedOps[i - dif])
continue;
460 const auto& op = (*circuit)[i];
461 if (op->IsBranching()) doublingCost *= 2;
463 const auto affectedQubits = op->AffectedQubits();
467 cost += doublingCost * affectedQubits.size();
470 if (affectedQubits.size() == 1)
471 cost += doublingCost;
472 else if (affectedQubits.size() == 2)
473 cost += doublingCost * 2;
474 else if (affectedQubits.size() == 3)
475 cost += doublingCost * 4;
479 if (hasMeasurementsInTheMiddle) {
480 double samplingCost = 0;
481 for (
size_t i = dif; i < circuit->size(); ++i) {
482 if (executedOps[i - dif])
continue;
484 const auto& op = (*circuit)[i];
485 if (op->IsBranching()) doublingCost *= 2;
487 const auto affectedQubits = op->AffectedQubits();
493 samplingCost += doublingCost * affectedQubits.size();
496 if (affectedQubits.size() == 1)
497 samplingCost += doublingCost;
498 else if (affectedQubits.size() == 2)
499 samplingCost += doublingCost * 2;
500 else if (affectedQubits.size() == 3)
501 samplingCost += doublingCost * 4;
505 samplingCost += doublingCost * nrQubitsSampled;
507 return cost + samplingCost * samples;
511 return cost + 30 * doublingCost + samples * nrQubits;
516 return std::numeric_limits<double>::infinity();
530 for (
char c : pauliString) {
531 if (c ==
'X' || c ==
'x' || c ==
'Y' || c ==
'y' || c ==
'Z' || c ==
'z')
536 const double opOrder = exp2(nrQubits);
540 cost += opOrder * (pauliCnt + 1);
544 const double twoQubitOpOrder = pow(maxBondDim, 3);
545 const double oneQubitOpOrder = pow(maxBondDim, 2);
549 cost += oneQubitOpOrder * pauliCnt + nrQubits * twoQubitOpOrder;
553 cost += nrQubits * nrQubits;
556 double doublingCost = 1;
557 for (
const auto& op : *circuit) {
558 if (op->IsBranching()) doublingCost *= 2;
560 cost += 4 * doublingCost * pauliCnt;
565 return std::numeric_limits<double>::infinity();
569 size_t nrQubits,
size_t depth,
double measureInsideProbability = 0.,
570 size_t nrMeasAtEnd = 0,
bool isClifford =
false,
571 size_t nrNonCliffordGatesLimit = 0,
size_t nrBranchingGatesLimit = 0) {
572 auto circuit = std::make_shared<Circuits::Circuit<>>();
573 std::random_device rdev;
574 std::mt19937 rng(rdev());
575 std::uniform_real_distribution<double> dist(0.0, 1.0);
576 std::uniform_real_distribution<double> paramDist(-2 * M_PI, 2 * M_PI);
577 std::uniform_int_distribution<Types::qubit_t> qubitDist(0, nrQubits - 1);
578 std::uniform_int_distribution<int> gateDist(
581 std::uniform_int_distribution<int> gateDistOneQubit(
584 std::vector<Types::qubit_t> qubits(nrQubits);
585 std::iota(qubits.begin(), qubits.end(), 0);
587 size_t nrNonCliffordGates = 0;
588 if (nrNonCliffordGatesLimit == 0 && !isClifford)
589 nrNonCliffordGatesLimit = depth;
591 size_t nrBranchingGates = 0;
592 if (nrBranchingGatesLimit == 0) nrBranchingGatesLimit = depth;
594 for (
size_t i = 0; i < depth; ++i) {
595 if (dist(rng) < measureInsideProbability) {
597 std::vector<std::pair<Types::qubit_t, size_t>> qs = {{q, q}};
598 circuit->AddOperation(
603 std::shuffle(qubits.begin(), qubits.end(), rng);
604 const auto q1 = qubits[0];
605 const auto q2 = qubits[1];
606 const auto q3 = qubits[2];
609 nrNonCliffordGatesLimit < depth
610 ? gateDistOneQubit(rng)
613 auto param1 = paramDist(rng);
614 auto param2 = paramDist(rng);
615 auto param3 = paramDist(rng);
616 auto param4 = paramDist(rng);
619 gateType, q1, q2, q3, param1, param2, param3, param4);
621 while (!theGate->IsClifford()) {
624 gateType, q1, q2, q3, param1, param2, param3, param4);
628 if (!theGate->IsClifford()) ++nrNonCliffordGates;
629 if (theGate->IsBranching()) ++nrBranchingGates;
631 if (nrNonCliffordGates > nrNonCliffordGatesLimit) {
636 gateType, q1, q2, q3, param1, param2, param3, param4);
637 while (!theGate->IsClifford()) {
641 gateType, q1, q2, q3, param1, param2, param3, param4);
643 --nrNonCliffordGates;
646 if (nrBranchingGates > nrBranchingGatesLimit) {
651 gateType, q1, q2, q3, param1, param2, param3, param4);
652 while (theGate->IsBranching()) {
655 gateType, q1, q2, q3, param1, param2, param3, param4);
660 circuit->AddOperation(theGate);
663 std::shuffle(circuit->begin(), circuit->end(), rng);
665 if (nrMeasAtEnd > 0) {
666 if (nrMeasAtEnd > nrQubits) nrMeasAtEnd = nrQubits;
667 std::shuffle(qubits.begin(), qubits.end(), rng);
669 for (
size_t i = 0; i < nrMeasAtEnd; ++i) {
670 std::vector<std::pair<Types::qubit_t, size_t>> qs = {{qubits[i], i}};
671 circuit->AddOperation(
682 size_t nrReps,
size_t maxBondDim) {
683 auto sim =
GetSimulator(simType, method, nrQubits, maxBondDim);
686 auto start = std::chrono::high_resolution_clock::now();
687 for (
size_t i = 0; i < nrReps; ++i) circuit->Execute(sim, dummyState);
688 auto end = std::chrono::high_resolution_clock::now();
689 return std::chrono::duration<double>(end - start).count();
695 size_t nrQubitsSampled,
size_t nrSamples,
size_t nrReps,
697 auto sim =
GetSimulator(simType, method, nrQubits, maxBondDim);
700 if (nrQubitsSampled > nrQubits) nrQubitsSampled = nrQubits;
702 std::iota(qubitsSampled.begin(), qubitsSampled.end(), 0);
704 const bool hasMeasurementsInTheMiddle = circuit->HasOpsAfterMeasurements();
706 auto start = std::chrono::high_resolution_clock::now();
708 if (hasMeasurementsInTheMiddle) {
709 for (
size_t i = 0; i < nrReps; ++i) {
710 const auto executedOps = circuit->ExecuteNonMeasurements(
714 for (
size_t sample = 0; sample < nrSamples; ++sample) {
715 circuit->ExecuteMeasurements(
716 sim, dummyState, executedOps);
720 for (
size_t i = 0; i < nrReps; ++i) {
721 circuit->Execute(sim, dummyState);
722 sim->SampleCountsMany(qubitsSampled, nrSamples);
725 auto end = std::chrono::high_resolution_clock::now();
727 return std::chrono::duration<double>(end - start).count();
733 const std::string& pauliString,
size_t nrReps,
size_t maxBondDim) {
734 auto sim =
GetSimulator(simType, method, nrQubits, maxBondDim);
736 auto start = std::chrono::high_resolution_clock::now();
737 for (
size_t i = 0; i < nrReps; ++i) {
738 circuit->Execute(sim, dummyState);
739 sim->ExpectationValue(pauliString);
741 auto end = std::chrono::high_resolution_clock::now();
742 return std::chrono::duration<double>(end - start).count();
747 size_t nrQubits,
size_t maxBondDim) {
750 const auto strVal = std::to_string(maxBondDim);
751 sim->Configure(
"matrix_product_state_max_bond_dimension", strVal.c_str());
753 sim->AllocateQubits(nrQubits);
754 sim->SetMultithreading(
false);
763 info.
nrQubits = circuit->GetMaxQubitIndex() + 1;
765 const bool hasMeasurementsInTheMiddle = circuit->HasOpsAfterMeasurements();
766 const std::vector<bool> executedOps =
767 circuit->ExecuteNonMeasurements(
nullptr, dummyState);
769 const size_t dif = circuit->size() - executedOps.size();
772 for (
const auto& op : *circuit) {
773 const auto affectedQubits = op->AffectedQubits();
776 if (hasMeasurementsInTheMiddle)
782 if (affectedQubits.size() == 1) {
785 }
else if (affectedQubits.size() == 2) {
788 }
else if (affectedQubits.size() == 3) {
790 if (i < dif || executedOps[i - dif])
800 static std::vector<ExecutionInfo>
ReadLog(
const std::string& logFilePath) {
801 std::vector<ExecutionInfo> executionInfos;
803 std::ifstream logFile(logFilePath);
804 if (!logFile.is_open()) {
805 std::cerr <<
"Failed to open log file: " << logFilePath << std::endl;
806 return executionInfos;
811 while (std::getline(logFile, line)) {
812 std::stringstream ss(line);
815 std::getline(ss, value,
',');
817 std::getline(ss, value,
',');
819 std::getline(ss, value,
',');
821 std::getline(ss, value,
',');
823 std::getline(ss, value,
',');
825 std::getline(ss, value,
',');
827 std::getline(ss, value,
',');
829 std::getline(ss, value,
',');
831 std::getline(ss, value,
',');
834 std::getline(ss, value,
',');
836 std::getline(ss, value,
',');
838 std::getline(ss, value,
',');
840 std::getline(ss, value,
',');
843 std::getline(ss, value,
',');
845 std::getline(ss, value,
',');
846 info.
runtime = std::stod(value);
850 executionInfos.push_back(std::move(info));
853 std::random_device rdev;
854 std::mt19937 rng(rdev());
855 std::shuffle(executionInfos.begin(), executionInfos.end(), rng);
857 return executionInfos;
862 size_t nrReps,
size_t nrMinQubits,
size_t nrMaxQubits,
size_t stepQubits,
863 size_t depthMin,
size_t depthMax,
size_t stepDepth,
864 double measureInsideProbability,
size_t nrMeasAtEndMin,
865 size_t nrMeasAtEndMax,
size_t stepMeasAtEnd,
866 size_t nrRandomCircuitsPerConfig,
const std::string& logFilePath,
867 size_t startBondDim = 16,
size_t endBondDim = 16) {
869 int nrNonCliffordGates =
static_cast<int>(depthMax);
870 int nrBranchingGates =
static_cast<int>(depthMax);
874 nrNonCliffordGates = 1;
876 nrNonCliffordGates = 0;
878 nrBranchingGates = 8;
881 std::cout <<
"Benchmarking execution for simType: "
882 <<
static_cast<int>(simType)
883 <<
", method: " <<
static_cast<int>(method) << std::endl;
887 for (
size_t nrQubits = nrMinQubits; nrQubits <= nrMaxQubits;
888 nrQubits += stepQubits) {
889 std::cout <<
" Qubits: " << nrQubits << std::endl;
890 for (
size_t depth = depthMin; depth <= depthMax; depth += stepDepth) {
891 std::cout <<
" Depth: " << depth << std::endl;
892 for (
size_t nrMeasAtEnd = nrMeasAtEndMin;
893 nrMeasAtEnd <= std::min(nrMeasAtEndMax, nrQubits);
894 nrMeasAtEnd += stepMeasAtEnd) {
895 std::cout <<
" Measurements at end: " << nrMeasAtEnd
897 for (
size_t i = 0; i < nrRandomCircuitsPerConfig; ++i) {
898 std::cout <<
" Random circuit: " << i + 1 <<
"/"
899 << nrRandomCircuitsPerConfig << std::endl;
901 isClifford = !isClifford;
904 nrQubits, depth, measureInsideProbability, nrMeasAtEnd,
905 isClifford, nrNonCliffordGates, nrBranchingGates);
907 for (
size_t maxBondDim = startBondDim; maxBondDim <= endBondDim;
920 pauli.resize(nrQubits);
921 std::random_device rd;
922 std::mt19937 g(rd());
923 std::uniform_int_distribution<int> dist(0, 3);
925 for (
size_t i = 0; i < nrQubits; ++i) {
926 const int v = dist(g);
948 size_t nrReps,
size_t nrMinQubits,
size_t nrMaxQubits,
size_t stepQubits,
949 size_t depthMin,
size_t depthMax,
size_t stepDepth,
950 size_t nrRandomCircuitsPerConfig,
951 const std::string& logFilePath,
size_t startBondDim = 16,
size_t endBondDim = 16) {
953 int nrNonCliffordGates =
static_cast<int>(depthMax);
954 int nrBranchingGates =
static_cast<int>(depthMax);
958 nrNonCliffordGates = 1;
960 nrNonCliffordGates = 0;
962 nrBranchingGates = 8;
966 std::cout <<
"Benchmarking Pauli expectation for simType: "
967 <<
static_cast<int>(simType)
968 <<
", method: " <<
static_cast<int>(method) << std::endl;
970 for (
size_t nrQubits = nrMinQubits; nrQubits <= nrMaxQubits;
971 nrQubits += stepQubits) {
972 std::cout <<
" Qubits: " << nrQubits << std::endl;
973 for (
size_t depth = depthMin; depth <= depthMax; depth += stepDepth) {
974 std::cout <<
" Depth: " << depth << std::endl;
975 for (
size_t i = 0; i < nrRandomCircuitsPerConfig; ++i) {
977 isClifford = !isClifford;
981 nrNonCliffordGates, nrBranchingGates);
984 std::cout <<
" Random circuit: " << i + 1 <<
"/"
985 << nrRandomCircuitsPerConfig
986 <<
" Pauli string: " << pauliString << std::endl;
987 for (
size_t maxBondDim = startBondDim; maxBondDim <= endBondDim;
989 std::cout <<
" Max bond dimension: " << maxBondDim
992 simType, method, circuit, pauliString, nrReps, maxBondDim, log);
1001 size_t nrReps,
size_t nrMinQubits,
size_t nrMaxQubits,
size_t stepQubits,
1002 size_t depthMin,
size_t depthMax,
size_t stepDepth,
size_t nrMeasAtEndMin,
1003 size_t nrMeasAtEndMax,
size_t stepMeasAtEnd,
size_t nrSamplesMin,
1004 size_t nrSamplesMax,
size_t multiplierSamples,
1005 size_t nrRandomCircuitsPerConfig,
const std::string& logFilePath,
1006 size_t startBondDim = 16,
size_t endBondDim = 16) {
1008 int nrNonCliffordGates =
static_cast<int>(depthMax);
1009 int nrBranchingGates =
static_cast<int>(depthMax);
1012 nrNonCliffordGates = 1;
1014 nrNonCliffordGates = 0;
1016 nrBranchingGates = 8;
1020 std::cout <<
"Benchmarking sampling for simType: "
1021 <<
static_cast<int>(simType)
1022 <<
", method: " <<
static_cast<int>(method) << std::endl;
1024 for (
size_t nrQubits = nrMinQubits; nrQubits <= nrMaxQubits;
1025 nrQubits += stepQubits) {
1026 std::cout <<
" Qubits: " << nrQubits << std::endl;
1027 for (
size_t depth = depthMin; depth <= depthMax; depth += stepDepth) {
1028 std::cout <<
" Depth: " << depth << std::endl;
1029 for (
size_t nrSamples = nrSamplesMin; nrSamples <= nrSamplesMax;
1030 nrSamples *= multiplierSamples) {
1031 std::cout <<
" Samples: " << nrSamples << std::endl;
1032 for (
size_t i = 0; i < nrRandomCircuitsPerConfig; ++i) {
1034 isClifford = !isClifford;
1035 const auto circuit =
1037 nrNonCliffordGates, nrBranchingGates);
1038 for (
size_t nrQubitsSampled = nrQubits; nrQubitsSampled >= 1;
1039 nrQubitsSampled /= 2) {
1040 std::cout <<
" Random circuit: " << i + 1 <<
"/"
1041 << nrRandomCircuitsPerConfig
1042 <<
" Qubits sampled: " << nrQubitsSampled << std::endl;
1043 for (
size_t maxBondDim = startBondDim; maxBondDim <= endBondDim;
1046 nrQubitsSampled, nrSamples, nrReps,
1061 const double estimatedCost =
1063 const double executionTime =
1068 std::stringstream ss;
1070 ss << info.nrQubits <<
"," << info.nrOneQubitOps <<
","
1071 << info.nrTwoQubitOps <<
"," << info.nrThreeQubitOps <<
","
1072 << info.nrMiddleMeasurementOps <<
"," << info.nrEndMeasurementOps <<
","
1073 << info.nrOneQubitOpsExecutedOnce <<
","
1074 << info.nrTwoQubitOpsExecutedOnce <<
","
1075 << info.nrThreeQubitOpsExecutedOnce <<
","
1076 <<
"0,0," << maxBondDim <<
","
1077 <<
"0," << estimatedCost <<
"," << executionTime;
1085 size_t nrQubitsSampled,
size_t nrSamples,
size_t nrReps,
1089 method, info.nrQubits, nrQubitsSampled, nrSamples, circuit, maxBondDim);
1090 const double samplingTime =
1092 nrQubitsSampled, nrSamples, nrReps, maxBondDim) /
1094 std::stringstream ss;
1095 ss << info.nrQubits <<
"," << info.nrOneQubitOps <<
","
1096 << info.nrTwoQubitOps <<
"," << info.nrThreeQubitOps <<
","
1097 << info.nrMiddleMeasurementOps <<
"," << info.nrEndMeasurementOps <<
","
1098 << info.nrOneQubitOpsExecutedOnce <<
","
1099 << info.nrTwoQubitOpsExecutedOnce <<
","
1100 << info.nrThreeQubitOpsExecutedOnce <<
"," << nrSamples <<
","
1101 << nrQubitsSampled <<
"," << maxBondDim <<
","
1102 <<
"0," << estimatedCost <<
"," << samplingTime;
1109 const std::string& pauliString,
size_t nrReps,
size_t maxBondDim,
1112 info.nrQubits = std::max(info.nrQubits, pauliString.size());
1114 pauliString, method, info.nrQubits, circuit, maxBondDim);
1115 const double expectationTime =
1117 pauliString, nrReps, maxBondDim) /
1120 size_t cntPauli = 0;
1121 for (
char c : pauliString) {
1122 if (c ==
'X' || c ==
'x' || c ==
'Y' || c ==
'y' || c ==
'Z' || c ==
'z')
1126 std::stringstream ss;
1127 ss << info.nrQubits <<
"," << info.nrOneQubitOps <<
","
1128 << info.nrTwoQubitOps <<
"," << info.nrThreeQubitOps <<
","
1129 << info.nrMiddleMeasurementOps <<
"," << info.nrEndMeasurementOps <<
","
1130 << info.nrOneQubitOpsExecutedOnce <<
","
1131 << info.nrTwoQubitOpsExecutedOnce <<
","
1132 << info.nrThreeQubitOpsExecutedOnce <<
","
1133 <<
"0,0," << maxBondDim <<
"," << cntPauli <<
"," << estimatedCost <<
","
1139 const std::string& logFilePath,
1140 const std::vector<size_t>& featureIndices) {
1141 const auto executionInfos =
ReadLog(logFilePath);
1143 std::vector<std::vector<double>> features;
1144 features.reserve(executionInfos.size());
1146 std::vector<double> targetValues;
1147 targetValues.reserve(executionInfos.size());
1149 for (
const auto& info : executionInfos) {
1150 std::vector<double> featureVector(featureIndices.size());
1151 for (
size_t i = 0; i < featureVector.size(); ++i)
1152 featureVector[i] = info.getFieldValue(featureIndices[i]);
1153 features.push_back(std::move(featureVector));
1155 targetValues.push_back(info.runtime);
1158 auto regressor = std::make_shared<Utils::MultipleLinearRegression>();
1159 regressor->SetSamples(features, targetValues);
static const std::shared_ptr< IQuantumGate< Time > > CreateGate(QuantumGateType type, size_t q1, size_t q2=0, size_t q3=0, double param1=0, double param2=0, double param3=0, double param4=0)
Construct a quantum gate.
Circuit class for holding the sequence of operations.
Measurement operation class.
The state class that stores the classical state of a quantum circuit execution.
static std::shared_ptr< Circuits::Circuit<> > GenerateRandomCircuit(size_t nrQubits, size_t depth, double measureInsideProbability=0., size_t nrMeasAtEnd=0, bool isClifford=false, size_t nrNonCliffordGatesLimit=0, size_t nrBranchingGatesLimit=0)
static double MeasureSamplingTime(Simulators::SimulatorType simType, Simulators::SimulationType method, size_t nrQubits, const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t nrQubitsSampled, size_t nrSamples, size_t nrReps, size_t maxBondDim)
static void BenchmarkAndLogPauliExpectation(Simulators::SimulatorType simType, Simulators::SimulationType method, size_t nrReps, size_t nrMinQubits, size_t nrMaxQubits, size_t stepQubits, size_t depthMin, size_t depthMax, size_t stepDepth, size_t nrRandomCircuitsPerConfig, const std::string &logFilePath, size_t startBondDim=16, size_t endBondDim=16)
static double MeasureExecutionTime(Simulators::SimulatorType simType, Simulators::SimulationType method, size_t nrQubits, const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t nrReps, size_t maxBondDim)
static void BenchmarkAndLogPauliExpectation(Simulators::SimulatorType simType, Simulators::SimulationType method, const std::shared_ptr< Circuits::Circuit<> > &circuit, const std::string &pauliString, size_t nrReps, size_t maxBondDim, Utils::LogFile &log)
static void BenchmarkAndLogSampling(Simulators::SimulatorType simType, Simulators::SimulationType method, size_t nrReps, size_t nrMinQubits, size_t nrMaxQubits, size_t stepQubits, size_t depthMin, size_t depthMax, size_t stepDepth, size_t nrMeasAtEndMin, size_t nrMeasAtEndMax, size_t stepMeasAtEnd, size_t nrSamplesMin, size_t nrSamplesMax, size_t multiplierSamples, size_t nrRandomCircuitsPerConfig, const std::string &logFilePath, size_t startBondDim=16, size_t endBondDim=16)
static double MeasurePauliExpectationTime(Simulators::SimulatorType simType, Simulators::SimulationType method, size_t nrQubits, const std::shared_ptr< Circuits::Circuit<> > &circuit, const std::string &pauliString, size_t nrReps, size_t maxBondDim)
static std::shared_ptr< Utils::MultipleLinearRegression > GetRegressor(const std::string &logFilePath, const std::vector< size_t > &featureIndices)
static std::shared_ptr< Simulators::ISimulator > GetSimulator(Simulators::SimulatorType simType, Simulators::SimulationType method, size_t nrQubits, size_t maxBondDim)
static double EstimatePauliExpectationCost(const std::string &pauliString, Simulators::SimulationType method, size_t nrQubits, const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t maxBondDim)
static void BenchmarkAndLogSampling(Simulators::SimulatorType simType, Simulators::SimulationType method, const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t nrQubitsSampled, size_t nrSamples, size_t nrReps, size_t maxBondDim, Utils::LogFile &log)
static double EstimateSamplingCost(Simulators::SimulationType method, size_t nrQubits, size_t nrQubitsSampled, size_t samples, const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t maxBondDim)
static std::string GeneratePauliString(size_t nrQubits)
static double EstimateExecutionCost(Simulators::SimulationType method, size_t nrQubits, const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t maxBondDim)
static CircuitInfo GetCircuitInfo(const std::shared_ptr< Circuits::Circuit<> > &circuit)
static void BenchmarkAndLogExecution(Simulators::SimulatorType simType, Simulators::SimulationType method, const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t nrReps, size_t maxBondDim, Utils::LogFile &log)
static std::vector< ExecutionInfo > ReadLog(const std::string &logFilePath)
static void BenchmarkAndLogExecution(Simulators::SimulatorType simType, Simulators::SimulationType method, size_t nrReps, size_t nrMinQubits, size_t nrMaxQubits, size_t stepQubits, size_t depthMin, size_t depthMax, size_t stepDepth, double measureInsideProbability, size_t nrMeasAtEndMin, size_t nrMeasAtEndMax, size_t stepMeasAtEnd, size_t nrRandomCircuitsPerConfig, const std::string &logFilePath, size_t startBondDim=16, size_t endBondDim=16)
static double GetSamplingCost(const std::shared_ptr< Circuits::Circuit<> > &circuit, size_t nrQubitsSampled, size_t samples)
static double GetCost(const std::shared_ptr< Circuits::Circuit<> > &circuit)
static std::shared_ptr< ISimulator > CreateSimulator(SimulatorType t=SimulatorType::kQCSim, SimulationType method=SimulationType::kMatrixProductState)
Create a quantum computing simulator.
void Log(const std::string &message)
QuantumGateType
The type of quantum gates.
@ kConditionalGate
conditional gate, similar with gate, but conditioned on something from 'OperationState'
@ kConditionalMeasurement
conditional measurement, similar with measurement, but conditioned on something from 'OperationState'
@ kMeasurement
measurement, result in 'OperationState'
@ kGate
the usual quantum gate, result stays in simulator's state
@ kReset
reset, no result in 'state', just apply measurement, then apply not on all qubits that were measured ...
SimulationType
The type of simulation.
@ kStatevector
statevector simulation type
@ kMatrixProductState
matrix product state simulation type
@ kStabilizer
Clifford gates simulation type.
@ kPauliPropagator
Pauli propagator simulation type.
@ kPathIntegral
Path integral simulation type.
SimulatorType
The type of simulator.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.
size_t nrTwoQubitOpsExecutedOnce
CircuitInfo(const CircuitInfo &other)=default
size_t nrEndMeasurementOps
size_t nrOneQubitOpsExecutedOnce
size_t nrThreeQubitOpsExecutedOnce
CircuitInfo & operator=(const CircuitInfo &other)=default
size_t nrMiddleMeasurementOps
double getFieldValue(size_t index) const
ExecutionInfo(const CircuitInfo &circuitInfo)
ExecutionInfo & operator=(const ExecutionInfo &other)=default
double getFieldValue(size_t index) const
ExecutionInfo(const ExecutionInfo &other)=default
ExecutionInfo & operator=(const CircuitInfo &circuitInfo)