32 #ifndef CLASSES_CIRCUITS_CIRCUITS_H_ 33 #define CLASSES_CIRCUITS_CIRCUITS_H_ 41 class QCircuit :
public IDisplay,
public IJSON {
48 std::vector<bool> measured_;
50 std::unordered_map<std::size_t, cmat>
52 std::unordered_map<std::string, idx> count_{};
54 std::unordered_map<std::string, idx>
66 void add_hash_(
const cmat& U, std::size_t hashU) {
69 auto search = cmat_hash_tbl_.find(hashU);
70 static internal::EqualEigen equal_eigen;
71 if (search != cmat_hash_tbl_.end())
74 if (!equal_eigen(search->second, U))
75 throw exception::CustomException(
"qpp::QCircuit::add_hash_()",
76 "Matrix hash collision");
79 cmat_hash_tbl_.insert({hashU, U});
99 SINGLE_CTRL_SINGLE_TARGET,
102 SINGLE_CTRL_MULTIPLE_TARGET,
105 MULTIPLE_CTRL_SINGLE_TARGET,
108 MULTIPLE_CTRL_MULTIPLE_TARGET,
115 SINGLE_cCTRL_SINGLE_TARGET,
118 SINGLE_cCTRL_MULTIPLE_TARGET,
122 MULTIPLE_cCTRL_SINGLE_TARGET,
126 MULTIPLE_cCTRL_MULTIPLE_TARGET,
142 friend std::ostream& operator<<(std::ostream& os,
143 const GateType& gate_type) {
148 case GateType::SINGLE:
154 case GateType::THREE:
160 case GateType::CUSTOM:
163 case GateType::SINGLE_CTRL_SINGLE_TARGET:
164 os <<
"SINGLE_CTRL_SINGLE_TARGET";
166 case GateType::SINGLE_CTRL_MULTIPLE_TARGET:
167 os <<
"SINGLE_CTRL_MULTIPLE_TARGET";
169 case GateType::MULTIPLE_CTRL_SINGLE_TARGET:
170 os <<
"MULTIPLE_CTRL_SINGLE_TARGET";
172 case GateType::MULTIPLE_CTRL_MULTIPLE_TARGET:
173 os <<
"MULTIPLE_CTRL_MULTIPLE_TARGET";
175 case GateType::CUSTOM_CTRL:
178 case GateType::SINGLE_cCTRL_SINGLE_TARGET:
179 os <<
"SINGLE_cCTRL_SINGLE_TARGET";
181 case GateType::SINGLE_cCTRL_MULTIPLE_TARGET:
182 os <<
"SINGLE_cCTRL_MULTIPLE_TARGET";
184 case GateType::MULTIPLE_cCTRL_SINGLE_TARGET:
185 os <<
"MULTIPLE_cCTRL_SINGLE_TARGET";
187 case GateType::MULTIPLE_cCTRL_MULTIPLE_TARGET:
188 os <<
"MULTIPLE_cCTRL_MULTIPLE_TARGET";
190 case GateType::CUSTOM_cCTRL:
191 os <<
"CUSTOM_cCTRL";
202 GateType gate_type_ = GateType::NONE;
203 std::size_t gate_hash_{};
204 std::vector<idx> ctrl_{};
205 std::vector<idx> target_{};
206 std::vector<idx> shift_{};
212 GateStep() =
default;
223 explicit GateStep(GateType gate_type, std::size_t gate_hash,
224 const std::vector<idx>& ctrl,
225 const std::vector<idx>& target,
226 const std::vector<idx>& shift = {},
227 std::string name = {})
228 : gate_type_{gate_type}, gate_hash_{gate_hash}, ctrl_{ctrl},
229 target_{target}, shift_{shift}, name_{name} {}
239 friend std::ostream& operator<<(std::ostream& os,
240 const GateStep& gate_step) {
241 os << gate_step.gate_type_ <<
", ";
242 if (gate_step.gate_type_ >= GateType::SINGLE_cCTRL_SINGLE_TARGET)
243 os <<
"c_ctrl = " << disp(gate_step.ctrl_,
", ") <<
", ";
244 else if (gate_step.gate_type_ >= GateType::SINGLE_CTRL_SINGLE_TARGET)
245 os <<
"ctrl = " << disp(gate_step.ctrl_,
", ") <<
", ";
246 os <<
"target = " << disp(gate_step.target_,
", ") <<
", ";
247 if (!gate_step.shift_.empty())
248 os <<
"shift = " << disp(gate_step.shift_,
", ") <<
", ";
249 os <<
"name = " <<
'\"' << gate_step.name_ <<
'\"';
257 enum class MeasureType {
302 friend std::ostream& operator<<(std::ostream& os,
303 const MeasureType& measure_type) {
304 switch (measure_type) {
305 case MeasureType::NONE:
306 os <<
"MEASURE NONE";
308 case MeasureType::MEASURE_Z:
311 case MeasureType::MEASURE_Z_MANY:
312 os <<
"MEASURE_Z_MANY";
314 case MeasureType::MEASURE_V:
317 case MeasureType::MEASURE_V_MANY:
318 os <<
"MEASURE_V_MANY";
320 case MeasureType::MEASURE_Z_ND:
321 os <<
"MEASURE_Z_ND";
323 case MeasureType::MEASURE_Z_MANY_ND:
324 os <<
"MEASURE_Z_MANY_ND";
326 case MeasureType::MEASURE_V_ND:
327 os <<
"MEASURE_V_ND";
329 case MeasureType::MEASURE_V_MANY_ND:
330 os <<
"MEASURE_V_MANY_ND";
332 case MeasureType::RESET:
335 case MeasureType::RESET_MANY:
338 case MeasureType::DISCARD:
341 case MeasureType::DISCARD_MANY:
342 os <<
"DISCARD_MANY";
353 MeasureType measurement_type_ = MeasureType::NONE;
354 std::vector<std::size_t> mats_hash_{};
355 std::vector<idx> target_{};
364 MeasureStep() =
default;
376 explicit MeasureStep(MeasureType measurement_type,
377 const std::vector<std::size_t>& mats_hash,
378 const std::vector<idx>& target, idx c_reg,
379 std::string name = {})
380 : measurement_type_{measurement_type}, mats_hash_{mats_hash},
381 target_{target}, c_reg_{c_reg}, name_{name} {}
391 friend std::ostream& operator<<(std::ostream& os,
392 const MeasureStep& measure_step) {
393 os << measure_step.measurement_type_ <<
", ";
394 os <<
"target = " << disp(measure_step.target_,
", ") <<
", ";
395 if (measure_step.measurement_type_ != MeasureType::RESET &&
396 measure_step.measurement_type_ != MeasureType::RESET_MANY &&
397 measure_step.measurement_type_ != MeasureType::DISCARD &&
398 measure_step.measurement_type_ != MeasureType::DISCARD_MANY)
399 os <<
"c_reg = " << measure_step.c_reg_ <<
", ";
400 os <<
"name = " <<
'\"' << measure_step.name_ <<
'\"';
408 enum class StepType {
416 std::vector<GateStep> gates_{};
417 std::vector<MeasureStep> measurements_{};
418 std::vector<StepType> step_types_{};
425 const std::vector<MeasureStep>& get_measurements_() const noexcept {
426 return measurements_;
434 const std::vector<GateStep>& get_gates_() const noexcept {
return gates_; }
441 const std::unordered_map<std::size_t, cmat>& get_cmat_hash_tbl_() const
443 return cmat_hash_tbl_;
455 const QCircuit* qc_{
nullptr};
461 class value_type_ :
public IDisplay {
465 const QCircuit* value_type_qc_;
467 StepType type_{StepType::NONE};
468 idx ip_{
static_cast<idx
>(-1)};
469 std::vector<GateStep>::const_iterator
471 std::vector<MeasureStep>::const_iterator
480 explicit value_type_(
const QCircuit* value_type_qc)
481 : value_type_qc_{value_type_qc} {}
487 value_type_(
const value_type_&) =
default;
495 value_type_& operator=(
const value_type_&) =
default;
507 std::ostream& display(std::ostream& os)
const override {
510 std::to_string(value_type_qc_->get_step_count()).size() + 1;
513 if (type_ == StepType::GATE) {
515 os << std::setw(text_width) << ip_;
517 idx pos = std::distance(std::begin(value_type_qc_->gates_),
519 os << value_type_qc_->get_gates_()[pos];
522 else if (type_ == StepType::MEASUREMENT) {
524 os << std::setw(text_width) << ip_;
527 std::distance(std::begin(value_type_qc_->measurements_),
531 value_type_qc_->measurements_[pos].measurement_type_) {
532 case MeasureType::NONE:
534 case MeasureType::MEASURE_Z:
535 case MeasureType::MEASURE_Z_MANY:
536 case MeasureType::MEASURE_V:
537 case MeasureType::MEASURE_V_MANY:
540 case MeasureType::MEASURE_Z_ND:
541 case MeasureType::MEASURE_Z_MANY_ND:
542 case MeasureType::MEASURE_V_ND:
543 case MeasureType::MEASURE_V_MANY_ND:
546 case MeasureType::RESET:
547 case MeasureType::RESET_MANY:
550 case MeasureType::DISCARD:
551 case MeasureType::DISCARD_MANY:
556 os << value_type_qc_->get_measurements_()[pos];
559 else if (type_ == StepType::NOP) {
561 os << std::setw(text_width) << ip_;
573 value_type_ elem_{
nullptr};
579 iterator() =
default;
585 iterator(
const iterator&) =
default;
593 iterator& operator=(
const iterator&) =
default;
600 iterator& operator++() {
604 if (qc_ ==
nullptr) {
605 throw exception::InvalidIterator(
606 "qpp::QCircuit::iterator::operator++()");
610 if (qc_->get_step_count() == 0) {
611 throw exception::InvalidIterator(
612 "qpp::QCircuit::iterator::operator++()");
616 if (elem_.ip_ == qc_->get_step_count()) {
617 throw exception::InvalidIterator(
618 "qpp::QCircuit::iterator::operator++()");
623 if (elem_.type_ == StepType::GATE) {
624 std::advance(elem_.gates_ip_, 1);
627 else if (elem_.type_ == StepType::MEASUREMENT) {
628 std::advance(elem_.measurements_ip_, 1);
631 else if (elem_.type_ == StepType::NOP) {
641 if (elem_.ip_ == qc_->get_step_count()) {
642 elem_.type_ = StepType::NONE;
645 elem_.type_ = qc_->step_types_[elem_.ip_];
656 iterator operator++(
int) {
657 iterator retval = *
this;
668 bool operator==(
const iterator& rhs)
const {
669 return std::tie(elem_.type_, elem_.ip_, elem_.gates_ip_,
670 elem_.measurements_ip_) ==
671 std::tie(rhs.elem_.type_, rhs.elem_.ip_, rhs.elem_.gates_ip_,
672 rhs.elem_.measurements_ip_);
682 bool operator!=(iterator rhs)
const {
return !(*
this == rhs); }
689 const value_type_& operator*()
const {
694 if (qc_ ==
nullptr || elem_.ip_ == qc_->get_step_count())
695 throw exception::InvalidIterator(
696 "qpp::QCircuit::iterator::operator*()");
707 void set_begin_(
const QCircuit* qc) {
709 elem_ = value_type_{qc_};
711 if (qc_ !=
nullptr) {
712 if (qc_->get_step_count() != 0)
714 elem_.type_ = qc_->step_types_[0];
717 elem_.gates_ip_ = std::begin(qc_->gates_);
718 elem_.measurements_ip_ = std::begin(qc_->measurements_);
727 void set_end_(
const QCircuit* qc) {
729 elem_ = value_type_{qc_};
731 if (qc_ !=
nullptr) {
732 if (qc->get_step_count() != 0) {
733 elem_.ip_ = qc->get_step_count();
735 elem_.gates_ip_ = std::end(qc->gates_);
736 elem_.measurements_ip_ = std::end(qc->measurements_);
741 using difference_type = ptrdiff_t;
742 using value_type = value_type_;
743 using pointer =
const value_type*;
744 using reference =
const value_type&;
745 using iterator_category = std::forward_iterator_tag;
748 using const_iterator = iterator;
767 const_iterator begin() const noexcept {
779 const_iterator cbegin() const noexcept {
803 const_iterator end() const noexcept {
815 const_iterator cend() const noexcept {
833 explicit QCircuit(idx nq, idx nc = 0, idx d = 2, std::string name = {})
834 : nq_{nq}, nc_{nc}, d_{d}, name_{name}, measured_(nq,
false) {
840 throw exception::OutOfRange(
"qpp::QCircuit::QCircuit()");
847 virtual ~QCircuit() =
default;
855 idx get_nq() const noexcept {
return nq_; }
862 idx get_nc() const noexcept {
return nc_; }
869 idx get_d() const noexcept {
return d_; }
876 std::string get_name()
const {
return name_; }
883 idx get_measured(idx i)
const {
887 throw exception::OutOfRange(
"qpp::QCircuit::get_measured()");
898 std::vector<idx> get_measured()
const {
899 std::vector<idx> result;
900 for (idx i = 0; i < nq_; ++i)
902 result.emplace_back(i);
912 std::vector<idx> get_non_measured()
const {
913 std::vector<idx> result;
914 for (idx i = 0; i < nq_; ++i)
915 if (!get_measured(i))
916 result.emplace_back(i);
927 idx get_gate_count(
const std::string& name)
const {
932 result = count_.at(name);
945 idx get_gate_count()
const {
948 for (
auto&& elem : count_)
949 result += elem.second;
960 idx get_gate_depth(
const std::string& name)
const {
962 std::vector<idx> heights(nc_ + nq_, 0);
965 for (
auto&& step : *
this) {
967 if (step.type_ == StepType::GATE) {
968 GateStep gate_step = *step.gates_ip_;
970 if (name != __FILE__
"__total_gate_depth__" &&
971 gate_step.name_ != name)
976 std::vector<idx> ctrl = gate_step.ctrl_;
977 std::vector<idx> target = gate_step.target_;
978 std::vector<idx> ctrl_target;
979 ctrl_target.reserve(ctrl.size() + target.size());
980 ctrl_target.insert(ctrl_target.end(), ctrl.begin(), ctrl.end());
981 ctrl_target.insert(ctrl_target.end(), target.begin(),
985 switch (gate_step.gate_type_) {
987 case GateType::SINGLE:
989 case GateType::THREE:
990 case GateType::CUSTOM:
992 case GateType::SINGLE_CTRL_SINGLE_TARGET:
993 case GateType::SINGLE_CTRL_MULTIPLE_TARGET:
994 case GateType::MULTIPLE_CTRL_SINGLE_TARGET:
995 case GateType::MULTIPLE_CTRL_MULTIPLE_TARGET:
996 case GateType::CUSTOM_CTRL:
998 for (
auto&& i : ctrl_target)
999 if (heights[nc_ + i] > max_height)
1000 max_height = heights[nc_ + i];
1002 for (
auto&& i : ctrl_target)
1003 heights[nc_ + i] = max_height + 1;
1005 case GateType::SINGLE_cCTRL_SINGLE_TARGET:
1006 case GateType::SINGLE_cCTRL_MULTIPLE_TARGET:
1007 case GateType::MULTIPLE_cCTRL_SINGLE_TARGET:
1008 case GateType::MULTIPLE_cCTRL_MULTIPLE_TARGET:
1009 case GateType::CUSTOM_cCTRL:
1011 for (
auto&& i : ctrl)
1012 if (heights[i] > max_height)
1013 max_height = heights[i];
1014 for (
auto&& i : target)
1015 if (heights[nc_ + i] > max_height)
1016 max_height = heights[nc_ + i];
1018 for (
auto&& i : ctrl)
1019 heights[i] = max_height + 1;
1021 for (
auto&& i : target)
1022 heights[nc_ + i] = max_height + 1;
1028 return found ? *std::max_element(std::begin(heights), std::end(heights))
1037 idx get_gate_depth()
const {
1038 return get_gate_depth(__FILE__
"__total_gate_depth__");
1047 idx get_measurement_depth(
const std::string& name)
const {
1049 std::vector<idx> heights(nc_ + nq_, 0);
1052 for (
auto&& step : *
this) {
1054 if (step.type_ == StepType::MEASUREMENT) {
1055 MeasureStep measure_step = *step.measurements_ip_;
1056 if (name != __FILE__
"__total_measurement_depth__" &&
1057 measure_step.name_ != name)
1062 std::vector<idx> target = measure_step.target_;
1063 idx c_reg = measure_step.c_reg_;
1066 switch (measure_step.measurement_type_) {
1067 case MeasureType::NONE:
1068 case MeasureType::MEASURE_Z:
1069 case MeasureType::MEASURE_Z_MANY:
1070 case MeasureType::MEASURE_V:
1071 case MeasureType::MEASURE_V_MANY:
1072 case MeasureType::MEASURE_Z_ND:
1073 case MeasureType::MEASURE_Z_MANY_ND:
1074 case MeasureType::MEASURE_V_ND:
1075 case MeasureType::MEASURE_V_MANY_ND:
1077 if (heights[c_reg] > max_height)
1078 max_height = heights[c_reg];
1079 for (
auto&& i : target)
1080 if (heights[nc_ + i] > max_height)
1081 max_height = heights[nc_ + i];
1083 heights[c_reg] = max_height + 1;
1084 for (
auto&& i : target)
1085 heights[nc_ + i] = max_height + 1;
1087 case MeasureType::RESET:
1088 case MeasureType::RESET_MANY:
1089 case MeasureType::DISCARD:
1090 case MeasureType::DISCARD_MANY:
1091 for (
auto&& i : target)
1092 if (heights[nc_ + i] > max_height)
1093 max_height = heights[nc_ + i];
1095 for (
auto&& i : target)
1096 heights[nc_ + i] = max_height + 1;
1102 return found ? *std::max_element(std::begin(heights), std::end(heights))
1111 idx get_measurement_depth()
const {
1112 return get_measurement_depth(__FILE__
"__total_measurement_depth__");
1123 idx get_depth()
const {
return get_gate_depth() + get_measurement_depth(); }
1131 idx get_measurement_count(
const std::string& name)
const {
1136 result = measurement_count_.at(name);
1149 idx get_measurement_count()
const {
1152 for (
auto&& elem : measurement_count_)
1153 result += elem.second;
1164 idx get_step_count() const noexcept {
return step_types_.size(); }
1171 idx get_nop_count()
const {
1172 return std::count_if(
1173 std::begin(step_types_), std::end(step_types_),
1174 [](
const StepType& s) {
return s == StepType::NOP; });
1185 QCircuit& set_name(
const std::string& name) {
1202 QCircuit& add_qudit(idx n = 1, idx i = -1) {
1205 if (i == static_cast<idx>(-1)) {
1207 measured_.insert(std::end(measured_), n,
false);
1209 throw exception::OutOfRange(
"qpp::QCircuit::add_qudit()");
1215 measured_.insert(std::next(std::begin(measured_), i), n,
false);
1218 for (
auto& gate : gates_) {
1219 for (
auto& pos : gate.ctrl_) {
1223 for (
auto& pos : gate.target_) {
1230 for (
auto& measurement : measurements_) {
1231 for (
auto& pos : measurement.target_) {
1251 QCircuit& add_dit(idx n = 1, idx i = -1) {
1254 if (i == static_cast<idx>(-1))
1257 throw exception::OutOfRange(
"qpp::QCircuit::add_dit()");
1263 for (
auto& gate : gates_) {
1264 switch (gate.gate_type_) {
1266 case GateType::SINGLE_cCTRL_SINGLE_TARGET:
1267 case GateType::SINGLE_cCTRL_MULTIPLE_TARGET:
1268 case GateType::MULTIPLE_cCTRL_SINGLE_TARGET:
1269 case GateType::MULTIPLE_cCTRL_MULTIPLE_TARGET:
1270 case GateType::CUSTOM_cCTRL:
1271 for (
auto& pos : gate.ctrl_) {
1282 for (
auto& measurement : measurements_) {
1283 if (measurement.c_reg_ >= i)
1284 measurement.c_reg_ += n;
1298 QCircuit& gate(
const cmat& U, idx i, std::string name = {}) {
1304 throw exception::OutOfRange(
"qpp::QCircuit::gate()");
1306 if (get_measured(i))
1307 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::gate()");
1310 if (!internal::check_square_mat(U))
1311 throw exception::MatrixNotSquare(
"qpp::QCircuit::gate()");
1313 if (static_cast<idx>(U.rows()) != d_)
1314 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::gate()");
1315 }
catch (exception::Exception&) {
1316 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1322 name = qpp::Gates::get_instance().get_name(U);
1323 std::size_t hashU = hash_eigen(U);
1324 add_hash_(U, hashU);
1325 gates_.emplace_back(GateType::SINGLE, hashU, std::vector<idx>{},
1326 std::vector<idx>{i}, std::vector<idx>{}, name);
1327 step_types_.emplace_back(StepType::GATE);
1342 QCircuit& gate(
const cmat& U, idx i, idx j, std::string name = {}) {
1347 if (i >= nq_ || j >= nq_ || i == j)
1348 throw exception::OutOfRange(
"qpp::QCircuit::gate()");
1349 if (get_measured(i) || get_measured(j))
1350 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::gate()");
1353 if (!internal::check_square_mat(U))
1354 throw exception::MatrixNotSquare(
"qpp::QCircuit::gate()");
1356 if (static_cast<idx>(U.rows()) != d_ * d_)
1357 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::gate()");
1358 }
catch (exception::Exception&) {
1359 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1365 name = qpp::Gates::get_instance().get_name(U);
1366 std::size_t hashU = hash_eigen(U);
1367 add_hash_(U, hashU);
1368 gates_.emplace_back(GateType::TWO, hashU, std::vector<idx>{},
1369 std::vector<idx>{i, j}, std::vector<idx>{}, name);
1370 step_types_.emplace_back(StepType::GATE);
1386 QCircuit& gate(
const cmat& U, idx i, idx j, idx k, std::string name = {}) {
1391 if (i >= nq_ || j >= nq_ || k >= nq_ || (i == j) || (i == k) ||
1393 throw exception::OutOfRange(
"qpp::QCircuit::gate()");
1394 if (get_measured(i) || get_measured(j) || get_measured(k))
1395 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::gate()");
1398 if (!internal::check_square_mat(U))
1399 throw exception::MatrixNotSquare(
"qpp::QCircuit::gate()");
1401 if (static_cast<idx>(U.rows()) != d_ * d_ * d_)
1402 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::gate()");
1403 }
catch (exception::Exception&) {
1404 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1410 name = qpp::Gates::get_instance().get_name(U);
1411 std::size_t hashU = hash_eigen(U);
1412 add_hash_(U, hashU);
1413 gates_.emplace_back(GateType::THREE, hashU, std::vector<idx>{},
1414 std::vector<idx>{i, j, k}, std::vector<idx>{},
1416 step_types_.emplace_back(StepType::GATE);
1432 QCircuit& gate_fan(
const cmat& U,
const std::vector<idx>& target,
1433 std::string name = {}) {
1439 throw exception::ZeroSize(
"qpp::QCircuit::gate_fan()");
1440 for (
auto&& elem : target) {
1442 throw exception::OutOfRange(
"qpp::QCircuit::gate_fan()");
1444 if (get_measured(elem))
1445 throw exception::QuditAlreadyMeasured(
1446 "qpp::QCircuit::gate_fan()");
1449 if (!internal::check_no_duplicates(target))
1450 throw exception::Duplicates(
"qpp::QCircuit::gate_fan()");
1453 if (!internal::check_square_mat(U))
1454 throw exception::MatrixNotSquare(
"qpp::QCircuit::gate_fan()");
1456 if (static_cast<idx>(U.rows()) != d_)
1457 throw exception::DimsMismatchMatrix(
1458 "qpp::QCircuit::gate_fan()");
1459 }
catch (exception::Exception&) {
1460 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1466 name = qpp::Gates::get_instance().get_name(U);
1467 std::size_t hashU = hash_eigen(U);
1468 add_hash_(U, hashU);
1469 gates_.emplace_back(GateType::FAN, hashU, std::vector<idx>{}, target,
1470 std::vector<idx>{}, name);
1471 step_types_.emplace_back(StepType::GATE);
1472 count_[name] += target.size();
1490 QCircuit& gate_fan(
const cmat& U,
const std::initializer_list<idx>& target,
1491 std::string name = {}) {
1492 return gate_fan(U, std::vector<idx>(target), name);
1503 QCircuit& gate_fan(
const cmat& U, std::string name = {}) {
1508 if (!internal::check_square_mat(U))
1509 throw exception::MatrixNotSquare(
"qpp::QCircuit::gate_fan()");
1511 if (static_cast<idx>(U.rows()) != d_)
1512 throw exception::DimsMismatchMatrix(
1513 "qpp::QCircuit::gate_fan()");
1514 }
catch (exception::Exception&) {
1515 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1521 name = qpp::Gates::get_instance().get_name(U);
1522 std::size_t hashU = hash_eigen(U);
1523 add_hash_(U, hashU);
1524 gates_.emplace_back(GateType::FAN, hashU, std::vector<idx>{},
1525 get_non_measured(), std::vector<idx>{}, name);
1526 step_types_.emplace_back(StepType::GATE);
1527 count_[name] += get_non_measured().size();
1541 QCircuit& gate_custom(
const cmat& U,
const std::vector<idx>& target,
1542 std::string name = {}) {
1545 idx n =
static_cast<idx
>(target.size());
1546 idx D =
static_cast<idx
>(std::llround(std::pow(d_, n)));
1551 throw exception::ZeroSize(
"qpp::QCircuit::gate_custom()");
1552 for (
auto&& elem : target) {
1554 throw exception::OutOfRange(
"qpp::QCircuit::gate_custom()");
1556 if (get_measured(elem))
1557 throw exception::QuditAlreadyMeasured(
1558 "qpp::QCircuit::gate_custom()");
1561 if (!internal::check_no_duplicates(target))
1562 throw exception::Duplicates(
"qpp::QCircuit::gate_custom()");
1565 if (!internal::check_square_mat(U))
1566 throw exception::MatrixNotSquare(
1567 "qpp::QCircuit::gate_custom()");
1569 if (static_cast<idx>(U.rows()) != D)
1570 throw exception::DimsMismatchMatrix(
1571 "qpp::QCircuit::gate_custom()");
1572 }
catch (exception::Exception&) {
1573 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1579 name = qpp::Gates::get_instance().get_name(U);
1580 std::size_t hashU = hash_eigen(U);
1581 add_hash_(U, hashU);
1582 gates_.emplace_back(GateType::CUSTOM, hashU, std::vector<idx>{}, target,
1583 std::vector<idx>{}, name);
1584 step_types_.emplace_back(StepType::GATE);
1599 QCircuit& QFT(
const std::vector<idx>& target,
bool swap =
true) {
1604 throw exception::ZeroSize(
"qpp::QCircuit::QFT()");
1605 for (
auto&& elem : target) {
1607 throw exception::OutOfRange(
"qpp::QCircuit::QFT()");
1609 if (get_measured(elem))
1610 throw exception::QuditAlreadyMeasured(
1611 "qpp::QCircuit::QFT()");
1614 if (!internal::check_no_duplicates(target))
1615 throw exception::Duplicates(
"qpp::QCircuit::QFT()");
1616 }
catch (exception::Exception&) {
1617 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1622 idx n_subsys = target.size();
1625 for (idx i = 0; i < n_subsys; ++i) {
1627 gate(Gates::get_instance().H, target[i]);
1629 for (idx j = 2; j <= n_subsys - i; ++j) {
1632 Rj << 1, 0, 0, exp(2.0 * pi * 1_i / std::pow(2, j));
1633 CTRL(Rj, target[i + j - 1], target[i], {},
1634 "CTRL-R" + std::to_string(j));
1639 for (idx i = 0; i < n_subsys / 2; ++i) {
1640 gate(Gates::get_instance().SWAP, target[i],
1641 target[n_subsys - i - 1]);
1646 for (idx i = 0; i < n_subsys; ++i) {
1648 gate(Gates::get_instance().Fd(d_), target[i],
"Fd");
1650 for (idx j = 2; j <= n_subsys - i; ++j) {
1652 cmat Rj = cmat::Zero(d_, d_);
1653 for (idx m = 0; m < d_; ++m) {
1654 Rj(m, m) = exp(2.0 * pi * m * 1_i / std::pow(d_, j));
1656 CTRL(Rj, target[i + j - 1], target[i], {},
1657 "CTRL-R" + std::to_string(j) +
"d");
1662 for (idx i = 0; i < n_subsys / 2; ++i) {
1663 gate(Gates::get_instance().SWAPd(d_), target[i],
1664 target[n_subsys - i - 1],
"SWAPd");
1682 QCircuit& QFT(
const std::initializer_list<idx>& target,
bool swap =
true) {
1683 return QFT(std::vector<idx>(target), swap);
1693 QCircuit& QFT(
bool swap =
true) {
return QFT(get_non_measured(), swap); }
1704 QCircuit& TFQ(
const std::vector<idx>& target,
1705 bool swap QPP_UNUSED_ =
true) {
1710 throw exception::ZeroSize(
"qpp::QCircuit::TFQ()");
1711 for (
auto&& elem : target) {
1713 throw exception::OutOfRange(
"qpp::QCircuit::TFQ()");
1715 if (get_measured(elem))
1716 throw exception::QuditAlreadyMeasured(
1717 "qpp::QCircuit::TFQ()");
1720 if (!internal::check_no_duplicates(target))
1721 throw exception::Duplicates(
"qpp::QCircuit::TFQ()");
1722 }
catch (exception::Exception&) {
1723 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1728 idx n_subsys = target.size();
1733 for (idx i = n_subsys / 2; i-- > 0;) {
1734 gate(Gates::get_instance().SWAP, target[i],
1735 target[n_subsys - i - 1]);
1738 for (idx i = n_subsys; i-- > 0;) {
1740 for (idx j = n_subsys - i + 1; j-- > 2;) {
1743 Rj << 1, 0, 0, exp(-2.0 * pi * 1_i / std::pow(2, j));
1744 CTRL(Rj, target[i + j - 1], target[i], {},
1745 "CTRL-R" + std::to_string(j) +
"+");
1748 gate(Gates::get_instance().H, target[i]);
1753 for (idx i = n_subsys / 2; i-- > 0;) {
1754 gate(Gates::get_instance().SWAPd(d_), target[i],
1755 target[n_subsys - i - 1],
"SWAPd");
1758 for (idx i = n_subsys; i-- > 0;) {
1760 for (idx j = n_subsys - i + 1; j-- > 2;) {
1762 cmat Rj = cmat::Zero(d_, d_);
1763 for (idx m = 0; m < d_; ++m) {
1764 Rj(m, m) = exp(-2.0 * pi * m * 1_i / std::pow(d_, j));
1766 CTRL(Rj, target[i + j - 1], target[i], {},
1767 "CTRL-R" + std::to_string(j) +
"d+");
1770 gate(qpp::adjoint(Gates::get_instance().Fd(d_)), target[i],
1788 QCircuit& TFQ(
const std::initializer_list<idx>& target,
bool swap =
true) {
1789 return TFQ(std::vector<idx>(target), swap);
1799 QCircuit& TFQ(
bool swap =
true) {
return TFQ(get_non_measured(), swap); }
1814 QCircuit& CTRL(
const cmat& U, idx ctrl, idx target, idx shift = 0,
1815 std::string name = {}) {
1820 if (ctrl >= nq_ || target >= nq_ || ctrl == target)
1821 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1822 if (get_measured(ctrl) || get_measured(target))
1823 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::CTRL()");
1826 if (!internal::check_square_mat(U))
1827 throw exception::MatrixNotSquare(
"qpp::QCircuit::CTRL()");
1829 if (static_cast<idx>(U.rows()) != d_)
1830 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::CTRL()");
1834 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1835 }
catch (exception::Exception&) {
1836 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1842 std::string gate_name = qpp::Gates::get_instance().get_name(U);
1843 name = gate_name.empty() ?
"CTRL" :
"CTRL-" + gate_name;
1845 std::size_t hashU = hash_eigen(U);
1846 add_hash_(U, hashU);
1847 gates_.emplace_back(GateType::SINGLE_CTRL_SINGLE_TARGET, hashU,
1848 std::vector<idx>{ctrl}, std::vector<idx>{target},
1849 std::vector<idx>{shift}, name);
1850 step_types_.emplace_back(StepType::GATE);
1870 QCircuit& CTRL(
const cmat& U, idx ctrl,
const std::vector<idx>& target,
1871 idx shift = 0, std::string name = {}) {
1877 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1878 if (get_measured(ctrl))
1879 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::CTRL()");
1883 throw exception::ZeroSize(
"qpp::QCircuit::CTRL()");
1884 for (
auto&& elem : target) {
1886 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1888 if (get_measured(elem))
1889 throw exception::QuditAlreadyMeasured(
1890 "qpp::QCircuit::CTRL()");
1893 if (!internal::check_no_duplicates(target))
1894 throw exception::Duplicates(
"qpp::QCircuit::CTRL()");
1897 for (
auto&& elem : target)
1899 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1902 if (!internal::check_square_mat(U))
1903 throw exception::MatrixNotSquare(
"qpp::QCircuit::CTRL()");
1905 if (static_cast<idx>(U.rows()) != d_)
1906 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::CTRL()");
1910 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1911 }
catch (exception::Exception&) {
1912 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1918 std::string gate_name = qpp::Gates::get_instance().get_name(U);
1919 name = gate_name.empty() ?
"CTRL" :
"CTRL-" + gate_name;
1921 std::size_t hashU = hash_eigen(U);
1922 add_hash_(U, hashU);
1923 gates_.emplace_back(GateType::SINGLE_CTRL_MULTIPLE_TARGET, hashU,
1924 std::vector<idx>{ctrl}, target,
1925 std::vector<idx>{shift}, name);
1926 step_types_.emplace_back(StepType::GATE);
1946 QCircuit& CTRL(
const cmat& U,
const std::vector<idx>& ctrl, idx target,
1947 const std::vector<idx>& shift = {}, std::string name = {}) {
1952 for (
auto&& elem : ctrl) {
1954 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1956 if (get_measured(elem))
1957 throw exception::QuditAlreadyMeasured(
1958 "qpp::QCircuit::CTRL()");
1961 if (!internal::check_no_duplicates(ctrl))
1962 throw exception::Duplicates(
"qpp::QCircuit::CTRL()");
1966 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1967 if (get_measured(target))
1968 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::CTRL()");
1971 for (
auto&& elem : ctrl)
1973 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1976 if (!internal::check_square_mat(U))
1977 throw exception::MatrixNotSquare(
"qpp::QCircuit::CTRL()");
1979 if (static_cast<idx>(U.rows()) != d_)
1980 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::CTRL()");
1983 if (!shift.empty() && (shift.size() != ctrl.size()))
1984 throw exception::SizeMismatch(
"qpp::QCircuit::CTRL()");
1986 for (
auto&& elem : shift)
1988 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
1989 }
catch (exception::Exception&) {
1990 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
1996 std::string gate_name = qpp::Gates::get_instance().get_name(U);
1997 name = gate_name.empty() ?
"CTRL" :
"CTRL-" + gate_name;
1999 std::size_t hashU = hash_eigen(U);
2000 add_hash_(U, hashU);
2001 gates_.emplace_back(GateType::MULTIPLE_CTRL_SINGLE_TARGET, hashU, ctrl,
2002 std::vector<idx>{target}, shift, name);
2003 step_types_.emplace_back(StepType::GATE);
2025 QCircuit& CTRL(
const cmat& U,
const std::vector<idx>& ctrl,
2026 const std::vector<idx>& target,
2027 const std::vector<idx>& shift = {}, std::string name = {}) {
2032 for (
auto&& elem : ctrl) {
2034 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
2036 if (get_measured(elem))
2037 throw exception::QuditAlreadyMeasured(
2038 "qpp::QCircuit::CTRL()");
2041 if (!internal::check_no_duplicates(ctrl))
2042 throw exception::Duplicates(
"qpp::QCircuit::CTRL()");
2046 throw exception::ZeroSize(
"qpp::QCircuit::CTRL()");
2047 for (
auto&& elem : target) {
2049 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
2051 if (get_measured(elem))
2052 throw exception::QuditAlreadyMeasured(
2053 "qpp::QCircuit::CTRL()");
2056 if (!internal::check_no_duplicates(target))
2057 throw exception::Duplicates(
"qpp::QCircuit::CTRL()");
2060 for (
auto&& elem_ctrl : ctrl)
2061 for (
auto&& elem_target : target)
2062 if (elem_ctrl == elem_target)
2063 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
2066 if (!internal::check_square_mat(U))
2067 throw exception::MatrixNotSquare(
"qpp::QCircuit::CTRL()");
2069 if (static_cast<idx>(U.rows()) != d_)
2070 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::CTRL()");
2073 if (!shift.empty() && (shift.size() != ctrl.size()))
2074 throw exception::SizeMismatch(
"qpp::QCircuit::CTRL()");
2076 for (
auto&& elem : shift)
2078 throw exception::OutOfRange(
"qpp::QCircuit::CTRL()");
2079 }
catch (exception::Exception&) {
2080 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2086 std::string gate_name = qpp::Gates::get_instance().get_name(U);
2087 name = gate_name.empty() ?
"CTRL" :
"CTRL-" + gate_name;
2089 std::size_t hashU = hash_eigen(U);
2090 add_hash_(U, hashU);
2091 gates_.emplace_back(GateType::MULTIPLE_CTRL_MULTIPLE_TARGET, hashU,
2092 ctrl, std::vector<idx>{target}, shift, name);
2093 step_types_.emplace_back(StepType::GATE);
2115 QCircuit& CTRL_custom(
const cmat& U,
const std::vector<idx>& ctrl,
2116 const std::vector<idx>& target,
2117 const std::vector<idx>& shift = {},
2118 std::string name = {}) {
2121 idx n =
static_cast<idx
>(target.size());
2122 idx D =
static_cast<idx
>(std::llround(std::pow(d_, n)));
2126 for (
auto&& elem : ctrl) {
2128 throw exception::OutOfRange(
"qpp::QCircuit::CTRL_custom()");
2130 if (get_measured(elem))
2131 throw exception::QuditAlreadyMeasured(
2132 "qpp::QCircuit::CTRL_custom()");
2135 if (!internal::check_no_duplicates(ctrl))
2136 throw exception::Duplicates(
"qpp::QCircuit::CTRL_custom()");
2140 throw exception::ZeroSize(
"qpp::QCircuit::CTRL_custom()");
2141 for (
auto&& elem : target) {
2143 throw exception::OutOfRange(
"qpp::QCircuit::CTRL_custom()");
2145 if (get_measured(elem))
2146 throw exception::QuditAlreadyMeasured(
2147 "qpp::QCircuit::CTRL_custom()");
2151 for (
auto&& elem_ctrl : ctrl)
2152 for (
auto&& elem_target : target)
2153 if (elem_ctrl == elem_target)
2154 throw exception::OutOfRange(
2155 "qpp::QCircuit::CTRL_custom()");
2158 if (!internal::check_square_mat(U))
2159 throw exception::MatrixNotSquare(
2160 "qpp::QCircuit::CTRL_custom()");
2162 if (static_cast<idx>(U.rows()) != D)
2163 throw exception::DimsMismatchMatrix(
2164 "qpp::QCircuit::CTRL_custom()");
2167 if (!shift.empty() && (shift.size() != ctrl.size()))
2168 throw exception::SizeMismatch(
"qpp::QCircuit::CTRL_custom()");
2170 for (
auto&& elem : shift)
2172 throw exception::OutOfRange(
2173 "qpp::QCircuit::CTRL_custom()");
2174 }
catch (exception::Exception&) {
2175 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2181 std::string gate_name = qpp::Gates::get_instance().get_name(U);
2182 name = gate_name.empty() ?
"CTRL" :
"CTRL-" + gate_name;
2184 std::size_t hashU = hash_eigen(U);
2185 add_hash_(U, hashU);
2186 gates_.emplace_back(GateType::CUSTOM_CTRL, hashU, ctrl, target, shift,
2188 step_types_.emplace_back(StepType::GATE);
2208 QCircuit& cCTRL(
const cmat& U, idx ctrl_dit, idx target, idx shift = 0,
2209 std::string name = {}) {
2214 if (ctrl_dit >= nc_ || target >= nq_)
2215 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2216 if (get_measured(target))
2217 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::cCTRL()");
2220 if (!internal::check_square_mat(U))
2221 throw exception::MatrixNotSquare(
"qpp::QCircuit::cCTRL()");
2223 if (static_cast<idx>(U.rows()) != d_)
2224 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::cCTRL()");
2228 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2229 }
catch (exception::Exception&) {
2230 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2236 std::string gate_name = qpp::Gates::get_instance().get_name(U);
2237 name = gate_name.empty() ?
"cCTRL" :
"cCTRL-" + gate_name;
2240 std::size_t hashU = hash_eigen(U);
2241 add_hash_(U, hashU);
2242 gates_.emplace_back(GateType::SINGLE_cCTRL_SINGLE_TARGET, hashU,
2243 std::vector<idx>{ctrl_dit},
2244 std::vector<idx>{target}, std::vector<idx>{shift},
2246 step_types_.emplace_back(StepType::GATE);
2266 QCircuit& cCTRL(
const cmat& U, idx ctrl_dit,
const std::vector<idx>& target,
2267 idx shift = 0, std::string name = {}) {
2272 if (ctrl_dit >= nc_)
2273 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2277 throw exception::ZeroSize(
"qpp::QCircuit::cCTRL()");
2278 for (
auto&& elem : target) {
2280 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2282 if (get_measured(elem))
2283 throw exception::QuditAlreadyMeasured(
2284 "qpp::QCircuit::cCTRL()");
2287 if (!internal::check_no_duplicates(target))
2288 throw exception::Duplicates(
"qpp::QCircuit::cCTRL()");
2291 if (!internal::check_square_mat(U))
2292 throw exception::MatrixNotSquare(
"qpp::QCircuit::cCTRL()");
2294 if (static_cast<idx>(U.rows()) != d_)
2295 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::cCTRL()");
2299 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2300 }
catch (exception::Exception&) {
2301 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2307 std::string gate_name = qpp::Gates::get_instance().get_name(U);
2308 name = gate_name.empty() ?
"cCTRL" :
"cCTRL-" + gate_name;
2310 std::size_t hashU = hash_eigen(U);
2311 add_hash_(U, hashU);
2312 gates_.emplace_back(GateType::SINGLE_cCTRL_MULTIPLE_TARGET, hashU,
2313 std::vector<idx>{ctrl_dit}, target,
2314 std::vector<idx>{shift}, name);
2315 step_types_.emplace_back(StepType::GATE);
2335 QCircuit& cCTRL(
const cmat& U,
const std::vector<idx>& ctrl_dits,
2336 idx target,
const std::vector<idx>& shift = {},
2337 std::string name = {}) {
2342 for (
auto&& elem : ctrl_dits) {
2344 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2347 if (!internal::check_no_duplicates(ctrl_dits))
2348 throw exception::Duplicates(
"qpp::QCircuit::cCTRL()");
2352 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2354 if (get_measured(target))
2355 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::cCTRL()");
2358 if (!internal::check_square_mat(U))
2359 throw exception::MatrixNotSquare(
"qpp::QCircuit::cCTRL()");
2361 if (static_cast<idx>(U.rows()) != d_)
2362 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::cCTRL()");
2365 if (!shift.empty() && (shift.size() != ctrl_dits.size()))
2366 throw exception::SizeMismatch(
"qpp::QCircuit::cCTRL()");
2368 for (
auto&& elem : shift)
2370 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2372 }
catch (exception::Exception&) {
2373 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2379 std::string gate_name = qpp::Gates::get_instance().get_name(U);
2380 name = gate_name.empty() ?
"cCTRL" :
"cCTRL-" + gate_name;
2382 std::size_t hashU = hash_eigen(U);
2383 add_hash_(U, hashU);
2384 gates_.emplace_back(GateType::MULTIPLE_cCTRL_SINGLE_TARGET, hashU,
2385 ctrl_dits, std::vector<idx>{target}, shift, name);
2386 step_types_.emplace_back(StepType::GATE);
2408 QCircuit& cCTRL(
const cmat& U,
const std::vector<idx>& ctrl_dits,
2409 const std::vector<idx>& target,
2410 const std::vector<idx>& shift = {}, std::string name = {}) {
2415 for (
auto&& elem : ctrl_dits) {
2417 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2420 if (!internal::check_no_duplicates(ctrl_dits))
2421 throw exception::Duplicates(
"qpp::QCircuit::cCTRL()");
2425 throw exception::ZeroSize(
"qpp::QCircuit::cCTRL()");
2426 for (
auto&& elem : target) {
2428 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2430 if (get_measured(elem))
2431 throw exception::QuditAlreadyMeasured(
2432 "qpp::QCircuit::cCTRL()");
2435 if (!internal::check_no_duplicates(target))
2436 throw exception::Duplicates(
"qpp::QCircuit::cCTRL()");
2439 if (!internal::check_square_mat(U))
2440 throw exception::MatrixNotSquare(
"qpp::QCircuit::cCTRL()");
2442 if (static_cast<idx>(U.rows()) != d_)
2443 throw exception::DimsMismatchMatrix(
"qpp::QCircuit::cCTRL()");
2446 if (!shift.empty() && (shift.size() != ctrl_dits.size()))
2447 throw exception::SizeMismatch(
"qpp::QCircuit::cCTRL()");
2449 for (
auto&& elem : shift)
2451 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2452 }
catch (exception::Exception&) {
2453 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2459 std::string gate_name = qpp::Gates::get_instance().get_name(U);
2460 name = gate_name.empty() ?
"cCTRL" :
"cCTRL-" + gate_name;
2462 std::size_t hashU = hash_eigen(U);
2463 add_hash_(U, hashU);
2464 gates_.emplace_back(GateType::MULTIPLE_cCTRL_MULTIPLE_TARGET, hashU,
2465 ctrl_dits, std::vector<idx>{target}, shift, name);
2466 step_types_.emplace_back(StepType::GATE);
2488 QCircuit& cCTRL_custom(
const cmat& U,
const std::vector<idx>& ctrl_dits,
2489 const std::vector<idx>& target,
2490 const std::vector<idx>& shift = {},
2491 std::string name = {}) {
2494 idx n =
static_cast<idx
>(target.size());
2495 idx D =
static_cast<idx
>(std::llround(std::pow(d_, n)));
2499 for (
auto&& elem : ctrl_dits) {
2501 throw exception::OutOfRange(
2502 "qpp::QCircuit::cCTRL_custom()");
2505 if (!internal::check_no_duplicates(ctrl_dits))
2506 throw exception::Duplicates(
"qpp::QCircuit::cCTRL_custom()");
2510 throw exception::ZeroSize(
"qpp::QCircuit::cCTRL_custom()");
2511 for (
auto&& elem : target) {
2513 throw exception::OutOfRange(
2514 "qpp::QCircuit::cCTRL_custom()");
2516 if (get_measured(elem))
2517 throw exception::QuditAlreadyMeasured(
2518 "qpp::QCircuit::cCTRL_custom()");
2521 if (!internal::check_no_duplicates(target))
2522 throw exception::Duplicates(
"qpp::QCircuit::cCTRL_custom()");
2525 if (!internal::check_square_mat(U))
2526 throw exception::MatrixNotSquare(
2527 "qpp::QCircuit::cCTRL_custom()");
2529 if (static_cast<idx>(U.rows()) != D)
2530 throw exception::DimsMismatchMatrix(
2531 "qpp::QCircuit::cCTRL_custom()");
2534 if (!shift.empty() && (shift.size() != ctrl_dits.size()))
2535 throw exception::SizeMismatch(
"qpp::QCircuit::cCTRL()");
2537 for (
auto&& elem : shift)
2539 throw exception::OutOfRange(
"qpp::QCircuit::cCTRL()");
2540 }
catch (exception::Exception&) {
2541 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2547 std::string gate_name = qpp::Gates::get_instance().get_name(U);
2548 name = gate_name.empty() ?
"cCTRL" :
"cCTRL-" + gate_name;
2550 std::size_t hashU = hash_eigen(U);
2551 add_hash_(U, hashU);
2552 gates_.emplace_back(GateType::CUSTOM_cCTRL, hashU, ctrl_dits, target,
2554 step_types_.emplace_back(StepType::GATE);
2571 QCircuit& measureZ(idx target, idx c_reg,
bool destructive =
true,
2572 std::string name = {}) {
2578 throw exception::OutOfRange(
"qpp::QCircuit::measureZ()");
2581 throw exception::OutOfRange(
"qpp::QCircuit::measureZ()");
2583 if (get_measured(target))
2584 throw exception::QuditAlreadyMeasured(
2585 "qpp:QCircuit::measureZ()");
2586 }
catch (exception::Exception&) {
2587 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2595 measured_[target] =
true;
2596 measurements_.emplace_back(MeasureType::MEASURE_Z,
2597 std::vector<std::size_t>{},
2598 std::vector<idx>{target}, c_reg, name);
2600 measurements_.emplace_back(MeasureType::MEASURE_Z_ND,
2601 std::vector<std::size_t>{},
2602 std::vector<idx>{target}, c_reg, name);
2604 step_types_.emplace_back(StepType::MEASUREMENT);
2605 ++measurement_count_[name];
2624 QCircuit& measureZ(
const std::vector<idx>& target, idx c_reg,
2625 bool destructive =
true, std::string name = {}) {
2631 throw exception::ZeroSize(
"qpp::QCircuit::measureZ()");
2632 for (
auto&& elem : target) {
2635 throw exception::OutOfRange(
"qpp::QCircuit::measureZ()");
2637 if (get_measured(elem))
2638 throw exception::QuditAlreadyMeasured(
2639 "qpp:QCircuit::measureZ()");
2643 throw exception::OutOfRange(
"qpp::QCircuit::measureZ()");
2644 }
catch (exception::Exception&) {
2645 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2654 for (
auto&& elem : target) {
2655 measured_[elem] =
true;
2657 measurements_.emplace_back(MeasureType::MEASURE_Z_MANY,
2658 std::vector<std::size_t>{}, target,
2661 measurements_.emplace_back(MeasureType::MEASURE_Z_MANY_ND,
2662 std::vector<std::size_t>{}, target,
2665 step_types_.emplace_back(StepType::MEASUREMENT);
2666 ++measurement_count_[name];
2686 QCircuit& measureV(
const cmat& V, idx target, idx c_reg,
2687 bool destructive =
true, std::string name = {}) {
2693 throw exception::OutOfRange(
"qpp::QCircuit::measureV()");
2696 throw exception::OutOfRange(
"qpp::QCircuit::measureV()");
2698 if (get_measured(target))
2699 throw exception::QuditAlreadyMeasured(
2700 "qpp:QCircuit::measureV()");
2701 }
catch (exception::Exception&) {
2702 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2708 name =
"m" + qpp::Gates::get_instance().get_name(V);
2711 measured_[target] =
true;
2712 measurements_.emplace_back(MeasureType::MEASURE_V,
2713 std::vector<std::size_t>{hash_eigen(V)},
2714 std::vector<idx>{target}, c_reg, name);
2716 measurements_.emplace_back(MeasureType::MEASURE_V_ND,
2717 std::vector<std::size_t>{hash_eigen(V)},
2718 std::vector<idx>{target}, c_reg, name);
2720 step_types_.emplace_back(StepType::MEASUREMENT);
2721 ++measurement_count_[name];
2741 QCircuit& measureV(
const cmat& V,
const std::vector<idx>& target, idx c_reg,
2742 bool destructive =
true, std::string name = {}) {
2748 throw exception::ZeroSize(
"qpp::QCircuit::measureV()");
2749 for (
auto&& elem : target) {
2751 throw exception::OutOfRange(
"qpp::QCircuit::measureV()");
2753 if (get_measured(elem))
2754 throw exception::QuditAlreadyMeasured(
2755 "qpp::QCircuit::measureV()");
2758 if (!internal::check_no_duplicates(target))
2759 throw exception::Duplicates(
"qpp::QCircuit::measureV()");
2763 throw exception::OutOfRange(
"qpp::QCircuit::measureV()");
2765 for (
auto&& elem : target)
2766 if (get_measured(elem))
2767 throw exception::QuditAlreadyMeasured(
2768 "qpp::QCircuit::measureV()");
2769 }
catch (exception::Exception&) {
2770 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2776 name =
"m" + qpp::Gates::get_instance().get_name(V);
2779 for (
auto&& elem : target)
2780 measured_[elem] =
true;
2781 measurements_.emplace_back(MeasureType::MEASURE_V_MANY,
2782 std::vector<std::size_t>{hash_eigen(V)},
2783 target, c_reg, name);
2785 measurements_.emplace_back(MeasureType::MEASURE_V_MANY_ND,
2786 std::vector<std::size_t>{hash_eigen(V)},
2787 target, c_reg, name);
2789 step_types_.emplace_back(StepType::MEASUREMENT);
2790 ++measurement_count_[name];
2803 QCircuit& discard(idx target, std::string name = {}) {
2809 throw exception::OutOfRange(
"qpp::QCircuit::discard()");
2811 if (get_measured(target))
2812 throw exception::QuditAlreadyMeasured(
2813 "qpp:QCircuit::discard()");
2814 }
catch (exception::Exception&) {
2815 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2823 measured_[target] =
true;
2824 measurements_.emplace_back(MeasureType::DISCARD,
2825 std::vector<std::size_t>{},
2826 std::vector<idx>{target}, -1, name);
2828 step_types_.emplace_back(StepType::MEASUREMENT);
2829 ++measurement_count_[name];
2842 QCircuit& discard(
const std::vector<idx>& target, std::string name = {}) {
2848 throw exception::ZeroSize(
"qpp::QCircuit::discard()");
2849 for (
auto&& elem : target) {
2852 throw exception::OutOfRange(
"qpp::QCircuit::discard()");
2854 if (get_measured(elem))
2855 throw exception::QuditAlreadyMeasured(
2856 "qpp:QCircuit::discard()");
2858 }
catch (exception::Exception&) {
2859 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2867 for (
auto&& elem : target) {
2868 measured_[elem] =
true;
2870 measurements_.emplace_back(MeasureType::DISCARD_MANY,
2871 std::vector<std::size_t>{}, target, -1,
2873 step_types_.emplace_back(StepType::MEASUREMENT);
2874 ++measurement_count_[name];
2888 step_types_.emplace_back(StepType::NOP);
2903 QCircuit& reset(idx target, std::string name = {}) {
2909 throw exception::OutOfRange(
"qpp::QCircuit::reset()");
2911 if (get_measured(target))
2912 throw exception::QuditAlreadyMeasured(
"qpp:QCircuit::reset()");
2913 }
catch (exception::Exception&) {
2914 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2921 measurements_.emplace_back(MeasureType::RESET,
2922 std::vector<std::size_t>{},
2923 std::vector<idx>{target}, -1, name);
2924 step_types_.emplace_back(StepType::MEASUREMENT);
2925 ++measurement_count_[name];
2940 QCircuit& reset(
const std::vector<idx>& target, std::string name = {}) {
2946 throw exception::ZeroSize(
"qpp::QCircuit::reset()");
2947 for (
auto&& elem : target) {
2950 throw exception::OutOfRange(
"qpp::QCircuit::reset()");
2952 if (get_measured(elem))
2953 throw exception::QuditAlreadyMeasured(
2954 "qpp:QCircuit::reset()");
2956 }
catch (exception::Exception&) {
2957 std::cerr <<
"At STEP " << get_step_count() <<
"\n";
2964 measurements_.emplace_back(MeasureType::RESET_MANY,
2965 std::vector<std::size_t>{}, target, -1,
2967 step_types_.emplace_back(StepType::MEASUREMENT);
2968 ++measurement_count_[name];
2982 QCircuit& replicate(idx n) {
2986 throw exception::OutOfRange(
"qpp::QCircuit::replicate()");
2987 if (!get_measured().empty())
2988 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit::replicate()");
2993 auto gates_copy = gates_;
2994 idx gates_size = gates_.size();
2996 auto step_types_copy = step_types_;
2997 idx step_types_size = step_types_.size();
2999 gates_.resize(gates_.size() * n);
3000 step_types_.resize(step_types_size * n);
3002 for (idx i = 0; i < n - 1; ++i) {
3003 std::copy(std::begin(gates_copy), std::end(gates_copy),
3004 std::next(std::begin(gates_), (i + 1) * gates_size));
3006 std::begin(step_types_copy), std::end(step_types_copy),
3007 std::next(std::begin(step_types_), (i + 1) * step_types_size));
3010 for (
auto& elem : count_)
3038 QCircuit& add_circuit(QCircuit other, bigint pos_qudit, idx pos_dit = -1) {
3043 throw exception::DimsNotEqual(
"qpp::QCircuit::add_circuit()");
3045 if (pos_dit == static_cast<idx>(-1))
3047 else if (pos_dit > nc_)
3048 throw exception::OutOfRange(
"qpp::QCircuit::add_circuit()");
3051 if (pos_qudit >= 0 && static_cast<idx>(pos_qudit) < nq_) {
3053 i < std::min(static_cast<idx>(nq_ - pos_qudit), other.nq_);
3055 if (get_measured(pos_qudit + i))
3056 throw exception::QuditAlreadyMeasured(
3057 "qpp::QCircuit::add_circuit()");
3062 idx extra_qudits = 0;
3064 if (pos_qudit < 0) {
3065 extra_qudits = std::abs(pos_qudit);
3066 add_qudit(extra_qudits, 0);
3068 idx tmp = pos_qudit + other.nq_;
3070 extra_qudits = tmp - nq_;
3071 add_qudit(extra_qudits);
3077 for (
auto& gate : other.gates_) {
3078 switch (gate.gate_type_) {
3080 case GateType::SINGLE_cCTRL_SINGLE_TARGET:
3081 case GateType::SINGLE_cCTRL_MULTIPLE_TARGET:
3082 case GateType::MULTIPLE_cCTRL_SINGLE_TARGET:
3083 case GateType::MULTIPLE_cCTRL_MULTIPLE_TARGET:
3084 case GateType::CUSTOM_cCTRL:
3085 for (
auto& pos : gate.ctrl_) {
3091 for (
auto& pos : gate.ctrl_) {
3098 for (
auto& pos : gate.target_) {
3104 for (
auto& measurement : other.measurements_) {
3105 for (
auto& pos : measurement.target_) {
3108 measurement.c_reg_ += pos_dit;
3115 add_dit(other.nc_, pos_dit);
3118 measured_.insert(std::next(std::begin(measured_), pos_dit),
3119 std::begin(other.measured_),
3120 std::end(other.measured_));
3123 gates_.insert(std::end(gates_), std::begin(other.gates_),
3124 std::end(other.gates_));
3127 measurements_.insert(std::end(measurements_),
3128 std::begin(other.measurements_),
3129 std::end(other.measurements_));
3132 step_types_.insert(std::end(step_types_), std::begin(other.step_types_),
3133 std::end(other.step_types_));
3137 for (
auto& elem : other.cmat_hash_tbl_)
3138 cmat_hash_tbl_[elem.first] = elem.second;
3140 for (
auto& elem : other.count_)
3141 count_[elem.first] += elem.second;
3143 for (
auto& elem : other.measurement_count_)
3144 measurement_count_[elem.first] += elem.second;
3156 QCircuit& kron(
const QCircuit& qc) {
3157 add_circuit(qc, nq_);
3167 QCircuit& adjoint() {
3170 if (get_measured().size() > 0)
3171 throw exception::QuditAlreadyMeasured(
"qpp::QCircuit()::adjoint()");
3174 auto htbl = cmat_hash_tbl_;
3175 cmat_hash_tbl_.clear();
3177 std::reverse(std::begin(gates_), std::end(gates_));
3178 std::reverse(std::begin(step_types_), std::end(step_types_));
3180 for (
auto& elem : gates_) {
3182 std::size_t hashU = elem.gate_hash_;
3183 cmat U = htbl[hashU];
3186 cmat Udagger = qpp::adjoint(U);
3187 std::size_t hashUdagger = hash_eigen(Udagger);
3190 elem.gate_hash_ = hashUdagger;
3191 if (!elem.name_.empty())
3193 add_hash_(Udagger, hashUdagger);
3209 std::string to_JSON(
bool enclosed_in_curly_brackets =
true)
const override {
3212 if (enclosed_in_curly_brackets)
3215 result +=
"\"nq\" : " + std::to_string(nq_);
3216 result +=
", \"nc\" : " + std::to_string(nc_);
3217 result +=
", \"d\" : " + std::to_string(d_);
3218 result +=
", \"name\" : \"" + name_ +
'\"';
3220 bool is_first =
true;
3221 std::ostringstream ss;
3222 result +=
", \"steps\" : [";
3223 for (
auto&& elem : *
this) {
3229 result +=
"{\"step\" : " + std::to_string(elem.ip_) +
", ";
3230 result +=
"\"type\" : ";
3232 if (elem.type_ == StepType::GATE) {
3233 idx pos = std::distance(std::begin(elem.value_type_qc_->gates_),
3237 ss << gates_[pos].gate_type_;
3238 result +=
'\"' + ss.str() +
"\", ";
3239 if (!gates_[pos].ctrl_.empty()) {
3242 ss << disp(gates_[pos].ctrl_,
", ");
3243 if (gates_[pos].gate_type_ >=
3244 GateType::SINGLE_cCTRL_SINGLE_TARGET)
3245 result +=
"\"c_ctrl\" : " + ss.str() +
", ";
3247 result +=
"\"ctrl\" : " + ss.str() +
", ";
3251 ss << disp(gates_[pos].target_,
", ");
3252 result +=
"\"target\" : " + ss.str() +
", ";
3254 if (!gates_[pos].shift_.empty()) {
3257 ss << disp(gates_[pos].shift_,
", ");
3258 result +=
"\"shift\" : " + ss.str() +
", ";
3261 result +=
"\"name\" : ";
3262 result +=
'\"' + gates_[pos].name_ +
"\"}";
3265 else if (elem.type_ == StepType::MEASUREMENT) {
3266 idx pos = std::distance(
3267 std::begin(elem.value_type_qc_->measurements_),
3268 elem.measurements_ip_);
3271 ss << measurements_[pos].measurement_type_;
3272 result +=
'\"' + ss.str() +
"\", ";
3275 ss << disp(measurements_[pos].target_,
", ");
3276 result +=
"\"target\" : " + ss.str() +
", ";
3278 if (measurements_[pos].measurement_type_ !=
3279 MeasureType::RESET &&
3280 measurements_[pos].measurement_type_ !=
3281 MeasureType::RESET_MANY &&
3282 measurements_[pos].measurement_type_ !=
3283 MeasureType::DISCARD &&
3284 measurements_[pos].measurement_type_ !=
3285 MeasureType::DISCARD_MANY)
3286 result +=
"\"c_reg\" : " +
3287 std::to_string(measurements_[pos].c_reg_) +
", ";
3289 result +=
"\"name\" : ";
3290 result +=
'\"' + measurements_[pos].name_ +
"\"}";
3294 else if (elem.type_ == StepType::NOP) {
3295 result += std::string{
"\"NOP\""} +
"}";
3303 result +=
"\"step count\" : " + std::to_string(get_step_count()) +
", ";
3305 "\"total gate count\" : " + std::to_string(get_gate_count()) +
", ";
3307 "\"total gate depth\" : " + std::to_string(get_gate_depth()) +
", ";
3308 result +=
"\"total measurement count\" : " +
3309 std::to_string(get_measurement_count()) +
", ";
3310 result +=
"\"total measurement depth\" : " +
3311 std::to_string(get_measurement_depth()) +
", ";
3312 result +=
"\"total depth\" : " + std::to_string(get_depth()) +
", ";
3316 ss << disp(get_measured(),
", ");
3317 result +=
"\"measured/discarded (destructive)\" : " + ss.str() +
", ";
3321 ss << disp(get_non_measured(),
", ");
3322 result +=
"\"non-measured/non-discarded\" : " + ss.str();
3324 if (enclosed_in_curly_brackets)
3336 friend QCircuit adjoint(QCircuit qc) {
3339 if (qc.get_measured().size() > 0)
3340 throw exception::QuditAlreadyMeasured(
"qpp::adjoint()");
3343 return qc.adjoint();
3354 friend QCircuit kron(
const QCircuit& qc1,
const QCircuit& qc2) {
3357 return qc.kron(qc2);
3370 friend QCircuit replicate(QCircuit qc, idx n) {
3374 throw exception::OutOfRange(
"qpp::replicate()");
3375 if (!qc.get_measured().empty())
3376 throw exception::QuditAlreadyMeasured(
"qpp::replicate()");
3381 return qc.replicate(n);
3406 friend QCircuit add_circuit(QCircuit qc1,
const QCircuit& qc2,
3407 bigint pos_qudit, idx pos_dit = -1) {
3408 return qc1.add_circuit(qc2, pos_qudit, pos_dit);
3421 std::ostream& display(std::ostream& os)
const override {
3422 os <<
"nq = " << nq_ <<
", nc = " << nc_ <<
", d = " << d_;
3425 os <<
", name = \"" << name_ <<
"\"\n";
3427 os <<
", name = \"\"\n";
3429 for (
auto&& elem : *
this) {
3433 os <<
"step count: " << get_step_count() <<
'\n';
3434 os <<
"total gate count: " << get_gate_count() <<
'\n';
3435 os <<
"total gate depth: " << get_gate_depth() <<
'\n';
3436 os <<
"total measurement count: " << get_measurement_count() <<
'\n';
3437 os <<
"total measurement depth: " << get_measurement_depth() <<
'\n';
3438 os <<
"total depth: " << get_depth() <<
'\n';
3439 os <<
"measured/discarded (destructive): " << disp(get_measured(),
", ")
3441 os <<
"non-measured/non-discarded: " << disp(get_non_measured(),
", ");
Quantum++ main namespace.
Definition: circuits.h:35