45 TensorNetwork(
size_t numQubits) : rng(std::random_device{}()), uniformZeroOne(0, 1)
47 lastTensors.resize(numQubits);
48 lastTensorsSuper.resize(numQubits);
49 lastTensorIndices.resize(numQubits);
50 lastTensorIndicesSuper.resize(numQubits);
52 qubitsMap.resize(numQubits);
76 const auto gateQubitsNumber = gate.getQubitsNumber();
77 if (gateQubitsNumber > 1)
78 AddTwoQubitsGate(gate, q1, q2);
80 AddOneQubitGate(gate, q1);
87 contractor->SetMultithreading(enableMultithreading);
91 const auto lastTensorIdOnQubit = lastTensors[qubit];
92 const auto lastTensorIndexOnQubit = lastTensorIndices[qubit];
100 const double result = contractor->Contract(*
this, qubit);
105 lastTensors[qubit] = lastTensorIdOnQubit;
106 lastTensorIndices[qubit] = lastTensorIndexOnQubit;
109 tensors.resize(tensors.size() - 1);
133 if (pauliString.empty())
135 else if (!contractor)
138 auto savedTensorsNrLocal = tensors.size();
139 auto saveLastTensorsLocal = lastTensors;
140 auto saveLastTensorIndicesLocal = lastTensorIndices;
143 const QC::Gates::PauliXGate<TensorNode::MatrixClass> XGate;
144 const QC::Gates::PauliYGate<TensorNode::MatrixClass> YGate;
145 const QC::Gates::PauliZGate<TensorNode::MatrixClass> ZGate;
147 std::unordered_set<Types::qubit_t> usedQubits;
151 const char op = toupper(pauliString[q]);
155 AddOneQubitExpectationValueOp(XGate, q);
156 usedQubits.insert(q);
159 AddOneQubitExpectationValueOp(YGate, q);
160 usedQubits.insert(q);
163 AddOneQubitExpectationValueOp(ZGate, q);
164 usedQubits.insert(q);
173 if (usedQubits.empty())
176 const double result = Contract(usedQubits);
178 tensors.resize(savedTensorsNrLocal);
179 lastTensors.swap(saveLastTensorsLocal);
180 lastTensorIndices.swap(saveLastTensorIndicesLocal);
190 const auto tensorCount = tensors.size();
191 auto queryLastTensors = lastTensors;
192 auto queryLastTensorIndices = lastTensorIndices;
193 const auto restoreQuery = [&]() {
194 tensors.resize(tensorCount);
195 lastTensors.swap(queryLastTensors);
196 lastTensorIndices.swap(queryLastTensorIndices);
206 const bool expected = (outcome & mask) == 0;
227 const double prob = uniformZeroOne(rng);
243 auto tensorNode = std::make_shared<TensorNode>();
244 tensorNode->SetProjector(qubit, zero);
246 const auto newTensorId =
static_cast<Index>(tensors.size());
247 tensorNode->SetId(newTensorId);
256 const auto tensorOnQubitId = lastTensors[qubit];
257 const auto indexOnQubit = lastTensorIndices[qubit];
260 const auto &lastTensor = tensors[tensorOnQubitId];
261 lastTensor->connections[indexOnQubit] = newTensorId;
262 lastTensor->connectionsIndices[indexOnQubit] = 0;
266 tensorNode->connections[0] = tensorOnQubitId;
267 tensorNode->connectionsIndices[0] = indexOnQubit;
270 tensors.emplace_back(std::move(tensorNode));
273 lastTensors[qubit] = newTensorId;
274 lastTensorIndices[qubit] = 1;
281 const double renorm = 1. / sqrt(prob);
283 projMat(0, 0) = renorm;
285 projMat(1, 1) = renorm;
287 const QC::Gates::SingleQubitGate<TensorNode::MatrixClass> projOp(projMat);
294 return lastTensors.size();
307 const std::vector<std::shared_ptr<TensorNode>> &
GetTensors()
const
314 return qubitsGroups.at(qubitsMap[q]);
319 saveTensors.resize(tensors.size());
320 for (
size_t i = 0; i < tensors.size(); ++i)
321 saveTensors[i] = tensors[i]->CloneWithoutTensorCopy();
323 saveQubitsMap = qubitsMap;
324 saveQubitsGroups = qubitsGroups;
331 savedTensorsNr = tensors.size();
332 saveLastTensors = lastTensors;
333 saveLastTensorsSuper = lastTensorsSuper;
334 saveLastTensorIndices = lastTensorIndices;
335 saveLastTensorIndicesSuper = lastTensorIndicesSuper;
342 tensors.resize(saveTensors.size());
343 for (
size_t i = 0; i < tensors.size(); ++i)
344 tensors[i] = saveTensors[i]->CloneWithoutTensorCopy();
346 qubitsMap = saveQubitsMap;
347 qubitsGroups = saveQubitsGroups;
352 tensors.resize(savedTensorsNr);
353 lastTensors = saveLastTensors;
354 lastTensorsSuper = saveLastTensorsSuper;
355 lastTensorIndices = saveLastTensorIndices;
356 lastTensorIndicesSuper = saveLastTensorIndicesSuper;
361 tensors.swap(saveTensors);
363 qubitsMap.swap(saveQubitsMap);
364 qubitsGroups.swap(saveQubitsGroups);
373 tensors.resize(savedTensorsNr);
375 lastTensors.swap(saveLastTensors);
376 lastTensorsSuper.swap(saveLastTensorsSuper);
377 lastTensorIndices.swap(saveLastTensorIndices);
378 lastTensorIndicesSuper.swap(saveLastTensorIndicesSuper);
387 saveQubitsMap.clear();
388 saveQubitsGroups.clear();
395 saveLastTensors.clear();
396 saveLastTensorsSuper.clear();
398 saveLastTensorIndices.clear();
399 saveLastTensorIndicesSuper.clear();
407 const auto lastTensorId = lastTensors[q];
408 const auto lastTensorSuperId = lastTensorsSuper[q];
409 const auto &lastTensor = tensors[lastTensorId];
410 const auto &lastTensorSuper = tensors[lastTensorSuperId];
412 const auto tensorIndexOnQubit = lastTensorIndices[q];
413 const auto tensorSuperIndexOnQubit = lastTensorIndicesSuper[q];
416 lastTensor->connections[tensorIndexOnQubit] = lastTensorSuperId;
417 lastTensor->connectionsIndices[tensorIndexOnQubit] = tensorSuperIndexOnQubit;
420 lastTensorSuper->connections[tensorSuperIndexOnQubit] = lastTensorId;
421 lastTensorSuper->connectionsIndices[tensorSuperIndexOnQubit] = tensorIndexOnQubit;
429 const auto lastTensorId = lastTensors[q];
430 const auto lastTensorSuperId = lastTensorsSuper[q];
431 const auto &lastTensor = tensors[lastTensorId];
432 const auto &lastTensorSuper = tensors[lastTensorSuperId];
434 const auto tensorIndexOnQubit = lastTensorIndices[q];
435 const auto tensorSuperIndexOnQubit = lastTensorIndicesSuper[q];
457 enableMultithreading = multithreading;
469 return enableMultithreading;
472 std::unique_ptr<TensorNetwork>
Clone()
const
474 auto cloned = std::make_unique<TensorNetwork>(0);
480 cloned->tensors.reserve(tensors.size());
481 for (
const auto &node : tensors)
482 cloned->tensors.push_back(node->CloneWithoutTensorCopy());
484 cloned->lastTensors = lastTensors;
485 cloned->lastTensorsSuper = lastTensorsSuper;
488 cloned->lastTensorIndices = lastTensorIndices;
489 cloned->lastTensorIndicesSuper = lastTensorIndicesSuper;
492 cloned->qubitsMap = qubitsMap;
494 cloned->qubitsGroups = qubitsGroups;
497 cloned->savedTensorsNr = savedTensorsNr;
498 cloned->saveTensors.reserve(saveTensors.size());
499 for (
const auto &node : saveTensors)
500 cloned->saveTensors.push_back(node->CloneWithoutTensorCopy());
502 cloned->saveLastTensors = saveLastTensors;
503 cloned->saveLastTensorsSuper = saveLastTensorsSuper;
506 cloned->saveLastTensorIndices = saveLastTensorIndices;
508 cloned->saveLastTensorIndicesSuper = saveLastTensorIndicesSuper;
511 cloned->saveQubitsMap = saveQubitsMap;
513 cloned->saveQubitsGroups = saveQubitsGroups;
516 cloned->enableMultithreading = enableMultithreading;
518 cloned->contractor = contractor->Clone();
524 void AddOneQubitExpectationValueOp(
const QC::Gates::QuantumGateWithOp<TensorNode::MatrixClass> &gate,
Types::qubit_t q)
526 auto tensorNode = std::make_shared<TensorNode>();
527 tensorNode->SetGate(gate, q);
529 auto lastTensorId = lastTensors[q];
530 const auto &lastTensor = tensors[lastTensorId];
538 auto lastTensorIndexForQubit = lastTensorIndices[q];
540 auto tensorId =
static_cast<Index>(tensors.size());
541 tensorNode->SetId(tensorId);
550 lastTensor->connections[lastTensorIndexForQubit] = tensorId;
551 lastTensor->connectionsIndices[lastTensorIndexForQubit] = 0;
553 tensorNode->connections[0] = lastTensorId;
554 tensorNode->connectionsIndices[0] = lastTensorIndexForQubit;
556 tensors.emplace_back(std::move(tensorNode));
559 lastTensors[q] = tensorId;
561 lastTensorIndices[q] = 1;
564 void AddOneQubitGate(
const QC::Gates::QuantumGateWithOp<TensorNode::MatrixClass> &gate,
Types::qubit_t q,
bool contractWithTwoQubitTensors =
false,
565 bool contract =
true)
569 auto tensorNode = std::make_shared<TensorNode>();
570 tensorNode->SetGate(gate, q);
572 auto lastTensorId = lastTensors[q];
573 const auto &lastTensor = tensors[lastTensorId];
581 auto lastTensorIndexForQubit = lastTensorIndices[q];
588 if (contract && (contractWithTwoQubitTensors || lastTensor->qubits.size() <= 2))
603 std::make_shared<Utils::Tensor<>>(lastTensor->tensor->Contract(*(tensorNode->tensor), lastTensorIndexForQubit, 0, enableMultithreading));
607 static const std::vector<size_t> indices{0, 1, 3, 2};
608 if (lastTensorIndexForQubit == 2)
613 const auto otherQubit = lastTensor->qubits[3];
614 const auto otherTensorId = lastTensors[otherQubit];
616 std::swap(lastTensor->qubits[2], lastTensor->qubits[3]);
617 std::swap(lastTensor->connections[2], lastTensor->connections[3]);
618 std::swap(lastTensor->connectionsIndices[2], lastTensor->connectionsIndices[3]);
620 lastTensorIndices[q] = 3;
622 if (otherTensorId == lastTensorId)
623 lastTensorIndices[otherQubit] = 2;
628 const auto &otherTensor = tensors[lastTensor->connections[2]];
630 const auto otherIndex = lastTensor->connectionsIndices[2];
631 otherTensor->connectionsIndices[otherIndex] = 2;
635 tensorNode->SetSuper();
637 lastTensorId = lastTensorsSuper[q];
638 const auto &lastTensorSuper = tensors[lastTensorId];
639 lastTensorIndexForQubit = lastTensorIndicesSuper[q];
641 lastTensorSuper->tensor =
642 std::make_shared<Utils::Tensor<>>(lastTensorSuper->tensor->Contract(*(tensorNode->tensor), lastTensorIndexForQubit, 0, enableMultithreading));
644 if (lastTensorIndexForQubit == 2)
648 const auto otherQubit = lastTensorSuper->qubits[3];
649 const auto otherTensorId = lastTensorsSuper[otherQubit];
651 std::swap(lastTensorSuper->qubits[2], lastTensorSuper->qubits[3]);
652 std::swap(lastTensorSuper->connections[2], lastTensorSuper->connections[3]);
653 std::swap(lastTensorSuper->connectionsIndices[2], lastTensorSuper->connectionsIndices[3]);
655 lastTensorIndicesSuper[q] = 3;
657 if (otherTensorId == lastTensorId)
658 lastTensorIndicesSuper[otherQubit] = 2;
663 const auto &otherTensor = tensors[lastTensorSuper->connections[2]];
665 const auto otherIndex = lastTensorSuper->connectionsIndices[2];
666 otherTensor->connectionsIndices[otherIndex] = 2;
672 auto tensorId =
static_cast<Index>(tensors.size());
673 tensorNode->SetId(tensorId);
682 lastTensor->connections[lastTensorIndexForQubit] = tensorId;
683 lastTensor->connectionsIndices[lastTensorIndexForQubit] = 0;
685 tensorNode->connections[0] = lastTensorId;
686 tensorNode->connectionsIndices[0] = lastTensorIndexForQubit;
688 tensors.emplace_back(std::move(tensorNode));
691 lastTensors[q] = tensorId;
693 lastTensorIndices[q] = 1;
697 tensorNode = std::make_shared<TensorNode>();
699 tensorNode->SetGate(gate, q);
700 tensorNode->SetSuper();
702 tensorId =
static_cast<Index>(tensors.size());
703 tensorNode->SetId(tensorId);
712 lastTensorId = lastTensorsSuper[q];
713 const auto &lastTensorSuper = tensors[lastTensorId];
714 lastTensorIndexForQubit = lastTensorIndicesSuper[q];
715 lastTensorSuper->connections[lastTensorIndexForQubit] = tensorId;
716 lastTensorSuper->connectionsIndices[lastTensorIndexForQubit] = 0;
718 tensorNode->connections[0] = lastTensorId;
719 tensorNode->connectionsIndices[0] = lastTensorIndexForQubit;
721 tensors.emplace_back(std::move(tensorNode));
724 lastTensorsSuper[q] = tensorId;
726 lastTensorIndicesSuper[q] = 1;
732 const size_t q1group = qubitsMap[q1];
733 const size_t q2group = qubitsMap[q2];
735 if (q1group != q2group)
738 for (
const auto qg : qubitsGroups[q2group])
740 qubitsMap[qg] = q1group;
741 qubitsGroups[q1group].insert(qg);
743 qubitsGroups.erase(q2group);
750 auto tensorNode = std::make_shared<TensorNode>();
751 tensorNode->SetGate(gate, q1, q2);
753 auto tensorId =
static_cast<Index>(tensors.size());
754 tensorNode->SetId(tensorId);
763 auto lastTensorId = lastTensors[q1];
765 const auto &lastTensor = tensors[lastTensorId];
766 auto lastTensorIndexForQubit = lastTensorIndices[q1];
767 lastTensor->connections[lastTensorIndexForQubit] = tensorId;
768 lastTensor->connectionsIndices[lastTensorIndexForQubit] = 0;
770 tensorNode->connections[0] = lastTensorId;
771 tensorNode->connectionsIndices[0] = lastTensorIndexForQubit;
773 lastTensorId = lastTensors[q2];
774 const auto &lastTensor2 = tensors[lastTensorId];
775 lastTensorIndexForQubit = lastTensorIndices[q2];
776 lastTensor2->connections[lastTensorIndexForQubit] = tensorId;
777 lastTensor2->connectionsIndices[lastTensorIndexForQubit] = 1;
779 tensorNode->connections[1] = lastTensorId;
780 tensorNode->connectionsIndices[1] = lastTensorIndices[q2];
782 tensors.emplace_back(std::move(tensorNode));
785 lastTensors[q1] = tensorId;
786 lastTensors[q2] = tensorId;
788 lastTensorIndices[q1] = 2;
789 lastTensorIndices[q2] = 3;
793 tensorNode = std::make_shared<TensorNode>();
795 tensorNode->SetGate(gate, q1, q2);
796 tensorNode->SetSuper();
798 tensorId =
static_cast<Index>(tensors.size());
799 tensorNode->SetId(tensorId);
808 lastTensorId = lastTensorsSuper[q1];
809 const auto &lastTensorSuper = tensors[lastTensorId];
810 lastTensorIndexForQubit = lastTensorIndicesSuper[q1];
811 lastTensorSuper->connections[lastTensorIndexForQubit] = tensorId;
812 lastTensorSuper->connectionsIndices[lastTensorIndexForQubit] = 0;
814 tensorNode->connections[0] = lastTensorId;
815 tensorNode->connectionsIndices[0] = lastTensorIndexForQubit;
817 lastTensorId = lastTensorsSuper[q2];
818 const auto &lastTensor2Super = tensors[lastTensorId];
819 lastTensorIndexForQubit = lastTensorIndicesSuper[q2];
820 lastTensor2Super->connections[lastTensorIndexForQubit] = tensorId;
821 lastTensor2Super->connectionsIndices[lastTensorIndexForQubit] = 1;
823 tensorNode->connections[1] = lastTensorId;
824 tensorNode->connectionsIndices[1] = lastTensorIndicesSuper[q2];
826 tensors.emplace_back(std::move(tensorNode));
829 lastTensorsSuper[q1] = tensorId;
830 lastTensorsSuper[q2] = tensorId;
832 lastTensorIndicesSuper[q1] = 2;
833 lastTensorIndicesSuper[q2] = 3;
840 contractor->SetMultithreading(enableMultithreading);
847 for (
auto &group : qubitsGroups)
849 const double groupResult = contractor->Contract(*
this,
850 *group.second.begin());
852 if (groupResult == 0)
854 result *= groupResult;
866 double Contract(
const std::unordered_set<Types::qubit_t> &qubits)
870 contractor->SetMultithreading(enableMultithreading);
877 for (
auto &group : qubitsGroups)
880 for (
const auto q : group.second)
881 if (qubits.find(q) != qubits.end())
885 const double groupResult = contractor->Contract(*
this, q);
887 if (groupResult == 0)
889 result *= groupResult;
903 void Clean(
size_t numQubits)
905 SetQubitsTensors(numQubits);
908 void SetQubitsTensors(
size_t numQubits)
913 qubitsGroups[q].insert(q);
915 auto tensorNode = std::make_shared<TensorNode>();
916 tensorNode->SetQubit(q);
917 tensorNode->SetId(
static_cast<Index>(tensors.size()));
919 lastTensors[q] = tensorNode->GetId();
920 lastTensorIndices[q] = 0;
921 tensors.emplace_back(std::move(tensorNode));
923 tensorNode = std::make_shared<TensorNode>();
924 tensorNode->SetQubit(q);
925 tensorNode->SetId(
static_cast<Index>(tensors.size()));
926 tensorNode->SetSuper();
928 lastTensorsSuper[q] = tensorNode->GetId();
929 lastTensorIndicesSuper[q] = 0;
930 tensors.emplace_back(std::move(tensorNode));
934 void SetQubitsTensorsClear(
size_t numQubits)
939 qubitsGroups[q].insert(q);
941 lastTensors[q] = 2 * q;
942 lastTensorIndices[q] = 0;
944 lastTensorsSuper[q] = lastTensors[q] + 1;
945 lastTensorIndicesSuper[q] = 0;
949 std::vector<std::shared_ptr<TensorNode>> tensors;
951 std::vector<Index> lastTensors;
952 std::vector<Index> lastTensorsSuper;
954 std::vector<Index> lastTensorIndices;
955 std::vector<Index> lastTensorIndicesSuper;
958 std::vector<size_t> qubitsMap;
960 std::unordered_map<size_t, std::unordered_set<Types::qubit_t>> qubitsGroups;
963 size_t savedTensorsNr = 0;
964 std::vector<std::shared_ptr<TensorNode>> saveTensors;
966 std::vector<Index> saveLastTensors;
967 std::vector<Index> saveLastTensorsSuper;
970 std::vector<Index> saveLastTensorIndices;
971 std::vector<Index> saveLastTensorIndicesSuper;
974 std::vector<size_t> saveQubitsMap;
976 std::unordered_map<size_t, std::unordered_set<Types::qubit_t>> saveQubitsGroups;
979 std::shared_ptr<ITensorContractor> contractor;
981 bool enableMultithreading =
true;
984 std::uniform_real_distribution<double> uniformZeroOne;