32 #ifndef CLASSES_CIRCUITS_ENGINES_H_ 33 #define CLASSES_CIRCUITS_ENGINES_H_ 41 class QEngine :
public IDisplay,
public IJSON {
53 std::vector<double> probs_{};
54 std::vector<idx> dits_{};
55 std::vector<idx> subsys_{};
64 explicit state_(
const QCircuit* qc) : qc_{qc} {
67 if (qc->get_nq() == 0)
68 throw exception::ZeroSize(
"qpp::QEngine::state_::reset()");
77 state_(
const state_&) =
default;
85 state_& operator=(
const state_&) =
default;
91 psi_ = States::get_instance().zero(qc_->get_nq(), qc_->get_d());
92 probs_ = std::vector<double>(qc_->get_nc(), 0);
93 dits_ = std::vector<idx>(qc_->get_nc(), 0);
94 subsys_ = std::vector<idx>(qc_->get_nq(), 0);
95 std::iota(std::begin(subsys_), std::end(subsys_), 0);
98 std::map<std::string, idx, internal::EqualSameSizeStringDits>
106 void set_measured_(idx i) {
108 throw exception::QuditAlreadyMeasured(
109 "qpp::QEngine::set_measured_()");
110 st_.subsys_[i] =
static_cast<idx
>(-1);
111 for (idx m = i; m < qc_->get_nq(); ++m) {
112 if (!get_measured(m)) {
127 std::vector<idx> get_relative_pos_(std::vector<idx> v) {
128 idx vsize = v.size();
129 for (idx i = 0; i < vsize; ++i) {
130 if (get_measured(v[i]))
131 throw exception::QuditAlreadyMeasured(
132 "qpp::QEngine::get_relative_pos_()");
133 v[i] = st_.subsys_[v[i]];
150 explicit QEngine(
const QCircuit& qc)
151 : qc_{std::addressof(qc)}, st_{qc_}, stats_{} {}
157 QEngine(
const QEngine&) =
default;
165 QEngine& operator=(
const QEngine&) =
default;
170 QEngine(QCircuit&&) =
delete;
175 virtual ~QEngine() =
default;
183 ket get_psi()
const {
return st_.psi_; }
190 std::vector<idx> get_dits()
const {
return st_.dits_; }
198 idx get_dit(idx i)
const {
199 if (i >= qc_->get_nc())
200 throw exception::OutOfRange(
"qpp::QEngine::get_dit()");
225 std::vector<double> get_probs()
const {
return st_.probs_; }
233 bool get_measured(idx i)
const {
234 return st_.subsys_[i] ==
static_cast<idx
>(-1);
242 std::vector<idx> get_measured()
const {
243 std::vector<idx> result;
244 for (idx i = 0; i < qc_->get_nq(); ++i)
246 result.emplace_back(i);
256 std::vector<idx> get_non_measured()
const {
257 std::vector<idx> result;
258 for (idx i = 0; i < qc_->get_nq(); ++i)
259 if (!get_measured(i))
260 result.emplace_back(i);
270 const QCircuit& get_circuit() const& noexcept {
return *qc_; }
277 QCircuit get_circuit() const&& noexcept {
return *qc_; }
288 std::map<std::string, idx, internal::EqualSameSizeStringDits>
302 QEngine& set_dit(idx i, idx value) {
303 if (i >= qc_->get_nc())
304 throw exception::OutOfRange(
"qpp::QEngine::set_dit()");
305 st_.dits_[i] = value;
319 QEngine& set_psi(
const ket& psi) {
322 idx n = get_non_measured().size();
323 idx D =
static_cast<idx
>(std::llround(std::pow(qc_->get_d(), n)));
324 if (static_cast<idx>(psi.rows()) != D)
325 throw exception::DimsNotEqual(
"qpp::QEngine::set_psi()");
339 QEngine& reset_stats() {
368 virtual QEngine& execute(
const QCircuit::iterator::value_type& elem) {
372 if (elem.value_type_qc_ != qc_)
373 throw exception::InvalidIterator(
"qpp::QEngine::execute()");
377 auto h_tbl = qc_->get_cmat_hash_tbl_();
378 idx d = qc_->get_d();
381 if (elem.type_ == QCircuit::StepType::GATE) {
382 auto gates = qc_->get_gates_();
385 std::distance(std::begin(qc_->get_gates_()), elem.gates_ip_);
387 std::vector<idx> ctrl_rel_pos;
388 std::vector<idx> target_rel_pos =
389 get_relative_pos_(gates[q_ip].target_);
391 switch (gates[q_ip].gate_type_) {
392 case QCircuit::GateType::NONE:
394 case QCircuit::GateType::SINGLE:
395 case QCircuit::GateType::TWO:
396 case QCircuit::GateType::THREE:
397 case QCircuit::GateType::CUSTOM:
398 st_.psi_ = apply(st_.psi_, h_tbl[gates[q_ip].gate_hash_],
401 case QCircuit::GateType::FAN:
402 for (idx m = 0; m < gates[q_ip].target_.size(); ++m)
404 apply(st_.psi_, h_tbl[gates[q_ip].gate_hash_],
405 {target_rel_pos[m]}, d);
407 case QCircuit::GateType::SINGLE_CTRL_SINGLE_TARGET:
408 case QCircuit::GateType::SINGLE_CTRL_MULTIPLE_TARGET:
409 case QCircuit::GateType::MULTIPLE_CTRL_SINGLE_TARGET:
410 case QCircuit::GateType::MULTIPLE_CTRL_MULTIPLE_TARGET:
411 case QCircuit::GateType::CUSTOM_CTRL:
412 ctrl_rel_pos = get_relative_pos_(gates[q_ip].ctrl_);
413 st_.psi_ = applyCTRL(
414 st_.psi_, h_tbl[gates[q_ip].gate_hash_], ctrl_rel_pos,
415 target_rel_pos, d, gates[q_ip].shift_);
417 case QCircuit::GateType::SINGLE_cCTRL_SINGLE_TARGET:
418 case QCircuit::GateType::SINGLE_cCTRL_MULTIPLE_TARGET:
419 case QCircuit::GateType::MULTIPLE_cCTRL_SINGLE_TARGET:
420 case QCircuit::GateType::MULTIPLE_cCTRL_MULTIPLE_TARGET:
421 case QCircuit::GateType::CUSTOM_cCTRL:
422 if (st_.dits_.empty()) {
424 apply(st_.psi_, h_tbl[gates[q_ip].gate_hash_],
427 bool should_apply =
true;
430 if (!gates[q_ip].shift_.empty()) {
431 first_dit = (st_.dits_[(gates[q_ip].ctrl_)[0]] +
432 gates[q_ip].shift_[0]) %
434 for (idx m = 1; m < gates[q_ip].ctrl_.size(); ++m) {
435 if ((st_.dits_[(gates[q_ip].ctrl_)[m]] +
436 gates[q_ip].shift_[m]) %
439 should_apply =
false;
446 first_dit = st_.dits_[(gates[q_ip].ctrl_)[0]];
447 for (idx m = 1; m < gates[q_ip].ctrl_.size(); ++m) {
448 if (st_.dits_[(gates[q_ip].ctrl_)[m]] !=
450 should_apply =
false;
458 powm(h_tbl[gates[q_ip].gate_hash_], first_dit),
467 else if (elem.type_ == QCircuit::StepType::MEASUREMENT) {
468 auto measurements = qc_->get_measurements_();
469 idx m_ip = std::distance(std::begin(qc_->get_measurements_()),
470 elem.measurements_ip_);
472 std::vector<idx> target_rel_pos =
473 get_relative_pos_(measurements[m_ip].target_);
475 std::vector<idx> resZ;
479 std::vector<double> probs;
480 std::vector<cmat> states;
482 switch (measurements[m_ip].measurement_type_) {
483 case QCircuit::MeasureType::NONE:
485 case QCircuit::MeasureType::MEASURE_Z:
486 std::tie(resZ, probZ, st_.psi_) =
487 measure_seq(st_.psi_, target_rel_pos, d);
488 st_.dits_[measurements[m_ip].c_reg_] = resZ[0];
489 st_.probs_[measurements[m_ip].c_reg_] = probZ;
490 set_measured_(measurements[m_ip].target_[0]);
492 case QCircuit::MeasureType::MEASURE_Z_MANY:
493 std::tie(resZ, probZ, st_.psi_) =
494 measure_seq(st_.psi_, target_rel_pos, d);
495 st_.dits_[measurements[m_ip].c_reg_] = multiidx2n(
496 resZ, std::vector<idx>(target_rel_pos.size(), d));
497 st_.probs_[measurements[m_ip].c_reg_] = probZ;
498 for (
auto&& elem : measurements[m_ip].target_)
501 case QCircuit::MeasureType::MEASURE_V:
502 std::tie(mres, probs, states) = measure(
503 st_.psi_, h_tbl[measurements[m_ip].mats_hash_[0]],
505 st_.psi_ = states[mres];
506 st_.dits_[measurements[m_ip].c_reg_] = mres;
507 st_.probs_[measurements[m_ip].c_reg_] = probs[mres];
508 set_measured_(measurements[m_ip].target_[0]);
510 case QCircuit::MeasureType::MEASURE_V_MANY:
511 std::tie(mres, probs, states) = measure(
512 st_.psi_, h_tbl[measurements[m_ip].mats_hash_[0]],
514 st_.psi_ = states[mres];
515 st_.dits_[measurements[m_ip].c_reg_] = mres;
516 st_.probs_[measurements[m_ip].c_reg_] = probs[mres];
517 for (
auto&& elem : measurements[m_ip].target_)
520 case QCircuit::MeasureType::MEASURE_Z_ND:
521 std::tie(resZ, probZ, st_.psi_) =
522 measure_seq(st_.psi_, target_rel_pos, d,
false);
523 st_.dits_[measurements[m_ip].c_reg_] = resZ[0];
524 st_.probs_[measurements[m_ip].c_reg_] = probZ;
526 case QCircuit::MeasureType::MEASURE_Z_MANY_ND:
527 std::tie(resZ, probZ, st_.psi_) =
528 measure_seq(st_.psi_, target_rel_pos, d,
false);
529 st_.dits_[measurements[m_ip].c_reg_] = multiidx2n(
530 resZ, std::vector<idx>(target_rel_pos.size(), d));
531 st_.probs_[measurements[m_ip].c_reg_] = probZ;
533 case QCircuit::MeasureType::MEASURE_V_ND:
534 case QCircuit::MeasureType::MEASURE_V_MANY_ND:
535 std::tie(mres, probs, states) = measure(
536 st_.psi_, h_tbl[measurements[m_ip].mats_hash_[0]],
537 target_rel_pos, d,
false);
538 st_.psi_ = states[mres];
539 st_.dits_[measurements[m_ip].c_reg_] = mres;
540 st_.probs_[measurements[m_ip].c_reg_] = probs[mres];
542 case QCircuit::MeasureType::RESET:
543 case QCircuit::MeasureType::RESET_MANY:
544 st_.psi_ = qpp::reset(st_.psi_, target_rel_pos, d);
546 case QCircuit::MeasureType::DISCARD:
547 std::tie(std::ignore, std::ignore, st_.psi_) =
548 measure_seq(st_.psi_, target_rel_pos, d);
549 set_measured_(measurements[m_ip].target_[0]);
551 case QCircuit::MeasureType::DISCARD_MANY:
552 std::tie(std::ignore, std::ignore, st_.psi_) =
553 measure_seq(st_.psi_, target_rel_pos, d);
554 for (
auto&& elem : measurements[m_ip].target_)
561 else if (elem.type_ == QCircuit::StepType::NOP) {
579 QEngine& execute(
const QCircuit::iterator& it) {
return execute(*it); }
591 QEngine& execute(idx reps = 1,
bool clear_stats =
true) {
592 auto initial_engine_state = st_;
597 for (idx i = 0; i < reps; ++i) {
599 st_ = initial_engine_state;
601 for (
auto&& elem : *qc_)
602 (void) execute(elem);
605 if (qc_->get_measurement_count() > 0) {
606 std::vector<idx> m_res = get_dits();
608 std::stringstream ss;
609 ss << disp(m_res,
" ",
"",
"");
627 std::string to_JSON(
bool enclosed_in_curly_brackets =
true)
const override {
630 if (enclosed_in_curly_brackets)
633 std::ostringstream ss;
634 ss << disp(get_measured(),
", ");
635 result +=
"\"measured/discarded (destructive)\" : " + ss.str() +
", ";
639 ss << disp(get_non_measured(),
", ");
640 result +=
"\"non-measured/non-discarded\" : " + ss.str();
644 result +=
", \"last probs\": ";
645 ss << disp(get_probs(),
", ");
650 result +=
", \"last dits\": ";
651 ss << disp(get_dits(),
", ");
658 if (!stats_.empty()) {
659 result +=
", \"stats\": {";
661 for (
auto&& elem : get_stats())
663 result +=
"\"reps\": " + std::to_string(reps) +
", ";
664 result +=
"\"outcomes\": " + std::to_string(stats_.size()) +
", ";
666 std::vector<idx> dits_dims(qc_->get_nc(), qc_->get_d());
667 bool is_first =
true;
668 for (
auto&& elem : get_stats()) {
674 <<
"[" << elem.first <<
"]" 675 <<
"\" : " << elem.second;
681 if (enclosed_in_curly_brackets)
697 std::ostream& display(std::ostream& os)
const override {
698 os <<
"measured/discarded (destructive): " << disp(get_measured(),
", ")
700 os <<
"non-measured/non-discarded: " << disp(get_non_measured(),
", ")
702 os <<
"last probs: " << disp(get_probs(),
", ") <<
'\n';
703 os <<
"last dits: " << disp(get_dits(),
", ");
706 if (!stats_.empty()) {
708 for (
auto&& elem : get_stats())
711 os <<
'\t' <<
"reps: " << reps <<
'\n';
712 os <<
'\t' <<
"outcomes: " << stats_.size() <<
'\n';
713 std::vector<idx> dits_dims(qc_->get_nc(), qc_->get_d());
714 bool is_first =
true;
715 for (
auto&& elem : get_stats()) {
720 os <<
'\t' <<
"[" << elem.first <<
"]" 721 <<
": " << elem.second;
740 template <
typename NoiseModel>
741 class QNoisyEngine :
public QEngine {
743 std::vector<std::vector<idx>> noise_results_;
752 explicit QNoisyEngine(
const QCircuit& qc,
const NoiseModel& noise)
753 : QEngine{qc}, noise_{noise}, noise_results_(qc.get_step_count()) {
757 if (qc.get_d() != noise.get_d())
758 throw exception::DimsNotEqual(
"qpp::QNoisyEngine::QNoisyEngine()");
762 using QEngine::execute;
769 QNoisyEngine& execute(
const QCircuit::iterator::value_type& elem)
override {
771 std::vector<idx> target_rel_pos = get_relative_pos_(get_non_measured());
772 if (elem.type_ != QCircuit::StepType::MEASUREMENT) {
774 for (
auto&& i : target_rel_pos) {
775 st_.psi_ = noise_(st_.psi_, i);
777 noise_results_[elem.ip_].emplace_back(noise_.get_last_idx());
781 (void) QEngine::execute(elem);
799 std::vector<std::vector<idx>> get_noise_results()
const {
800 return noise_results_;
Quantum++ main namespace.
Definition: circuits.h:35