Quantum++  v1.2
A modern C++11 quantum computing library
circuits.h
Go to the documentation of this file.
1 /*
2  * This file is part of Quantum++.
3  *
4  * MIT License
5  *
6  * Copyright (c) 2013 - 2019 Vlad Gheorghiu (vgheorgh@gmail.com)
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
32 #ifndef CLASSES_CIRCUITS_H_
33 #define CLASSES_CIRCUITS_H_
34 
35 namespace qpp {
41 class QCircuit : public IDisplay, public IJSON {
42  friend class QEngine;
43  const idx nq_;
44  const idx nc_;
45  const idx d_;
46  std::string name_;
47  std::vector<bool> measured_;
48 
49  std::unordered_map<std::size_t, cmat>
51  std::unordered_map<std::string, idx>
53  count_{};
54  std::unordered_map<std::string, idx>
55  depth_{};
56  std::unordered_map<std::string, idx>
58 
67  void add_hash_(const cmat& U, std::size_t hashU) {
68  // EXCEPTION CHECKS
69 
70  auto search = cmat_hash_tbl_.find(hashU);
71  static internal::EqualEigen equal_eigen;
72  if (search != cmat_hash_tbl_.end()) // found the hash in the table
73  {
74  // have a hash collision
75  if (!equal_eigen(search->second, U))
76  throw exception::CustomException("qpp::QCircuit::add_hash_()",
77  "Matrix hash collision");
78  }
79  // END EXCEPTION CHECKS
80  cmat_hash_tbl_.insert({hashU, U});
81  }
82 
83  public:
87  enum class GateType {
88  NONE,
89 
90  SINGLE,
91 
92  TWO,
93 
94  THREE,
95 
96  CUSTOM,
97 
98  FAN,
99 
100  QFT,
101 
102  TFQ,
103 
105 
108 
111 
114 
117  CUSTOM_CTRL,
118 
121 
124 
128 
132 
135  CUSTOM_cCTRL,
136  };
138 
147  friend std::ostream& operator<<(std::ostream& os,
148  const GateType& gate_type) {
149  switch (gate_type) {
150  case GateType::NONE:
151  os << "GATE NONE";
152  break;
153  case GateType::SINGLE:
154  os << "SINGLE";
155  break;
156  case GateType::TWO:
157  os << "TWO";
158  break;
159  case GateType::THREE:
160  os << "THREE";
161  break;
162  case GateType::FAN:
163  os << "FAN";
164  break;
165  case GateType::QFT:
166  os << "QFT";
167  break;
168  case GateType::TFQ:
169  os << "TFQ";
170  break;
171  case GateType::CUSTOM:
172  os << "CUSTOM";
173  break;
175  os << "SINGLE_CTRL_SINGLE_TARGET";
176  break;
178  os << "SINGLE_CTRL_MULTIPLE_TARGET";
179  break;
181  os << "MULTIPLE_CTRL_SINGLE_TARGET";
182  break;
184  os << "MULTIPLE_CTRL_MULTIPLE_TARGET";
185  break;
187  os << "CUSTOM_CTRL";
188  break;
190  os << "SINGLE_cCTRL_SINGLE_TARGET";
191  break;
193  os << "SINGLE_cCTRL_MULTIPLE_TARGET";
194  break;
196  os << "MULTIPLE_cCTRL_SINGLE_TARGET";
197  break;
199  os << "MULTIPLE_cCTRL_MULTIPLE_TARGET";
200  break;
202  os << "CUSTOM_cCTRL";
203  break;
204  }
205 
206  return os;
207  }
208 
212  struct GateStep {
214  std::size_t gate_hash_;
215  std::vector<idx> ctrl_;
216  std::vector<idx> target_;
217  std::string name_;
218 
221  GateStep() = default;
232  explicit GateStep(GateType gate_type, std::size_t gate_hash,
233  const std::vector<idx>& ctrl,
234  const std::vector<idx>& target, std::string name = "")
235  : gate_type_{gate_type},
236  gate_hash_{gate_hash}, ctrl_{ctrl}, target_{target}, name_{name} {
237  }
238  };
239 
247  friend std::ostream& operator<<(std::ostream& os,
248  const GateStep& gate_step) {
249  os << gate_step.gate_type_ << ", ";
251  os << "ctrl = " << disp(gate_step.ctrl_, ", ") << ", ";
252  os << "target = " << disp(gate_step.target_, ", ") << ", ";
253  os << "name = " << '\"' << gate_step.name_ << '\"';
254 
255  return os;
256  }
257 
261  enum class MeasureType {
262  NONE,
263 
264  MEASURE_Z,
265 
266  MEASURE_V,
267 
271  };
274 
283  friend std::ostream& operator<<(std::ostream& os,
284  const MeasureType& measure_type) {
285  switch (measure_type) {
286  case MeasureType::NONE:
287  os << "MEASURE NONE";
288  break;
290  os << "MEASURE_Z";
291  break;
293  os << "MEASURE_V";
294  break;
296  os << "MEASURE_V_MANY";
297  break;
298  }
299 
300  return os;
301  }
302 
306  struct MeasureStep {
308  std::vector<std::size_t> mats_hash_;
309  std::vector<idx> target_;
312  std::string name_;
314 
317  MeasureStep() = default;
328  explicit MeasureStep(MeasureType measurement_type,
329  const std::vector<std::size_t>& mats_hash,
330  const std::vector<idx>& target, idx c_reg,
331  std::string name = "")
332  : measurement_type_{measurement_type}, mats_hash_{mats_hash},
333  target_{target}, c_reg_{c_reg}, name_{name} {}
334  };
335 
343  friend std::ostream& operator<<(std::ostream& os,
344  const MeasureStep& measure_step) {
345  os << measure_step.measurement_type_ << ", ";
346  os << "target = " << disp(measure_step.target_, ", ") << ", ";
347  os << "c_reg = " << measure_step.c_reg_ << ", ";
348  os << "name = " << '\"' << measure_step.name_ << '\"';
349  os << " ";
350 
351  return os;
352  }
353 
357  enum class StepType {
358  NONE,
359  GATE,
360  MEASUREMENT,
361  };
362 
363  private:
364  std::vector<GateStep> gates_{};
365  std::vector<MeasureStep> measurements_{};
366  std::vector<StepType> step_types_{};
367 
373  const std::vector<MeasureStep>& get_measurements_() const noexcept {
374  return measurements_;
375  }
376 
382  const std::vector<GateStep>& get_gates_() const noexcept { return gates_; }
383 
389  const std::unordered_map<std::size_t, cmat>& get_cmat_hash_tbl_() const
390  noexcept {
391  return cmat_hash_tbl_;
392  }
393 
394  public:
400  class iterator {
402  const QCircuit* qc_{nullptr};
403 
404  class value_type_ : public IDisplay {
405  public:
408 
410  idx ip_{static_cast<idx>(-1)};
411  std::vector<GateStep>::const_iterator
413  std::vector<MeasureStep>::const_iterator
415 
421  explicit value_type_(const QCircuit* value_type_qc)
422  : value_type_qc_{value_type_qc} {}
423 
424  // silence -Weffc++ class has pointer data members
428  value_type_(const value_type_&) = default;
429 
430  // silence -Weffc++ class has pointer data members
436  value_type_& operator=(const value_type_&) = default;
437 
438  private:
448  std::ostream& display(std::ostream& os) const override {
449  // field spacing for the step number
450  idx text_width =
451  std::to_string(value_type_qc_->get_step_count()).size() + 1;
452 
453  // gate step
454  if (type_ == StepType::GATE) {
455  os << std::left;
456  os << std::setw(text_width) << ip_;
457  os << std::right;
458  idx pos = std::distance(std::begin(value_type_qc_->gates_),
459  gates_ip_);
460  os << value_type_qc_->get_gates_()[pos];
461  }
462  // measurement step
463  else if (type_ == StepType::MEASUREMENT) {
464  os << std::left;
465  os << std::setw(text_width) << ip_;
466  os << std::right;
467  idx pos =
468  std::distance(std::begin(value_type_qc_->measurements_),
470  os << "|> " << value_type_qc_->get_measurements_()[pos];
471  }
472  // otherwise
473  else {
474  }
475 
476  return os;
477  }
478  }; /* class value_type_ */
479 
480  value_type_ elem_{nullptr};
481 
482  public:
486  iterator() = default;
487 
488  // silence -Weffc++ class has pointer data members
492  iterator(const iterator&) = default;
493 
494  // silence -Weffc++ class has pointer data members
500  iterator& operator=(const iterator&) = default;
501 
508  // EXCEPTION CHECKS
509 
510  // protects against incrementing invalid iterators
511  if (qc_ == nullptr) {
513  "qpp::QCircuit::iterator::operator++()");
514  }
515 
516  // protects against incrementing an empty circuit iterator
517  if (qc_->get_step_count() == 0) {
519  "qpp::QCircuit::iterator::operator++()");
520  }
521 
522  // protects against incrementing past the end
523  if (elem_.ip_ == qc_->get_step_count()) {
525  "qpp::QCircuit::iterator::operator++()");
526  }
527  // END EXCEPTION CHECKS
528 
529  // gate step
530  if (elem_.type_ == StepType::GATE) {
531  std::advance(elem_.gates_ip_, 1);
532  }
533  // measurement step
534  else if (elem_.type_ == StepType::MEASUREMENT) {
535  std::advance(elem_.measurements_ip_, 1);
536  }
537  // otherwise
538  else {
539  }
540 
541  // increment the instruction pointer
542  ++elem_.ip_;
543 
544  // if we hit the end
545  if (elem_.ip_ == qc_->get_step_count()) {
547  } else {
548  // set the next step type
550  }
551 
552  return *this;
553  }
554 
561  iterator retval = *this;
562  ++(*this);
563  return retval;
564  }
565 
572  bool operator==(const iterator& rhs) const {
573  return std::tie(elem_.type_, elem_.ip_, elem_.gates_ip_,
575  std::tie(rhs.elem_.type_, rhs.elem_.ip_, rhs.elem_.gates_ip_,
576  rhs.elem_.measurements_ip_);
577  }
578 
586  bool operator!=(iterator rhs) const { return !(*this == rhs); }
587 
593  const value_type_& operator*() const {
594  // EXCEPTION CHECKS
595 
596  // protects against de-referencing past the last element or against
597  // de-referencing invalid iterators
598  if (qc_ == nullptr || elem_.ip_ == qc_->get_step_count())
600  "qpp::QCircuit::iterator::operator*()");
601  // END EXCEPTION CHECKS
602 
603  return elem_;
604  }
605 
611  void set_begin_(const QCircuit* qc) {
612  qc_ = qc;
613  elem_ = value_type_{qc_};
614 
615  if (qc_ != nullptr) {
616  if (qc_->get_step_count() != 0) // non-empty circuit
617  {
618  elem_.type_ = qc_->step_types_[0];
619  elem_.ip_ = 0;
620  }
621  elem_.gates_ip_ = std::begin(qc_->gates_);
622  elem_.measurements_ip_ = std::begin(qc_->measurements_);
623  }
624  }
625 
631  void set_end_(const QCircuit* qc) {
632  qc_ = qc;
633  elem_ = value_type_{qc_};
634 
635  if (qc_ != nullptr) {
636  if (qc->get_step_count() != 0) {
637  elem_.ip_ = qc->get_step_count();
638  }
639  elem_.gates_ip_ = std::end(qc->gates_);
640  elem_.measurements_ip_ = std::end(qc->measurements_);
641  }
642  }
643 
644  // iterator traits
645  using difference_type = long long;
647  using pointer = const value_type*;
648  using reference = const value_type&;
649  using iterator_category = std::forward_iterator_tag;
650  };
651 
653 
660  iterator it;
661  it.set_begin_(this);
662 
663  return it;
664  }
665 
671  const_iterator begin() const noexcept {
672  iterator it;
673  it.set_begin_(this);
674 
675  return it;
676  }
677 
683  const_iterator cbegin() const noexcept {
684  iterator it;
685  it.set_begin_(this);
686 
687  return it;
688  }
689 
696  iterator it;
697  it.set_end_(this);
698 
699  return it;
700  }
701 
707  const_iterator end() const noexcept {
708  iterator it;
709  it.set_end_(this);
710 
711  return it;
712  }
713 
719  const_iterator cend() const noexcept {
720  iterator it;
721  it.set_end_(this);
722 
723  return it;
724  }
725 
737  explicit QCircuit(idx nq, idx nc = 0, idx d = 2, std::string name = "")
738  : nq_{nq}, nc_{nc}, d_{d}, name_{name}, measured_(nq, false) {
739  // EXCEPTION CHECKS
740 
741  if (nq == 0)
742  throw exception::ZeroSize("qpp::QCircuit::QCircuit()");
743  if (d < 2)
744  throw exception::OutOfRange("qpp::QCircuit::QCircuit()");
745  // END EXCEPTION CHECKS
746  }
747 
751  virtual ~QCircuit() = default;
752 
753  // getters
759  idx get_nq() const noexcept { return nq_; }
760 
766  idx get_nc() const noexcept { return nc_; }
767 
773  idx get_d() const noexcept { return d_; }
774 
780  std::string get_name() const { return name_; }
781 
787  idx get_measured(idx i) const {
788  // EXCEPTION CHECKS
789 
790  if (i >= nq_)
791  throw exception::OutOfRange("qpp::QCircuit::get_measured()");
792  // END EXCEPTION CHECKS
793 
794  return measured_[i];
795  }
796 
802  std::vector<idx> get_measured() const {
803  std::vector<idx> result;
804  for (idx i = 0; i < nq_; ++i)
805  if (get_measured(i))
806  result.emplace_back(i);
807 
808  return result;
809  }
810 
816  std::vector<idx> get_non_measured() const {
817  std::vector<idx> result;
818  for (idx i = 0; i < nq_; ++i)
819  if (!get_measured(i))
820  result.emplace_back(i);
821 
822  return result;
823  }
824 
830  idx get_gate_count() const noexcept {
831  idx result = 0;
832  for (auto&& elem : count_)
833  result += elem.second;
834 
835  return result;
836  }
837 
844  idx get_gate_count(const std::string& name) const {
845  idx result = 0;
846  // EXCEPTION CHECKS
847 
848  try {
849  result = count_.at(name);
850  } catch (...) {
851  std::cerr << "In qpp::QCircuit::get_gate_count()\n";
852  throw;
853  }
854  // END EXCEPTION CHECKS
855 
856  return result;
857  }
858 
864  idx get_gate_depth() const {
865  throw exception::NotImplemented("qpp::QCircuit::get_gate_depth()");
866  }
867 
874  idx get_gate_depth(const std::string& name QPP_UNUSED_) const {
875  throw exception::NotImplemented("qpp::QCircuit::get_gate_depth()");
876  }
877 
883  idx get_measurement_count() const noexcept {
884  idx result = 0;
885  for (auto&& elem : measurement_count_)
886  result += elem.second;
887 
888  return result;
889  }
890 
897  idx get_measurement_count(const std::string& name) const {
898  idx result = 0;
899  // EXCEPTION CHECKS
900 
901  try {
902  result = measurement_count_.at(name);
903  } catch (...) {
904  std::cerr << "In qpp::QCircuit::get_measurement_count()\n";
905  throw;
906  }
907  // END EXCEPTION CHECKS
908 
909  return result;
910  }
911 
918  idx get_step_count() const noexcept { return step_types_.size(); }
919  // end getters
920 
929  QCircuit& gate(const cmat& U, idx i, std::string name = "") {
930  // EXCEPTION CHECKS
931 
932  try {
933  // check valid target
934  if (i >= nq_)
935  throw exception::OutOfRange("qpp::QCircuit::gate()");
936  // check not measured before
937  if (get_measured(i))
938  throw exception::QuditAlreadyMeasured("qpp::QCircuit::gate()");
939 
940  // check square matrix for the gate
942  throw exception::MatrixNotSquare("qpp::QCircuit::gate()");
943  // check correct dimension
944  if (static_cast<idx>(U.rows()) != d_)
945  throw exception::DimsMismatchMatrix("qpp::QCircuit::gate()");
946  } catch (exception::Exception&) {
947  std::cerr << "At STEP " << get_step_count() << "\n";
948  throw;
949  }
950  // END EXCEPTION CHECKS
951 
952  if (name == "")
954  std::size_t hashU = hash_eigen(U);
955  add_hash_(U, hashU);
956  gates_.emplace_back(GateType::SINGLE, hashU, std::vector<idx>{},
957  std::vector<idx>{i}, name);
958  step_types_.push_back(StepType::GATE);
959  ++count_[name];
960 
961  return *this;
962  }
963 
973  QCircuit& gate(const cmat& U, idx i, idx j, std::string name = "") {
974  // EXCEPTION CHECKS
975 
976  try {
977  // check valid target
978  if (i >= nq_ || j >= nq_ || i == j)
979  throw exception::OutOfRange("qpp::QCircuit::gate()");
980  if (get_measured(i) || get_measured(j))
981  throw exception::QuditAlreadyMeasured("qpp::QCircuit::gate()");
982 
983  // check square matrix for the gate
985  throw exception::MatrixNotSquare("qpp::QCircuit::gate()");
986  // check correct dimension
987  if (static_cast<idx>(U.rows()) != d_ * d_)
988  throw exception::DimsMismatchMatrix("qpp::QCircuit::gate()");
989  } catch (exception::Exception&) {
990  std::cerr << "At STEP " << get_step_count() << "\n";
991  throw;
992  }
993  // END EXCEPTION CHECKS
994 
995  if (name == "")
997  std::size_t hashU = hash_eigen(U);
998  add_hash_(U, hashU);
999  gates_.emplace_back(GateType::TWO, hashU, std::vector<idx>{},
1000  std::vector<idx>{i, j}, name);
1001  step_types_.push_back(StepType::GATE);
1002  ++count_[name];
1003 
1004  return *this;
1005  }
1006 
1017  QCircuit& gate(const cmat& U, idx i, idx j, idx k, std::string name = "") {
1018  // EXCEPTION CHECKS
1019 
1020  try {
1021  // check valid target
1022  if (i >= nq_ || j >= nq_ || k >= nq_ || (i == j) || (i == k) ||
1023  (j == k))
1024  throw exception::OutOfRange("qpp::QCircuit::gate()");
1025  if (get_measured(i) || get_measured(j) || get_measured(k))
1026  throw exception::QuditAlreadyMeasured("qpp::QCircuit::gate()");
1027 
1028  // check square matrix for the gate
1030  throw exception::MatrixNotSquare("qpp::QCircuit::gate()");
1031  // check correct dimension
1032  if (static_cast<idx>(U.rows()) != d_ * d_ * d_)
1033  throw exception::DimsMismatchMatrix("qpp::QCircuit::gate()");
1034  } catch (exception::Exception&) {
1035  std::cerr << "At STEP " << get_step_count() << "\n";
1036  throw;
1037  }
1038  // END EXCEPTION CHECKS
1039 
1040  if (name == "")
1041  name = qpp::Gates::get_instance().get_name(U);
1042  std::size_t hashU = hash_eigen(U);
1043  add_hash_(U, hashU);
1044  gates_.emplace_back(GateType::THREE, hashU, std::vector<idx>{},
1045  std::vector<idx>{i, j, k}, name);
1046  step_types_.push_back(StepType::GATE);
1047  ++count_[name];
1048 
1049  return *this;
1050  }
1051 
1062  QCircuit& gate_fan(const cmat& U, const std::vector<idx>& target,
1063  std::string name = "") {
1064  // EXCEPTION CHECKS
1065 
1066  try {
1067  // check valid target
1068  if (target.size() == 0)
1069  throw exception::ZeroSize("qpp::QCircuit::gate_fan()");
1070  for (auto&& elem : target) {
1071  if (elem >= nq_)
1072  throw exception::OutOfRange("qpp::QCircuit::gate_fan()");
1073  // check target was not measured before
1074  if (get_measured(elem))
1076  "qpp::QCircuit::gate_fan()");
1077  }
1078  // check no duplicates target
1079  if (!internal::check_no_duplicates(target))
1080  throw exception::Duplicates("qpp::QCircuit::gate_fan()");
1081 
1082  // check square matrix for the gate
1084  throw exception::MatrixNotSquare("qpp::QCircuit::gate_fan()");
1085  // check correct dimension
1086  if (static_cast<idx>(U.rows()) != d_)
1088  "qpp::QCircuit::gate_fan()");
1089  } catch (exception::Exception&) {
1090  std::cerr << "At STEP " << get_step_count() << "\n";
1091  throw;
1092  }
1093  // END EXCEPTION CHECKS
1094 
1095  if (name == "")
1096  name = qpp::Gates::get_instance().get_name(U);
1097  std::size_t hashU = hash_eigen(U);
1098  add_hash_(U, hashU);
1099  gates_.emplace_back(GateType::FAN, hashU, std::vector<idx>{}, target,
1100  name);
1101  step_types_.push_back(StepType::GATE);
1102  count_[name] += target.size();
1103 
1104  return *this;
1105  }
1106 
1107  // std::initializer_list overload, avoids ambiguity for 2-element lists, see
1108  // http://stackoverflow.com
1109  // /questions/26750039/ambiguity-when-using-initializer-list-as-parameter
1120  QCircuit& gate_fan(const cmat& U, const std::initializer_list<idx>& target,
1121  std::string name = "") {
1122  return gate_fan(U, std::vector<idx>(target), name);
1123  }
1124 
1133  QCircuit& gate_fan(const cmat& U, std::string name = "") {
1134  // EXCEPTION CHECKS
1135 
1136  try {
1137  // check square matrix for the gate
1139  throw exception::MatrixNotSquare("qpp::QCircuit::gate_fan()");
1140  // check correct dimension
1141  if (static_cast<idx>(U.rows()) != d_)
1143  "qpp::QCircuit::gate_fan()");
1144  } catch (exception::Exception&) {
1145  std::cerr << "At STEP " << get_step_count() << "\n";
1146  throw;
1147  }
1148  // END EXCEPTION CHECKS
1149 
1150  if (name == "")
1151  name = qpp::Gates::get_instance().get_name(U);
1152  std::size_t hashU = hash_eigen(U);
1153  add_hash_(U, hashU);
1154  gates_.emplace_back(GateType::FAN, hashU, std::vector<idx>{},
1155  get_non_measured(), name);
1156  step_types_.push_back(StepType::GATE);
1157  count_[name] += get_non_measured().size();
1158 
1159  return *this;
1160  }
1161 
1172  QCircuit& gate_custom(const cmat& U, const std::vector<idx>& target,
1173  std::string name = "") {
1174  // EXCEPTION CHECKS
1175 
1176  idx n = static_cast<idx>(target.size());
1177  idx D = static_cast<idx>(std::llround(std::pow(d_, n)));
1178 
1179  try {
1180  // check valid target
1181  if (target.size() == 0)
1182  throw exception::ZeroSize("qpp::QCircuit::gate_custom()");
1183  for (auto&& elem : target) {
1184  if (elem >= nq_)
1185  throw exception::OutOfRange("qpp::QCircuit::gate_custom()");
1186  // check target was not measured before
1187  if (get_measured(elem))
1189  "qpp::QCircuit::gate_custom()");
1190  }
1191  // check no duplicates target
1192  if (!internal::check_no_duplicates(target))
1193  throw exception::Duplicates("qpp::QCircuit::gate_custom()");
1194 
1195  // check square matrix for the gate
1198  "qpp::QCircuit::gate_custom()");
1199  // check correct dimension
1200  if (static_cast<idx>(U.rows()) != D)
1202  "qpp::QCircuit::gate_custom()");
1203  } catch (exception::Exception&) {
1204  std::cerr << "At STEP " << get_step_count() << "\n";
1205  throw;
1206  }
1207  // END EXCEPTION CHECKS
1208 
1209  if (name == "")
1210  name = qpp::Gates::get_instance().get_name(U);
1211  std::size_t hashU = hash_eigen(U);
1212  add_hash_(U, hashU);
1213  gates_.emplace_back(GateType::CUSTOM, hashU, std::vector<idx>{}, target,
1214  name);
1215  step_types_.push_back(StepType::GATE);
1216  ++count_[name];
1217 
1218  return *this;
1219  }
1220 
1221  // QFT
1231  QCircuit& QFT(const std::vector<idx>& target,
1232  bool swap QPP_UNUSED_ = true) {
1233  // EXCEPTION CHECKS
1234 
1235  try {
1236  throw exception::NotImplemented("qpp::QCircuit::QFT()");
1237  } catch (exception::Exception&) {
1238  std::cerr << "At STEP " << get_step_count() << "\n";
1239  throw;
1240  }
1241  // END EXCEPTION CHECKS
1242 
1243  gates_.emplace_back(GateType::QFT, 0, std::vector<idx>{}, target,
1244  "QFT");
1245  step_types_.push_back(StepType::GATE);
1246 
1247  return *this;
1248  }
1249 
1250  // TFQ
1260  QCircuit& TFQ(const std::vector<idx>& target,
1261  bool swap QPP_UNUSED_ = true) {
1262  // EXCEPTION CHECKS
1263 
1264  try {
1265  throw exception::NotImplemented("qpp::QCircuit::TFQ()");
1266  } catch (exception::Exception&) {
1267  std::cerr << "At STEP " << get_step_count() << "\n";
1268  throw;
1269  }
1270  // END EXCEPTION CHECKS
1271  gates_.emplace_back(GateType::TFQ, 0, std::vector<idx>{}, target,
1272  "TFQ");
1273  step_types_.push_back(StepType::GATE);
1274 
1275  return *this;
1276  }
1277 
1278  // single ctrl single target
1289  QCircuit& CTRL(const cmat& U, idx ctrl, idx target, std::string name = "") {
1290  // EXCEPTION CHECKS
1291 
1292  try {
1293  // check valid ctrl and target
1294  if (ctrl >= nq_ || target >= nq_ || ctrl == target)
1295  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1296  if (get_measured(ctrl) || get_measured(target))
1297  throw exception::QuditAlreadyMeasured("qpp::QCircuit::CTRL()");
1298 
1299  // check square matrix for the gate
1301  throw exception::MatrixNotSquare("qpp::QCircuit::CTRL()");
1302  // check correct dimension
1303  if (static_cast<idx>(U.rows()) != d_)
1304  throw exception::DimsMismatchMatrix("qpp::QCircuit::CTRL()");
1305  } catch (exception::Exception&) {
1306  std::cerr << "At STEP " << get_step_count() << "\n";
1307  throw;
1308  }
1309  // END EXCEPTION CHECKS
1310 
1311  if (name == "") {
1312  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1313  name = gate_name == "" ? "CTRL" : "CTRL-" + gate_name;
1314  }
1315  std::size_t hashU = hash_eigen(U);
1316  add_hash_(U, hashU);
1317  gates_.emplace_back(GateType::SINGLE_CTRL_SINGLE_TARGET, hashU,
1318  std::vector<idx>{ctrl}, std::vector<idx>{target},
1319  name);
1320  step_types_.push_back(StepType::GATE);
1321  ++count_[name];
1322 
1323  return *this;
1324  }
1325 
1326  // single ctrl multiple target
1338  QCircuit& CTRL(const cmat& U, idx ctrl, const std::vector<idx>& target,
1339  std::string name = "") {
1340  // EXCEPTION CHECKS
1341 
1342  try {
1343  // check valid ctrl
1344  if (ctrl >= nq_)
1345  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1346  if (get_measured(ctrl))
1347  throw exception::QuditAlreadyMeasured("qpp::QCircuit::CTRL()");
1348 
1349  // check valid target
1350  if (target.size() == 0)
1351  throw exception::ZeroSize("qpp::QCircuit::CTRL()");
1352  for (auto&& elem : target) {
1353  if (elem >= nq_)
1354  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1355  // check target was not measured before
1356  if (get_measured(elem))
1358  "qpp::QCircuit::CTRL()");
1359  }
1360  // check no duplicates target
1361  if (!internal::check_no_duplicates(target))
1362  throw exception::Duplicates("qpp::QCircuit::CTRL()");
1363 
1364  // check ctrl and target don't share common elements
1365  for (auto&& elem : target)
1366  if (elem == ctrl)
1367  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1368 
1369  // check square matrix for the gate
1371  throw exception::MatrixNotSquare("qpp::QCircuit::CTRL()");
1372  // check correct dimension
1373  if (static_cast<idx>(U.rows()) != d_)
1374  throw exception::DimsMismatchMatrix("qpp::QCircuit::CTRL()");
1375  } catch (exception::Exception&) {
1376  std::cerr << "At STEP " << get_step_count() << "\n";
1377  throw;
1378  }
1379  // END EXCEPTION CHECKS
1380 
1381  if (name == "") {
1382  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1383  name = gate_name == "" ? "CTRL" : "CTRL-" + gate_name;
1384  }
1385  std::size_t hashU = hash_eigen(U);
1386  add_hash_(U, hashU);
1387  gates_.emplace_back(GateType::SINGLE_CTRL_MULTIPLE_TARGET, hashU,
1388  std::vector<idx>{ctrl}, target, name);
1389  step_types_.push_back(StepType::GATE);
1390  ++count_[name];
1391 
1392  return *this;
1393  }
1394 
1395  // multiple ctrl single target
1406  QCircuit& CTRL(const cmat& U, const std::vector<idx>& ctrl, idx target,
1407  std::string name = "") {
1408  // EXCEPTION CHECKS
1409 
1410  try {
1411  // check valid ctrl
1412  for (auto&& elem : ctrl) {
1413  if (elem >= nq_)
1414  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1415  // check ctrl was not measured before
1416  if (get_measured(elem))
1418  "qpp::QCircuit::CTRL()");
1419  }
1420  // check no duplicates ctrl
1421  if (!internal::check_no_duplicates(ctrl))
1422  throw exception::Duplicates("qpp::QCircuit::CTRL()");
1423 
1424  // check valid target
1425  if (target >= nq_)
1426  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1427  if (get_measured(target))
1428  throw exception::QuditAlreadyMeasured("qpp::QCircuit::CTRL()");
1429 
1430  // check ctrl and target don't share common elements
1431  for (auto&& elem : ctrl)
1432  if (elem == target)
1433  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1434 
1435  // check square matrix for the gate
1437  throw exception::MatrixNotSquare("qpp::QCircuit::CTRL()");
1438  // check correct dimension
1439  if (static_cast<idx>(U.rows()) != d_)
1440  throw exception::DimsMismatchMatrix("qpp::QCircuit::CTRL()");
1441  } catch (exception::Exception&) {
1442  std::cerr << "At STEP " << get_step_count() << "\n";
1443  throw;
1444  }
1445  // END EXCEPTION CHECKS
1446 
1447  if (name == "") {
1448  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1449  name = gate_name == "" ? "CTRL" : "CTRL-" + gate_name;
1450  }
1451  std::size_t hashU = hash_eigen(U);
1452  add_hash_(U, hashU);
1453  gates_.emplace_back(GateType::MULTIPLE_CTRL_SINGLE_TARGET, hashU, ctrl,
1454  std::vector<idx>{target}, name);
1455  step_types_.push_back(StepType::GATE);
1456  ++count_[name];
1457 
1458  return *this;
1459  }
1460 
1461  // multiple ctrl multiple target
1462  // FIXME
1474  QCircuit& CTRL(const cmat& U, const std::vector<idx>& ctrl,
1475  const std::vector<idx>& target, std::string name = "") {
1476  // EXCEPTION CHECKS
1477 
1478  try {
1479  // check valid ctrl
1480  for (auto&& elem : ctrl) {
1481  if (elem >= nq_)
1482  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1483  // check ctrl was not measured before
1484  if (get_measured(elem))
1486  "qpp::QCircuit::CTRL()");
1487  }
1488  // check no duplicates ctrl
1489  if (!internal::check_no_duplicates(ctrl))
1490  throw exception::Duplicates("qpp::QCircuit::CTRL()");
1491 
1492  // check valid target
1493  if (target.size() == 0)
1494  throw exception::ZeroSize("qpp::QCircuit::CTRL()");
1495  for (auto&& elem : target) {
1496  if (elem >= nq_)
1497  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1498  // check target was not measured before
1499  if (get_measured(elem))
1501  "qpp::QCircuit::CTRL()");
1502  }
1503  // check no duplicates target
1504  if (!internal::check_no_duplicates(target))
1505  throw exception::Duplicates("qpp::QCircuit::CTRL()");
1506 
1507  // check ctrl and target don't share common elements
1508  for (auto&& elem_ctrl : ctrl)
1509  for (auto&& elem_target : target)
1510  if (elem_ctrl == elem_target)
1511  throw exception::OutOfRange("qpp::QCircuit::CTRL()");
1512 
1513  // check square matrix for the gate
1515  throw exception::MatrixNotSquare("qpp::QCircuit::CTRL()");
1516  // check correct dimension
1517  if (static_cast<idx>(U.rows()) != d_)
1518  throw exception::DimsMismatchMatrix("qpp::QCircuit::CTRL()");
1519  } catch (exception::Exception&) {
1520  std::cerr << "At STEP " << get_step_count() << "\n";
1521  throw;
1522  }
1523  // END EXCEPTION CHECKS
1524 
1525  if (name == "") {
1526  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1527  name = gate_name == "" ? "CTRL" : "CTRL-" + gate_name;
1528  }
1529  std::size_t hashU = hash_eigen(U);
1530  add_hash_(U, hashU);
1531  gates_.emplace_back(GateType::MULTIPLE_CTRL_MULTIPLE_TARGET, hashU,
1532  ctrl, std::vector<idx>{target}, name);
1533  step_types_.push_back(StepType::GATE);
1534  ++count_[name];
1535 
1536  return *this;
1537  }
1538 
1539  // custom multiple control composed target
1552  QCircuit& CTRL_custom(const cmat& U, const std::vector<idx>& ctrl,
1553  const std::vector<idx>& target,
1554  std::string name = "") {
1555  // EXCEPTION CHECKS
1556 
1557  idx n = static_cast<idx>(target.size());
1558  idx D = static_cast<idx>(std::llround(std::pow(d_, n)));
1559 
1560  try {
1561  // check valid ctrl
1562  for (auto&& elem : ctrl) {
1563  if (elem >= nq_)
1564  throw exception::OutOfRange("qpp::QCircuit::CTRL_custom()");
1565  // check ctrl was not measured before
1566  if (get_measured(elem))
1568  "qpp::QCircuit::CTRL_custom()");
1569  }
1570  // check no duplicates ctrl
1571  if (!internal::check_no_duplicates(ctrl))
1572  throw exception::Duplicates("qpp::QCircuit::CTRL_custom()");
1573 
1574  // check valid target
1575  if (target.size() == 0)
1576  throw exception::ZeroSize("qpp::QCircuit::CTRL_custom()");
1577  for (auto&& elem : target) {
1578  if (elem >= nq_)
1579  throw exception::OutOfRange("qpp::QCircuit::CTRL_custom()");
1580  // check target was not measured before
1581  if (get_measured(elem))
1583  "qpp::QCircuit::CTRL_custom()");
1584  }
1585 
1586  // check ctrl and target don't share common elements
1587  for (auto&& elem_ctrl : ctrl)
1588  for (auto&& elem_target : target)
1589  if (elem_ctrl == elem_target)
1590  throw exception::OutOfRange(
1591  "qpp::QCircuit::CTRL_custom()");
1592 
1593  // check square matrix for the gate
1596  "qpp::QCircuit::CTRL_custom()");
1597  // check correct dimension
1598  if (static_cast<idx>(U.rows()) != D)
1600  "qpp::QCircuit::CTRL_custom()");
1601  } catch (exception::Exception&) {
1602  std::cerr << "At STEP " << get_step_count() << "\n";
1603  throw;
1604  }
1605  // END EXCEPTION CHECKS
1606 
1607  if (name == "") {
1608  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1609  name = gate_name == "" ? "CTRL" : "CTRL-" + gate_name;
1610  }
1611  std::size_t hashU = hash_eigen(U);
1612  add_hash_(U, hashU);
1613  gates_.emplace_back(GateType::CUSTOM_CTRL, hashU, ctrl, target, name);
1614  step_types_.push_back(StepType::GATE);
1615  ++count_[name];
1616 
1617  return *this;
1618  }
1619 
1620  // single ctrl single target
1621  // FIXME, use the corresponding dits
1632  QCircuit& cCTRL(const cmat& U, idx ctrl_dit, idx target,
1633  std::string name = "") {
1634  // EXCEPTION CHECKS
1635 
1636  try {
1637  // check valid ctrl_dit and target
1638  if (ctrl_dit >= nc_ || target >= nq_)
1639  throw exception::OutOfRange("qpp::QCircuit::cCTRL()");
1640  if (get_measured(target))
1641  throw exception::QuditAlreadyMeasured("qpp::QCircuit::cCTRL()");
1642 
1643  // check square matrix for the gate
1645  throw exception::MatrixNotSquare("qpp::QCircuit::cCTRL()");
1646  // check correct dimension
1647  if (static_cast<idx>(U.rows()) != d_)
1648  throw exception::DimsMismatchMatrix("qpp::QCircuit::cCTRL()");
1649  } catch (exception::Exception&) {
1650  std::cerr << "At STEP " << get_step_count() << "\n";
1651  throw;
1652  }
1653  // END EXCEPTION CHECKS
1654 
1655  if (name == "") {
1656  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1657  name = gate_name == "" ? "cCTRL" : "cCTRL-" + gate_name;
1658  }
1659  std::size_t hashU = hash_eigen(U);
1660  add_hash_(U, hashU);
1661  gates_.emplace_back(GateType::SINGLE_cCTRL_SINGLE_TARGET, hashU,
1662  std::vector<idx>{ctrl_dit},
1663  std::vector<idx>{target}, name);
1664  step_types_.push_back(StepType::GATE);
1665  ++count_[name];
1666 
1667  return *this;
1668  }
1669 
1670  // single ctrl multiple targets
1682  QCircuit& cCTRL(const cmat& U, idx ctrl_dit, const std::vector<idx>& target,
1683  std::string name = "") {
1684  // EXCEPTION CHECKS
1685 
1686  try {
1687  // check valid ctrl_dit
1688  if (ctrl_dit >= nc_)
1689  throw exception::OutOfRange("qpp::QCircuit::cCTRL()");
1690 
1691  // check valid target
1692  if (target.size() == 0)
1693  throw exception::ZeroSize("qpp::QCircuit::cCTRL()");
1694  for (auto&& elem : target) {
1695  if (elem >= nq_)
1696  throw exception::OutOfRange("qpp::QCircuit::cCTRL()");
1697  // check target was not measured before
1698  if (get_measured(elem))
1700  "qpp::QCircuit::cCTRL()");
1701  }
1702  // check no duplicates target
1703  if (!internal::check_no_duplicates(target))
1704  throw exception::Duplicates("qpp::QCircuit::cCTRL()");
1705 
1706  // check square matrix for the gate
1708  throw exception::MatrixNotSquare("qpp::QCircuit::cCTRL()");
1709  // check correct dimension
1710  if (static_cast<idx>(U.rows()) != d_)
1711  throw exception::DimsMismatchMatrix("qpp::QCircuit::cCTRL()");
1712  } catch (exception::Exception&) {
1713  std::cerr << "At STEP " << get_step_count() << "\n";
1714  throw;
1715  }
1716  // END EXCEPTION CHECKS
1717 
1718  if (name == "") {
1719  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1720  name = gate_name == "" ? "cCTRL" : "cCTRL-" + gate_name;
1721  }
1722  std::size_t hashU = hash_eigen(U);
1723  add_hash_(U, hashU);
1724  gates_.emplace_back(GateType::SINGLE_cCTRL_MULTIPLE_TARGET, hashU,
1725  std::vector<idx>{ctrl_dit}, target, name);
1726  step_types_.push_back(StepType::GATE);
1727  ++count_[name];
1728 
1729  return *this;
1730  }
1731 
1732  // multiple ctrl single target
1743  QCircuit& cCTRL(const cmat& U, const std::vector<idx>& ctrl_dits,
1744  idx target, std::string name = "") {
1745  // EXCEPTION CHECKS
1746 
1747  try {
1748  // check valid ctrl_dits
1749  for (auto&& elem : ctrl_dits) {
1750  if (elem >= nc_)
1751  throw exception::OutOfRange("qpp::QCircuit::cCTRL()");
1752  }
1753  // check no duplicates ctrl_dits
1754  if (!internal::check_no_duplicates(ctrl_dits))
1755  throw exception::Duplicates("qpp::QCircuit::cCTRL()");
1756 
1757  // check valid target
1758  if (target >= nq_)
1759  throw exception::OutOfRange("qpp::QCircuit::cCTRL()");
1760  // check target was not measured before
1761  if (get_measured(target))
1762  throw exception::QuditAlreadyMeasured("qpp::QCircuit::cCTRL()");
1763 
1764  // check square matrix for the gate
1766  throw exception::MatrixNotSquare("qpp::QCircuit::cCTRL()");
1767  // check correct dimension
1768  if (static_cast<idx>(U.rows()) != d_)
1769  throw exception::DimsMismatchMatrix("qpp::QCircuit::cCTRL()");
1770  } catch (exception::Exception&) {
1771  std::cerr << "At STEP " << get_step_count() << "\n";
1772  throw;
1773  }
1774  // END EXCEPTION CHECKS
1775 
1776  if (name == "") {
1777  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1778  name = gate_name == "" ? "cCTRL" : "cCTRL-" + gate_name;
1779  }
1780  std::size_t hashU = hash_eigen(U);
1781  add_hash_(U, hashU);
1782  gates_.emplace_back(GateType::MULTIPLE_cCTRL_SINGLE_TARGET, hashU,
1783  ctrl_dits, std::vector<idx>{target}, name);
1784  step_types_.push_back(StepType::GATE);
1785  ++count_[name];
1786 
1787  return *this;
1788  }
1789 
1790  // multiple ctrl multiple targets
1803  QCircuit& cCTRL(const cmat& U, const std::vector<idx>& ctrl_dits,
1804  const std::vector<idx>& target, std::string name = "") {
1805  // EXCEPTION CHECKS
1806 
1807  try {
1808  // check valid ctrl_dits
1809  for (auto&& elem : ctrl_dits) {
1810  if (elem >= nc_)
1811  throw exception::OutOfRange("qpp::QCircuit::cCTRL()");
1812  }
1813  // check no duplicates ctrl_dits
1814  if (!internal::check_no_duplicates(ctrl_dits))
1815  throw exception::Duplicates("qpp::QCircuit::cCTRL()");
1816 
1817  // check valid target
1818  if (target.size() == 0)
1819  throw exception::ZeroSize("qpp::QCircuit::cCTRL()");
1820  for (auto&& elem : target) {
1821  if (elem >= nq_)
1822  throw exception::OutOfRange("qpp::QCircuit::cCTRL()");
1823  // check target was not measured before
1824  if (get_measured(elem))
1826  "qpp::QCircuit::cCTRL()");
1827  }
1828  // check no duplicates target
1829  if (!internal::check_no_duplicates(target))
1830  throw exception::Duplicates("qpp::QCircuit::cCTRL()");
1831 
1832  // check square matrix for the gate
1834  throw exception::MatrixNotSquare("qpp::QCircuit::cCTRL()");
1835  // check correct dimension
1836  if (static_cast<idx>(U.rows()) != d_)
1837  throw exception::DimsMismatchMatrix("qpp::QCircuit::cCTRL()");
1838  } catch (exception::Exception&) {
1839  std::cerr << "At STEP " << get_step_count() << "\n";
1840  throw;
1841  }
1842  // END EXCEPTION CHECKS
1843 
1844  if (name == "") {
1845  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1846  name = gate_name == "" ? "cCTRL" : "cCTRL-" + gate_name;
1847  }
1848  std::size_t hashU = hash_eigen(U);
1849  add_hash_(U, hashU);
1851  ctrl_dits, std::vector<idx>{target}, name);
1852  step_types_.push_back(StepType::GATE);
1853  ++count_[name];
1854 
1855  return *this;
1856  }
1857 
1858  // custom controlled gate with multiple controls and multiple targets
1871  QCircuit& cCTRL_custom(const cmat& U, const std::vector<idx>& ctrl_dits,
1872  const std::vector<idx>& target,
1873  std::string name = "") {
1874  // EXCEPTION CHECKS
1875 
1876  idx n = static_cast<idx>(target.size());
1877  idx D = static_cast<idx>(std::llround(std::pow(d_, n)));
1878 
1879  try {
1880  // check valid ctrl_dits
1881  for (auto&& elem : ctrl_dits) {
1882  if (elem >= nc_)
1883  throw exception::OutOfRange(
1884  "qpp::QCircuit::cCTRL_custom()");
1885  }
1886  // check no duplicates ctrl_dits
1887  if (!internal::check_no_duplicates(ctrl_dits))
1888  throw exception::Duplicates("qpp::QCircuit::cCTRL_custom()");
1889 
1890  // check valid target
1891  if (target.size() == 0)
1892  throw exception::ZeroSize("qpp::QCircuit::cCTRL_custom()");
1893  for (auto&& elem : target) {
1894  if (elem >= nq_)
1895  throw exception::OutOfRange(
1896  "qpp::QCircuit::cCTRL_custom()");
1897  // check target was not measured before
1898  if (get_measured(elem))
1900  "qpp::QCircuit::cCTRL_custom()");
1901  }
1902  // check no duplicates target
1903  if (!internal::check_no_duplicates(target))
1904  throw exception::Duplicates("qpp::QCircuit::cCTRL_custom()");
1905 
1906  // check square matrix for the gate
1909  "qpp::QCircuit::cCTRL_custom()");
1910  // check correct dimension
1911  if (static_cast<idx>(U.rows()) != D)
1913  "qpp::QCircuit::cCTRL_custom()");
1914  } catch (exception::Exception&) {
1915  std::cerr << "At STEP " << get_step_count() << "\n";
1916  throw;
1917  }
1918  // END EXCEPTION CHECKS
1919 
1920  if (name == "") {
1921  std::string gate_name = qpp::Gates::get_instance().get_name(U);
1922  name = gate_name == "" ? "cCTRL" : "cCTRL-" + gate_name;
1923  }
1924  std::size_t hashU = hash_eigen(U);
1925  add_hash_(U, hashU);
1926  gates_.emplace_back(GateType::CUSTOM_cCTRL, hashU, ctrl_dits, target,
1927  name);
1928  step_types_.push_back(StepType::GATE);
1929  ++count_[name];
1930 
1931  return *this;
1932  }
1933 
1934  // Z measurement of single qudit
1944  QCircuit& measureZ(idx target, idx c_reg, std::string name = "") {
1945  // EXCEPTION CHECKS
1946 
1947  try {
1948  // measuring non-existing qudit
1949  if (target >= nq_)
1950  throw exception::OutOfRange("qpp::QCircuit::measureZ()");
1951  // trying to put the result into a non-existing classical slot
1952  if (c_reg >= nc_)
1953  throw exception::OutOfRange("qpp::QCircuit::measureZ()");
1954  // qudit was measured before
1955  if (get_measured(target))
1956  throw exception::QuditAlreadyMeasured("qpp:QCircuit::measureZ");
1957  } catch (exception::Exception&) {
1958  std::cerr << "At STEP " << get_step_count() << "\n";
1959  throw;
1960  }
1961  // END EXCEPTION CHECKS
1962 
1963  if (name == "")
1964  name = "Z";
1965  measured_[target] = true;
1967  std::vector<std::size_t>{},
1968  std::vector<idx>{target}, c_reg, name);
1970  ++measurement_count_[name];
1971 
1972  return *this;
1973  }
1974 
1975  // measurement of single qudit in the orthonormal basis or rank-1 projectors
1976  // specified by the columns of matrix V
1989  QCircuit& measureV(const cmat& V, idx target, idx c_reg,
1990  std::string name = "") {
1991  // EXCEPTION CHECKS
1992 
1993  try {
1994  // measuring non-existing qudit
1995  if (target >= nq_)
1996  throw exception::OutOfRange("qpp::QCircuit::measureV()");
1997  // trying to put the result into a non-existing classical slot
1998  if (c_reg >= nc_)
1999  throw exception::OutOfRange("qpp::QCircuit::measureV()");
2000  // qudit was measured before
2001  if (get_measured(target))
2002  throw exception::QuditAlreadyMeasured("qpp:QCircuit::measureV");
2003  } catch (exception::Exception&) {
2004  std::cerr << "At STEP " << get_step_count() << "\n";
2005  throw;
2006  }
2007  // END EXCEPTION CHECKS
2008 
2009  if (name == "")
2010  name = qpp::Gates::get_instance().get_name(V);
2011  measured_[target] = true;
2013  std::vector<std::size_t>{hash_eigen(V)},
2014  std::vector<idx>{target}, c_reg, name);
2016  ++measurement_count_[name];
2017 
2018  return *this;
2019  }
2020 
2021  // measurement of multiple qudits in the orthonormal basis or rank-1
2022  // projectors specified by the columns of matrix V
2035  QCircuit& measureV(const cmat& V, const std::vector<idx>& target, idx c_reg,
2036  std::string name = "") {
2037  // EXCEPTION CHECKS
2038 
2039  try {
2040  // check valid target
2041  if (target.size() == 0)
2042  throw exception::ZeroSize("qpp::QCircuit::measureV()");
2043  for (auto&& elem : target) {
2044  if (elem >= nq_)
2045  throw exception::OutOfRange("qpp::QCircuit::measureV()");
2046  // check target was not measured before
2047  if (get_measured(elem))
2049  "qpp::QCircuit::measureV()");
2050  }
2051  // check no duplicates target
2052  if (!internal::check_no_duplicates(target))
2053  throw exception::Duplicates("qpp::QCircuit::measureV()");
2054 
2055  // trying to put the result into a non-existing classical slot
2056  if (c_reg >= nc_)
2057  throw exception::OutOfRange("qpp::QCircuit::measureV()");
2058  // qudit was measured before
2059  for (auto&& elem : target)
2060  if (get_measured(elem))
2062  "qpp::QCircuit::measureV");
2063  } catch (exception::Exception&) {
2064  std::cerr << "At STEP " << get_step_count() << "\n";
2065  throw;
2066  }
2067  // END EXCEPTION CHECKS
2068 
2069  if (name == "")
2070  name = qpp::Gates::get_instance().get_name(V);
2071  for (auto&& elem : target)
2072  measured_[elem] = true;
2074  std::vector<std::size_t>{hash_eigen(V)},
2075  target, c_reg, name);
2077  ++measurement_count_[name];
2078 
2079  return *this;
2080  }
2081 
2091  std::string to_JSON(bool enclosed_in_curly_brackets = true) const override {
2092  std::string result;
2093 
2094  if (enclosed_in_curly_brackets)
2095  result += "{";
2096 
2097  result += "\"nq\" : " + std::to_string(nq_);
2098  result += ", \"nc\" : " + std::to_string(nc_);
2099  result += ", \"d\" : " + std::to_string(d_);
2100  result += ", \"name\" : \"" + name_ + "\"";
2101 
2102  bool is_first = true;
2103  std::ostringstream ss;
2104  result += ", \"steps\" : [";
2105  for (auto&& elem : *this) {
2106  if (is_first) {
2107  is_first = false;
2108  } else {
2109  result += ", ";
2110  }
2111  result += "{\"step\" : " + std::to_string(elem.ip_) + ", ";
2112  result += "\"type\" : ";
2113  // gate step
2114  if (elem.type_ == StepType::GATE) {
2115  idx pos = std::distance(std::begin(elem.value_type_qc_->gates_),
2116  elem.gates_ip_);
2117  ss.str("");
2118  ss.clear();
2119  ss << gates_[pos].gate_type_;
2120  result += "\"" + ss.str() + "\", ";
2121  if (gates_[pos].ctrl_.size() != 0) {
2122  ss.str("");
2123  ss.clear();
2124  ss << disp(gates_[pos].ctrl_, ", ");
2125  result += "\"ctrl\" : " + ss.str() + ", ";
2126  }
2127  ss.str("");
2128  ss.clear();
2129  ss << disp(gates_[pos].target_, ", ");
2130  result += "\"target\" : " + ss.str() + ", ";
2131  result += "\"name\" : ";
2132  result += "\"" + gates_[pos].name_ + "\"" + "}";
2133  }
2134  // measurement step
2135  else if (elem.type_ == StepType::MEASUREMENT) {
2136  idx pos = std::distance(
2137  std::begin(elem.value_type_qc_->measurements_),
2138  elem.measurements_ip_);
2139  ss.str("");
2140  ss.clear();
2141  ss << measurements_[pos].measurement_type_;
2142  result += "\"" + ss.str() + "\", ";
2143  ss.str("");
2144  ss.clear();
2145  ss << disp(measurements_[pos].target_, ", ");
2146  result += "\"target\" : " + ss.str() + ", ";
2147  result +=
2148  "\"c_reg\" : " + std::to_string(measurements_[pos].c_reg_) +
2149  ", ";
2150  result += "\"name\" : ";
2151  result += "\"" + measurements_[pos].name_ + "\"" + "}";
2152 
2153  }
2154  // otherwise
2155  else {
2156  }
2157  } // end for
2158  result += "], "; // end steps
2159 
2160  ss << get_gate_count();
2161  result += "\"gate count\" : " + std::to_string(get_gate_count()) + ", ";
2162 
2163  ss.str("");
2164  ss.clear();
2165  ss << disp(get_measured(), ", ");
2166  result += "\"measured positions\" : " + ss.str() + ", ";
2167 
2168  ss.str("");
2169  ss.clear();
2170  ss << disp(get_non_measured(), ", ");
2171  result += "\"non-measured positions\" : " + ss.str();
2172 
2173  if (enclosed_in_curly_brackets)
2174  result += "}";
2175 
2176  return result;
2177  } /* to_JSON() */
2178  private:
2188  std::ostream& display(std::ostream& os) const override {
2189  os << "nq = " << nq_ << ", nc = " << nc_ << ", d = " << d_;
2190 
2191  if (name_ != "") // if the circuit is named
2192  os << ", name = \"" << name_ << "\"\n";
2193  else
2194  os << ", name = \"\"\n";
2195 
2196  for (auto&& elem : *this) {
2197  os << elem << '\n';
2198  }
2199 
2200  os << "gate count: " << get_gate_count() << '\n';
2201  os << "measured positions: " << disp(get_measured(), ", ") << '\n';
2202  os << "non-measured positions: " << disp(get_non_measured(), ", ");
2203 
2204  return os;
2205  }
2206 }; /* class QCircuit */
2207 
2213 class QEngine : public IDisplay, public IJSON {
2214  protected:
2215  const QCircuit* qc_;
2217  std::vector<idx> dits_;
2218  std::vector<double> probs_;
2219  std::vector<idx> subsys_;
2220 
2227  void set_measured_(idx i) {
2228  if (get_measured(i))
2230  "qpp::QEngine::set_measured_()");
2231  subsys_[i] = static_cast<idx>(-1); // set qudit i to measured state
2232  for (idx m = i; m < qc_->get_nq(); ++m) {
2233  if (!get_measured(m)) {
2234  --subsys_[m];
2235  }
2236  }
2237  }
2238 
2239  // giving a vector of non-measured qudits, get their relative position wrt
2240  // the measured qudits
2247  std::vector<idx> get_relative_pos_(std::vector<idx> v) {
2248  idx vsize = v.size();
2249  for (idx i = 0; i < vsize; ++i) {
2250  if (get_measured(v[i]))
2252  "qpp::QEngine::get_relative_pos_()");
2253  v[i] = subsys_[v[i]];
2254  }
2255  return v;
2256  }
2257 
2258  public:
2270  explicit QEngine(const QCircuit& qc)
2271  : qc_{std::addressof(qc)}, psi_{States::get_instance().zero(
2272  qc.get_nq(), qc.get_d())},
2273  dits_(qc.get_nc(), 0), probs_(qc.get_nc(), 0),
2274  subsys_(qc.get_nq(), 0) {
2275  std::iota(std::begin(subsys_), std::end(subsys_), 0);
2276  }
2277 
2278  // silence -Weffc++ class has pointer data members
2282  QEngine(const QEngine&) = default;
2283 
2284  // silence -Weffc++ class has pointer data members
2290  QEngine& operator=(const QEngine&) = default;
2291 
2295  QEngine(QCircuit&&) = delete;
2296 
2300  virtual ~QEngine() = default;
2301 
2302  // getters
2308  ket get_psi() const { return psi_; }
2309 
2315  ket& get_ref_psi() { return psi_; }
2316 
2322  std::vector<idx> get_dits() const { return dits_; }
2323 
2331  idx get_dit(idx i) const {
2332  if (i > qc_->get_nc())
2333  throw exception::OutOfRange("qpp::QEngine::get_dit()");
2334 
2335  return dits_[i];
2336  }
2337 
2348  std::vector<double> get_probs() const { return probs_; }
2349 
2356  bool get_measured(idx i) const {
2357  return subsys_[i] == static_cast<idx>(-1);
2358  }
2359 
2365  std::vector<idx> get_measured() const {
2366  std::vector<idx> result;
2367  for (idx i = 0; i < qc_->get_nq(); ++i)
2368  if (get_measured(i))
2369  result.emplace_back(i);
2370 
2371  return result;
2372  }
2373 
2379  std::vector<idx> get_not_measured() const {
2380  std::vector<idx> result;
2381  for (idx i = 0; i < qc_->get_nq(); ++i)
2382  if (!get_measured(i))
2383  result.emplace_back(i);
2384 
2385  return result;
2386  }
2387 
2393  const QCircuit& get_circuit() const noexcept { return *qc_; }
2394  // end getters
2395 
2396  // setters
2404  QEngine& set_dit(idx i, idx value) {
2405  if (i > qc_->get_nc())
2406  throw exception::OutOfRange("qpp::QEngine::set_dit()");
2407  dits_[i] = value;
2408 
2409  return *this;
2410  }
2411  // end setters
2412 
2419  void reset() {
2421  dits_ = std::vector<idx>(qc_->get_nc(), 0);
2422  probs_ = std::vector<double>(qc_->get_nc(), 0);
2423  std::iota(std::begin(subsys_), std::end(subsys_), 0);
2424  }
2425 
2432  // EXCEPTION CHECKS
2433 
2434  // iterator must point to the same quantum circuit
2435  if (elem.value_type_qc_ != qc_)
2436  throw exception::InvalidIterator("qpp::QEngine::execute()");
2437  // the rest of exceptions are caught by the iterator::operator*()
2438  // END EXCEPTION CHECKS
2439 
2440  auto h_tbl = qc_->get_cmat_hash_tbl_();
2441 
2442  // gate step
2443  if (elem.type_ == QCircuit::StepType::GATE) {
2444  auto gates = qc_->get_gates_();
2445 
2446  idx q_ip =
2447  std::distance(std::begin(qc_->get_gates_()), elem.gates_ip_);
2448 
2449  std::vector<idx> ctrl_rel_pos;
2450  std::vector<idx> target_rel_pos =
2451  get_relative_pos_(gates[q_ip].target_);
2452 
2453  switch (gates[q_ip].gate_type_) {
2455  break;
2460  psi_ = apply(psi_, h_tbl[gates[q_ip].gate_hash_],
2461  target_rel_pos, qc_->get_d());
2462  break;
2464  for (idx m = 0; m < gates[q_ip].target_.size(); ++m)
2465  psi_ = apply(psi_, h_tbl[gates[q_ip].gate_hash_],
2466  {target_rel_pos[m]}, qc_->get_d());
2467  break;
2475  ctrl_rel_pos = get_relative_pos_(gates[q_ip].ctrl_);
2476  psi_ = applyCTRL(psi_, h_tbl[gates[q_ip].gate_hash_],
2477  ctrl_rel_pos, target_rel_pos, qc_->get_d());
2478  break;
2484  if (dits_.size() == 0) {
2485  psi_ = apply(psi_, h_tbl[gates[q_ip].gate_hash_],
2486  target_rel_pos, qc_->get_d());
2487  } else {
2488  bool should_apply = true;
2489  idx first_dit = dits_[(gates[q_ip].ctrl_)[0]];
2490  for (idx m = 0; m < gates[q_ip].ctrl_.size(); ++m) {
2491  if (dits_[(gates[q_ip].ctrl_)[m]] != first_dit) {
2492  should_apply = false;
2493  break;
2494  }
2495  }
2496  if (should_apply) {
2497  psi_ = apply(
2498  psi_,
2499  powm(h_tbl[gates[q_ip].gate_hash_], first_dit),
2500  target_rel_pos, qc_->get_d());
2501  }
2502  }
2503  break;
2504  } // end switch on gate type
2505  } // end if gate step
2506  // measurement step
2507  else if (elem.type_ == QCircuit::StepType::MEASUREMENT) {
2508  auto measurements = qc_->get_measurements_();
2509  idx m_ip = std::distance(std::begin(qc_->get_measurements_()),
2510  elem.measurements_ip_);
2511 
2512  std::vector<idx> target_rel_pos =
2513  get_relative_pos_(measurements[m_ip].target_);
2514 
2515  std::vector<idx> resZ;
2516  double probZ;
2517 
2518  idx mres = 0;
2519  std::vector<double> probs;
2520  std::vector<cmat> states;
2521 
2522  switch (measurements[m_ip].measurement_type_) {
2524  break;
2526  std::tie(resZ, probZ, psi_) =
2527  measure_seq(psi_, target_rel_pos, qc_->get_d());
2528  dits_[measurements[m_ip].c_reg_] = resZ[0];
2529  probs_[measurements[m_ip].c_reg_] = probZ;
2530  set_measured_(measurements[m_ip].target_[0]);
2531  break;
2533  std::tie(mres, probs, states) =
2534  measure(psi_, h_tbl[measurements[m_ip].mats_hash_[0]],
2535  target_rel_pos, qc_->get_d());
2536  psi_ = states[mres];
2537  dits_[measurements[m_ip].c_reg_] = mres;
2538  probs_[measurements[m_ip].c_reg_] = probs[mres];
2539  set_measured_(measurements[m_ip].target_[0]);
2540  break;
2542  std::tie(mres, probs, states) =
2543  measure(psi_, h_tbl[measurements[m_ip].mats_hash_[0]],
2544  target_rel_pos, qc_->get_d());
2545  psi_ = states[mres];
2546  dits_[measurements[m_ip].c_reg_] = mres;
2547  probs_[measurements[m_ip].c_reg_] = probs[mres];
2548  for (auto&& elem : measurements[m_ip].target_)
2549  set_measured_(elem);
2550  break;
2551  } // end switch on measurement type
2552  } // end else if measurement step
2553  // otherwise
2554  else {
2555  }
2556  }
2557 
2563  void execute(const QCircuit::iterator& it) { execute(*it); }
2564 
2575  std::string to_JSON(bool enclosed_in_curly_brackets = true) const override {
2576  std::string result;
2577 
2578  if (enclosed_in_curly_brackets)
2579  result += "{";
2580 
2581  std::ostringstream ss;
2582 
2583  result += "\"measured\" : ";
2584  ss << disp(get_measured(), ", ");
2585  result += ss.str();
2586 
2587  ss.str("");
2588  ss.clear();
2589  result += ", \"dits\" : ";
2590  ss << disp(get_dits(), ", ");
2591  result += ss.str();
2592 
2593  ss.str("");
2594  ss.clear();
2595  result += ", \"probs\" : ";
2596  ss << disp(get_probs(), ", ");
2597  result += ss.str();
2598 
2599  if (enclosed_in_curly_brackets)
2600  result += "}";
2601 
2602  return result;
2603  }
2604 
2605  private:
2615  std::ostream& display(std::ostream& os) const override {
2616  os << "measured: " << disp(get_measured(), ", ") << '\n';
2617  os << "dits: " << disp(get_dits(), ", ") << '\n';
2618  os << "probs: " << disp(get_probs(), ", ");
2619 
2620  return os;
2621  }
2622 }; /* class QEngine */
2623 
2624 } /* namespace qpp */
2625 
2626 #endif /* CLASSES_CIRCUITS_H_ */
std::vector< GateStep > gates_
gates
Definition: circuits.h:364
virtual ~QEngine()=default
Default virtual destructor.
idx get_gate_depth(const std::string &name QPP_UNUSED_) const
Quantum circuit gate depth.
Definition: circuits.h:874
Dimension(s) mismatch matrix size exception.
Definition: exception.h:300
unitary gate on 3 qudits
QCircuit & gate(const cmat &U, idx i, std::string name="")
Applies the single qudit gate U on single qudit i.
Definition: circuits.h:929
Invalid iterator.
Definition: exception.h:629
idx get_gate_count() const noexcept
Quantum circuit total gate count.
Definition: circuits.h:830
same unitary gate on multiple qudits
unitary gate on a single qudit
const QCircuit & get_circuit() const noexcept
Quantum circuit.
Definition: circuits.h:2393
QCircuit & measureV(const cmat &V, const std::vector< idx > &target, idx c_reg, std::string name="")
Joint measurement of multiple qudits in the orthonormal basis or rank-1 projectors specified by the c...
Definition: circuits.h:2035
ket get_psi() const
Underlying quantum state.
Definition: circuits.h:2308
ket zero(idx n, idx d=2) const
Zero state of n qudits.
Definition: states.h:121
std::vector< idx > get_dits() const
Vector with the values of the underlying classical dits.
Definition: circuits.h:2322
System (e.g. std::vector) has duplicates exception.
Definition: exception.h:585
QCircuit & CTRL(const cmat &U, idx ctrl, const std::vector< idx > &target, std::string name="")
Applies the single qudit controlled gate U with control qudit ctrl on every qudit listed in target...
Definition: circuits.h:1338
std::vector< idx > get_not_measured() const
Vector of non-measured qudit indexes.
Definition: circuits.h:2379
void set_end_(const QCircuit *qc)
Sets the iterator to std::begin(this)
Definition: circuits.h:631
MeasureType
Type of measurement being executed in a measurement step.
Definition: circuits.h:261
const_iterator cbegin() const noexcept
Constant iterator to the first element.
Definition: circuits.h:683
idx c_reg_
Definition: circuits.h:311
std::vector< idx > ctrl_
control
Definition: circuits.h:215
const QCircuit * qc_
pointer to constant quantum circuit
Definition: circuits.h:2215
QCircuit & TFQ(const std::vector< idx > &target, bool swap QPP_UNUSED_=true)
Applies the inverse quantum Fourier transform (as a series of gates) on the qudit indexes specified b...
Definition: circuits.h:1260
idx get_step_count() const noexcept
Quantum circuit total steps count, i.e. the sum of gate count and measurement count.
Definition: circuits.h:918
QEngine & operator=(const QEngine &)=default
Default copy assignment operator.
Custom exception.
Definition: exception.h:600
Qudit was already measured exception.
Definition: exception.h:571
std::vector< MeasureStep > measurements_
measurements
Definition: circuits.h:365
quantum inverse Fourier transform,
std::size_t gate_hash_
gate hash
Definition: circuits.h:214
std::string get_name() const
Quantum circuit name.
Definition: circuits.h:780
custom gate on multiple qudits
bool get_measured(idx i) const
Check whether qudit i was already measured.
Definition: circuits.h:2356
QCircuit & gate(const cmat &U, idx i, idx j, std::string name="")
Applies the two qudit gate U on qudits i and j.
Definition: circuits.h:973
std::vector< std::size_t > mats_hash_
Definition: circuits.h:308
friend std::ostream & operator<<(std::ostream &os, const MeasureType &measure_type)
Extraction operator overload for qpp::QCircuit::MeasureType enum class.
Definition: circuits.h:283
Definition: circuits.h:404
value_type_ elem_
Definition: circuits.h:480
idx ip_
instruction pointer
Definition: circuits.h:410
QCircuit & cCTRL(const cmat &U, const std::vector< idx > &ctrl_dits, const std::vector< idx > &target, std::string name="")
Applies the single qudit controlled gate U with multiple classical control dits listed in ctrl on eve...
Definition: circuits.h:1803
bool check_no_duplicates(std::vector< idx > v)
Definition: util.h:210
std::unordered_map< std::string, idx > measurement_count_
keeps track of the measurement counts
Definition: circuits.h:57
Eigen::VectorXcd ket
Complex (double precision) dynamic Eigen column vector.
Definition: types.h:54
std::vector< idx > subsys_
Definition: circuits.h:2219
std::vector< idx > target_
target where the gate is applied
Definition: circuits.h:216
GateStep()=default
Default constructor.
idx get_dit(idx i) const
Value of the classical dit at position i.
Definition: circuits.h:2331
const std::unordered_map< std::size_t, cmat > & get_cmat_hash_tbl_() const noexcept
Hash table with the matrices used in the circuit.
Definition: circuits.h:389
Quantum++ main namespace.
Definition: circuits.h:35
friend std::ostream & operator<<(std::ostream &os, const MeasureStep &measure_step)
Extraction operator overload for qpp::QCircuit::MeasureStep class.
Definition: circuits.h:343
const QCircuit * qc_
< non-owning pointer to const quantum circuit
Definition: circuits.h:402
const idx d_
qudit dimension
Definition: circuits.h:45
Code not yet implemented.
Definition: exception.h:616
StepType
Types of each step in the quantum circuit.
Definition: circuits.h:357
QCircuit & CTRL_custom(const cmat &U, const std::vector< idx > &ctrl, const std::vector< idx > &target, std::string name="")
Jointly applies the custom multiple-qudit controlled gate U with multiple control qudits listed in ct...
Definition: circuits.h:1552
const_iterator begin() const noexcept
Constant iterator to the first element.
Definition: circuits.h:671
std::vector< idx > get_measured() const
Vector of already measured qudit indexes.
Definition: circuits.h:2365
std::ostream & display(std::ostream &os) const override
qpp::IDisplay::display() override
Definition: circuits.h:2188
idx get_gate_count(const std::string &name) const
Quantum circuit gate count.
Definition: circuits.h:844
const value_type_ & operator*() const
Safe de-referencing operator.
Definition: circuits.h:593
QCircuit & gate(const cmat &U, idx i, idx j, idx k, std::string name="")
Applies the three qudit gate U on qudits i, j and k.
Definition: circuits.h:1017
Abstract class (interface) that mandates the definition of very basic JSON serialization support...
Definition: idisplay.h:106
idx get_measurement_count() const noexcept
Quantum circuit total measurement count.
Definition: circuits.h:883
iterator operator++(int)
Postfix increment operator.
Definition: circuits.h:560
std::string name_
optional circuit name
Definition: circuits.h:46
bool operator!=(iterator rhs) const
Inequality operator.
Definition: circuits.h:586
void set_measured_(idx i)
Marks qudit i as measured then re-label accordingly the remaining non-measured qudits.
Definition: circuits.h:2227
One step consisting only of measurements in the circuit.
Definition: circuits.h:306
QCircuit & measureV(const cmat &V, idx target, idx c_reg, std::string name="")
Measurement of single qudit in the orthonormal basis or rank-1 projectors specified by the columns of...
Definition: circuits.h:1989
iterator begin()
Iterator to the first element.
Definition: circuits.h:659
QCircuit & cCTRL(const cmat &U, idx ctrl_dit, idx target, std::string name="")
Applies the single qubit controlled gate U with classical control dit ctrl and target qudit target...
Definition: circuits.h:1632
dyn_mat< typename Derived1::Scalar > apply(const Eigen::MatrixBase< Derived1 > &state, const Eigen::MatrixBase< Derived2 > &A, const std::vector< idx > &target, const std::vector< idx > &dims)
Applies the gate A to the part target of the multi-partite state vector or density matrix state...
Definition: operations.h:444
QCircuit & cCTRL(const cmat &U, const std::vector< idx > &ctrl_dits, idx target, std::string name="")
Applies the single qudit controlled gate U with multiple classical control dits listed in ctrl on the...
Definition: circuits.h:1743
StepType type_
step type
Definition: circuits.h:409
std::vector< GateStep >::const_iterator gates_ip_
gates instruction pointer
Definition: circuits.h:412
Quantum circuit engine, executes qpp::QCircuit.
Definition: circuits.h:2213
value_type_(const QCircuit *value_type_qc)
Default value_type_ constructor.
Definition: circuits.h:421
dyn_mat< typename Derived1::Scalar > applyCTRL(const Eigen::MatrixBase< Derived1 > &state, const Eigen::MatrixBase< Derived2 > &A, const std::vector< idx > &ctrl, const std::vector< idx > &target, const std::vector< idx > &dims)
Applies the controlled-gate A to the part target of the multi-partite state vector or density matrix ...
Definition: operations.h:55
std::string to_JSON(bool enclosed_in_curly_brackets=true) const override
qpp::IJOSN::to_JSON() override
Definition: circuits.h:2575
QCircuit & gate_fan(const cmat &U, const std::vector< idx > &target, std::string name="")
Applies the single qudit gate U on every qudit listed in target.
Definition: circuits.h:1062
value_type_ & operator=(const value_type_ &)=default
Default copy assignment operator.
std::unordered_map< std::string, idx > count_
keeps track of the gate counts
Definition: circuits.h:53
Functor for comparing Eigen expressions for equality.
Definition: functions.h:2013
QCircuit & gate_fan(const cmat &U, std::string name="")
Applies the single qudit gate U on every remaining non-measured qudit.
Definition: circuits.h:1133
std::tuple< idx, std::vector< double >, std::vector< cmat > > measure(const Eigen::MatrixBase< Derived > &A, const std::vector< cmat > &Ks)
Measures the state vector or density operator A using the set of Kraus operators Ks.
Definition: instruments.h:206
MeasureStep(MeasureType measurement_type, const std::vector< std::size_t > &mats_hash, const std::vector< idx > &target, idx c_reg, std::string name="")
Constructs a measurement step instance.
Definition: circuits.h:328
void set_begin_(const QCircuit *qc)
Sets the iterator to std::begin(this)
Definition: circuits.h:611
void execute(const QCircuit::iterator::value_type &elem)
Executes one step in the quantum circuit.
Definition: circuits.h:2431
quantum Fourier transform,
Abstract class (interface) that mandates the definition of virtual std::ostream& display(std::ostream...
Definition: idisplay.h:47
const std::vector< MeasureStep > & get_measurements_() const noexcept
Vector of qpp::QCircuit::MeasureStep.
Definition: circuits.h:373
std::size_t hash_eigen(const Eigen::MatrixBase< Derived > &A, std::size_t seed=0)
Computes the hash of en Eigen matrix/vector/expression.
Definition: functions.h:1973
std::unordered_map< std::string, idx > depth_
keeps track of the gate depths
Definition: circuits.h:55
bool operator==(const iterator &rhs) const
Equality operator.
Definition: circuits.h:572
idx get_nc() const noexcept
Total number of classical dits in the circuit.
Definition: circuits.h:766
Quantum circuit bound-checking (safe) iterator.
Definition: circuits.h:400
std::string to_JSON(bool enclosed_in_curly_brackets=true) const override
qpp::IJOSN::to_JSON() override
Definition: circuits.h:2091
std::vector< idx > target_
target where the measurement is applied
Definition: circuits.h:310
iterator & operator=(const iterator &)=default
Default copy assignment operator.
idx get_measured(idx i) const
Check whether qudit i was already measured.
Definition: circuits.h:787
virtual ~QCircuit()=default
Default virtual destructor.
QCircuit & cCTRL_custom(const cmat &U, const std::vector< idx > &ctrl_dits, const std::vector< idx > &target, std::string name="")
Jointly applies the custom multiple-qudit controlled gate U with multiple classical control dits list...
Definition: circuits.h:1871
std::vector< idx > get_non_measured() const
Vector of non-measured qudit indexes.
Definition: circuits.h:816
Quantum circuit class.
Definition: circuits.h:41
iterator end()
Iterator to the next to the last element.
Definition: circuits.h:695
idx get_measurement_count(const std::string &name) const
Quantum circuit measurement count.
Definition: circuits.h:897
void execute(const QCircuit::iterator &it)
Executes one step in the quantum circuit.
Definition: circuits.h:2563
const std::vector< GateStep > & get_gates_() const noexcept
Vector of qpp::QCircuit::GateStep.
Definition: circuits.h:382
dyn_mat< typename Derived::Scalar > powm(const Eigen::MatrixBase< Derived > &A, idx n)
Fast matrix power based on the SQUARE-AND-MULTIPLY algorithm.
Definition: functions.h:800
ket psi_
state vector
Definition: circuits.h:2216
void reset()
Resets the engine.
Definition: circuits.h:2419
std::unordered_map< std::size_t, cmat > cmat_hash_tbl_
Definition: circuits.h:50
const_iterator cend() const noexcept
Constant iterator to the next to the last element.
Definition: circuits.h:719
MeasureType measurement_type_
measurement type
Definition: circuits.h:307
GateType gate_type_
gate type
Definition: circuits.h:213
QCircuit & CTRL(const cmat &U, const std::vector< idx > &ctrl, idx target, std::string name="")
Applies the single qudit controlled gate U with multiple control qudits listed in ctrl on the target ...
Definition: circuits.h:1406
QCircuit & QFT(const std::vector< idx > &target, bool swap QPP_UNUSED_=true)
Applies the quantum Fourier transform (as a series of gates) on the qudit indexes specified by target...
Definition: circuits.h:1231
bool check_square_mat(const Eigen::MatrixBase< Derived > &A)
Definition: util.h:99
Z measurement of single qudit.
QEngine & set_dit(idx i, idx value)
Sets the classical dit at position i.
Definition: circuits.h:2404
const_iterator end() const noexcept
Constant iterator to the next to the last element.
Definition: circuits.h:707
std::string get_name(const cmat &U) const
Get the name of the most common qubit gates.
Definition: gates.h:663
iterator()=default
Default constructor.
std::ostream & display(std::ostream &os) const override
qpp::IDisplay::display() override
Definition: circuits.h:448
QEngine(const QCircuit &qc)
Constructs a quantum engine out of a quantum circuit.
Definition: circuits.h:2270
iterator & operator++()
Prefix increment operator.
Definition: circuits.h:507
idx get_gate_depth() const
Quantum circuit total gate depth.
Definition: circuits.h:864
GateStep(GateType gate_type, std::size_t gate_hash, const std::vector< idx > &ctrl, const std::vector< idx > &target, std::string name="")
Constructs a gate step instance.
Definition: circuits.h:232
std::vector< idx > dits_
classical dits
Definition: circuits.h:2217
Argument out of range exception.
Definition: exception.h:515
QCircuit & gate_fan(const cmat &U, const std::initializer_list< idx > &target, std::string name="")
Applies the single qudit gate U on every qudit listed in target.
Definition: circuits.h:1120
GateType
Type of gate being executed in a gate step.
Definition: circuits.h:87
void add_hash_(const cmat &U, std::size_t hashU)
Adds matrix to the hash table.
Definition: circuits.h:67
static const Gates & get_instance() noexcept(std::is_nothrow_constructible< const Gates >::value)
Definition: singleton.h:92
std::ostream & display(std::ostream &os) const override
qpp::IDisplay::display() override
Definition: circuits.h:2615
std::string name_
custom name of the step
Definition: circuits.h:313
std::vector< double > probs_
measurement probabilities
Definition: circuits.h:2218
std::forward_iterator_tag iterator_category
iterator trait
Definition: circuits.h:649
Eigen::MatrixXcd cmat
Complex (double precision) dynamic Eigen matrix.
Definition: types.h:64
const idx nq_
number of qudits
Definition: circuits.h:43
std::tuple< std::vector< idx >, double, cmat > measure_seq(const Eigen::MatrixBase< Derived > &A, std::vector< idx > target, std::vector< idx > dims)
Sequentially measures the part target of the multi-partite state vector or density matrix A in the co...
Definition: instruments.h:697
QCircuit & CTRL(const cmat &U, const std::vector< idx > &ctrl, const std::vector< idx > &target, std::string name="")
Applies the single qudit controlled gate U with multiple control qudits listed in ctrl on every qudit...
Definition: circuits.h:1474
const idx nc_
number of classical "dits"
Definition: circuits.h:44
std::vector< double > get_probs() const
Vector of underlying measurement outcome probabilities.
Definition: circuits.h:2348
friend std::ostream & operator<<(std::ostream &os, const GateType &gate_type)
Extraction operator overload for qpp::QCircuit::GateType enum class.
Definition: circuits.h:147
One step consisting only of gates/operators in the circuit.
Definition: circuits.h:212
represents no measurement
unitary gate on 2 qudits
std::vector< idx > get_relative_pos_(std::vector< idx > v)
Giving a vector V of non-measured qudits, get their relative position with respect to the measured qu...
Definition: circuits.h:2247
idx get_nq() const noexcept
Total number of qudits in the circuit.
Definition: circuits.h:759
std::size_t idx
Non-negative integer index, make sure you use an unsigned type.
Definition: types.h:39
std::vector< MeasureStep >::const_iterator measurements_ip_
measurements instruction pointer
Definition: circuits.h:414
idx get_d() const noexcept
Dimension of the comprising qudits.
Definition: circuits.h:773
Matrix is not square exception.
Definition: exception.h:149
friend std::ostream & operator<<(std::ostream &os, const GateStep &gate_step)
Extraction operator overload for qpp::QCircuit::GateStep class.
Definition: circuits.h:247
ket & get_ref_psi()
Reference to the underlying quantum state.
Definition: circuits.h:2315
QCircuit & CTRL(const cmat &U, idx ctrl, idx target, std::string name="")
Applies the single qudit controlled gate U with control qudit ctrl and target qudit target...
Definition: circuits.h:1289
QCircuit & cCTRL(const cmat &U, idx ctrl_dit, const std::vector< idx > &target, std::string name="")
Applies the single qudit controlled gate U with classical control dit ctrl on every qudit listed in t...
Definition: circuits.h:1682
std::vector< idx > get_measured() const
Vector of already measured qudit indexes.
Definition: circuits.h:802
QCircuit & gate_custom(const cmat &U, const std::vector< idx > &target, std::string name="")
Jointly applies the custom multiple qudit gate U on the qudit indexes specified by target...
Definition: circuits.h:1172
long long difference_type
iterator trait
Definition: circuits.h:645
MeasureStep()=default
Default constructor.
QCircuit(idx nq, idx nc=0, idx d=2, std::string name="")
Constructs a quantum circuit.
Definition: circuits.h:737
std::string name_
custom name of the step
Definition: circuits.h:217
std::vector< bool > measured_
keeps track of the measured qudits
Definition: circuits.h:47
QCircuit & measureZ(idx target, idx c_reg, std::string name="")
Measurement of single qudit in the computational basis (Z-basis)
Definition: circuits.h:1944
internal::IOManipEigen disp(const Eigen::MatrixBase< Derived > &A, double chop=qpp::chop)
Eigen expression ostream manipulator.
Definition: input_output.h:44
Base class for generating Quantum++ custom exceptions.
Definition: exception.h:71
const QCircuit * value_type_qc_
< non-owning pointer to the parent iterator
Definition: circuits.h:407
Object has zero size exception.
Definition: exception.h:134
std::vector< StepType > step_types_
type of each step
Definition: circuits.h:366