diff --git a/quisp/backends/Backends.h b/quisp/backends/Backends.h index 7de7b5bf2..0dd30257b 100644 --- a/quisp/backends/Backends.h +++ b/quisp/backends/Backends.h @@ -1,15 +1,25 @@ #pragma once #include "ErrorTracking/Backend.h" +#include "ErrorTracking/Configuration.h" +#include "interfaces/IConfiguration.h" #include "interfaces/IQuantumBackend.h" +#include "interfaces/IQubit.h" #include "interfaces/IQubitId.h" // the namespace for exposing the backend namespace quisp::backends { +using abstract::EigenvalueResult; +using abstract::IConfiguration; using abstract::IQuantumBackend; using abstract::IQubit; using abstract::IQubitId; +using abstract::MeasurementOutcome; +using abstract::MeasureXResult; +using abstract::MeasureYResult; +using abstract::MeasureZResult; using error_tracking::ErrorTrackingBackend; +using error_tracking::ErrorTrackingConfiguration; using error_tracking::ErrorTrackingQubit; } // namespace quisp::backends diff --git a/quisp/backends/ErrorTracking/Backend.cc b/quisp/backends/ErrorTracking/Backend.cc index d62320f10..d6962dfc7 100644 --- a/quisp/backends/ErrorTracking/Backend.cc +++ b/quisp/backends/ErrorTracking/Backend.cc @@ -1,27 +1,73 @@ #include "Backend.h" #include "Qubit.h" +#include "backends/ErrorTracking/Configuration.h" +#include "backends/interfaces/IConfiguration.h" namespace quisp::backends::error_tracking { using error_tracking::ErrorTrackingQubit; -ErrorTrackingBackend::ErrorTrackingBackend(std::unique_ptr rng) : current_time(SimTime()), rng(std::move(rng)) {} +ErrorTrackingBackend::ErrorTrackingBackend(std::unique_ptr rng, std::unique_ptr configuration) + : current_time(SimTime()), rng(std::move(rng)) { + config = std::move(configuration); +} +ErrorTrackingBackend::ErrorTrackingBackend(std::unique_ptr rng, std::unique_ptr configuration, ICallback* cb) + : ErrorTrackingBackend(std::move(rng), std::move(configuration)) { + callback = cb; +} + ErrorTrackingBackend::~ErrorTrackingBackend() { for (auto& pair : qubits) { delete pair.first; } } + IQubit* ErrorTrackingBackend::getQubit(const IQubitId* id) { auto qubit = qubits.find(id); if (qubit != qubits.cend()) { return qubit->second.get(); } + throw std::runtime_error("ErrorTrackingBackend::getQubit: trying to get qubit with nonexisted Id."); +} + +IQubit* ErrorTrackingBackend::createQubit(const IQubitId* id, std::unique_ptr conf) { + if (qubits.find(id) != qubits.cend()) { + throw std::runtime_error("ErrorTrackingBackend::createQubit: trying to create qubit with already existing Id."); + } auto original_qubit = std::make_unique(id, this); + + IConfiguration* raw_conf = conf.release(); + ErrorTrackingConfiguration* et_conf = dynamic_cast(raw_conf); + + if (et_conf == nullptr) { + delete raw_conf; + throw std::runtime_error("ErrorTrackingBackend::getQubit: failed to cast. got invalid configulation."); + } + + original_qubit->configure(std::unique_ptr(et_conf)); auto* qubit_ptr = original_qubit.get(); qubits.insert({id, std::move(original_qubit)}); return qubit_ptr; } -const SimTime& ErrorTrackingBackend::getSimTime() { return current_time; } + +IQubit* ErrorTrackingBackend::createQubit(const IQubitId* id) { return createQubit(id, std::move(getDefaultConfiguration())); } + +void ErrorTrackingBackend::deleteQubit(const IQubitId* id) { + auto qubit_iterator = qubits.find(id); + if (qubit_iterator == qubits.cend()) { + throw std::runtime_error("ErrorTrackingBackend::deleteQubit: trying to delete qubit with unknown Id."); + } + qubits.erase(qubit_iterator); +} + +std::unique_ptr ErrorTrackingBackend::getDefaultConfiguration() const { + // copy the default backend configuration for each qubit + return std::make_unique(*config.get()); +} +const SimTime& ErrorTrackingBackend::getSimTime() { + if (callback != nullptr) callback->willUpdate(*this); + return current_time; +} void ErrorTrackingBackend::setSimTime(SimTime time) { current_time = time; } double ErrorTrackingBackend::dblrand() { return rng->doubleRandom(); } diff --git a/quisp/backends/ErrorTracking/Backend.h b/quisp/backends/ErrorTracking/Backend.h index ad38d944a..97ca4705e 100644 --- a/quisp/backends/ErrorTracking/Backend.h +++ b/quisp/backends/ErrorTracking/Backend.h @@ -3,12 +3,15 @@ #include #include +#include "../interfaces/IConfiguration.h" #include "../interfaces/IQuantumBackend.h" #include "../interfaces/IQubitId.h" #include "../interfaces/IRandomNumberGenerator.h" +#include "Configuration.h" #include "Qubit.h" namespace quisp::backends::error_tracking { +using abstract::IConfiguration; using abstract::IQuantumBackend; using abstract::IQubit; using abstract::IQubitId; @@ -18,9 +21,19 @@ using omnetpp::SimTime; class ErrorTrackingBackend : public IQuantumBackend { public: - ErrorTrackingBackend(std::unique_ptr rng); + class ICallback { + public: + virtual ~ICallback() {} + virtual void willUpdate(ErrorTrackingBackend& backend) = 0; + }; + ErrorTrackingBackend(std::unique_ptr rng, std::unique_ptr configuration); + ErrorTrackingBackend(std::unique_ptr rng, std::unique_ptr configuration, ICallback* callback); ~ErrorTrackingBackend(); + IQubit* createQubit(const IQubitId* id, std::unique_ptr conf) override; + IQubit* createQubit(const IQubitId* id) override; IQubit* getQubit(const IQubitId* id) override; + void deleteQubit(const IQubitId* id) override; + std::unique_ptr getDefaultConfiguration() const override; const SimTime& getSimTime() override; void setSimTime(SimTime time) override; double dblrand(); @@ -29,6 +42,8 @@ class ErrorTrackingBackend : public IQuantumBackend { std::unordered_map, IQubitId::Hash, IQubitId::Pred> qubits; SimTime current_time; const std::unique_ptr rng; + std::unique_ptr config; + ICallback* callback = nullptr; }; } // namespace quisp::backends::error_tracking diff --git a/quisp/backends/ErrorTracking/Backend_test.cc b/quisp/backends/ErrorTracking/Backend_test.cc index ccc0ba456..1efd08be4 100644 --- a/quisp/backends/ErrorTracking/Backend_test.cc +++ b/quisp/backends/ErrorTracking/Backend_test.cc @@ -1,8 +1,10 @@ #include "Backend.h" -#include #include #include #include "../interfaces/IRandomNumberGenerator.h" +#include "Configuration.h" +#include "Qubit.h" +#include "backends/interfaces/IConfiguration.h" #include "test.h" namespace { @@ -10,21 +12,67 @@ using namespace quisp::backends::error_tracking; using namespace quisp_test::backends; using namespace omnetpp; +class TestEtQubit : public ErrorTrackingQubit { + public: + using ErrorTrackingQubit::addErrorX; + using ErrorTrackingQubit::addErrorZ; + using ErrorTrackingQubit::applyMemoryError; + using ErrorTrackingQubit::applySingleQubitGateError; + using ErrorTrackingQubit::applyTwoQubitGateError; + using ErrorTrackingQubit::correlationMeasureX; + using ErrorTrackingQubit::correlationMeasureY; + using ErrorTrackingQubit::correlationMeasureZ; + using ErrorTrackingQubit::entangled_partner; + using ErrorTrackingQubit::gate_err_cnot; + using ErrorTrackingQubit::gate_err_h; + using ErrorTrackingQubit::gate_err_x; + using ErrorTrackingQubit::gate_err_z; + using ErrorTrackingQubit::getErrorMatrix; + using ErrorTrackingQubit::getQuantumState; + using ErrorTrackingQubit::has_completely_mixed_error; + using ErrorTrackingQubit::has_excitation_error; + using ErrorTrackingQubit::has_relaxation_error; + using ErrorTrackingQubit::has_x_error; + using ErrorTrackingQubit::has_z_error; + using ErrorTrackingQubit::localMeasureX; + using ErrorTrackingQubit::localMeasureZ; + using ErrorTrackingQubit::measureDensityIndependent; + using ErrorTrackingQubit::measurement_err; + using ErrorTrackingQubit::memory_err; + using ErrorTrackingQubit::setMemoryErrorRates; + using ErrorTrackingQubit::updated_time; +}; + +class EtBackend : public ErrorTrackingBackend { + public: + using ErrorTrackingBackend::qubits; + EtBackend(std::unique_ptr rng, std::unique_ptr config) : ErrorTrackingBackend(std::move(rng), std::move(config)) {} +}; + class EtBackendTest : public ::testing::Test { protected: virtual void SetUp() { SimTime::setScaleExp(-9); rng = new TestRNG(); - backend = std::make_unique(std::unique_ptr(rng)); + backend = std::make_unique(std::unique_ptr(rng), std::make_unique()); } TestRNG* rng; - std::unique_ptr backend; + std::unique_ptr backend; }; +TEST_F(EtBackendTest, createQubit) { + auto* id = new QubitId(123); + EXPECT_EQ(backend->qubits.size(), 0); + auto qubit = backend->createQubit(id); + EXPECT_EQ(backend->qubits.size(), 1); + ASSERT_THROW(backend->createQubit(id), std::runtime_error); + EXPECT_EQ(backend->qubits.size(), 1); +} + TEST_F(EtBackendTest, getQubit) { auto* id = new QubitId(123); EXPECT_EQ(backend->qubits.size(), 0); - auto qubit = backend->getQubit(id); + auto qubit = backend->createQubit(id); EXPECT_EQ(backend->qubits.size(), 1); EXPECT_EQ(qubit, backend->getQubit(id)); EXPECT_EQ(backend->qubits.size(), 1); @@ -35,4 +83,98 @@ TEST_F(EtBackendTest, getQubit) { EXPECT_EQ(same_qubit, qubit); } +TEST_F(EtBackendTest, getQubitTwice) { + auto* id = new QubitId(3); + backend->createQubit(id); + auto* qubit1 = backend->getQubit(id); + auto* qubit2 = backend->getQubit(id); + EXPECT_NE(qubit1, nullptr); + EXPECT_NE(qubit2, nullptr); + EXPECT_EQ(qubit1, qubit2); +} + +TEST_F(EtBackendTest, createQubitWithInvalidConfiguration) { + auto conf = new IConfiguration; + auto* id = new QubitId(4); + ASSERT_THROW({ backend->createQubit(id, std::unique_ptr(conf)); }, std::runtime_error); +} + +TEST_F(EtBackendTest, createQubitWithConfiguration) { + auto conf = new ErrorTrackingConfiguration; + conf->cnot_gate_err_rate = 0.75; + conf->cnot_gate_ix_err_ratio = 0.75 / 9.; + conf->cnot_gate_xi_err_ratio = 0.75 / 9.; + conf->cnot_gate_xx_err_ratio = 0.75 / 9.; + conf->cnot_gate_iy_err_ratio = 0.75 / 9.; + conf->cnot_gate_yi_err_ratio = 0.75 / 9.; + conf->cnot_gate_yy_err_ratio = 0.75 / 9.; + conf->cnot_gate_iz_err_ratio = 0.75 / 9.; + conf->cnot_gate_zi_err_ratio = 0.75 / 9.; + conf->cnot_gate_zz_err_ratio = 0.75 / 9.; + conf->h_gate_err_rate = 1.0; + conf->h_gate_x_err_ratio = 1. / 3.; + conf->h_gate_y_err_ratio = 1. / 3.; + conf->h_gate_z_err_ratio = 1. / 3.; + conf->x_gate_err_rate = 0.5; + conf->x_gate_x_err_ratio = 0.5 / 3.; + conf->x_gate_y_err_ratio = 0.5 / 3.; + conf->x_gate_z_err_ratio = 0.5 / 3.; + conf->z_gate_err_rate = 0.25; + conf->z_gate_x_err_ratio = 0.25 / 3.; + conf->z_gate_y_err_ratio = 0.25 / 3.; + conf->z_gate_z_err_ratio = 0.25 / 3.; + conf->measurement_x_err_rate = 0.23; + conf->measurement_y_err_rate = 0.24; + conf->measurement_z_err_rate = 0.25; + conf->memory_x_err_rate = 0.26; + conf->memory_y_err_rate = 0.27; + conf->memory_z_err_rate = 0.28; + conf->memory_relaxation_rate = 0.29; + conf->memory_excitation_rate = 0.30; + conf->memory_completely_mixed_rate = 0.31; + + auto conf2 = std::make_unique(*conf); + + auto* id = new QubitId(123); + EXPECT_EQ(backend->qubits.size(), 0); + auto* qubit = backend->createQubit(id, std::move(conf2)); + EXPECT_EQ(backend->qubits.size(), 1); + EXPECT_EQ(qubit, backend->getQubit(id)); + EXPECT_EQ(backend->qubits.size(), 1); + auto et_qubit = reinterpret_cast(qubit); + + EXPECT_EQ(et_qubit->gate_err_h.x_error_rate, conf->h_gate_x_err_ratio); + EXPECT_EQ(et_qubit->gate_err_h.y_error_rate, conf->h_gate_y_err_ratio); + EXPECT_EQ(et_qubit->gate_err_h.z_error_rate, conf->h_gate_z_err_ratio); + + EXPECT_EQ(et_qubit->gate_err_x.x_error_rate, conf->x_gate_x_err_ratio); + EXPECT_EQ(et_qubit->gate_err_x.y_error_rate, conf->x_gate_y_err_ratio); + EXPECT_EQ(et_qubit->gate_err_x.z_error_rate, conf->x_gate_z_err_ratio); + + EXPECT_EQ(et_qubit->gate_err_z.x_error_rate, conf->z_gate_x_err_ratio); + EXPECT_EQ(et_qubit->gate_err_z.y_error_rate, conf->z_gate_y_err_ratio); + EXPECT_EQ(et_qubit->gate_err_z.z_error_rate, conf->z_gate_z_err_ratio); + + EXPECT_EQ(et_qubit->measurement_err.x_error_rate, conf->measurement_x_err_rate); + EXPECT_EQ(et_qubit->measurement_err.y_error_rate, conf->measurement_y_err_rate); + EXPECT_EQ(et_qubit->measurement_err.z_error_rate, conf->measurement_z_err_rate); + + EXPECT_EQ(et_qubit->memory_err.x_error_rate, conf->memory_x_err_rate); + EXPECT_EQ(et_qubit->memory_err.y_error_rate, conf->memory_y_err_rate); + EXPECT_EQ(et_qubit->memory_err.z_error_rate, conf->memory_z_err_rate); + EXPECT_EQ(et_qubit->memory_err.excitation_error_rate, conf->memory_excitation_rate); + EXPECT_EQ(et_qubit->memory_err.relaxation_error_rate, conf->memory_relaxation_rate); + EXPECT_EQ(et_qubit->memory_err.completely_mixed_rate, conf->memory_completely_mixed_rate); + + EXPECT_EQ(et_qubit->gate_err_cnot.ix_error_rate, conf->cnot_gate_ix_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.xi_error_rate, conf->cnot_gate_xi_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.xx_error_rate, conf->cnot_gate_xx_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.iy_error_rate, conf->cnot_gate_iy_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.yi_error_rate, conf->cnot_gate_yi_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.yy_error_rate, conf->cnot_gate_yy_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.iz_error_rate, conf->cnot_gate_iz_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.zi_error_rate, conf->cnot_gate_zi_err_ratio); + EXPECT_EQ(et_qubit->gate_err_cnot.zz_error_rate, conf->cnot_gate_zz_err_ratio); +} + } // namespace diff --git a/quisp/backends/ErrorTracking/Configuration.h b/quisp/backends/ErrorTracking/Configuration.h new file mode 100644 index 000000000..cb15aa1ae --- /dev/null +++ b/quisp/backends/ErrorTracking/Configuration.h @@ -0,0 +1,53 @@ +#pragma once + +#include "../interfaces/IConfiguration.h" +namespace quisp::backends::error_tracking { +/** +@brief Configuration class contains all parameters and provides the way to retrieve it +*/ +class ErrorTrackingConfiguration : public abstract::IConfiguration { + public: + ErrorTrackingConfiguration() {} + ~ErrorTrackingConfiguration() {} + + // list up all params + double memory_x_err_rate; + double memory_y_err_rate; + double memory_z_err_rate; + double memory_excitation_rate; + double memory_relaxation_rate; + double memory_completely_mixed_rate; + + double measurement_x_err_rate; + double measurement_y_err_rate; + double measurement_z_err_rate; + + double x_gate_x_err_ratio; + double x_gate_y_err_ratio; + double x_gate_z_err_ratio; + double x_gate_err_rate; + + double z_gate_x_err_ratio; + double z_gate_y_err_ratio; + double z_gate_z_err_ratio; + double z_gate_err_rate; + + double h_gate_x_err_ratio; + double h_gate_y_err_ratio; + double h_gate_z_err_ratio; + double h_gate_err_rate; + + double cnot_gate_iz_err_ratio; + double cnot_gate_zi_err_ratio; + double cnot_gate_zz_err_ratio; + double cnot_gate_ix_err_ratio; + double cnot_gate_xi_err_ratio; + double cnot_gate_xx_err_ratio; + double cnot_gate_iy_err_ratio; + double cnot_gate_yi_err_ratio; + double cnot_gate_yy_err_ratio; + double cnot_gate_err_rate; + + protected: +}; +} // namespace quisp::backends::error_tracking diff --git a/quisp/backends/ErrorTracking/Qubit.cc b/quisp/backends/ErrorTracking/Qubit.cc index bd71c9e9f..de23c9f66 100644 --- a/quisp/backends/ErrorTracking/Qubit.cc +++ b/quisp/backends/ErrorTracking/Qubit.cc @@ -1,12 +1,21 @@ #include "Qubit.h" -#include #include "Backend.h" namespace quisp::backends::error_tracking { -ErrorTrackingQubit::ErrorTrackingQubit(const IQubitId* id, ErrorTrackingBackend* const backend) : id(id), memory_transition_matrix(MatrixXd::Zero(7, 7)), backend(backend) { - // emission_success_probability = par("emission_success_probability"); -} +ErrorTrackingQubit::ErrorTrackingQubit(const IQubitId* id, ErrorTrackingBackend* const backend) : id(id), memory_transition_matrix(MatrixXd::Zero(7, 7)), backend(backend) {} + ErrorTrackingQubit::~ErrorTrackingQubit() {} + +void ErrorTrackingQubit::configure(std::unique_ptr c) { + setMemoryErrorRates(c->memory_x_err_rate, c->memory_y_err_rate, c->memory_z_err_rate, c->memory_excitation_rate, c->memory_relaxation_rate, c->memory_completely_mixed_rate); + measurement_err.setParams(c->measurement_x_err_rate, c->measurement_y_err_rate, c->measurement_z_err_rate); + gate_err_h.setParams(c->h_gate_x_err_ratio, c->h_gate_y_err_ratio, c->h_gate_z_err_ratio, c->h_gate_err_rate); + gate_err_x.setParams(c->x_gate_x_err_ratio, c->x_gate_y_err_ratio, c->x_gate_z_err_ratio, c->x_gate_err_rate); + gate_err_z.setParams(c->z_gate_x_err_ratio, c->z_gate_y_err_ratio, c->z_gate_z_err_ratio, c->z_gate_err_rate); + gate_err_cnot.setParams(c->cnot_gate_err_rate, c->cnot_gate_ix_err_ratio, c->cnot_gate_xi_err_ratio, c->cnot_gate_xx_err_ratio, c->cnot_gate_iz_err_ratio, + c->cnot_gate_zi_err_ratio, c->cnot_gate_zz_err_ratio, c->cnot_gate_iy_err_ratio, c->cnot_gate_yi_err_ratio, c->cnot_gate_yy_err_ratio); +} + void ErrorTrackingQubit::setMemoryErrorRates(double x_error_rate, double y_error_rate, double z_error_rate, double excitation_rate, double relaxation_rate, double completely_mixed_rate) { memory_err.x_error_rate = x_error_rate; @@ -112,7 +121,6 @@ void ErrorTrackingQubit::applyTwoQubitGateError(TwoQubitGateErrorModel const& er } } void ErrorTrackingQubit::applyMemoryError() { - // update(); if (entangled_partner == nullptr && density_matrix_collapsed(0, 0).real() == -111 && !no_density_matrix_nullptr_entangled_partner_ok) { throw std::runtime_error("This must not happen in apply memory error"); } @@ -247,6 +255,14 @@ void ErrorTrackingQubit::setFree() { has_relaxation_error = false; has_excitation_error = false; has_completely_mixed_error = false; + + density_matrix_collapsed << -111, -111, -111, -111; + no_density_matrix_nullptr_entangled_partner_ok = false; + if (entangled_partner != nullptr) { + // entangled_partner->entangled_partner = nullptr; + entangled_partner = nullptr; + } + updated_time = backend->getSimTime(); } void ErrorTrackingQubit::setRelaxedDensityMatrix() { density_matrix_collapsed << 0, 0, 0, 1; @@ -255,8 +271,8 @@ void ErrorTrackingQubit::setRelaxedDensityMatrix() { has_relaxation_error = true; has_x_error = false; has_z_error = false; - // GOD_dm_Xerror = false; - // GOD_dm_Zerror = false; + god_dm_has_x_error = false; + god_dm_has_z_error = false; // Still entangled if (entangled_partner != nullptr) { @@ -271,8 +287,8 @@ void ErrorTrackingQubit::setExcitedDensityMatrix() { has_relaxation_error = false; has_x_error = false; has_z_error = false; - // GOD_dm_Xerror = false; - // GOD_dm_Zerror = false; + god_dm_has_x_error = false; + god_dm_has_z_error = false; if (entangled_partner != nullptr) { // If it used to be entangled... entangled_partner->updated_time = backend->getSimTime(); @@ -292,8 +308,6 @@ void ErrorTrackingQubit::setCompletelyMixedDensityMatrix() { } } -void ErrorTrackingQubit::update() { updated_time = backend->getSimTime(); } - MeasureXResult ErrorTrackingQubit::correlationMeasureX() { bool error = has_z_error; if (backend->dblrand() < measurement_err.x_error_rate) { @@ -399,7 +413,15 @@ bool ErrorTrackingQubit::purifyX(IQubit* const control_qubit) { applyMemoryError(); et_control_qubit->applyMemoryError(); gateCNOT(control_qubit); - return correlationMeasureZ() == MeasureZResult::NO_X_ERROR; + auto result = correlationMeasureZ() == MeasureZResult::NO_X_ERROR; + + // Trash qubit has been measured. Now, break the entanglement info of the partner. + // There is no need to overwrite its density matrix since we are only tracking errors. + if (entangled_partner != nullptr) { + entangled_partner->no_density_matrix_nullptr_entangled_partner_ok = true; + entangled_partner->entangled_partner = nullptr; + } + return result; } bool ErrorTrackingQubit::purifyZ(IQubit* const target_qubit) { @@ -411,9 +433,252 @@ bool ErrorTrackingQubit::purifyZ(IQubit* const target_qubit) { et_target_qubit->applyMemoryError(); et_target_qubit->gateCNOT(this); gateH(); - return this->correlationMeasureZ() == MeasureZResult::NO_X_ERROR; + auto result = correlationMeasureZ() == MeasureZResult::NO_X_ERROR; + + // Trash qubit has been measured. Now, break the entanglement info of the partner. + // There is no need to overwrite its density matrix since we are only tracking errors. + if (entangled_partner != nullptr) { + entangled_partner->no_density_matrix_nullptr_entangled_partner_ok = true; + entangled_partner->entangled_partner = nullptr; + } + + return result; } +Matrix2cd ErrorTrackingQubit::getErrorMatrix() { + if (has_completely_mixed_error || has_relaxation_error) { + throw std::runtime_error("CMerror in getErrorMatrix. Not supposed to happen."); + } + if (has_z_error && has_x_error) return pauli.Y; + if (has_z_error) return pauli.Z; + if (has_x_error) return pauli.X; + return pauli.I; +} + +// returns the density matrix of the Bell pair with error. This assumes that this is entangled with another stationary qubit. +// Measurement output will be based on this matrix, as long as it is still entangled. +QuantumState ErrorTrackingQubit::getQuantumState() { + if (has_excitation_error || has_relaxation_error) throw std::runtime_error("this qubit is excited or relaxed"); + if (entangled_partner == nullptr) throw std::runtime_error("no entangled partner"); + if (entangled_partner->has_excitation_error || entangled_partner->has_relaxation_error) throw std::runtime_error("partner qubit is excited or relaxed"); + + Matrix4cd error_mat = kroneckerProduct(getErrorMatrix(), entangled_partner->getErrorMatrix()).eval(); + // Assumes that the state is a 2 qubit state |00> + |11> + Vector4cd ideal_bell_state(1 / sqrt(2), 0, 0, 1 / sqrt(2)); + Vector4cd actual_bell_state = error_mat * ideal_bell_state; + + QuantumState q; + q.state_in_density_matrix = actual_bell_state * actual_bell_state.adjoint(); + q.state_in_ket = actual_bell_state; + return q; +} + +MeasurementOutcome ErrorTrackingQubit::measureDensityIndependent() { + if (this->entangled_partner == nullptr && density_matrix_collapsed(0, 0).real() == -111) { + std::cout << density_matrix_collapsed << "\n"; + throw std::runtime_error("Measuring a qubit that is not entangled with another qubit. Probably not what you want! Check whether address for each node is unique!!!"); + } + MeasurementOperator this_measurement = randomMeasurementBasisSelection(); // Select basis randomly + char output; + bool output_is_plus; + + // Add memory error depending on the idle time. If excited/relaxed, this will immediately break entanglement, leaving the other qubit as completely mixed. + applyMemoryError(); + + // This becomes nullptr if this qubit got excited/relaxed or measured. + if (this->entangled_partner != nullptr) { + if (this->entangled_partner->entangled_partner == nullptr) { + throw std::runtime_error("invalid entanglement partner"); + } + // if (partner_measured) error("Entangled partner not nullptr but partner already measured....? Probably wrong."); + if (has_completely_mixed_error || has_excitation_error || has_relaxation_error) { + std::cout << "[Error]" << this << "\n"; + throw std::runtime_error("Entangled but completely mixed / Excited / Relaxed ? Probably wrong."); + } + // Also do the same on the partner if it is still entangled! This could break the entanglement due to relaxation/excitation error! + entangled_partner->applyMemoryError(); + } + + /*-For debugging-*/ + char god_state = 'F'; // Completely mixed + + if (has_excitation_error) + god_state = 'E'; + else if (has_excitation_error /* XXX: this might be relaxation error? */) + god_state = 'R'; + else if (has_completely_mixed_error) + god_state = 'C'; + else if (!has_x_error && has_z_error) // To check stabilizers.... + god_state = 'Z'; + else if (has_x_error && !has_z_error) + god_state = 'X'; + else if (has_x_error && has_z_error) + god_state = 'Y'; + + /*---------------*/ + + // if there is an entanglement + if (this->entangled_partner != nullptr) { + // This qubit is nullptr + if (this->entangled_partner->entangled_partner == nullptr) { + throw std::runtime_error("Entangled_partner track wrong\n"); + } + } + + // if the partner qubit is measured, + if (this->partner_measured || has_completely_mixed_error || has_excitation_error || + has_relaxation_error) { // The case when the density matrix is completely local to this qubit. + + if (density_matrix_collapsed(0, 0).real() == -111) { // We always need some kind of density matrix inside this if statement. + throw std::runtime_error("Single qubit density matrix not stored properly after partner's measurement, excitation/relaxation error."); + } + bool x_err = has_x_error; + bool z_err = has_z_error; + // This qubit's density matrix was created when the partner measured his own. + // Because this qubit can be measured after that, we need to update the stored density matrix according to new errors occurred due to memory error. + + if (x_err != god_dm_has_x_error) { // Another X error to the dm. + density_matrix_collapsed = pauli.X * density_matrix_collapsed * pauli.X.adjoint(); + } + if (z_err != god_dm_has_z_error) { // Another Z error to the dm. + density_matrix_collapsed = pauli.Z * density_matrix_collapsed * pauli.Z.adjoint(); + } + + // std::cout<<"Not entangled anymore. Density matrix is "<dblrand(); + if (dbl < prob_plus.real()) { + output = '+'; + output_is_plus = true; + } else { + output = '-'; + output_is_plus = false; + } + // std::cout<<"\n This qubit was "<partner_measured && !has_completely_mixed_error && !(has_relaxation_error || has_excitation_error) && this->entangled_partner != nullptr) { + // This is assuming that this is some other qubit is entangled. Only Pauli errors are assumed. + QuantumState current_state = getQuantumState(); + std::cout << "Current entangled state is " << current_state.state_in_ket << "\n"; + + bool x_err = god_dm_has_x_error; + bool z_err = god_dm_has_z_error; + // std::cout<<"Entangled state is "<dblrand(); + + Vector2cd ms; + if (dbl < prob_plus.real()) { // Measurement output was plus + output = '+'; + ms = this_measurement.plus_ket; + output_is_plus = true; + } else { // Otherwise, it was negative. + output = '-'; + ms = this_measurement.minus_ket; + output_is_plus = false; + } + // Now we have to calculate the density matrix of a single qubit that used to be entangled with this. + Matrix2cd partners_dm, normalized_partners_dm; + partners_dm = kroneckerProduct(ms.adjoint(), measurement_op.identity).eval() * current_state.state_in_density_matrix * + kroneckerProduct(ms.adjoint(), measurement_op.identity).eval().adjoint(); + normalized_partners_dm = partners_dm / partners_dm.trace(); + std::cout << "kroneckerProduct(ms.adjoint(),meas_op.identity).eval() = " << kroneckerProduct(ms.adjoint(), measurement_op.identity).eval() << "\n"; + std::cout << "dm = " << current_state.state_in_density_matrix << "\n"; + std::cout << "State was " << kroneckerProduct(ms.adjoint(), measurement_op.identity).eval() * current_state.state_in_density_matrix << "\n"; + std::cout << "\n This qubit was " << this_measurement.basis << "(" << output << "). Partner's dm is now = " << normalized_partners_dm << "\n"; + entangled_partner->density_matrix_collapsed = normalized_partners_dm; + + // We actually do not need this as long as deleting entangled_partner completely is totally fine. + entangled_partner->partner_measured = true; + // if(entangled_partner->getIndex() == 71 && entangled_partner->node_address == 3) + // std::cout<<"-------------------"<node_address<<"] overwritten dm.\n"; + + // Break entanglement. + entangled_partner->entangled_partner = nullptr; + // Save what error it had, when this density matrix was calculated. + // Error may get updated in the future, so we need to track what error has been considered already in the dm. + entangled_partner->god_dm_has_x_error = entangled_partner->has_x_error; + entangled_partner->god_dm_has_z_error = entangled_partner->has_z_error; + } else { + throw std::runtime_error("Check condition in measure func."); + } + + // add measurement error + auto rand_num = backend->dblrand(); + if ((this_measurement.basis == measurement_op.x_basis.basis && rand_num < measurement_err.x_error_rate) || + (this_measurement.basis == measurement_op.y_basis.basis && rand_num < measurement_err.y_error_rate) || + (this_measurement.basis == measurement_op.z_basis.basis && rand_num < measurement_err.z_error_rate)) { + output_is_plus = !output_is_plus; + } + + MeasurementOutcome o; + o.basis = this_measurement.basis; + o.outcome_is_plus = output_is_plus; + o.GOD_clean = god_state; + return o; +} + +MeasurementOperator ErrorTrackingQubit::randomMeasurementBasisSelection() { + MeasurementOperator this_measurement; + double dbl = backend->dblrand(); // Random double value for random basis selection. + std::cout << "Random dbl = " << dbl << "! \n "; + + if (dbl < ((double)1 / (double)3)) { // X measurement! + std::cout << "X measurement\n"; + this_measurement.plus = measurement_op.x_basis.plus; + this_measurement.minus = measurement_op.x_basis.minus; + this_measurement.basis = measurement_op.x_basis.basis; + this_measurement.plus_ket = measurement_op.x_basis.plus_ket; + this_measurement.minus_ket = measurement_op.x_basis.minus_ket; + } else if (dbl >= ((double)1 / (double)3) && dbl < ((double)2 / (double)3)) { + std::cout << "Z measurement\n"; + this_measurement.plus = measurement_op.z_basis.plus; + this_measurement.minus = measurement_op.z_basis.minus; + this_measurement.basis = measurement_op.z_basis.basis; + this_measurement.plus_ket = measurement_op.z_basis.plus_ket; + this_measurement.minus_ket = measurement_op.z_basis.minus_ket; + } else { + std::cout << "Y measurement\n"; + this_measurement.plus = measurement_op.y_basis.plus; + this_measurement.minus = measurement_op.y_basis.minus; + this_measurement.basis = measurement_op.y_basis.basis; + this_measurement.plus_ket = measurement_op.y_basis.plus_ket; + this_measurement.minus_ket = measurement_op.y_basis.minus_ket; + } + return this_measurement; +} + +void ErrorTrackingQubit::assertEntangledPartnerValid() { + if (entangled_partner == nullptr && density_matrix_collapsed(0, 0).real() == -111 && !no_density_matrix_nullptr_entangled_partner_ok) { + throw std::runtime_error("ErrorTrackingQubit::assertEntangledPartnerValid: something went wrong"); + } + if (entangled_partner != nullptr) { + if (entangled_partner->entangled_partner == nullptr) { + throw std::runtime_error("ErrorTrackingQubit::assertEntangledPartnerValid: 1. Entanglement tracking is not doing its job."); + } + if (entangled_partner->entangled_partner != this) { + throw std::runtime_error("ErrorTrackingQubit::assertEntangledPartnerValid: 2. Entanglement tracking is not doing its job."); + } + } +} + +void ErrorTrackingQubit::setEntangledPartner(IQubit* const partner) { + auto* et_partner_qubit = dynamic_cast(partner); + if (et_partner_qubit == nullptr) throw std::runtime_error("ErrorTrackingQubit::setEntangledPartner: invalid qubit type passed"); + entangled_partner = et_partner_qubit; +} + +IQubit* const ErrorTrackingQubit::getEntangledPartner() const { return entangled_partner; } + +const IQubitId* const ErrorTrackingQubit::getId() const { return id; } + // Set error matrices. This is used in the process of simulating tomography. const SingleQubitErrorModel ErrorTrackingQubit::pauli = {.X = (Matrix2cd() << 0, 1, 1, 0).finished(), .Y = (Matrix2cd() << 0, Complex(0, -1), Complex(0, 1), 0).finished(), diff --git a/quisp/backends/ErrorTracking/Qubit.h b/quisp/backends/ErrorTracking/Qubit.h index c697cee67..e763502ee 100644 --- a/quisp/backends/ErrorTracking/Qubit.h +++ b/quisp/backends/ErrorTracking/Qubit.h @@ -1,11 +1,13 @@ #pragma once #include #include +#include #include #include #include #include "../interfaces/IQuantumBackend.h" #include "../interfaces/IQubit.h" +#include "backends/ErrorTracking/Configuration.h" #include "omnetpp/simtime.h" #include "types.h" @@ -15,15 +17,18 @@ using abstract::EigenvalueResult; using abstract::IQuantumBackend; using abstract::IQubit; using abstract::IQubitId; +using abstract::MeasurementOutcome; using abstract::MeasureXResult; using abstract::MeasureYResult; using abstract::MeasureZResult; using abstract::SimTime; using abstract::SimTimeUnit; using Eigen::Matrix2cd; +using Eigen::Matrix4cd; using Eigen::MatrixPower; using Eigen::MatrixXd; using Eigen::Vector2cd; +using Eigen::Vector4cd; class ErrorTrackingBackend; class ErrorTrackingQubit : public IQubit { @@ -34,31 +39,37 @@ class ErrorTrackingQubit : public IQubit { ~ErrorTrackingQubit(); void setMemoryErrorRates(double x_error_rate, double y_error_rate, double z_error_rate, double excitation_rate, double relaxation_rate, double completely_mixed_rate); void reset(); - + void configure(std::unique_ptr configuration); + const IQubitId* const getId() const override; void setFree() override; - MeasureXResult correlationMeasureX(); - MeasureYResult correlationMeasureY(); - MeasureZResult correlationMeasureZ(); - EigenvalueResult localMeasureX(); - EigenvalueResult localMeasureZ(); + MeasureXResult correlationMeasureX() override; + MeasureYResult correlationMeasureY() override; + MeasureZResult correlationMeasureZ() override; + EigenvalueResult localMeasureX() override; + EigenvalueResult localMeasureZ() override; void gateX() override; void gateZ() override; void gateH() override; void gateCNOT(IQubit* const control_qubit) override; bool purifyX(IQubit* const control_qubit) override; bool purifyZ(IQubit* const target_qubit) override; + MeasurementOutcome measureDensityIndependent() override; + void addErrorX() override; + void addErrorZ() override; + void assertEntangledPartnerValid() override; + void setEntangledPartner(IQubit* const partner) override; + IQubit* const getEntangledPartner() const override; protected: void applySingleQubitGateError(SingleGateErrorModel const& err); void applyTwoQubitGateError(TwoQubitGateErrorModel const& err, ErrorTrackingQubit* another_qubit); void applyMemoryError(); - void addErrorX(); - void addErrorZ(); void setRelaxedDensityMatrix(); void setExcitedDensityMatrix(); - void setCompletelyMixedDensityMatrix(); - - void update(); + void setCompletelyMixedDensityMatrix() override; + Matrix2cd getErrorMatrix(); + QuantumState getQuantumState(); + MeasurementOperator randomMeasurementBasisSelection(); // constants SingleGateErrorModel gate_err_h; @@ -73,11 +84,14 @@ class ErrorTrackingQubit : public IQubit { static const MeasurementOperators measurement_op; // state + bool god_dm_has_x_error = false; + bool god_dm_has_z_error = false; bool has_x_error = false; bool has_z_error = false; bool has_relaxation_error = false; bool has_excitation_error = false; bool has_completely_mixed_error = false; + bool partner_measured = false; SimTime updated_time = SimTime(0); Matrix2cd density_matrix_collapsed; // Used when partner has been measured. bool no_density_matrix_nullptr_entangled_partner_ok = false; diff --git a/quisp/backends/ErrorTracking/Qubit_gate_error_test.cc b/quisp/backends/ErrorTracking/Qubit_gate_error_test.cc index ee9c7971e..0c317ea01 100644 --- a/quisp/backends/ErrorTracking/Qubit_gate_error_test.cc +++ b/quisp/backends/ErrorTracking/Qubit_gate_error_test.cc @@ -1,6 +1,5 @@ #include #include -#include #include #include "test.h" @@ -15,10 +14,10 @@ class EtQubitGateErrorTest : public ::testing::Test { SimTime::setScaleExp(-9); rng = new TestRNG(); rng->double_value = .0; - backend = std::make_unique(std::unique_ptr(rng)); - qubit = dynamic_cast(backend->getQubit(new QubitId(0))); + backend = std::make_unique(std::unique_ptr(rng), std::make_unique()); + qubit = dynamic_cast(backend->createQubit(0)); if (qubit == nullptr) throw std::runtime_error("Qubit is nullptr"); - qubit2 = dynamic_cast(backend->getQubit(new QubitId(1))); + qubit2 = dynamic_cast(backend->createQubit(1)); if (qubit2 == nullptr) throw std::runtime_error("Qubit is nullptr"); backend->setSimTime(SimTime(1, SIMTIME_US)); fillParams(qubit); diff --git a/quisp/backends/ErrorTracking/Qubit_measurement_test.cc b/quisp/backends/ErrorTracking/Qubit_measurement_test.cc index 98d23c73d..d4cefbf29 100644 --- a/quisp/backends/ErrorTracking/Qubit_measurement_test.cc +++ b/quisp/backends/ErrorTracking/Qubit_measurement_test.cc @@ -1,6 +1,5 @@ #include #include -#include #include #include "test.h" @@ -15,17 +14,20 @@ class EtQubitMeasurementTest : public ::testing::Test { rng = new TestRNG(); rng->double_value = .0; - backend = std::make_unique(std::unique_ptr(rng)); - qubit = dynamic_cast(backend->getQubit(0)); - qubit2 = dynamic_cast(backend->getQubit(1)); - another_qubit = dynamic_cast(backend->getQubit(2)); + backend = std::make_unique(std::unique_ptr(rng), std::make_unique()); + qubit = dynamic_cast(backend->createQubit(0)); + another_qubit = dynamic_cast(backend->createQubit(2)); backend->setSimTime(SimTime(1, SIMTIME_US)); fillParams(qubit); - fillParams(qubit2); fillParams(another_qubit); } - + void reinitializeBellpair() { + qubit->reset(); + another_qubit->reset(); + qubit->entangled_partner = another_qubit; + another_qubit->entangled_partner = qubit; + } void fillParams(Qubit* qubit) { // ceiled values should be: // No error= 0.1, X error = 0.6, Z error = 0.7, Y error = 0.8, Excitation = 0.9, Relaxation = 1.0 @@ -81,7 +83,6 @@ class EtQubitMeasurementTest : public ::testing::Test { qubit->measurement_err.setParams(x_measurement_error_rate, y_measurement_error_rate, z_measurement_error_rate); } Qubit* qubit; - Qubit* qubit2; Qubit* another_qubit; std::unique_ptr backend; TestRNG* rng; @@ -197,8 +198,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { ASSERT_NE(qubit->entangled_partner, nullptr); ASSERT_NE(another_qubit->entangled_partner, nullptr); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::PLUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -206,8 +206,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::MINUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -215,8 +214,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::PLUS_ONE); @@ -225,8 +223,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::MINUS_ONE); @@ -235,8 +232,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::PLUS_ONE); @@ -245,8 +241,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::MINUS_ONE); @@ -255,8 +250,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.7; @@ -266,8 +260,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.3; @@ -280,9 +273,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithoutError) { TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { qubit->measurement_err.x_error_rate = 0.99; - qubit->entangled_partner = another_qubit; - another_qubit->entangled_partner = qubit; - + reinitializeBellpair(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::MINUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -290,8 +281,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::PLUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -299,8 +289,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::MINUS_ONE); @@ -309,8 +298,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::PLUS_ONE); @@ -319,8 +307,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::MINUS_ONE); @@ -329,8 +316,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureX(), EigenvalueResult::PLUS_ONE); @@ -339,8 +325,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.7; @@ -350,8 +335,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_TRUE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.3; @@ -363,11 +347,7 @@ TEST_F(EtQubitMeasurementTest, localXMeasurementWithError) { } TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { - qubit->entangled_partner = another_qubit; - another_qubit->entangled_partner = qubit; - - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::PLUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -375,8 +355,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::MINUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -384,8 +363,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::PLUS_ONE); @@ -394,8 +372,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::MINUS_ONE); @@ -404,8 +381,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::PLUS_ONE); @@ -414,8 +390,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::MINUS_ONE); @@ -424,8 +399,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.7; @@ -435,8 +409,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.3; @@ -449,11 +422,8 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithoutError) { TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { qubit->measurement_err.z_error_rate = 0.99; - qubit->entangled_partner = another_qubit; - another_qubit->entangled_partner = qubit; - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::MINUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -461,8 +431,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::PLUS_ONE); EXPECT_FALSE(qubit->has_x_error); @@ -470,8 +439,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::MINUS_ONE); @@ -480,8 +448,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::PLUS_ONE); @@ -490,8 +457,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.7; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::MINUS_ONE); @@ -500,8 +466,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorX(); rng->double_value = 0.3; EXPECT_EQ(qubit->localMeasureZ(), EigenvalueResult::PLUS_ONE); @@ -510,8 +475,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { EXPECT_FALSE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.7; @@ -521,8 +485,7 @@ TEST_F(EtQubitMeasurementTest, localZMeasurementWithError) { EXPECT_TRUE(another_qubit->has_x_error); EXPECT_FALSE(another_qubit->has_z_error); - qubit->reset(); - another_qubit->reset(); + reinitializeBellpair(); qubit->addErrorZ(); qubit->addErrorX(); rng->double_value = 0.3; diff --git a/quisp/backends/ErrorTracking/Qubit_memory_error_test.cc b/quisp/backends/ErrorTracking/Qubit_memory_error_test.cc index f6fcb8848..0746af55f 100644 --- a/quisp/backends/ErrorTracking/Qubit_memory_error_test.cc +++ b/quisp/backends/ErrorTracking/Qubit_memory_error_test.cc @@ -1,11 +1,17 @@ #include #include #include +#include #include +#include "backends/ErrorTracking/types.h" #include "test.h" namespace { using namespace quisp_test::backends; +using Eigen::Matrix2cd; +using Eigen::Matrix4cd; +using Eigen::Vector4cd; +using quisp::backends::error_tracking::QuantumState; class ETQubitMemoryErrorTest : public ::testing::Test { protected: @@ -14,8 +20,9 @@ class ETQubitMemoryErrorTest : public ::testing::Test { SimTime::setScaleExp(-9); rng = new TestRNG(); rng->double_value = .0; - backend = std::make_unique(std::unique_ptr(rng)); - qubit = dynamic_cast(backend->getQubit(0)); + backend = std::make_unique(std::unique_ptr(rng), std::make_unique()); + qubit = dynamic_cast(backend->createQubit(0)); + partner_qubit = dynamic_cast(backend->createQubit(1)); if (qubit == nullptr) throw std::runtime_error("Qubit is nullptr"); backend->setSimTime(SimTime(1, SIMTIME_US)); fillParams(qubit); @@ -34,6 +41,7 @@ class ETQubitMemoryErrorTest : public ::testing::Test { } Qubit* qubit; + Qubit* partner_qubit; std::unique_ptr backend; TestRNG* rng; }; @@ -392,4 +400,70 @@ TEST_F(ETQubitMemoryErrorTest, apply_memory_error_relaxation_error) { EXPECT_FALSE(qubit->has_completely_mixed_error); } +TEST_F(ETQubitMemoryErrorTest, getErrorMatrixTest) { + Matrix2cd err; + + err = qubit->getErrorMatrix(); + EXPECT_EQ(Matrix2cd::Identity(), err); + + Matrix2cd Z(2, 2); + Z << 1, 0, 0, -1; + qubit->addErrorZ(); + err = qubit->getErrorMatrix(); + EXPECT_EQ(Z, err); + qubit->setFree(); + + Matrix2cd X(2, 2); + X << 0, 1, 1, 0; + qubit->addErrorX(); + err = qubit->getErrorMatrix(); + EXPECT_EQ(X, err); + qubit->setFree(); + + Matrix2cd Y(2, 2); + Y << 0, Complex(0, -1), Complex(0, 1), 0; + qubit->addErrorX(); + qubit->addErrorZ(); + err = qubit->getErrorMatrix(); + EXPECT_EQ(Y, err); + qubit->setFree(); +} + +TEST_F(ETQubitMemoryErrorTest, getQuantumState) { + qubit->entangled_partner = partner_qubit; + + QuantumState state; + + state = qubit->getQuantumState(); + Vector4cd state_vector(4); + state_vector << 1 / sqrt(2), 0, 0, 1 / sqrt(2); + Matrix4cd dm(4, 4); + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); + + qubit->addErrorX(); + state = qubit->getQuantumState(); + state_vector << 0, 1 / sqrt(2), 1 / sqrt(2), 0; + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); + qubit->addErrorX(); + + partner_qubit->addErrorX(); + state = qubit->getQuantumState(); + state_vector << 0, 1 / sqrt(2), 1 / sqrt(2), 0; + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); + partner_qubit->addErrorX(); + + qubit->addErrorZ(); + state = qubit->getQuantumState(); + state_vector << 1 / sqrt(2), 0, 0, -1 / sqrt(2); + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); + qubit->addErrorZ(); +} } // namespace diff --git a/quisp/backends/ErrorTracking/Qubit_test.cc b/quisp/backends/ErrorTracking/Qubit_test.cc new file mode 100644 index 000000000..5b461034d --- /dev/null +++ b/quisp/backends/ErrorTracking/Qubit_test.cc @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include "backends/ErrorTracking/types.h" +#include "test.h" + +namespace { +using namespace quisp_test::backends; +using Eigen::Matrix2cd; +using Eigen::Matrix4cd; +using Eigen::Vector4cd; +using quisp::backends::error_tracking::QuantumState; + +class EtQubitTest : public ::testing::Test { + protected: + virtual void SetUp() { + // to avoid the omnetpp::SimTime assertion + SimTime::setScaleExp(-9); + rng = new TestRNG(); + rng->double_value = .0; + backend = std::make_unique(std::unique_ptr(rng), std::make_unique()); + qubit = dynamic_cast(backend->createQubit(0)); + partner_qubit = dynamic_cast(backend->createQubit(1)); + if (qubit == nullptr) throw std::runtime_error("Qubit is nullptr"); + backend->setSimTime(SimTime(1, SIMTIME_US)); + fillParams(qubit); + } + + void fillParams(Qubit* qubit) { + // ceiled values should be: + // No error= 0.1, X error = 0.6, Z error = 0.7, Y error = 0.8, Excitation = 0.9, Relaxation = 1.0 + double x_error_rate = .1; + double y_error_rate = .1; + double z_error_rate = .1; + double energy_excitation_rate = .1; + double energy_relaxation_rate = .1; + double completely_mixed_rate = 0; + qubit->setMemoryErrorRates(x_error_rate, y_error_rate, z_error_rate, energy_excitation_rate, energy_relaxation_rate, completely_mixed_rate); + } + + Qubit* qubit; + Qubit* partner_qubit; + std::unique_ptr backend; + TestRNG* rng; +}; + +TEST_F(EtQubitTest, getErrorMatrixTest) { + Matrix2cd err; + + err = qubit->getErrorMatrix(); + EXPECT_EQ(Matrix2cd::Identity(), err); + + Matrix2cd Z(2, 2); + Z << 1, 0, 0, -1; + qubit->addErrorZ(); + err = qubit->getErrorMatrix(); + EXPECT_EQ(Z, err); + qubit->setFree(); + + Matrix2cd X(2, 2); + X << 0, 1, 1, 0; + qubit->addErrorX(); + err = qubit->getErrorMatrix(); + EXPECT_EQ(X, err); + qubit->setFree(); + + Matrix2cd Y(2, 2); + Y << 0, Complex(0, -1), Complex(0, 1), 0; + qubit->addErrorX(); + qubit->addErrorZ(); + err = qubit->getErrorMatrix(); + EXPECT_EQ(Y, err); + qubit->setFree(); +} + +TEST_F(EtQubitTest, getQuantumState) { + qubit->setEntangledPartner(partner_qubit); + + QuantumState state; + + state = qubit->getQuantumState(); + Vector4cd state_vector(4); + state_vector << 1 / sqrt(2), 0, 0, 1 / sqrt(2); + Matrix4cd dm(4, 4); + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); + + qubit->addErrorX(); + state = qubit->getQuantumState(); + state_vector << 0, 1 / sqrt(2), 1 / sqrt(2), 0; + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); + qubit->addErrorX(); + + partner_qubit->addErrorX(); + state = qubit->getQuantumState(); + state_vector << 0, 1 / sqrt(2), 1 / sqrt(2), 0; + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); + partner_qubit->addErrorX(); + + qubit->addErrorZ(); + state = qubit->getQuantumState(); + state_vector << 1 / sqrt(2), 0, 0, -1 / sqrt(2); + dm = state_vector * state_vector.adjoint(); + EXPECT_EQ(dm, state.state_in_density_matrix); + EXPECT_EQ(state_vector, state.state_in_ket); +} + +TEST_F(EtQubitTest, setFreeUpdatesTime) { + qubit->setFree(); + EXPECT_EQ(qubit->updated_time, backend->getSimTime()); + auto last_updated_at = qubit->updated_time; + backend->setSimTime(10); + EXPECT_EQ(qubit->updated_time, last_updated_at); + qubit->setFree(); + EXPECT_EQ(qubit->updated_time, backend->getSimTime()); +} + +TEST_F(EtQubitTest, initialize_memory_transition_matrix) { + qubit->setMemoryErrorRates(.011, .012, .013, .014, .015, .0); + + auto mat = qubit->memory_transition_matrix; + + // each element means: "Clean Xerror Zerror Yerror Excited Relaxed Mixed" + Eigen::RowVectorXd row0(7); + double sigma = .011 + .013 + .012 + .014 + .015; + row0 << 1 - sigma, .011, .013, .012, .014, .015, .0; + ASSERT_EQ(mat.row(0), row0); + + Eigen::RowVectorXd row1(7); + row1 << .011, 1 - sigma, .012, .013, .014, .015, .0; + ASSERT_EQ(mat.row(1), row1); + + Eigen::RowVectorXd row2(7); + row2 << .013, .012, 1 - sigma, .011, .014, .015, .0; + ASSERT_EQ(mat.row(2), row2); + + Eigen::RowVectorXd row3(7); + row3 << .012, .013, .011, 1 - sigma, .014, .015, .0; + ASSERT_EQ(mat.row(3), row3); + + Eigen::RowVectorXd row4(7); + row4 << 0, 0, 0, 0, 1 - .015, .015, .0; + ASSERT_EQ(mat.row(4), row4); + + Eigen::RowVectorXd row5(7); + row5 << 0, 0, 0, 0, .014, 1 - .014, .0; + ASSERT_EQ(mat.row(5), row5); + + Eigen::RowVectorXd row6(7); + row6 << 0, 0, 0, 0, .014, .015, 1 - (.014 + .015); + ASSERT_EQ(mat.row(6), row6); +} + +TEST_F(EtQubitTest, addErrorX) { + EXPECT_FALSE(qubit->has_x_error); + qubit->addErrorX(); + EXPECT_TRUE(qubit->has_x_error); + qubit->addErrorX(); + EXPECT_FALSE(qubit->has_x_error); +} + +TEST_F(EtQubitTest, addErrorZ) { + EXPECT_FALSE(qubit->has_z_error); + qubit->addErrorZ(); + EXPECT_TRUE(qubit->has_z_error); + qubit->addErrorZ(); + EXPECT_FALSE(qubit->has_z_error); +} + +TEST_F(EtQubitTest, backend_mock) { + auto* qubit = backend->getQubit(1); + auto* another_qubit = backend->getQubit(1); + ASSERT_EQ(qubit, another_qubit); +} +} // namespace diff --git a/quisp/backends/ErrorTracking/test.h b/quisp/backends/ErrorTracking/test.h index a10479ae5..33f78e842 100644 --- a/quisp/backends/ErrorTracking/test.h +++ b/quisp/backends/ErrorTracking/test.h @@ -6,6 +6,7 @@ #include "../interfaces/IQubitId.h" #include "../interfaces/IRandomNumberGenerator.h" #include "Backend.h" +#include "Configuration.h" #include "Qubit.h" namespace quisp_test::backends { @@ -13,9 +14,11 @@ using omnetpp::SimTime; using ::quisp::backends::abstract::IQubit; using ::quisp::backends::abstract::IQubitId; using ::quisp::backends::error_tracking::ErrorTrackingBackend; +using ::quisp::backends::error_tracking::ErrorTrackingConfiguration; using ::quisp::backends::error_tracking::ErrorTrackingQubit; using namespace ::quisp::backends; using namespace ::quisp::backends::abstract; +using Complex = std::complex; class QubitId : public IQubitId { public: @@ -51,6 +54,8 @@ class Qubit : public ErrorTrackingQubit { using ErrorTrackingQubit::gate_err_h; using ErrorTrackingQubit::gate_err_x; using ErrorTrackingQubit::gate_err_z; + using ErrorTrackingQubit::getErrorMatrix; + using ErrorTrackingQubit::getQuantumState; using ErrorTrackingQubit::has_completely_mixed_error; using ErrorTrackingQubit::has_excitation_error; using ErrorTrackingQubit::has_relaxation_error; @@ -58,7 +63,9 @@ class Qubit : public ErrorTrackingQubit { using ErrorTrackingQubit::has_z_error; using ErrorTrackingQubit::localMeasureX; using ErrorTrackingQubit::localMeasureZ; + using ErrorTrackingQubit::measureDensityIndependent; using ErrorTrackingQubit::measurement_err; + using ErrorTrackingQubit::memory_transition_matrix; using ErrorTrackingQubit::setMemoryErrorRates; using ErrorTrackingQubit::updated_time; @@ -73,13 +80,14 @@ class Qubit : public ErrorTrackingQubit { class Backend : public ErrorTrackingBackend { public: using ErrorTrackingBackend::qubits; - Backend(std::unique_ptr rng) : ErrorTrackingBackend(std::move(rng)) {} - IQubit* getQubit(int id) { return getQubit(new QubitId(id)); } - IQubit* getQubit(const IQubitId* id) override { + Backend(std::unique_ptr rng, std::unique_ptr config) : ErrorTrackingBackend(std::move(rng), std::move(config)) {} + IQubit* createQubit(int id) { return this->createQubitInternal(new QubitId(id)); } + IQubit* getQubit(int id) { return this->getQubitInternal(new QubitId(id)); } + IQubit* getQubitInternal(const IQubitId* id) { return qubits.find(id)->second.get(); } + IQubit* createQubitInternal(const IQubitId* id) { auto qubit = qubits.find(id); - if (qubit != qubits.cend()) { - return qubit->second.get(); + return nullptr; } auto original_qubit = std::make_unique(id, this); auto* qubit_ptr = original_qubit.get(); diff --git a/quisp/backends/ErrorTracking/types.h b/quisp/backends/ErrorTracking/types.h index 40b209017..337f1163a 100644 --- a/quisp/backends/ErrorTracking/types.h +++ b/quisp/backends/ErrorTracking/types.h @@ -1,4 +1,4 @@ -#include +#pragma once #include #include @@ -140,14 +140,6 @@ struct MeasurementErrorModel { } }; -struct GodErrorState { - bool has_x_error; - bool has_z_error; - bool has_excitation_error; - bool has_relaxation_error; - bool has_completely_mixed_error; -}; - // Matrices of single qubit errors. Used when conducting tomography. struct SingleQubitErrorModel { Eigen::Matrix2cd X; // double 2*2 matrix @@ -172,4 +164,9 @@ struct MeasurementOperators { Eigen::Matrix2cd identity; }; +struct QuantumState { + Eigen::Matrix4cd state_in_density_matrix; + Eigen::Vector4cd state_in_ket; +}; + } // namespace quisp::backends::error_tracking diff --git a/quisp/backends/interfaces/IConfiguration.h b/quisp/backends/interfaces/IConfiguration.h new file mode 100644 index 000000000..755593ab8 --- /dev/null +++ b/quisp/backends/interfaces/IConfiguration.h @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace quisp::backends::abstract { + +/** + * @brief just an interface for the configuration to the backend + */ +class IConfiguration { + public: + IConfiguration(){}; + virtual ~IConfiguration(){}; +}; + +} // namespace quisp::backends::abstract diff --git a/quisp/backends/interfaces/IQuantumBackend.h b/quisp/backends/interfaces/IQuantumBackend.h index 724864cad..419c10fc8 100644 --- a/quisp/backends/interfaces/IQuantumBackend.h +++ b/quisp/backends/interfaces/IQuantumBackend.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include "IConfiguration.h" #include "IQubitId.h" namespace quisp::backends::abstract { @@ -19,7 +21,11 @@ class IQuantumBackend { IQuantumBackend(){}; virtual ~IQuantumBackend(){}; + virtual IQubit* createQubit(const IQubitId* id, std::unique_ptr conf) = 0; + virtual IQubit* createQubit(const IQubitId* id) = 0; virtual IQubit* getQubit(const IQubitId* id) = 0; + virtual void deleteQubit(const IQubitId* id) = 0; + virtual std::unique_ptr getDefaultConfiguration() const = 0; virtual const SimTime& getSimTime() = 0; virtual void setSimTime(SimTime time) = 0; diff --git a/quisp/backends/interfaces/IQubit.h b/quisp/backends/interfaces/IQubit.h index c512bef8d..c39a27f59 100644 --- a/quisp/backends/interfaces/IQubit.h +++ b/quisp/backends/interfaces/IQubit.h @@ -1,11 +1,40 @@ +#pragma once #include namespace quisp::backends::abstract { + +enum class MeasureXResult : int { + NO_Z_ERROR, + HAS_Z_ERROR, +}; +enum class MeasureYResult : int { + NO_XZ_ERROR, + HAS_XZ_ERROR, +}; +enum class MeasureZResult : int { + NO_X_ERROR, + HAS_X_ERROR, +}; +enum class EigenvalueResult : int { + PLUS_ONE, + MINUS_ONE, +}; +struct MeasurementOutcome { + char basis; + bool outcome_is_plus; + char GOD_clean; + bool operator==(const MeasurementOutcome &outcome) const { return basis == outcome.basis && outcome_is_plus == outcome.outcome_is_plus && GOD_clean == outcome.GOD_clean; } +}; + +class IQubitId; + class IQubit { public: IQubit(){}; virtual ~IQubit(){}; virtual void setFree() = 0; + virtual const IQubitId *const getId() const { throw std::runtime_error("getId is not implemented"); } + // // single qubit operations virtual void gateX() { throw std::runtime_error("gateX not implemented"); } virtual void gateY() { throw std::runtime_error("gateY not implemented"); } @@ -20,22 +49,24 @@ class IQubit { virtual void gateCZ(IQubit *const control_qubit) { throw std::runtime_error("gateCZ not implemented"); }; virtual bool purifyX(IQubit *const control_qubit) { throw std::runtime_error("gateCZ not implemented"); }; virtual bool purifyZ(IQubit *const target_qubit) { throw std::runtime_error("gateCZ not implemented"); }; -}; -enum class MeasureXResult : int { - NO_Z_ERROR, - HAS_Z_ERROR, -}; -enum class MeasureYResult : int { - NO_XZ_ERROR, - HAS_XZ_ERROR, -}; -enum class MeasureZResult : int { - NO_X_ERROR, - HAS_X_ERROR, -}; -enum class EigenvalueResult : int { - PLUS_ONE, - MINUS_ONE, + // measurements + virtual MeasureXResult correlationMeasureX() { throw std::runtime_error("correlationMeasureX not implemented"); } + virtual MeasureYResult correlationMeasureY() { throw std::runtime_error("correlationMeasureY not implemented"); } + virtual MeasureZResult correlationMeasureZ() { throw std::runtime_error("correlationMeasureZ not implemented"); } + virtual EigenvalueResult localMeasureX() { throw std::runtime_error("localMeasureX not implemented"); } + virtual EigenvalueResult localMeasureZ() { throw std::runtime_error("localMeasureZ not implemented"); } + virtual MeasurementOutcome measureDensityIndependent() { throw std::runtime_error("measureDensityIndependent not implemented"); } + + // for debugging + virtual void assertEntangledPartnerValid() { throw std::runtime_error("assertEntangledPartnerValid not implemented"); }; + + // deprecated (ErrorTraciking Qubit specific) + virtual void addErrorX() { throw std::runtime_error("addErrorX is not implemented. will be removed"); } + virtual void addErrorZ() { throw std::runtime_error("addErrorZ is not implemented. will be removed"); } + virtual void setCompletelyMixedDensityMatrix() { throw std::runtime_error("setCompletelyMixedDensityMatrix is not implemented. will be removed"); } + virtual void setEntangledPartner(IQubit *const partner) { throw std::runtime_error("setEntangledPartner is not implemented. will be removed"); } + virtual IQubit *const getEntangledPartner() const { throw std::runtime_error("getEntangledPartner is not implemented. will be removed"); } }; + } // namespace quisp::backends::abstract diff --git a/quisp/modules/Backend/Backend.cc b/quisp/modules/Backend/Backend.cc index a517e35f9..24d4e3336 100644 --- a/quisp/modules/Backend/Backend.cc +++ b/quisp/modules/Backend/Backend.cc @@ -1,7 +1,70 @@ #include "Backend.h" +#include "backends/ErrorTracking/Qubit.h" namespace quisp::modules::backend { + BackendContainer::BackendContainer() {} + BackendContainer::~BackendContainer() {} +void BackendContainer::initialize() { + auto backend_type = std::string(par("backend_type").stringValue()); + if (backend_type == "ErrorTrackingBackend") { + configureErrorTrackingBackend(); + } else { + throw omnetpp::cRuntimeError("Unknown backend type: %s", backend_type.c_str()); + } +} + +void BackendContainer::configureErrorTrackingBackend() { + auto conf = std::make_unique(); + conf->measurement_x_err_rate = par("x_measurement_error_rate").doubleValue(); + conf->measurement_y_err_rate = par("y_measurement_error_rate").doubleValue(); + conf->measurement_z_err_rate = par("z_measurement_error_rate").doubleValue(); + + conf->h_gate_err_rate = par("h_gate_error_rate").doubleValue(); + conf->h_gate_x_err_ratio = par("h_gate_x_error_ratio").doubleValue(); + conf->h_gate_y_err_ratio = par("h_gate_y_error_ratio").doubleValue(); + conf->h_gate_z_err_ratio = par("h_gate_z_error_ratio").doubleValue(); + + conf->x_gate_err_rate = par("x_gate_error_rate").doubleValue(); + conf->x_gate_x_err_ratio = par("x_gate_x_error_ratio").doubleValue(); + conf->x_gate_y_err_ratio = par("x_gate_y_error_ratio").doubleValue(); + conf->x_gate_z_err_ratio = par("x_gate_z_error_ratio").doubleValue(); + + conf->z_gate_err_rate = par("z_gate_error_rate").doubleValue(); + conf->z_gate_x_err_ratio = par("z_gate_x_error_ratio").doubleValue(); + conf->z_gate_y_err_ratio = par("z_gate_y_error_ratio").doubleValue(); + conf->z_gate_z_err_ratio = par("z_gate_z_error_ratio").doubleValue(); + + conf->cnot_gate_err_rate = par("cnot_gate_error_rate").doubleValue(); + conf->cnot_gate_iz_err_ratio = par("cnot_gate_iz_error_ratio").doubleValue(); + conf->cnot_gate_zi_err_ratio = par("cnot_gate_zi_error_ratio").doubleValue(); + conf->cnot_gate_zz_err_ratio = par("cnot_gate_zz_error_ratio").doubleValue(); + conf->cnot_gate_ix_err_ratio = par("cnot_gate_ix_error_ratio").doubleValue(); + conf->cnot_gate_xi_err_ratio = par("cnot_gate_xi_error_ratio").doubleValue(); + conf->cnot_gate_xx_err_ratio = par("cnot_gate_xx_error_ratio").doubleValue(); + conf->cnot_gate_iy_err_ratio = par("cnot_gate_iy_error_ratio").doubleValue(); + conf->cnot_gate_yi_err_ratio = par("cnot_gate_yi_error_ratio").doubleValue(); + conf->cnot_gate_yy_err_ratio = par("cnot_gate_yy_error_ratio").doubleValue(); + + conf->memory_x_err_rate = par("memory_x_error_rate").doubleValue(); + conf->memory_y_err_rate = par("memory_y_error_rate").doubleValue(); + conf->memory_z_err_rate = par("memory_z_error_rate").doubleValue(); + conf->memory_excitation_rate = par("memory_energy_excitation_rate").doubleValue(); + conf->memory_relaxation_rate = par("memory_energy_relaxation_rate").doubleValue(); + conf->memory_completely_mixed_rate = par("memory_completely_mixed_rate").doubleValue(); + + backend = std::make_unique(std::make_unique(this), std::move(conf), static_cast(this)); +} +void BackendContainer::willUpdate(ErrorTrackingBackend& backend) { backend.setSimTime(omnetpp::simTime()); } +void BackendContainer::finish() {} + +IQuantumBackend* BackendContainer::getQuantumBackend() { + if (backend == nullptr) { + throw omnetpp::cRuntimeError("Backend is not initialized"); + } + return backend.get(); +} + } // namespace quisp::modules::backend diff --git a/quisp/modules/Backend/Backend.h b/quisp/modules/Backend/Backend.h index a291229ef..91a7c6dc2 100644 --- a/quisp/modules/Backend/Backend.h +++ b/quisp/modules/Backend/Backend.h @@ -3,37 +3,28 @@ #include #include #include "RNG.h" +#include "backends/ErrorTracking/Qubit.h" namespace quisp::modules::backend { using quisp::modules::common::ErrorTrackingBackend; +using quisp::modules::common::ErrorTrackingConfiguration; using quisp::modules::common::IQuantumBackend; using rng::RNG; -class BackendContainer : public omnetpp::cSimpleModule { +class BackendContainer : public omnetpp::cSimpleModule, ErrorTrackingBackend::ICallback { public: BackendContainer(); ~BackendContainer(); - void initialize() override { - auto backend_type = std::string(par("backend_type").stringValue()); - if (backend_type == "ErrorTrackingBackend") { - backend = std::make_unique(std::make_unique(this)); - } else { - throw omnetpp::cRuntimeError("Unknown backend type: %s", backend_type.c_str()); - } - } + void initialize() override; + void finish() override; - void finish() override {} - - IQuantumBackend* getQuantumBackend() { - if (backend == nullptr) { - throw omnetpp::cRuntimeError("Backend is not initialized"); - } - return backend.get(); - } + IQuantumBackend* getQuantumBackend(); + void willUpdate(ErrorTrackingBackend& backend) override; protected: - std::unique_ptr backend; + void configureErrorTrackingBackend(); + std::unique_ptr backend = nullptr; }; Define_Module(BackendContainer); diff --git a/quisp/modules/Backend/Backend.ned b/quisp/modules/Backend/Backend.ned index 4edf2d232..16a8b0bcf 100644 --- a/quisp/modules/Backend/Backend.ned +++ b/quisp/modules/Backend/Backend.ned @@ -7,4 +7,44 @@ simple Backend @class(BackendContainer); @display("p=30,40;"); string backend_type = default("ErrorTrackingBackend"); + + // ErrorTracking Backend Configurations + // characteristics of the hardware + double memory_error_rate = default(0); + double memory_z_error_rate = default(1); + double memory_x_error_rate = default(1); + double memory_y_error_rate = default(1); + double memory_energy_excitation_rate = default(1); + double memory_energy_relaxation_rate = default(1); + double memory_completely_mixed_rate = default(1); + + double h_gate_error_rate = default(0); + double h_gate_x_error_ratio = default(1); + double h_gate_y_error_ratio = default(1); + double h_gate_z_error_ratio = default(1); + + double x_gate_error_rate = default(0); + double x_gate_x_error_ratio = default(1); + double x_gate_y_error_ratio = default(1); + double x_gate_z_error_ratio = default(1); + + double z_gate_error_rate = default(0); + double z_gate_x_error_ratio = default(1); + double z_gate_y_error_ratio = default(1); + double z_gate_z_error_ratio = default(1); + + double cnot_gate_error_rate = default(0); + double cnot_gate_iz_error_ratio = default(1); + double cnot_gate_zi_error_ratio = default(1); + double cnot_gate_zz_error_ratio = default(1); + double cnot_gate_ix_error_ratio = default(1); + double cnot_gate_xi_error_ratio = default(1); + double cnot_gate_xx_error_ratio = default(1); + double cnot_gate_iy_error_ratio = default(1); + double cnot_gate_yi_error_ratio = default(1); + double cnot_gate_yy_error_ratio = default(1); + + double x_measurement_error_rate = default(0); + double y_measurement_error_rate = default(0); + double z_measurement_error_rate = default(0); } diff --git a/quisp/modules/Backend/Backend_test.cc b/quisp/modules/Backend/Backend_test.cc index 12073ee5a..13f3575f8 100644 --- a/quisp/modules/Backend/Backend_test.cc +++ b/quisp/modules/Backend/Backend_test.cc @@ -1,12 +1,14 @@ #include "Backend.h" #include #include +#include "backends/interfaces/IQuantumBackend.h" #include "modules/common_types.h" namespace { using namespace quisp_test; using OriginalBackendContainer = quisp::modules::backend::BackendContainer; using quisp::modules::backend::ErrorTrackingBackend; +using quisp::modules::backend::ErrorTrackingConfiguration; class BackendContainer : public OriginalBackendContainer { public: @@ -16,31 +18,66 @@ class BackendContainer : public OriginalBackendContainer { ~BackendContainer() override {} }; -TEST(BackendContainer, constructor) { BackendContainer backend; } +class BackendContainerTest : public ::testing::Test { + protected: + virtual void SetUp() { + auto *sim = utils::prepareSimulation(); + backend = new BackendContainer(); + setParDouble(backend, "x_measurement_error_rate", .02); + setParDouble(backend, "y_measurement_error_rate", .03); + setParDouble(backend, "z_measurement_error_rate", .04); + setParDouble(backend, "h_gate_error_rate", .05); + setParDouble(backend, "h_gate_x_error_ratio", .06); + setParDouble(backend, "h_gate_y_error_ratio", .07); + setParDouble(backend, "h_gate_z_error_ratio", .08); + setParDouble(backend, "x_gate_error_rate", .06); + setParDouble(backend, "x_gate_x_error_ratio", .07); + setParDouble(backend, "x_gate_y_error_ratio", .08); + setParDouble(backend, "x_gate_z_error_ratio", .09); + setParDouble(backend, "z_gate_error_rate", .10); + setParDouble(backend, "z_gate_x_error_ratio", .11); + setParDouble(backend, "z_gate_y_error_ratio", .12); + setParDouble(backend, "z_gate_z_error_ratio", .13); + setParDouble(backend, "cnot_gate_error_rate", .14); + setParDouble(backend, "cnot_gate_ix_error_ratio", .15); + setParDouble(backend, "cnot_gate_xi_error_ratio", .16); + setParDouble(backend, "cnot_gate_xx_error_ratio", .17); + setParDouble(backend, "cnot_gate_iy_error_ratio", .18); + setParDouble(backend, "cnot_gate_yi_error_ratio", .19); + setParDouble(backend, "cnot_gate_yy_error_ratio", .20); + setParDouble(backend, "cnot_gate_iz_error_ratio", .21); + setParDouble(backend, "cnot_gate_zi_error_ratio", .22); + setParDouble(backend, "cnot_gate_zz_error_ratio", .23); + setParDouble(backend, "memory_x_error_rate", .24); + setParDouble(backend, "memory_y_error_rate", .25); + setParDouble(backend, "memory_z_error_rate", .26); + setParDouble(backend, "memory_energy_excitation_rate", .27); + setParDouble(backend, "memory_energy_relaxation_rate", .28); + setParDouble(backend, "memory_completely_mixed_rate", .29); + sim->registerComponent(backend); + } + virtual void TearDown() {} -TEST(BackendContainer, callInitialize) { - auto *sim = utils::prepareSimulation(); - BackendContainer *backend = new BackendContainer(); - sim->registerComponent(backend); + // managed by cSimulation, so we don't need to use unique_ptr nor delete manually. + BackendContainer *backend; +}; + +TEST_F(BackendContainerTest, constructor) { BackendContainer backend; } + +TEST_F(BackendContainerTest, callInitialize) { setParStr(backend, "backend_type", "ErrorTrackingBackend"); EXPECT_EQ(backend->backend, nullptr); backend->callInitialize(); EXPECT_NE(backend->backend, nullptr); } -TEST(BackendContainer, callInitializeWithInvalidBackend) { - auto *sim = utils::prepareSimulation(); - BackendContainer *backend = new BackendContainer(); - sim->registerComponent(backend); +TEST_F(BackendContainerTest, callInitializeWithInvalidBackend) { setParStr(backend, "backend_type", "SomeInvalidBackend"); EXPECT_EQ(backend->backend, nullptr); EXPECT_THROW(backend->callInitialize(), omnetpp::cRuntimeError); } -TEST(BackendContainer, getQuantumBackend) { - auto *sim = utils::prepareSimulation(); - BackendContainer *backend = new BackendContainer(); - sim->registerComponent(backend); +TEST_F(BackendContainerTest, getQuantumBackend) { setParStr(backend, "backend_type", "ErrorTrackingBackend"); backend->callInitialize(); ASSERT_NE(backend->backend, nullptr); @@ -49,4 +86,48 @@ TEST(BackendContainer, getQuantumBackend) { auto *et_backend = dynamic_cast(b); EXPECT_NE(et_backend, nullptr); } + +TEST_F(BackendContainerTest, getQuantumBackendWithoutInit) { + setParStr(backend, "backend_type", "ErrorTrackingBackend"); + ASSERT_EQ(backend->backend, nullptr); + EXPECT_ANY_THROW({ backend->getQuantumBackend(); }); +} + +TEST_F(BackendContainerTest, getBackendConfiguration) { + setParStr(backend, "backend_type", "ErrorTrackingBackend"); + backend->callInitialize(); + ASSERT_NE(backend->backend, nullptr); + auto *b = backend->getQuantumBackend(); + ASSERT_NE(b, nullptr); + auto *et_backend = dynamic_cast(b); + + auto conf = et_backend->getDefaultConfiguration(); + ASSERT_NE(conf, nullptr); + auto et_conf = dynamic_cast(conf.get()); + ASSERT_NE(et_conf, nullptr); +} + +TEST_F(BackendContainerTest, getCopyOfBackendConfiguration) { + setParStr(backend, "backend_type", "ErrorTrackingBackend"); + backend->callInitialize(); + ASSERT_NE(backend->backend, nullptr); + auto *b = backend->getQuantumBackend(); + ASSERT_NE(b, nullptr); + auto *et_backend = dynamic_cast(b); + + auto conf = et_backend->getDefaultConfiguration(); + auto et_conf = dynamic_cast(conf.get()); + + auto conf2 = et_backend->getDefaultConfiguration(); + auto et_conf2 = dynamic_cast(conf2.get()); + + // confirm et_conf and et_conf2 are different intstances + et_conf->cnot_gate_err_rate = 10; + EXPECT_NE(et_conf->cnot_gate_err_rate, et_conf2->cnot_gate_err_rate); + EXPECT_NE(et_conf, et_conf2); +} + +TEST_F(BackendContainerTest, finish) { + EXPECT_NO_THROW({ backend->finish(); }); +} } // namespace diff --git a/quisp/modules/PhysicalConnection/BSA/BellStateAnalyzer.cc b/quisp/modules/PhysicalConnection/BSA/BellStateAnalyzer.cc index ccfbf9a4c..97f47dfa1 100644 --- a/quisp/modules/PhysicalConnection/BSA/BellStateAnalyzer.cc +++ b/quisp/modules/PhysicalConnection/BSA/BellStateAnalyzer.cc @@ -292,10 +292,6 @@ void BellStateAnalyzer::GOD_updateEntangledInfoParameters_of_qubits() { right_statQubit_ptr->setEntangledPartnerInfo(left_statQubit_ptr); if (right_photon_Xerr) right_statQubit_ptr->addXerror(); if (right_photon_Zerr) right_statQubit_ptr->addZerror(); - if (right_statQubit_ptr->entangled_partner == nullptr || left_statQubit_ptr->entangled_partner == nullptr) { - std::cout << "Entangling failed\n"; - error("Entangling failed"); - } n_res++; emit(GOD_num_resSignal, n_res); } diff --git a/quisp/modules/QNIC/StationaryQubit/IStationaryQubit.h b/quisp/modules/QNIC/StationaryQubit/IStationaryQubit.h index c885b284b..162d7cb3e 100644 --- a/quisp/modules/QNIC/StationaryQubit/IStationaryQubit.h +++ b/quisp/modules/QNIC/StationaryQubit/IStationaryQubit.h @@ -1,28 +1,18 @@ #pragma once #include +#include #include #include + namespace quisp { namespace types { -enum class MeasureXResult : int { - NO_Z_ERROR, - HAS_Z_ERROR, -}; -enum class MeasureYResult : int { - NO_XZ_ERROR, - HAS_XZ_ERROR, -}; -enum class MeasureZResult : int { - NO_X_ERROR, - HAS_X_ERROR, -}; - -enum class EigenvalueResult : int { - PLUS_ONE, - MINUS_ONE, -}; +using quisp::backends::EigenvalueResult; +using quisp::backends::MeasurementOutcome; +using quisp::backends::MeasureXResult; +using quisp::backends::MeasureYResult; +using quisp::backends::MeasureZResult; enum class CliffordOperator : int { Id = 0, @@ -54,128 +44,13 @@ enum class CliffordOperator : int { } // namespace types namespace modules { -struct emission_error_model { - double pauli_error_rate; // Overall error rate - double Z_error_rate; - double X_error_rate; - double Y_error_rate; - double Loss_error_rate; - - double No_error_ceil; - double X_error_ceil; - double Y_error_ceil; - double Z_error_ceil; - double Loss_error_ceil; -}; - -struct SingleGateErrorModel { - double pauli_error_rate; // Overall error rate - double Z_error_rate; - double X_error_rate; - double Y_error_rate; - - double No_error_ceil; - double Z_error_ceil; - double X_error_ceil; - double Y_error_ceil; -}; - -struct TwoQubitGateErrorModel { - double pauli_error_rate; // Overall error rate - double IZ_error_rate; - double ZI_error_rate; - double ZZ_error_rate; - double IY_error_rate; - double YI_error_rate; - double YY_error_rate; - double IX_error_rate; - double XI_error_rate; - double XX_error_rate; - - double No_error_ceil; - double IZ_error_ceil; - double ZI_error_ceil; - double ZZ_error_ceil; - double IY_error_ceil; - double YI_error_ceil; - double YY_error_ceil; - double IX_error_ceil; - double XI_error_ceil; - double XX_error_ceil; -}; - -struct memory_error_model { - double error_rate; // Overall error rate - double Z_error_rate; - double X_error_rate; - double Y_error_rate; - double excitation_error_rate; - double relaxation_error_rate; - double completely_mixed_rate; -}; - -struct MeasurementErrorModel { - double x_error_rate; - double y_error_rate; - double z_error_rate; -}; - -struct GodErrorState { - bool has_x_error = false; - bool has_z_error = false; - bool has_excitation_error = false; - bool has_relaxation_error = false; - bool has_completely_mixed_error = false; -}; - -// Matrices of single qubit errors. Used when conducting tomography. -struct single_qubit_error { - Eigen::Matrix2cd X; // double 2*2 matrix - Eigen::Matrix2cd Y; // complex double 2*2 matrix - Eigen::Matrix2cd Z; - Eigen::Matrix2cd I; -}; - -struct quantum_state { - Eigen::Matrix4cd state_in_density_matrix; - Eigen::Vector4cd state_in_ket; -}; - -struct measurement_output_probabilities { - double probability_plus_plus; // P(+,+) - double probability_minus_plus; // P(+,-) - double probability_plus_minus; // P(-,+) - double probability_minus_minus; // P(-,-) -}; - -struct measurement_operator { - Eigen::Matrix2cd plus; - Eigen::Matrix2cd minus; - Eigen::Vector2cd plus_ket; - Eigen::Vector2cd minus_ket; - char basis; -}; - -// Single qubit -struct measurement_operators { - measurement_operator X_basis; - measurement_operator Y_basis; - measurement_operator Z_basis; - Eigen::Matrix2cd identity; -}; - -struct measurement_outcome { - char basis; - bool outcome_is_plus; - char GOD_clean; - bool operator==(const measurement_outcome &outcome) const { return basis == outcome.basis && outcome_is_plus == outcome.outcome_is_plus && GOD_clean == outcome.GOD_clean; } -}; class IStationaryQubit : public omnetpp::cSimpleModule { public: IStationaryQubit(){}; virtual ~IStationaryQubit(){}; + // RTC virtual void setFree(bool consumed) = 0; /*In use. E.g. waiting for purification result.*/ virtual void Lock(unsigned long rs_id, int rule_id, int action_id) = 0; @@ -198,18 +73,10 @@ class IStationaryQubit : public omnetpp::cSimpleModule { /** * Performs measurement and returns +(true) or -(false) based on the density matrix of the state. Used for tomography. * */ - virtual measurement_outcome measure_density_independent() = 0; /*Separate dm calculation*/ - virtual types::EigenvalueResult measureX() = 0; - virtual types::EigenvalueResult measureY() = 0; - virtual types::EigenvalueResult measureZ() = 0; - - virtual void CNOT_gate(IStationaryQubit *control_qubit) = 0; - virtual void Hadamard_gate() = 0; - virtual void Z_gate() = 0; - virtual void X_gate() = 0; - virtual bool Xpurify(IStationaryQubit *resource_qubit) = 0; - virtual bool Zpurify(IStationaryQubit *resource_qubit) = 0; + // RandomMeasureAction + virtual types::MeasurementOutcome measure_density_independent() = 0; /*Separate dm calculation*/ + // graph internal virtual void cnotGate(IStationaryQubit *control_qubit) = 0; virtual void hadamardGate() = 0; virtual void zGate() = 0; @@ -219,49 +86,29 @@ class IStationaryQubit : public omnetpp::cSimpleModule { virtual void excite() = 0; virtual void relax() = 0; + // SwappingAction, SimultaneousSwappingAction + virtual void CNOT_gate(IStationaryQubit *control_qubit) = 0; + // SimultaneousSwappingAction + virtual void Hadamard_gate() = 0; + // RTC + virtual void Z_gate() = 0; + virtual void X_gate() = 0; + // Action + virtual bool Xpurify(IStationaryQubit *resource_qubit) = 0; + virtual bool Zpurify(IStationaryQubit *resource_qubit) = 0; + /*GOD parameters*/ - GodErrorState god_err; + // SwappingAction virtual void setEntangledPartnerInfo(IStationaryQubit *partner) = 0; - virtual void setCompletelyMixedDensityMatrix() = 0; - virtual void addXerror() = 0; - virtual void addZerror() = 0; + virtual backends::IQubit *getEntangledPartner() const = 0; + virtual backends::IQubit *getBackendQubitRef() const = 0; + virtual int getPartnerStationaryQubitAddress() const = 0; + virtual void assertEntangledPartnerValid() = 0; - int stationary_qubit_address; - int node_address; int qnic_address; int qnic_type; int qnic_index; - int god_entangled_stationary_qubit_address; - int god_entangled_node_address; - int god_entangled_qnic_address; - int god_entangled_qnic_type; - int action_index; - bool no_density_matrix_nullptr_entangled_partner_ok; - - /** Pointer to the entangled qubit*/ - IStationaryQubit *entangled_partner = nullptr; - /** Photon emitted at*/ - omnetpp::simtime_t emitted_time = -1; - /** Stationary qubit last updated at*/ - omnetpp::simtime_t updated_time = -1; - - /** Standard deviation */ - double emission_jittering_standard_deviation; - - SingleGateErrorModel Hgate_error; - SingleGateErrorModel Xgate_error; - SingleGateErrorModel Zgate_error; - TwoQubitGateErrorModel CNOTgate_error; - MeasurementErrorModel Measurement_error; - - Eigen::Matrix2cd Density_Matrix_Collapsed; // Used when partner has been measured. - bool partner_measured; - bool completely_mixed; - bool excited_or_relaxed; - bool GOD_dm_Xerror; - bool GOD_dm_Zerror; }; - } // namespace modules } // namespace quisp diff --git a/quisp/modules/QNIC/StationaryQubit/QubitId.h b/quisp/modules/QNIC/StationaryQubit/QubitId.h new file mode 100644 index 000000000..f0e97bdbc --- /dev/null +++ b/quisp/modules/QNIC/StationaryQubit/QubitId.h @@ -0,0 +1,33 @@ +#pragma once +#include "backends/Backends.h" +#include "modules/QNIC/StationaryQubit/IStationaryQubit.h" + +namespace quisp::modules::qubit_id { + +class QubitId : public quisp::backends::IQubitId { + public: + QubitId(int node_addr, int qnic_index, int qnic_type, int qubit_addr) : node_addr(node_addr), qnic_index(qnic_index), qnic_type(qnic_type), qubit_addr((qubit_addr)) {} + std::size_t hash() const override { + size_t seed = std::hash()(node_addr); + hashCombine(seed, qnic_index); + hashCombine(seed, qnic_type); + hashCombine(seed, qubit_addr); + return seed; + } + + bool compare(const IQubitId& id_ref) const override { + const QubitId& id = dynamic_cast(id_ref); + return node_addr == id.node_addr && qnic_index == id.qnic_index && qnic_type == id.qnic_type && qubit_addr == id.qubit_addr; + } + + int node_addr; + int qnic_index; + int qnic_type; + int qubit_addr; + + protected: + // https://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine + void hashCombine(std::size_t& seed, int const& v) const { seed ^= std::hash()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } +}; + +} // namespace quisp::modules::qubit_id diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit.cc b/quisp/modules/QNIC/StationaryQubit/StationaryQubit.cc index 503c094ec..51abed301 100644 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit.cc +++ b/quisp/modules/QNIC/StationaryQubit/StationaryQubit.cc @@ -10,16 +10,21 @@ #include #include #include +#include #include #include #include #include +#include "modules/QNIC/StationaryQubit/QubitId.h" +#include "omnetpp/cexception.h" using namespace Eigen; using quisp::messages::PhotonicQubit; +using quisp::modules::qubit_id::QubitId; using quisp::types::CliffordOperator; using quisp::types::EigenvalueResult; +using quisp::types::MeasurementOutcome; using quisp::types::MeasureXResult; using quisp::types::MeasureYResult; using quisp::types::MeasureZResult; @@ -40,59 +45,6 @@ StationaryQubit::StationaryQubit() : provider(utils::ComponentProvider{this}) {} void StationaryQubit::initialize() { // read and set parameters emission_success_probability = par("emission_success_probability"); - memory_err.X_error_rate = (double)par("memory_x_error_rate").doubleValue(); - memory_err.Y_error_rate = (double)par("memory_y_error_rate").doubleValue(); - memory_err.Z_error_rate = (double)par("memory_z_error_rate").doubleValue(); - memory_err.excitation_error_rate = (double)par("memory_energy_excitation_rate").doubleValue(); - memory_err.relaxation_error_rate = (double)par("memory_energy_relaxation_rate").doubleValue(); - memory_err.completely_mixed_rate = (double)par("memory_completely_mixed_rate").doubleValue(); - memory_err.error_rate = memory_err.X_error_rate + memory_err.Y_error_rate + memory_err.Z_error_rate + memory_err.excitation_error_rate + memory_err.relaxation_error_rate + - memory_err.completely_mixed_rate; // This is per μs. - Memory_Transition_matrix = MatrixXd::Zero(7, 7); - // clang-format off - Memory_Transition_matrix << - 1 - memory_err.error_rate, memory_err.X_error_rate, memory_err.Z_error_rate, memory_err.Y_error_rate, memory_err.excitation_error_rate, memory_err.relaxation_error_rate, memory_err.completely_mixed_rate, - memory_err.X_error_rate, 1 - memory_err.error_rate, memory_err.Y_error_rate, memory_err.Z_error_rate, memory_err.excitation_error_rate, memory_err.relaxation_error_rate, memory_err.completely_mixed_rate, - memory_err.Z_error_rate, memory_err.Y_error_rate, 1 - memory_err.error_rate, memory_err.X_error_rate, memory_err.excitation_error_rate, memory_err.relaxation_error_rate, memory_err.completely_mixed_rate, - memory_err.Y_error_rate, memory_err.Z_error_rate, memory_err.X_error_rate, 1 - memory_err.error_rate, memory_err.excitation_error_rate, memory_err.relaxation_error_rate, memory_err.completely_mixed_rate, - 0, 0, 0, 0, 1 - memory_err.relaxation_error_rate - memory_err.completely_mixed_rate, memory_err.relaxation_error_rate, memory_err.completely_mixed_rate, - 0, 0, 0, 0, memory_err.excitation_error_rate, 1 - memory_err.excitation_error_rate - memory_err.completely_mixed_rate, memory_err.completely_mixed_rate, - 0, 0, 0, 0, memory_err.excitation_error_rate, memory_err.relaxation_error_rate, 1 - memory_err.excitation_error_rate - memory_err.relaxation_error_rate; - // clang-format on - god_err.has_x_error = false; - god_err.has_z_error = false; - god_err.has_excitation_error = false; - god_err.has_relaxation_error = false; - god_err.has_completely_mixed_error = false; - setSingleQubitGateErrorModel(Hgate_error, "h_gate"); - setSingleQubitGateErrorModel(Xgate_error, "x_gate"); - setSingleQubitGateErrorModel(Zgate_error, "z_gate"); - setTwoQubitGateErrorCeilings(CNOTgate_error, "cnot_gate"); - setMeasurementErrorModel(Measurement_error); - - // Set error matrices. This is used in the process of simulating tomography. - Pauli.X << 0, 1, 1, 0; - Pauli.Y << 0, Complex(0, -1), Complex(0, 1), 0; - Pauli.Z << 1, 0, 0, -1; - Pauli.I << 1, 0, 0, 1; - - // Set measurement operators. This is used in the process of simulating tomography. - meas_op.X_basis.plus << 0.5, 0.5, 0.5, 0.5; - meas_op.X_basis.minus << 0.5, -0.5, -0.5, 0.5; - meas_op.X_basis.plus_ket << 1 / sqrt(2), 1 / sqrt(2); - meas_op.X_basis.minus_ket << 1 / sqrt(2), -1 / sqrt(2); - meas_op.X_basis.basis = 'X'; - meas_op.Z_basis.plus << 1, 0, 0, 0; - meas_op.Z_basis.minus << 0, 0, 0, 1; - meas_op.Z_basis.plus_ket << 1, 0; - meas_op.Z_basis.minus_ket << 0, 1; - meas_op.Z_basis.basis = 'Z'; - meas_op.Y_basis.plus << 0.5, Complex(0, -0.5), Complex(0, 0.5), 0.5; - meas_op.Y_basis.minus << 0.5, Complex(0, 0.5), Complex(0, -0.5), 0.5; - meas_op.Y_basis.plus_ket << 1 / sqrt(2), Complex(0, 1 / sqrt(2)); - meas_op.Y_basis.minus_ket << 1 / sqrt(2), -Complex(0, 1 / sqrt(2)); - meas_op.Y_basis.basis = 'Y'; - meas_op.identity << 1, 0, 0, 1; // Get parameters from omnet stationary_qubit_address = par("stationary_qubit_address"); @@ -101,27 +53,67 @@ void StationaryQubit::initialize() { qnic_type = par("qnic_type"); qnic_index = par("qnic_index"); emission_jittering_standard_deviation = par("emission_jittering_standard_deviation").doubleValue(); - setFree(false); /* e^(t/T1) energy relaxation, e^(t/T2) phase relaxation. Want to use only 1/10 of T1 and T2 in general.*/ // initialize variables for graph state representation tracking vertex_operator = CliffordOperator::H; - auto *backend = provider.getQuantumBackend(); - // qubit_ref = backend->getQubit({node_address, qnic_index, qnic_type, stationary_qubit_address}); + backend = provider.getQuantumBackend(); + auto config = prepareBackendQubitConfiguration(true); + qubit_ref = backend->createQubit(new QubitId(node_address, qnic_index, qnic_type, stationary_qubit_address), std::move(config)); + if (qubit_ref == nullptr) throw std::runtime_error("qubit_ref nullptr error"); + setFree(false); // watch variables to show them in the GUI WATCH(emitted_time); - WATCH(updated_time); - WATCH(god_err.has_x_error); - WATCH(god_err.has_z_error); - WATCH(god_err.has_excitation_error); - WATCH(god_err.has_relaxation_error); - WATCH(god_err.has_completely_mixed_error); WATCH(is_busy); } +std::unique_ptr StationaryQubit::prepareBackendQubitConfiguration(bool overwrite) { + auto conf = backend->getDefaultConfiguration(); + if (!overwrite) return conf; + if (auto et_conf = dynamic_cast(conf.get())) { + et_conf->measurement_x_err_rate = par("x_measurement_error_rate").doubleValue(); + et_conf->measurement_y_err_rate = par("y_measurement_error_rate").doubleValue(); + et_conf->measurement_z_err_rate = par("z_measurement_error_rate").doubleValue(); + + et_conf->h_gate_err_rate = par("h_gate_error_rate").doubleValue(); + et_conf->h_gate_x_err_ratio = par("h_gate_x_error_ratio").doubleValue(); + et_conf->h_gate_y_err_ratio = par("h_gate_y_error_ratio").doubleValue(); + et_conf->h_gate_z_err_ratio = par("h_gate_z_error_ratio").doubleValue(); + + et_conf->x_gate_err_rate = par("x_gate_error_rate").doubleValue(); + et_conf->x_gate_x_err_ratio = par("x_gate_x_error_ratio").doubleValue(); + et_conf->x_gate_y_err_ratio = par("x_gate_y_error_ratio").doubleValue(); + et_conf->x_gate_z_err_ratio = par("x_gate_z_error_ratio").doubleValue(); + + et_conf->z_gate_err_rate = par("z_gate_error_rate").doubleValue(); + et_conf->z_gate_x_err_ratio = par("z_gate_x_error_ratio").doubleValue(); + et_conf->z_gate_y_err_ratio = par("z_gate_y_error_ratio").doubleValue(); + et_conf->z_gate_z_err_ratio = par("z_gate_z_error_ratio").doubleValue(); + + et_conf->cnot_gate_err_rate = par("cnot_gate_error_rate").doubleValue(); + et_conf->cnot_gate_iz_err_ratio = par("cnot_gate_iz_error_ratio").doubleValue(); + et_conf->cnot_gate_zi_err_ratio = par("cnot_gate_zi_error_ratio").doubleValue(); + et_conf->cnot_gate_zz_err_ratio = par("cnot_gate_zz_error_ratio").doubleValue(); + et_conf->cnot_gate_ix_err_ratio = par("cnot_gate_ix_error_ratio").doubleValue(); + et_conf->cnot_gate_xi_err_ratio = par("cnot_gate_xi_error_ratio").doubleValue(); + et_conf->cnot_gate_xx_err_ratio = par("cnot_gate_xx_error_ratio").doubleValue(); + et_conf->cnot_gate_iy_err_ratio = par("cnot_gate_iy_error_ratio").doubleValue(); + et_conf->cnot_gate_yi_err_ratio = par("cnot_gate_yi_error_ratio").doubleValue(); + et_conf->cnot_gate_yy_err_ratio = par("cnot_gate_yy_error_ratio").doubleValue(); + + et_conf->memory_x_err_rate = par("memory_x_error_rate").doubleValue(); + et_conf->memory_y_err_rate = par("memory_y_error_rate").doubleValue(); + et_conf->memory_z_err_rate = par("memory_z_error_rate").doubleValue(); + et_conf->memory_excitation_rate = par("memory_energy_excitation_rate").doubleValue(); + et_conf->memory_relaxation_rate = par("memory_energy_relaxation_rate").doubleValue(); + et_conf->memory_completely_mixed_rate = par("memory_completely_mixed_rate").doubleValue(); + } + return conf; +} + void StationaryQubit::finish() {} /** @@ -145,217 +137,27 @@ void StationaryQubit::handleMessage(cMessage *msg) { } } -void StationaryQubit::setSingleQubitGateErrorModel(SingleGateErrorModel &model, std::string gate_name) { - auto err_rate_name = gate_name + std::string("_error_rate"); - auto x_ratio_name = gate_name + std::string("_x_error_ratio"); - auto z_ratio_name = gate_name + std::string("_z_error_ratio"); - auto y_ratio_name = gate_name + std::string("_y_error_ratio"); - model.pauli_error_rate = par(err_rate_name.c_str()).doubleValue(); - auto x_ratio = par(x_ratio_name.c_str()).doubleValue(); - auto z_ratio = par(z_ratio_name.c_str()).doubleValue(); - auto y_ratio = par(y_ratio_name.c_str()).doubleValue(); - - double sum = x_ratio + z_ratio + y_ratio; - if (sum == 0) { - x_ratio = 1.; - z_ratio = 1.; - y_ratio = 1.; - sum = 3.; - } - - model.X_error_rate = model.pauli_error_rate * (x_ratio / sum); - model.Y_error_rate = model.pauli_error_rate * (y_ratio / sum); - model.Z_error_rate = model.pauli_error_rate * (z_ratio / sum); - model.No_error_ceil = 1 - model.pauli_error_rate; - model.X_error_ceil = model.No_error_ceil + model.X_error_rate; - model.Z_error_ceil = model.X_error_ceil + model.Z_error_rate; - model.Y_error_ceil = model.Z_error_ceil + model.Y_error_rate; -} - -void StationaryQubit::setTwoQubitGateErrorCeilings(TwoQubitGateErrorModel &model, std::string gate_name) { - // prepare parameter names - std::string err_rate_name = std::string(gate_name) + std::string("_error_rate"); - auto ix_ratio_name = gate_name + std::string("_ix_error_ratio"); - auto xi_ratio_name = gate_name + std::string("_xi_error_ratio"); - auto xx_rationame = gate_name + std::string("_xx_error_ratio"); - - auto iz_ratio_name = gate_name + std::string("_iz_error_ratio"); - auto zi_ratio_name = gate_name + std::string("_zi_error_ratio"); - auto zz_ratio_name = gate_name + std::string("_zz_error_ratio"); - - auto iy_ratio_name = gate_name + std::string("_iy_error_ratio"); - auto yi_ratio_name = gate_name + std::string("_yi_error_ratio"); - auto yy_ratio_name = gate_name + std::string("_yy_error_ratio"); - - // get error ratios from parameter - model.pauli_error_rate = par(err_rate_name.c_str()).doubleValue(); - double ix_ratio = par(ix_ratio_name.c_str()).doubleValue(); - double xi_ratio = par(xi_ratio_name.c_str()).doubleValue(); - double xx_ratio = par(xx_rationame.c_str()).doubleValue(); - - double iz_ratio = par(iz_ratio_name.c_str()).doubleValue(); - double zi_ratio = par(zi_ratio_name.c_str()).doubleValue(); - double zz_ratio = par(zz_ratio_name.c_str()).doubleValue(); - - double iy_ratio = par(iy_ratio_name.c_str()).doubleValue(); - double yi_ratio = par(yi_ratio_name.c_str()).doubleValue(); - double yy_ratio = par(yy_ratio_name.c_str()).doubleValue(); - - double ratio_sum = ix_ratio + xi_ratio + xx_ratio + iz_ratio + zi_ratio + zz_ratio + iy_ratio + yi_ratio + yy_ratio; - - if (ratio_sum == 0) { - ix_ratio = 1.; - xi_ratio = 1.; - xx_ratio = 1.; - iz_ratio = 1.; - zi_ratio = 1.; - zz_ratio = 1.; - iy_ratio = 1.; - yi_ratio = 1.; - yy_ratio = 1.; - ratio_sum = 9.; - } - - model.IX_error_rate = model.pauli_error_rate * (ix_ratio / ratio_sum); - model.XI_error_rate = model.pauli_error_rate * (xi_ratio / ratio_sum); - model.XX_error_rate = model.pauli_error_rate * (xx_ratio / ratio_sum); - - model.IZ_error_rate = model.pauli_error_rate * (iz_ratio / ratio_sum); - model.ZI_error_rate = model.pauli_error_rate * (zi_ratio / ratio_sum); - model.ZZ_error_rate = model.pauli_error_rate * (zz_ratio / ratio_sum); - - model.IY_error_rate = model.pauli_error_rate * (iy_ratio / ratio_sum); - model.YI_error_rate = model.pauli_error_rate * (yi_ratio / ratio_sum); - model.YY_error_rate = model.pauli_error_rate * (yy_ratio / ratio_sum); - - model.No_error_ceil = 1 - model.pauli_error_rate; - model.IX_error_ceil = model.No_error_ceil + model.IX_error_rate; - model.XI_error_ceil = model.IX_error_ceil + model.XI_error_rate; - model.XX_error_ceil = model.XI_error_ceil + model.XX_error_rate; - - model.IZ_error_ceil = model.XX_error_ceil + model.IZ_error_rate; - model.ZI_error_ceil = model.IZ_error_ceil + model.ZI_error_rate; - model.ZZ_error_ceil = model.ZI_error_ceil + model.ZZ_error_rate; - - model.IY_error_ceil = model.ZZ_error_ceil + model.IY_error_rate; - model.YI_error_ceil = model.IY_error_ceil + model.YI_error_rate; - model.YY_error_ceil = model.YI_error_ceil + model.YY_error_rate; -} - -void StationaryQubit::setMeasurementErrorModel(MeasurementErrorModel &model) { - model.x_error_rate = par("x_measurement_error_rate").doubleValue(); - model.y_error_rate = par("y_measurement_error_rate").doubleValue(); - model.z_error_rate = par("z_measurement_error_rate").doubleValue(); -} - -MeasureXResult StationaryQubit::correlationMeasureX() { - bool error = god_err.has_z_error; - if (dblrand() < Measurement_error.x_error_rate) { - error = !error; - } - return error ? MeasureXResult::HAS_Z_ERROR : MeasureXResult::NO_Z_ERROR; -} - -MeasureYResult StationaryQubit::correlationMeasureY() { - bool error = god_err.has_z_error != god_err.has_x_error; - if (dblrand() < Measurement_error.y_error_rate) { - error = !error; - } - return error ? MeasureYResult::HAS_XZ_ERROR : MeasureYResult::NO_XZ_ERROR; -} - -MeasureZResult StationaryQubit::correlationMeasureZ() { - bool error = god_err.has_x_error; - if (dblrand() < Measurement_error.x_error_rate) { - error = !error; - } - return error ? MeasureZResult::HAS_X_ERROR : MeasureZResult::NO_X_ERROR; -} - -EigenvalueResult StationaryQubit::localMeasureX() { - // the Z error will propagate to its partner; This only works for Bell pair and entanglement swapping for now - if (this->entangled_partner != nullptr && god_err.has_z_error) { - this->entangled_partner->addZerror(); - } - - auto result = EigenvalueResult::PLUS_ONE; - if (dblrand() < 0.5) { - result = EigenvalueResult::MINUS_ONE; - if (this->entangled_partner != nullptr) { - this->entangled_partner->addZerror(); - } - } - if (dblrand() < this->Measurement_error.x_error_rate) { - result = result == EigenvalueResult::PLUS_ONE ? EigenvalueResult::MINUS_ONE : EigenvalueResult::PLUS_ONE; - } - return result; -} - +MeasureXResult StationaryQubit::correlationMeasureX() { return qubit_ref->correlationMeasureX(); } +MeasureYResult StationaryQubit::correlationMeasureY() { return qubit_ref->correlationMeasureY(); } +MeasureZResult StationaryQubit::correlationMeasureZ() { return qubit_ref->correlationMeasureZ(); } +EigenvalueResult StationaryQubit::localMeasureX() { return qubit_ref->localMeasureX(); } EigenvalueResult StationaryQubit::localMeasureY() { error("Not Yet Implemented"); return EigenvalueResult::PLUS_ONE; } - -EigenvalueResult StationaryQubit::localMeasureZ() { - // the X error will propagate to its partner; This only works for Bell pair and entanglement swapping for now - if (this->entangled_partner != nullptr && god_err.has_x_error) { - this->entangled_partner->addXerror(); - } - - auto result = EigenvalueResult::PLUS_ONE; - if (dblrand() < 0.5) { - result = EigenvalueResult::MINUS_ONE; - if (this->entangled_partner != nullptr) { - this->entangled_partner->addXerror(); - } - } - if (dblrand() < this->Measurement_error.z_error_rate) { - result = result == EigenvalueResult::PLUS_ONE ? EigenvalueResult::MINUS_ONE : EigenvalueResult::PLUS_ONE; - } - return result; -} +EigenvalueResult StationaryQubit::localMeasureZ() { return qubit_ref->localMeasureZ(); } // Convert X to Z, and Z to X error. Therefore, Y error stays as Y. -void StationaryQubit::Hadamard_gate() { - // Need to add noise here later - applySingleQubitGateError(Hgate_error); - bool z = god_err.has_z_error; - god_err.has_z_error = god_err.has_x_error; - god_err.has_x_error = z; -} - -void StationaryQubit::Z_gate() { - // Need to add noise here later - applySingleQubitGateError(Zgate_error); - god_err.has_z_error = !god_err.has_z_error; -} - -void StationaryQubit::X_gate() { - // Need to add noise here later - applySingleQubitGateError(Xgate_error); - god_err.has_x_error = !god_err.has_x_error; -} - -void StationaryQubit::CNOT_gate(IStationaryQubit *control_qubit) { - // Need to add noise here later - applyTwoQubitGateError(CNOTgate_error, check_and_cast(control_qubit)); +void StationaryQubit::Hadamard_gate() { qubit_ref->gateH(); } +void StationaryQubit::Z_gate() { qubit_ref->gateZ(); } +void StationaryQubit::X_gate() { qubit_ref->gateX(); } - if (control_qubit->god_err.has_x_error) { - // X error propagates from control to target. If an X error is already present, then it cancels out. - god_err.has_x_error = !god_err.has_x_error; - } - - if (god_err.has_z_error) { - // Z error propagates from target to control. If an Z error is already present, then it cancels out. - control_qubit->god_err.has_z_error = !control_qubit->god_err.has_z_error; - } -} +void StationaryQubit::CNOT_gate(IStationaryQubit *control_qubit) { qubit_ref->gateCNOT(check_and_cast(control_qubit)->qubit_ref); } // This is invoked whenever a photon is emitted out from this particular qubit. void StationaryQubit::setBusy() { is_busy = true; emitted_time = simTime(); - updated_time = simTime(); // Should be no error at this time. if (hasGUI()) { getDisplayString().setTagArg("i", 1, "red"); } @@ -364,34 +166,15 @@ void StationaryQubit::setBusy() { // Re-initialization of this stationary qubit // This is called at the beginning of the simulation (in initialization() above), and whenever it is reinitialized via the RealTimeController. void StationaryQubit::setFree(bool consumed) { - num_purified = 0; + qubit_ref->setFree(); + is_busy = false; locked = false; locked_ruleset_id = -1; locked_rule_id = -1; action_index = -1; - - is_busy = false; emitted_time = -1; - updated_time = simTime(); - - partner_measured = false; - completely_mixed = false; - excited_or_relaxed = false; - GOD_dm_Zerror = false; - GOD_dm_Xerror = false; - Density_Matrix_Collapsed << -111, -111, -111, -111; - no_density_matrix_nullptr_entangled_partner_ok = false; - god_entangled_stationary_qubit_address = -1; - god_entangled_node_address = -1; - god_entangled_qnic_address = -1; - god_entangled_qnic_type = -1; - god_err.has_x_error = false; - god_err.has_z_error = false; - god_err.has_excitation_error = false; - god_err.has_relaxation_error = false; - god_err.has_completely_mixed_error = false; - entangled_partner = nullptr; - EV_DEBUG << "Freeing this qubit!!!" << this << " at qnode: " << node_address << " qnic_type: " << qnic_type << " qnic_index: " << qnic_index << "\n"; + + EV_DEBUG << "Freeing this qubit! " << this << " at qnode: " << node_address << " qnic_type: " << qnic_type << " qnic_index: " << qnic_index << "\n"; if (hasGUI()) { if (consumed) { bubble("Consumed!"); @@ -403,6 +186,9 @@ void StationaryQubit::setFree(bool consumed) { } } +backends::IQubit *StationaryQubit::getEntangledPartner() const { return qubit_ref->getEntangledPartner(); } +void StationaryQubit::assertEntangledPartnerValid() { qubit_ref->assertEntangledPartnerValid(); } + /*To avoid disturbing this qubit.*/ void StationaryQubit::Lock(unsigned long rs_id, int rule_id, int action_id) { if (rs_id == -1 || rule_id == -1 || action_id == -1) { @@ -476,582 +262,34 @@ void StationaryQubit::emitPhoton(int pulse) { } // This gets direcltly invoked when darkcount happened in BellStateAnalyzer.cc. -void StationaryQubit::setCompletelyMixedDensityMatrix() { - this->Density_Matrix_Collapsed << (double)1 / (double)2, 0, 0, (double)1 / (double)2; - // std::cout<<"Dm completely mixed "<Density_Matrix_Collapsed<<"\n"; - this->completely_mixed = true; - this->excited_or_relaxed = false; - - if (this->entangled_partner != nullptr) { // Eliminate entangled information - this->entangled_partner->entangled_partner = nullptr; - this->entangled_partner = nullptr; - } - this->god_err.has_completely_mixed_error = true; - this->god_err.has_excitation_error = false; - this->god_err.has_relaxation_error = false; - this->god_err.has_x_error = false; - this->god_err.has_z_error = false; - this->GOD_dm_Xerror = false; - this->GOD_dm_Zerror = false; - if (hasGUI()) { - bubble("Completely mixed. darkcount"); - getDisplayString().setTagArg("i", 1, "black"); - } -} - -// This gets invoked in memory error simulation or by BellStateAnalyzer if photonLoss + darkcount. -void StationaryQubit::setExcitedDensityMatrix() { - Density_Matrix_Collapsed << 1, 0, 0, 0; // Overwrite density matrix - completely_mixed = false; - excited_or_relaxed = true; // It is excited - - god_err.has_excitation_error = true; - god_err.has_relaxation_error = false; - god_err.has_completely_mixed_error = false; - god_err.has_x_error = false; - god_err.has_z_error = false; - GOD_dm_Xerror = false; - GOD_dm_Zerror = false; - if (hasGUI()) { - bubble("Completely mixed. darkcount"); - getDisplayString().setTagArg("i", 1, "white"); - } - - if (this->entangled_partner != nullptr) { // If it used to be entangled... - // error("What?"); - this->entangled_partner->updated_time = simTime(); - // This also eliminates the entanglement information. - this->entangled_partner->setCompletelyMixedDensityMatrix(); - } // else it is already not entangled. e.g. excited -> relaxed. -} - -void StationaryQubit::setRelaxedDensityMatrix() { - Density_Matrix_Collapsed << 0, 0, 0, 1; - completely_mixed = false; - excited_or_relaxed = true; - god_err.has_excitation_error = false; - god_err.has_relaxation_error = true; - god_err.has_completely_mixed_error = false; - god_err.has_x_error = false; - god_err.has_z_error = false; - GOD_dm_Xerror = false; - GOD_dm_Zerror = false; - if (hasGUI()) { - bubble("Completely mixed. darkcount"); - getDisplayString().setTagArg("i", 1, "white"); - } - - // Still entangled - if (this->entangled_partner != nullptr) { - this->entangled_partner->updated_time = simTime(); - this->entangled_partner->setCompletelyMixedDensityMatrix(); - } // else it is already not entangled. e.g. excited -> relaxed. -} +[[deprecated]] void StationaryQubit::setCompletelyMixedDensityMatrix() { qubit_ref->setCompletelyMixedDensityMatrix(); } void StationaryQubit::setEntangledPartnerInfo(IStationaryQubit *partner) { // When BSA succeeds, this method gets invoked to store entangled partner information. // This will also be sent classically to the partner node afterwards. - entangled_partner = partner; - god_entangled_stationary_qubit_address = partner->stationary_qubit_address; - god_entangled_node_address = partner->node_address; - god_entangled_qnic_address = partner->qnic_address; - god_entangled_qnic_type = partner->qnic_type; + qubit_ref->setEntangledPartner(partner->getBackendQubitRef()); +} + +backends::IQubit *StationaryQubit::getBackendQubitRef() const { return qubit_ref; } +int StationaryQubit::getPartnerStationaryQubitAddress() const { + auto *partner_qubit_ref = qubit_ref->getEntangledPartner(); + auto *partner_id = dynamic_cast(partner_qubit_ref->getId()); + if (partner_id == nullptr) cRuntimeError("StationaryQubit::getPartnerStationaryQubitAddress: null partner backend qubit id cast"); + return partner_id->qubit_addr; } /* Add another X error. If an X error already exists, then they cancel out */ -void StationaryQubit::addXerror() { this->god_err.has_x_error = !this->god_err.has_x_error; } +[[deprecated]] void StationaryQubit::addXerror() { qubit_ref->addErrorX(); } /* Add another Z error. If an Z error already exists, then they cancel out */ -void StationaryQubit::addZerror() { this->god_err.has_z_error = !this->god_err.has_z_error; } +[[deprecated]] void StationaryQubit::addZerror() { qubit_ref->addErrorZ(); } // Only tracks error propagation. If two booleans (Alice and Bob) agree (truetrue or falsefalse), keep the purified ebit. -bool StationaryQubit::Xpurify(IStationaryQubit *resource_qubit /*Controlled*/) { - // std::cout<<"X puri\n"; - // This could result in completelty mixed, excited, relaxed, which also affects the entangled partner. - applyMemoryError(); - check_and_cast(resource_qubit)->applyMemoryError(); - /*Target qubit*/ this->CNOT_gate(resource_qubit /*controlled qubit*/); - bool meas = this->correlationMeasureZ() == MeasureZResult::NO_X_ERROR; - return meas; -} - -bool StationaryQubit::Zpurify(IStationaryQubit *resource_qubit /*Target*/) { - applyMemoryError(); // This could result in completelty mixed, excited, relaxed, which also affects the entangled partner. - check_and_cast(resource_qubit)->applyMemoryError(); - /*Target qubit*/ resource_qubit->CNOT_gate(this /*controlled qubit*/); - this->Hadamard_gate(); - bool meas = this->correlationMeasureZ() == MeasureZResult::NO_X_ERROR; - return meas; -} +bool StationaryQubit::Xpurify(IStationaryQubit *resource_qubit /*Controlled*/) { return qubit_ref->purifyX(check_and_cast(resource_qubit)->qubit_ref); } -// Single qubit memory error based on Markov-Chain -void StationaryQubit::applyMemoryError() { - if (entangled_partner == nullptr && Density_Matrix_Collapsed(0, 0).real() == -111 && !no_density_matrix_nullptr_entangled_partner_ok) - error("This must not happen in apply memory error"); +bool StationaryQubit::Zpurify(IStationaryQubit *resource_qubit /*Target*/) { return qubit_ref->purifyZ(check_and_cast(resource_qubit)->qubit_ref); } - // If no memory error occurs, or if the state is completely mixed, skip this memory error simulation. - if (memory_err.error_rate == 0) { - // error("memory error is set to 0. If on purpose, that is fine. Comment this out."); - return; - } - - // Check when the error got updated last time. - // Errors will be performed depending on the difference between that time and the current time. - double time_evolution = simTime().dbl() - updated_time.dbl(); - double time_evolution_microsec = time_evolution * 1000000 /** 100*/; - if (time_evolution_microsec > 0) { - // Perform Monte-Carlo error simulation on this qubit. - bool has_x_err = god_err.has_x_error; - bool has_z_err = god_err.has_z_error; - bool is_excited = god_err.has_excitation_error; - bool is_relaxed = god_err.has_relaxation_error; - bool is_completely_mixed = god_err.has_completely_mixed_error; - if (completely_mixed != is_completely_mixed) { - error("[apply_memory_error] Completely mixed flag not matching"); - } - if (excited_or_relaxed != is_excited && excited_or_relaxed != is_relaxed) { - error("[apply_memory_error] Relaxed/Excited flag not matching"); - } - - bool skip_exponentiation = false; - for (int i = 0; i < Memory_Transition_matrix.cols(); i++) { - if (Memory_Transition_matrix(0, i) == 1) { - // Do not to the exponentiation! Eigen will mess up the exponentiation anyway... - skip_exponentiation = true; - break; - } - } - - MatrixXd transition_mat(7, 7); - if (!skip_exponentiation) { - // calculate time evoluted error matrix: Q^(time_evolution_microsec) in Eq 5.3 - MatrixPower q_pow(Memory_Transition_matrix); - transition_mat = q_pow(time_evolution_microsec); - } else { - transition_mat = Memory_Transition_matrix; - } - - // validate transition_mat - for (int r = 0; r < transition_mat.rows(); r++) { - double col_sum = 0; - for (int i = 0; i < transition_mat.cols(); i++) { - col_sum += transition_mat(r, i); - } - if (col_sum > 1.01 || col_sum < 0.99) { - std::cout << "col_sum = " << col_sum << std::endl; - error("Row of the transition matrix does not sum up to 1."); - } - } - - if (std::isnan(transition_mat(0, 0))) { - std::cout << "transition_mat: " << transition_mat << std::endl; - error("Transition maatrix is NaN. This is Eigen's fault."); - } - - // pi(0 ~ 6) vector in Eq 5.3 - MatrixXd pi_vector(1, 7); // I, X, Z, Y, Ex, Re, Cm - if (is_excited) { - pi_vector << 0, 0, 0, 0, 1, 0, 0; // excitation error - } else if (is_relaxed) { - pi_vector << 0, 0, 0, 0, 0, 1, 0; // relaxation error - } else if (is_completely_mixed) { - pi_vector << 0, 0, 0, 0, 0, 0, 1; // completely mixed error - } else if (has_z_err && has_x_err) { - pi_vector << 0, 0, 0, 1, 0, 0, 0; // Y error - } else if (has_z_err && !has_x_err) { - pi_vector << 0, 0, 1, 0, 0, 0, 0; // Z error - } else if (!has_z_err && has_x_err) { - pi_vector << 0, 1, 0, 0, 0, 0, 0; // X error - } else { - pi_vector << 1, 0, 0, 0, 0, 0, 0; // No error - } - // pi(t) in Eq 5.3 - // Clean, X, Z, Y, Excited, Relaxed - MatrixXd output_vector(1, 6); - // take error rate vector from DynamicTransitionMatrix Eq 5.3 - output_vector = pi_vector * transition_mat; - - /* this prepares the sectors for Monte-Carlo. later, we'll pick a random value and check with this sectors. - * - * 0.0 clean_ceil z_ceil excited_ceil 1.0 - * | | | | | - * | No Error | X Error | Z Error | Y Error | Excitation | Relaxation | Cmpletely Mixed | - * | | | - * x_ceil y_ceil relaxed_ceil - */ - double clean_ceil = output_vector(0, 0); - double x_ceil = clean_ceil + output_vector(0, 1); - double z_ceil = x_ceil + output_vector(0, 2); - double y_ceil = z_ceil + output_vector(0, 3); - double excited_ceil = y_ceil + output_vector(0, 4); - double relaxed_ceil = excited_ceil + output_vector(0, 5); - - // Gives a random double between 0.0 ~ 1.0 - double rand = dblrand(); - - if (rand < clean_ceil) { - // Qubit will end up with no error - god_err.has_x_error = false; - god_err.has_z_error = false; - } else if (clean_ceil <= rand && rand < x_ceil && (clean_ceil != x_ceil)) { - // X error - god_err.has_x_error = true; - god_err.has_z_error = false; - } else if (x_ceil <= rand && rand < z_ceil && (x_ceil != z_ceil)) { - // Z error - god_err.has_x_error = false; - god_err.has_z_error = true; - } else if (z_ceil <= rand && rand < y_ceil && (z_ceil != y_ceil)) { - // Y error - god_err.has_x_error = true; - god_err.has_z_error = true; - } else if (y_ceil <= rand && rand < excited_ceil && (y_ceil != excited_ceil)) { - // Excitation error - // Also sets the partner completely mixed if it used to be entangled. - setExcitedDensityMatrix(); - } else if (excited_ceil <= rand && rand < relaxed_ceil && (excited_ceil != relaxed_ceil)) { - // Excitation error - // Also sets the partner completely mixed if it used to be entangled. - setRelaxedDensityMatrix(); - } else { - // Memory completely mixed error - - // If this qubit still used to be entangled with another qubit. - if (entangled_partner != nullptr) { - entangled_partner->updated_time = simTime(); - // Break entanglement with partner. Overwrite its density matrix. - entangled_partner->setCompletelyMixedDensityMatrix(); - } - setCompletelyMixedDensityMatrix(); - } - } - updated_time = simTime(); -} - -Matrix2cd StationaryQubit::getErrorMatrix(StationaryQubit *qubit) { - if (qubit->god_err.has_completely_mixed_error || qubit->god_err.has_relaxation_error) { - error("CMerror in getErrorMatrix. Not supposed to happen."); - } - - auto has_z_err = qubit->god_err.has_z_error; - auto has_x_err = qubit->god_err.has_x_error; - - if (has_z_err && has_x_err) return Pauli.Y; - if (has_z_err) return Pauli.Z; - if (has_x_err) return Pauli.X; - return Pauli.I; -} - -// returns the density matrix of the Bell pair with error. This assumes that this is entangled with another stationary qubit. -// Measurement output will be based on this matrix, as long as it is still entangled. -quantum_state StationaryQubit::getQuantumState() { - if (this->excited_or_relaxed) error("this qubit is excited or relaxed"); - if (this->entangled_partner == nullptr) error("no entangled partner"); - if (this->entangled_partner->excited_or_relaxed) error("partner qubit is excited or relaxed"); - - Matrix4cd error_mat = kroneckerProduct(getErrorMatrix(this), getErrorMatrix(check_and_cast(entangled_partner))).eval(); - // Assumes that the state is a 2 qubit state |00> + |11> - Vector4cd ideal_bell_state(1 / sqrt(2), 0, 0, 1 / sqrt(2)); - Vector4cd actual_bell_state = error_mat * ideal_bell_state; - - quantum_state q; - q.state_in_density_matrix = actual_bell_state * actual_bell_state.adjoint(); - q.state_in_ket = actual_bell_state; - return q; -} - -void StationaryQubit::applySingleQubitGateError(SingleGateErrorModel const &err) { - if (err.pauli_error_rate == 0) { - return; - } - // Gives a random double between 0.0 ~ 1.0 - double rand = dblrand(); - - /* - * 0.0 No_error_ceil Z_error_ceil 1.0 - * | | | | - * | No Error | X Error | Z Error | Y Error | - * | - * X_error_ceil - */ - if (rand <= err.No_error_ceil) { - // No error - } else if (err.No_error_ceil < rand && rand <= err.X_error_ceil && (err.No_error_ceil != err.X_error_ceil)) { - // X error - addXerror(); - } else if (err.X_error_ceil < rand && rand <= err.Z_error_ceil && (err.X_error_ceil != err.Z_error_ceil)) { - // Z error - addZerror(); - } else { - // Y error - addZerror(); - addXerror(); - } -} - -void StationaryQubit::applyTwoQubitGateError(TwoQubitGateErrorModel const &err, StationaryQubit *another_qubit) { - if (err.pauli_error_rate == 0) { - return; - } - - // Gives a random double between 0.0 ~ 1.0 - double rand = dblrand(); - - /* - * 0.0 No_error_ceil XI_error_ceil IY_error_ceil YY_error_ceil ZI_error_ceil 1.0 - * | | | | | | | - * | No err | IX err | XI err | XX err | IY err | YI err | YY err | IZ err | ZI err | ZZ err | - * | | | | - * IX_error_ceil XX_error_ceil YI_error_ceil IZ_error_ceil - */ - if (rand <= err.No_error_ceil) { - // No error - } else if (err.No_error_ceil < rand && rand <= err.IX_error_ceil && (err.No_error_ceil != err.IX_error_ceil)) { - // IX error - addXerror(); - } else if (err.IX_error_ceil < rand && rand <= err.XI_error_ceil && (err.IX_error_ceil != err.XI_error_ceil)) { - // XI error - another_qubit->addXerror(); - } else if (err.XI_error_ceil < rand && rand <= err.XX_error_ceil && (err.XI_error_ceil != err.XX_error_ceil)) { - // XX error - addXerror(); - another_qubit->addXerror(); - } else if (err.XX_error_ceil < rand && rand <= err.IZ_error_ceil && (err.XX_error_ceil != err.IZ_error_ceil)) { - // IZ error - addZerror(); - } else if (err.IZ_error_ceil < rand && rand <= err.ZI_error_ceil && (err.IZ_error_ceil != err.ZI_error_ceil)) { - // ZI error - another_qubit->addZerror(); - } else if (err.ZI_error_ceil < rand && rand <= err.ZZ_error_ceil && (err.ZI_error_ceil != err.ZZ_error_ceil)) { - // ZZ error - addZerror(); - another_qubit->addZerror(); - } else if (err.ZZ_error_ceil < rand && rand <= err.IY_error_ceil && (err.ZZ_error_ceil != err.IY_error_ceil)) { - // IY error - addXerror(); - addZerror(); - } else if (err.IY_error_ceil < rand && rand <= err.YI_error_ceil && (err.IY_error_ceil != err.YI_error_ceil)) { - // YI error - another_qubit->addXerror(); - another_qubit->addZerror(); - } else { - // YY error - addXerror(); - addZerror(); - another_qubit->addXerror(); - another_qubit->addZerror(); - } -} - -measurement_outcome StationaryQubit::measure_density_independent() { - if (this->entangled_partner == nullptr && this->Density_Matrix_Collapsed(0, 0).real() == -111) { - std::cout << Density_Matrix_Collapsed << "\n"; - std::cout << "Measuring" << this << "in node[" << node_address << "]\n"; - std::cout << this->getIndex() << "\n"; - error("Measuring a qubit that is not entangled with another qubit. Probably not what you want! Check whether address for each node is unique!!!"); - } - measurement_operator this_measurement = Random_Measurement_Basis_Selection(); // Select basis randomly - char Output; - bool Output_is_plus; - - // Add memory error depending on the idle time. If excited/relaxed, this will immediately break entanglement, leaving the other qubit as completely mixed. - applyMemoryError(); - - // This becomes nullptr if this qubit got excited/relaxed or measured. - if (this->entangled_partner != nullptr) { - if (this->entangled_partner->entangled_partner == nullptr) { - std::cout << "Entanglement not tracked well between partners." << this << " in node[" << node_address << "]\n"; - std::cout << "Partner must be " << this->entangled_partner << " in node[" << this->entangled_partner->node_address << "]\n"; - error("NO!"); - } - if (this->partner_measured) error("Entangled partner not nullptr but partner already measured....? Probably wrong."); - if (this->completely_mixed || this->excited_or_relaxed) { - std::cout << "[Error]" << this << "\n"; - error("Entangled but completely mixed / Excited / Relaxed ? Probably wrong."); - } - // Also do the same on the partner if it is still entangled! This could break the entanglement due to relaxation/excitation error! - check_and_cast(this->entangled_partner)->applyMemoryError(); - } - - /*-For debugging-*/ - char GOD_state = 'F'; // Completely mixed - - if (this->god_err.has_excitation_error) - GOD_state = 'E'; - else if (this->god_err.has_excitation_error) - GOD_state = 'R'; - else if (this->god_err.has_completely_mixed_error) - GOD_state = 'C'; - else if (!this->god_err.has_x_error && this->god_err.has_z_error) // To check stabilizers.... - GOD_state = 'Z'; - else if (this->god_err.has_x_error && !this->god_err.has_z_error) - GOD_state = 'X'; - else if (this->god_err.has_x_error && this->god_err.has_z_error) - GOD_state = 'Y'; - - /*---------------*/ - - if (this->completely_mixed != this->god_err.has_completely_mixed_error) { - error("Cm track wrong\n"); - } - if (this->excited_or_relaxed && !this->god_err.has_excitation_error && !this->god_err.has_relaxation_error) { - std::cout << "this->excited_or_relaxed = " << this->excited_or_relaxed << ", !this->god_err.has_relaxation_error=" << !this->god_err.has_relaxation_error - << "!this->god_err.has_excitation_error=" << !this->god_err.has_excitation_error; - error("Ex/Re track wrong\n"); - } - // if there is an entanglement - if (this->entangled_partner != nullptr) { - // This qubit is nullptr - if (this->entangled_partner->entangled_partner == nullptr) { - error("Entangled_partner track wrong\n"); - } - // check completely mixed tracking - if (this->entangled_partner->completely_mixed != this->entangled_partner->god_err.has_completely_mixed_error) { - error("Partner Cm track wrong\n"); - } - // check excited and relaxation tracking - if (this->entangled_partner->excited_or_relaxed && !this->entangled_partner->god_err.has_excitation_error && !this->entangled_partner->god_err.has_relaxation_error) { - error("Partner Re/Ex track wrong\n"); - } - if (this->entangled_partner->god_err.has_completely_mixed_error || this->entangled_partner->god_err.has_relaxation_error || - this->entangled_partner->god_err.has_excitation_error) { - // error("Partner CM/Re/Ex track wrong\n"); - } - } - - // if the partner qubit is measured, - if (this->partner_measured || this->completely_mixed || this->excited_or_relaxed) { // The case when the density matrix is completely local to this qubit. - // if this qubit is said to be completely mixed and no set value - if (this->completely_mixed && !this->god_err.has_completely_mixed_error) { - error("Mismatch between flags."); - } - if (this->Density_Matrix_Collapsed(0, 0).real() == -111) { // We always need some kind of density matrix inside this if statement. - error("Single qubit density matrix not stored properly after partner's measurement, excitation/relaxation error."); - } - bool Xerr = this->god_err.has_x_error; - bool Zerr = this->god_err.has_z_error; - // This qubit's density matrix was created when the partner measured his own. - // Because this qubit can be measured after that, we need to update the stored density matrix according to new errors occurred due to memory error. - - if (Xerr != GOD_dm_Xerror) { // Another X error to the dm. - // error("NO"); - Density_Matrix_Collapsed = Pauli.X * Density_Matrix_Collapsed * Pauli.X.adjoint(); - } - if (Zerr != GOD_dm_Zerror) { // Another Z error to the dm. - // error("NO!"); - Density_Matrix_Collapsed = Pauli.Z * Density_Matrix_Collapsed * Pauli.Z.adjoint(); - } - - // std::cout<<"Not entangled anymore. Density matrix is "<partner_measured && !this->completely_mixed && !this->excited_or_relaxed && this->entangled_partner != nullptr) { - // This is assuming that this is some other qubit is entangled. Only Pauli errors are assumed. - quantum_state current_state = getQuantumState(); - EV << "Current entangled state is " << current_state.state_in_ket << "\n"; - - bool Xerr = this->god_err.has_x_error; - bool Zerr = this->god_err.has_z_error; - // std::cout<<"Entangled state is "<Density_Matrix_Collapsed = normalized_partners_dm; - - // We actually do not need this as long as deleting entangled_partner completely is totally fine. - entangled_partner->partner_measured = true; - // if(entangled_partner->getIndex() == 71 && entangled_partner->node_address == 3) - // std::cout<<"-------------------"<node_address<<"] overwritten dm.\n"; - - // Break entanglement. - entangled_partner->entangled_partner = nullptr; - // Save what error it had, when this density matrix was calculated. - // Error may get updated in the future, so we need to track what error has been considered already in the dm. - entangled_partner->GOD_dm_Xerror = entangled_partner->god_err.has_x_error; - entangled_partner->GOD_dm_Zerror = entangled_partner->god_err.has_z_error; - } else { - error("Check condition in measure func."); - } - - // add measurement error - auto rand_num = dblrand(); - if (this_measurement.basis == meas_op.X_basis.basis && rand_num < Measurement_error.x_error_rate || - this_measurement.basis == meas_op.Y_basis.basis && rand_num < Measurement_error.y_error_rate || - this_measurement.basis == meas_op.Z_basis.basis && rand_num < Measurement_error.z_error_rate) { - Output_is_plus = !Output_is_plus; - } - - measurement_outcome o; - o.basis = this_measurement.basis; - o.outcome_is_plus = Output_is_plus; - o.GOD_clean = GOD_state; - return o; -} - -measurement_operator StationaryQubit::Random_Measurement_Basis_Selection() { - measurement_operator this_measurement; - double dbl = dblrand(); // Random double value for random basis selection. - EV << "Random dbl = " << dbl << "! \n "; - - if (dbl < ((double)1 / (double)3)) { // X measurement! - EV << "X measurement\n"; - this_measurement.plus = meas_op.X_basis.plus; - this_measurement.minus = meas_op.X_basis.minus; - this_measurement.basis = meas_op.X_basis.basis; - this_measurement.plus_ket = meas_op.X_basis.plus_ket; - this_measurement.minus_ket = meas_op.X_basis.minus_ket; - } else if (dbl >= ((double)1 / (double)3) && dbl < ((double)2 / (double)3)) { - EV << "Z measurement\n"; - this_measurement.plus = meas_op.Z_basis.plus; - this_measurement.minus = meas_op.Z_basis.minus; - this_measurement.basis = meas_op.Z_basis.basis; - this_measurement.plus_ket = meas_op.Z_basis.plus_ket; - this_measurement.minus_ket = meas_op.Z_basis.minus_ket; - } else { - EV << "Y measurement\n"; - this_measurement.plus = meas_op.Y_basis.plus; - this_measurement.minus = meas_op.Y_basis.minus; - this_measurement.basis = meas_op.Y_basis.basis; - this_measurement.plus_ket = meas_op.Y_basis.plus_ket; - this_measurement.minus_ket = meas_op.Y_basis.minus_ket; - } - return this_measurement; -} +MeasurementOutcome StationaryQubit::measure_density_independent() { return qubit_ref->measureDensityIndependent(); } // protected internal graph backend functions diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit.h b/quisp/modules/QNIC/StationaryQubit/StationaryQubit.h index b7c31e2f4..60616a601 100644 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit.h +++ b/quisp/modules/QNIC/StationaryQubit/StationaryQubit.h @@ -7,13 +7,15 @@ #pragma once #include +#include #include #include #include #include "IStationaryQubit.h" +#include "QubitId.h" +#include "backends/interfaces/IQuantumBackend.h" -namespace quisp { -namespace modules { +namespace quisp::modules { #define STATIONARYQUBIT_PULSE_BEGIN 0x01 #define STATIONARYQUBIT_PULSE_END 0x02 @@ -25,8 +27,8 @@ namespace modules { * \ref https://arxiv.org/abs/1908.10758 */ -typedef std::complex Complex; using quisp::modules::common::IBackendQubit; +using quisp::modules::common::IConfiguration; using quisp::modules::common::IQuantumBackend; class StationaryQubit : public IStationaryQubit { @@ -96,14 +98,14 @@ class StationaryQubit : public IStationaryQubit { virtual types::EigenvalueResult localMeasureY() override; virtual types::EigenvalueResult localMeasureZ() override; - virtual types::EigenvalueResult measureX() override; - virtual types::EigenvalueResult measureY() override; - virtual types::EigenvalueResult measureZ() override; + virtual types::EigenvalueResult measureX(); + virtual types::EigenvalueResult measureY(); + virtual types::EigenvalueResult measureZ(); /** * Performs measurement and returns +(true) or -(false) based on the density matrix of the state. Used for tomography. * */ // virtual std::bitset<1> measure_density(char basis_this_qubit);/*Simultaneous dm calculation*/ - virtual measurement_outcome measure_density_independent() override; /*Separate dm calculation*/ + virtual types::MeasurementOutcome measure_density_independent() override; /*Separate dm calculation*/ /** * \brief Two qubit CNOT gate. @@ -133,26 +135,19 @@ class StationaryQubit : public IStationaryQubit { /*GOD parameters*/ void setEntangledPartnerInfo(IStationaryQubit *partner) override; - void setCompletelyMixedDensityMatrix() override; + void setCompletelyMixedDensityMatrix(); void setRelaxedDensityMatrix(); void setExcitedDensityMatrix(); - void addXerror() override; - void addZerror() override; + void addXerror(); + void addZerror(); + backends::IQubit *getEntangledPartner() const override; + backends::IQubit *getBackendQubitRef() const override; + int getPartnerStationaryQubitAddress() const override; - double emission_success_probability; - - SingleGateErrorModel Hgate_error; - SingleGateErrorModel Xgate_error; - SingleGateErrorModel Zgate_error; - TwoQubitGateErrorModel CNOTgate_error; - MeasurementErrorModel Measurement_error; - memory_error_model memory_err; + // for debugging + void assertEntangledPartnerValid() override; - single_qubit_error Pauli; - measurement_operators meas_op; - // https://arxiv.org/abs/1908.10758 Eq 5.2 - Eigen::MatrixXd Memory_Transition_matrix; /*I,X,Y,Z,Ex,Rl for single qubit. Unit in μs.*/ - int num_purified; + double emission_success_probability; bool locked; unsigned long locked_ruleset_id; @@ -164,25 +159,28 @@ class StationaryQubit : public IStationaryQubit { void handleMessage(omnetpp::cMessage *msg) override; messages::PhotonicQubit *generateEntangledPhoton(); void setBusy(); - // returns the matrix that represents the errors on the Bell pair. (e.g. XY, XZ and ZI...) Eigen::Matrix2cd getErrorMatrix(StationaryQubit *qubit); - // returns the dm of the physical Bell pair. Used for tomography. - quantum_state getQuantumState(); - measurement_operator Random_Measurement_Basis_Selection(); - void setSingleQubitGateErrorModel(SingleGateErrorModel &model, std::string gate_name); - void setTwoQubitGateErrorCeilings(TwoQubitGateErrorModel &model, std::string gate_name); - void setMeasurementErrorModel(MeasurementErrorModel &model); - /*Applies memory error to the given qubit*/ - void applyMemoryError(); - - void applySingleQubitGateError(SingleGateErrorModel const &err); - void applyTwoQubitGateError(TwoQubitGateErrorModel const &err, StationaryQubit *another_qubit); + + /** + * get the default backend configuration from the Bcakend module. + * if overwrite arg is true, collect StationaryQubit's backend qubit config + * and overwrite the default configuration with it. + * if you want to use different qubit configuration, it's useful. + */ + std::unique_ptr prepareBackendQubitConfiguration(bool overwrite); // this is for debugging. class internal use only. // and it's different from QubitRecord's one. bool is_busy; + // photon emitted at + omnetpp::simtime_t emitted_time = -1; + // Standard deviation + double emission_jittering_standard_deviation; + int stationary_qubit_address; + int node_address; + utils::ComponentProvider provider; + IQuantumBackend *backend; }; -} // namespace modules -} // namespace quisp +} // namespace quisp::modules diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit.ned b/quisp/modules/QNIC/StationaryQubit/StationaryQubit.ned index 176c3b700..b1e2d49d5 100644 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit.ned +++ b/quisp/modules/QNIC/StationaryQubit/StationaryQubit.ned @@ -28,48 +28,32 @@ simple StationaryQubit double emission_x_error_rate = default(0); double emission_y_error_rate = default(0); - // ZZZ -- these are configured at boot time - // characteristics of the hardware - // could eventually change over time if we model dynamic - // changes to the device - double memory_z_error_rate = default(0); - double memory_x_error_rate = default(0); - double memory_y_error_rate = default(0); - double memory_energy_excitation_rate = default(0); - double memory_energy_relaxation_rate = default(0); - double memory_completely_mixed_rate = default(0); + // ErrorTracking Backend Qubit Configuration + // if overwrite_backend_qubit_config is true, + // these params overwrite the default configuration at the backend module. + double memory_error_rate = default(0); + double memory_z_error_rate = default(1); + double memory_x_error_rate = default(1); + double memory_y_error_rate = default(1); + double memory_energy_excitation_rate = default(1); + double memory_energy_relaxation_rate = default(1); + double memory_completely_mixed_rate = default(1); - // ZZZ -- these are configured at boot time - // characteristics of the hardware - // could eventually change over time if we model dynamic - // changes to the device double h_gate_error_rate = default(0); double h_gate_x_error_ratio = default(1); double h_gate_y_error_ratio = default(1); double h_gate_z_error_ratio = default(1); - // ZZZ -- these are configured at boot time - // characteristics of the hardware - // could eventually change over time if we model dynamic - // changes to the device double x_gate_error_rate = default(0); double x_gate_x_error_ratio = default(1); double x_gate_y_error_ratio = default(1); double x_gate_z_error_ratio = default(1); - // ZZZ -- these are configured at boot time - // characteristics of the hardware - // could eventually change over time if we model dynamic - // changes to the device double z_gate_error_rate = default(0); double z_gate_x_error_ratio = default(1); double z_gate_y_error_ratio = default(1); double z_gate_z_error_ratio = default(1); - // ZZZ -- these are configured at boot time - // characteristics of the hardware - // could eventually change over time if we model dynamic - // changes to the device double cnot_gate_error_rate = default(0); double cnot_gate_iz_error_ratio = default(1); double cnot_gate_zi_error_ratio = default(1); diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_gate_error_test.cc b/quisp/modules/QNIC/StationaryQubit/StationaryQubit_gate_error_test.cc deleted file mode 100644 index aecdba91c..000000000 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_gate_error_test.cc +++ /dev/null @@ -1,585 +0,0 @@ -#include -#include -#include -#include -#include "StationaryQubit.h" -#include "omnetpp/simtime.h" - -using namespace quisp::modules; -using namespace quisp::modules::common; -using namespace quisp_test; -namespace { -class Strategy : public TestComponentProviderStrategy { - public: - Strategy() : backend(new MockQuantumBackend()) {} - ~Strategy() {} - IQuantumBackend *getQuantumBackend() override { return backend; } - MockQuantumBackend *backend; -}; - -class StatQubitTarget : public StationaryQubit { - public: - using StationaryQubit::applySingleQubitGateError; - using StationaryQubit::applyTwoQubitGateError; - using StationaryQubit::initialize; - using StationaryQubit::par; - using StationaryQubit::setSingleQubitGateErrorModel; - using StationaryQubit::setTwoQubitGateErrorCeilings; - StatQubitTarget() : StationaryQubit() { - setComponentType(new TestModuleType("test qubit")); - provider.setStrategy(std::make_unique()); - } - void reset() { - setFree(true); - updated_time = SimTime(0); - no_density_matrix_nullptr_entangled_partner_ok = true; - } - void fillParams() { - setParDouble(this, "emission_success_probability", 0.5); - setParDouble(this, "memory_x_error_rate", 1.11111111e-7); - setParDouble(this, "memory_y_error_rate", 1.11111111e-7); - setParDouble(this, "memory_z_error_rate", 1.11111111e-7); - setParDouble(this, "memory_energy_excitation_rate", 0.000198); - setParDouble(this, "memory_energy_relaxation_rate", 0.00000198); - setParDouble(this, "memory_completely_mixed_rate", 0); - - // No error= 0.4, X error = 0.6, Z error = 0.8, Y error = 1.0 - setParDouble(this, "h_gate_error_rate", 0.6); - setParDouble(this, "h_gate_x_error_ratio", 1); - setParDouble(this, "h_gate_z_error_ratio", 1); - setParDouble(this, "h_gate_y_error_ratio", 1); - - setParDouble(this, "x_gate_error_rate", 0.6); - setParDouble(this, "x_gate_x_error_ratio", 1); - setParDouble(this, "x_gate_z_error_ratio", 1); - setParDouble(this, "x_gate_y_error_ratio", 1); - - setParDouble(this, "z_gate_error_rate", 0.6); - setParDouble(this, "z_gate_x_error_ratio", 1); - setParDouble(this, "z_gate_z_error_ratio", 1); - setParDouble(this, "z_gate_y_error_ratio", 1); - - // clean = 0.1, - // IX = 0.2, XI = 0.3, XX = 0.4, - // IZ = 0.5, ZI = 0.6, ZZ = 0.7, - // IY = 0.8, IY = 0.9, YY = 1.0 - setParDouble(this, "cnot_gate_error_rate", 0.9); - setParDouble(this, "cnot_gate_ix_error_ratio", 1); - setParDouble(this, "cnot_gate_xi_error_ratio", 1); - setParDouble(this, "cnot_gate_xx_error_ratio", 1); - setParDouble(this, "cnot_gate_iz_error_ratio", 1); - setParDouble(this, "cnot_gate_zi_error_ratio", 1); - setParDouble(this, "cnot_gate_zz_error_ratio", 1); - setParDouble(this, "cnot_gate_iy_error_ratio", 1); - setParDouble(this, "cnot_gate_yi_error_ratio", 1); - setParDouble(this, "cnot_gate_yy_error_ratio", 1); - - setParDouble(this, "x_measurement_error_rate", 1.0 / 2000); - setParDouble(this, "y_measurement_error_rate", 1.0 / 2000); - setParDouble(this, "z_measurement_error_rate", 1.0 / 2000); - - setParInt(this, "stationary_qubit_address", 1); - setParInt(this, "node_address", 1); - setParInt(this, "qnic_address", 1); - setParInt(this, "qnic_type", 0); - setParInt(this, "qnic_index", 0); - setParDouble(this, "emission_jittering_standard_deviation", 0.5); - } -}; - -TEST(StatQubitGateErrorTest, SetSingleQubitGateErrorCeilings) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - setParDouble(qubit, "x_gate_error_rate", 0.1); - setParDouble(qubit, "x_gate_x_error_ratio", 1); - setParDouble(qubit, "x_gate_z_error_ratio", 2); - setParDouble(qubit, "x_gate_y_error_ratio", 3); - sim->registerComponent(qubit); - qubit->setSingleQubitGateErrorModel(qubit->Xgate_error, std::string("x_gate")); - auto &error_model = qubit->Xgate_error; - EXPECT_FALSE(std::isnan(error_model.X_error_rate)); - EXPECT_FALSE(std::isnan(error_model.Y_error_rate)); - EXPECT_FALSE(std::isnan(error_model.Z_error_rate)); - EXPECT_FALSE(std::isnan(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isnan(error_model.No_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.X_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.Z_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.Y_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.X_error_rate)); - EXPECT_FALSE(std::isinf(error_model.Y_error_rate)); - EXPECT_FALSE(std::isinf(error_model.Z_error_rate)); - EXPECT_FALSE(std::isinf(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isinf(error_model.No_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.X_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.Z_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.Y_error_ceil)); - EXPECT_DOUBLE_EQ(error_model.pauli_error_rate, 0.1); - EXPECT_DOUBLE_EQ(error_model.X_error_rate, 0.1 * 1 / 6); - EXPECT_DOUBLE_EQ(error_model.Z_error_rate, 0.2 * 1 / 6); - EXPECT_DOUBLE_EQ(error_model.Y_error_rate, 0.3 * 1 / 6); -} - -TEST(StatQubitGateErrorTest, SetSingleQubitGateErrorCeilings_div_by_zero) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - setParDouble(qubit, "x_gate_error_rate", 0.1); - setParDouble(qubit, "x_gate_x_error_ratio", 0); - setParDouble(qubit, "x_gate_z_error_ratio", 0); - setParDouble(qubit, "x_gate_y_error_ratio", 0); - sim->registerComponent(qubit); - qubit->setSingleQubitGateErrorModel(qubit->Xgate_error, std::string("x_gate")); - auto &error_model = qubit->Xgate_error; - EXPECT_FALSE(std::isnan(error_model.X_error_rate)); - EXPECT_FALSE(std::isnan(error_model.Y_error_rate)); - EXPECT_FALSE(std::isnan(error_model.Z_error_rate)); - EXPECT_FALSE(std::isnan(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isnan(error_model.No_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.X_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.Z_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.Y_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.X_error_rate)); - EXPECT_FALSE(std::isinf(error_model.Y_error_rate)); - EXPECT_FALSE(std::isinf(error_model.Z_error_rate)); - EXPECT_FALSE(std::isinf(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isinf(error_model.No_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.X_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.Z_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.Y_error_ceil)); - EXPECT_DOUBLE_EQ(error_model.pauli_error_rate, 0.1); - EXPECT_DOUBLE_EQ(error_model.X_error_rate, 0.1 * 1 / 3); - EXPECT_DOUBLE_EQ(error_model.Z_error_rate, 0.1 * 1 / 3); - EXPECT_DOUBLE_EQ(error_model.Y_error_rate, 0.1 * 1 / 3); -} - -TEST(StatQubitGateErrorTest, SetTwoQubitGateErrorCeilings) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - setParDouble(qubit, "cnot_gate_error_rate", 0.1); - setParDouble(qubit, "cnot_gate_ix_error_ratio", 1); - setParDouble(qubit, "cnot_gate_xi_error_ratio", 1); - setParDouble(qubit, "cnot_gate_xx_error_ratio", 1); - setParDouble(qubit, "cnot_gate_iz_error_ratio", 1); - setParDouble(qubit, "cnot_gate_zi_error_ratio", 1); - setParDouble(qubit, "cnot_gate_zz_error_ratio", 1); - setParDouble(qubit, "cnot_gate_iy_error_ratio", 1); - setParDouble(qubit, "cnot_gate_yi_error_ratio", 1); - setParDouble(qubit, "cnot_gate_yy_error_ratio", 1); - sim->registerComponent(qubit); - qubit->setTwoQubitGateErrorCeilings(qubit->CNOTgate_error, std::string("cnot_gate")); - auto const &error_model = qubit->CNOTgate_error; - EXPECT_FALSE(std::isnan(error_model.IX_error_rate)); - EXPECT_FALSE(std::isnan(error_model.XI_error_rate)); - EXPECT_FALSE(std::isnan(error_model.XX_error_rate)); - EXPECT_FALSE(std::isnan(error_model.IZ_error_rate)); - EXPECT_FALSE(std::isnan(error_model.ZI_error_rate)); - EXPECT_FALSE(std::isnan(error_model.ZZ_error_rate)); - EXPECT_FALSE(std::isnan(error_model.IY_error_rate)); - EXPECT_FALSE(std::isnan(error_model.YI_error_rate)); - EXPECT_FALSE(std::isnan(error_model.YY_error_rate)); - EXPECT_FALSE(std::isnan(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isnan(error_model.No_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.XI_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.IX_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.XX_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.ZI_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.IZ_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.ZZ_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.YI_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.IY_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.YY_error_ceil)); - - EXPECT_FALSE(std::isinf(error_model.XI_error_rate)); - EXPECT_FALSE(std::isinf(error_model.IX_error_rate)); - EXPECT_FALSE(std::isinf(error_model.XX_error_rate)); - EXPECT_FALSE(std::isinf(error_model.ZI_error_rate)); - EXPECT_FALSE(std::isinf(error_model.IZ_error_rate)); - EXPECT_FALSE(std::isinf(error_model.ZZ_error_rate)); - EXPECT_FALSE(std::isinf(error_model.YI_error_rate)); - EXPECT_FALSE(std::isinf(error_model.IY_error_rate)); - EXPECT_FALSE(std::isinf(error_model.YY_error_rate)); - EXPECT_FALSE(std::isinf(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isinf(error_model.No_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.XI_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.IX_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.XX_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.ZI_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.IZ_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.ZZ_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.YI_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.IY_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.YY_error_ceil)); - EXPECT_DOUBLE_EQ(error_model.pauli_error_rate, 0.1); - EXPECT_DOUBLE_EQ(error_model.XI_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.IX_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.XX_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.ZI_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.IZ_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.ZZ_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.YI_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.IY_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.YY_error_rate, 0.1 * 1 / 9); -} - -TEST(StatQubitGateErrorTest, SetTwoQubitGateErrorCeilings_div_by_zero) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - setParDouble(qubit, "cnot_gate_error_rate", 0.1); - setParDouble(qubit, "cnot_gate_ix_error_ratio", 0); - setParDouble(qubit, "cnot_gate_xi_error_ratio", 0); - setParDouble(qubit, "cnot_gate_xx_error_ratio", 0); - setParDouble(qubit, "cnot_gate_iz_error_ratio", 0); - setParDouble(qubit, "cnot_gate_zi_error_ratio", 0); - setParDouble(qubit, "cnot_gate_zz_error_ratio", 0); - setParDouble(qubit, "cnot_gate_iy_error_ratio", 0); - setParDouble(qubit, "cnot_gate_yi_error_ratio", 0); - setParDouble(qubit, "cnot_gate_yy_error_ratio", 0); - sim->registerComponent(qubit); - qubit->setTwoQubitGateErrorCeilings(qubit->CNOTgate_error, std::string("cnot_gate")); - auto const &error_model = qubit->CNOTgate_error; - EXPECT_FALSE(std::isnan(error_model.IX_error_rate)); - EXPECT_FALSE(std::isnan(error_model.XI_error_rate)); - EXPECT_FALSE(std::isnan(error_model.XX_error_rate)); - EXPECT_FALSE(std::isnan(error_model.IZ_error_rate)); - EXPECT_FALSE(std::isnan(error_model.ZI_error_rate)); - EXPECT_FALSE(std::isnan(error_model.ZZ_error_rate)); - EXPECT_FALSE(std::isnan(error_model.IY_error_rate)); - EXPECT_FALSE(std::isnan(error_model.YI_error_rate)); - EXPECT_FALSE(std::isnan(error_model.YY_error_rate)); - EXPECT_FALSE(std::isnan(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isnan(error_model.No_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.XI_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.IX_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.XX_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.ZI_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.IZ_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.ZZ_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.YI_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.IY_error_ceil)); - EXPECT_FALSE(std::isnan(error_model.YY_error_ceil)); - - EXPECT_FALSE(std::isinf(error_model.XI_error_rate)); - EXPECT_FALSE(std::isinf(error_model.IX_error_rate)); - EXPECT_FALSE(std::isinf(error_model.XX_error_rate)); - EXPECT_FALSE(std::isinf(error_model.ZI_error_rate)); - EXPECT_FALSE(std::isinf(error_model.IZ_error_rate)); - EXPECT_FALSE(std::isinf(error_model.ZZ_error_rate)); - EXPECT_FALSE(std::isinf(error_model.YI_error_rate)); - EXPECT_FALSE(std::isinf(error_model.IY_error_rate)); - EXPECT_FALSE(std::isinf(error_model.YY_error_rate)); - EXPECT_FALSE(std::isinf(error_model.pauli_error_rate)); - EXPECT_FALSE(std::isinf(error_model.No_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.XI_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.IX_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.XX_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.ZI_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.IZ_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.ZZ_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.YI_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.IY_error_ceil)); - EXPECT_FALSE(std::isinf(error_model.YY_error_ceil)); - EXPECT_DOUBLE_EQ(error_model.pauli_error_rate, 0.1); - EXPECT_DOUBLE_EQ(error_model.XI_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.IX_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.XX_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.ZI_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.IZ_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.ZZ_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.YI_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.IY_error_rate, 0.1 * 1 / 9); - EXPECT_DOUBLE_EQ(error_model.YY_error_rate, 0.1 * 1 / 9); -} - -TEST(StatQubitGateErrorTest, do_nothing_single_qubit_gate) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - setParDouble(qubit, "x_gate_error_rate", 0.0); - sim->registerComponent(qubit); - - qubit->callInitialize(); - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - - qubit->applySingleQubitGateError(qubit->Xgate_error); - - EXPECT_EQ(qubit->updated_time, SimTime(0, SIMTIME_US)); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); -} - -TEST(StatQubitGateErrorTest, do_nothing_two_qubit_gate) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - auto *qubit2 = new StatQubitTarget{}; - sim->registerComponent(qubit); - sim->registerComponent(qubit2); - - qubit->fillParams(); - qubit2->fillParams(); - setParDouble(qubit, "cnot_gate_error_rate", 0.0); - qubit->callInitialize(); - qubit2->callInitialize(); - qubit->reset(); - qubit2->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - qubit2->god_err.has_x_error = true; - qubit2->god_err.has_z_error = true; - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit2->god_err.has_x_error); - EXPECT_TRUE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - - qubit->applyTwoQubitGateError(qubit->CNOTgate_error, qubit2); - - EXPECT_EQ(qubit->updated_time, SimTime(0, SIMTIME_US)); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit2->god_err.has_x_error); - EXPECT_TRUE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); -} - -TEST(StatQubitGateErrorTest, apply_single_qubit_gate_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - sim->registerComponent(qubit); - - qubit->callInitialize(); - sim->setSimTime(SimTime(1, SIMTIME_US)); - // No error - qubit->reset(); - rng->doubleValue = 0.35; - qubit->applySingleQubitGateError(qubit->Xgate_error); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // X error - qubit->reset(); - rng->doubleValue = 0.45; - qubit->applySingleQubitGateError(qubit->Xgate_error); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Z error - qubit->reset(); - rng->doubleValue = 0.65; - qubit->applySingleQubitGateError(qubit->Xgate_error); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Y error - qubit->reset(); - rng->doubleValue = 0.85; - qubit->applySingleQubitGateError(qubit->Xgate_error); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); -} - -TEST(StatQubitGateErrorTest, apply_two_qubit_gate_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit1 = new StatQubitTarget{}; - auto *qubit2 = new StatQubitTarget{}; - qubit1->fillParams(); - qubit2->fillParams(); - sim->registerComponent(qubit1); - sim->registerComponent(qubit2); - qubit1->callInitialize(); - qubit2->callInitialize(); - - sim->setSimTime(SimTime(1, SIMTIME_US)); - - // No error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.05; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_FALSE(qubit1->god_err.has_x_error); - EXPECT_FALSE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_FALSE(qubit2->god_err.has_x_error); - EXPECT_FALSE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // IX error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.15; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_TRUE(qubit1->god_err.has_x_error); - EXPECT_FALSE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_FALSE(qubit2->god_err.has_x_error); - EXPECT_FALSE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // XI error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.25; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_FALSE(qubit1->god_err.has_x_error); - EXPECT_FALSE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_TRUE(qubit2->god_err.has_x_error); - EXPECT_FALSE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // XX error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.35; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_TRUE(qubit1->god_err.has_x_error); - EXPECT_FALSE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_TRUE(qubit2->god_err.has_x_error); - EXPECT_FALSE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // IZ error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.45; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_FALSE(qubit1->god_err.has_x_error); - EXPECT_TRUE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_FALSE(qubit2->god_err.has_x_error); - EXPECT_FALSE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // ZI error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.55; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_FALSE(qubit1->god_err.has_x_error); - EXPECT_FALSE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_FALSE(qubit2->god_err.has_x_error); - EXPECT_TRUE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // ZZ error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.65; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_FALSE(qubit1->god_err.has_x_error); - EXPECT_TRUE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_FALSE(qubit2->god_err.has_x_error); - EXPECT_TRUE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // IY error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.75; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_TRUE(qubit1->god_err.has_x_error); - EXPECT_TRUE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_FALSE(qubit2->god_err.has_x_error); - EXPECT_FALSE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // YI error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.85; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_FALSE(qubit1->god_err.has_x_error); - EXPECT_FALSE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_TRUE(qubit2->god_err.has_x_error); - EXPECT_TRUE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); - - // YY error - qubit1->reset(); - qubit2->reset(); - rng->doubleValue = 0.95; - qubit1->applyTwoQubitGateError(qubit1->CNOTgate_error, qubit2); - EXPECT_TRUE(qubit1->god_err.has_x_error); - EXPECT_TRUE(qubit1->god_err.has_z_error); - EXPECT_FALSE(qubit1->god_err.has_excitation_error); - EXPECT_FALSE(qubit1->god_err.has_relaxation_error); - EXPECT_FALSE(qubit1->god_err.has_completely_mixed_error); - EXPECT_TRUE(qubit2->god_err.has_x_error); - EXPECT_TRUE(qubit2->god_err.has_z_error); - EXPECT_FALSE(qubit2->god_err.has_excitation_error); - EXPECT_FALSE(qubit2->god_err.has_relaxation_error); - EXPECT_FALSE(qubit2->god_err.has_completely_mixed_error); -} -} // namespace diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_internal_stabilizer_graph_test.cc b/quisp/modules/QNIC/StationaryQubit/StationaryQubit_internal_stabilizer_graph_test.cc index 3f565c1c4..2d265146a 100644 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_internal_stabilizer_graph_test.cc +++ b/quisp/modules/QNIC/StationaryQubit/StationaryQubit_internal_stabilizer_graph_test.cc @@ -635,4 +635,4 @@ TEST(StatQubitInternalGraphTest, graphMeasureZGHZState) { } } } -} // end namespace \ No newline at end of file +} // end namespace diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_measurement_test.cc b/quisp/modules/QNIC/StationaryQubit/StationaryQubit_measurement_test.cc deleted file mode 100644 index 8695b4dfd..000000000 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_measurement_test.cc +++ /dev/null @@ -1,610 +0,0 @@ -#include -#include -#include -#include -#include "StationaryQubit.h" -#include "modules/QNIC/StationaryQubit/IStationaryQubit.h" -#include "omnetpp/simtime.h" - -using namespace quisp::modules; -using namespace quisp::modules::common; -using namespace quisp_test; -namespace { - -class Strategy : public TestComponentProviderStrategy { - public: - Strategy() : backend(new MockQuantumBackend()) {} - ~Strategy() {} - IQuantumBackend *getQuantumBackend() override { return backend; } - MockQuantumBackend *backend; -}; - -class StatQubitTarget : public StationaryQubit { - public: - using StationaryQubit::addXerror; - using StationaryQubit::addZerror; - using StationaryQubit::correlationMeasureX; - using StationaryQubit::correlationMeasureY; - using StationaryQubit::correlationMeasureZ; - using StationaryQubit::initialize; - using StationaryQubit::localMeasureX; - using StationaryQubit::localMeasureY; - using StationaryQubit::localMeasureZ; - using StationaryQubit::par; - using StationaryQubit::setMeasurementErrorModel; - StatQubitTarget() : StationaryQubit() { - setComponentType(new TestModuleType("test qubit")); - provider.setStrategy(std::make_unique()); - } - void reset() { - this->god_err.has_x_error = false; - this->god_err.has_z_error = false; - // this->god_err.has_Y_error = false; not implemeted yet - } - void fillParams() { - setParDouble(this, "emission_success_probability", 0.5); - setParDouble(this, "memory_x_error_rate", 1.11111111e-7); - setParDouble(this, "memory_y_error_rate", 1.11111111e-7); - setParDouble(this, "memory_z_error_rate", 1.11111111e-7); - setParDouble(this, "memory_energy_excitation_rate", 0.000198); - setParDouble(this, "memory_energy_relaxation_rate", 0.00000198); - setParDouble(this, "memory_completely_mixed_rate", 0); - - // No error= 0.4, X error = 0.6, Z error = 0.8, Y error = 1.0 - setParDouble(this, "h_gate_error_rate", 0.6); - setParDouble(this, "h_gate_x_error_ratio", 1); - setParDouble(this, "h_gate_z_error_ratio", 1); - setParDouble(this, "h_gate_y_error_ratio", 1); - - setParDouble(this, "x_gate_error_rate", 0.6); - setParDouble(this, "x_gate_x_error_ratio", 1); - setParDouble(this, "x_gate_z_error_ratio", 1); - setParDouble(this, "x_gate_y_error_ratio", 1); - - setParDouble(this, "z_gate_error_rate", 0.6); - setParDouble(this, "z_gate_x_error_ratio", 1); - setParDouble(this, "z_gate_z_error_ratio", 1); - setParDouble(this, "z_gate_y_error_ratio", 1); - - // clean = 0.1, - // IX = 0.2, XI = 0.3, XX = 0.4, - // IZ = 0.5, ZI = 0.6, ZZ = 0.7, - // IY = 0.8, IY = 0.9, YY = 1.0 - setParDouble(this, "cnot_gate_error_rate", 0.9); - setParDouble(this, "cnot_gate_ix_error_ratio", 1); - setParDouble(this, "cnot_gate_xi_error_ratio", 1); - setParDouble(this, "cnot_gate_xx_error_ratio", 1); - setParDouble(this, "cnot_gate_iz_error_ratio", 1); - setParDouble(this, "cnot_gate_zi_error_ratio", 1); - setParDouble(this, "cnot_gate_zz_error_ratio", 1); - setParDouble(this, "cnot_gate_iy_error_ratio", 1); - setParDouble(this, "cnot_gate_yi_error_ratio", 1); - setParDouble(this, "cnot_gate_yy_error_ratio", 1); - - setParDouble(this, "x_measurement_error_rate", 1.0 / 2000); - setParDouble(this, "y_measurement_error_rate", 1.0 / 2000); - setParDouble(this, "z_measurement_error_rate", 1.0 / 2000); - - setParInt(this, "stationary_qubit_address", 1); - setParInt(this, "node_address", 1); - setParInt(this, "qnic_address", 1); - setParInt(this, "qnic_type", 0); - setParInt(this, "qnic_index", 0); - setParDouble(this, "emission_jittering_standard_deviation", 0.5); - } -}; - -TEST(StatQubitMeasurementTest, SetMeasurementErrorRate) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - setParDouble(qubit, "x_measurement_error_rate", 0.1); - setParDouble(qubit, "y_measurement_error_rate", 0.2); - setParDouble(qubit, "z_measurement_error_rate", 0.4); - sim->registerComponent(qubit); - qubit->setMeasurementErrorModel(qubit->Measurement_error); - auto &error_model = qubit->Measurement_error; - EXPECT_FALSE(std::isnan(error_model.x_error_rate)); - EXPECT_FALSE(std::isnan(error_model.y_error_rate)); - EXPECT_FALSE(std::isnan(error_model.z_error_rate)); - EXPECT_DOUBLE_EQ(error_model.x_error_rate, 0.1); - EXPECT_DOUBLE_EQ(error_model.y_error_rate, 0.2); - EXPECT_DOUBLE_EQ(error_model.z_error_rate, 0.4); -} - -TEST(StatQubitMeasurementTest, CorrelationMeasureXwithoutError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::NO_Z_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::HAS_Z_ERROR); -} - -TEST(StatQubitMeasurementTest, CorrelationMeasureXwithError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - - // X error - qubit->addXerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::NO_Z_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::HAS_Z_ERROR); - - // Y error - qubit->addZerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::HAS_Z_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::NO_Z_ERROR); - - // Z error - qubit->addXerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::HAS_Z_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureX(), quisp::types::MeasureXResult::NO_Z_ERROR); -} - -TEST(StatQubitMeasurementTest, CorrelationMeasureYwithoutError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::NO_XZ_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::HAS_XZ_ERROR); -} - -TEST(StatQubitMeasurementTest, CorrelationMeasureYwithError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - - // X error - qubit->addXerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::HAS_XZ_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::NO_XZ_ERROR); - - // Y error - qubit->addZerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::NO_XZ_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::HAS_XZ_ERROR); - - // Z error - qubit->addXerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::HAS_XZ_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureY(), quisp::types::MeasureYResult::NO_XZ_ERROR); -} - -TEST(StatQubitMeasurementTest, CorrelationMeasureZwithoutError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::NO_X_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::HAS_X_ERROR); -} - -TEST(StatQubitMeasurementTest, CorrelationMeasureZwithError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - - // X error - qubit->addXerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::HAS_X_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::NO_X_ERROR); - - // Y error - qubit->addZerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::HAS_X_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::NO_X_ERROR); - - // Z error - qubit->addXerror(); - rng->doubleValue = 0.5; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::NO_X_ERROR); - rng->doubleValue = 1.0 / 3000; - EXPECT_EQ(qubit->correlationMeasureZ(), quisp::types::MeasureZResult::HAS_X_ERROR); -} - -TEST(StatQubitMeasurementTest, localXMeasurementWithoutError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - auto *another_qubit = new StatQubitTarget{}; - qubit->fillParams(); - another_qubit->fillParams(); - qubit->entangled_partner = another_qubit; - another_qubit->entangled_partner = qubit; - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); -} - -TEST(StatQubitMeasurementTest, localXMeasurementWithError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - auto *another_qubit = new StatQubitTarget{}; - qubit->fillParams(); - another_qubit->fillParams(); - setParDouble(qubit, "x_measurement_error_rate", 0.99); - qubit->entangled_partner = another_qubit; - another_qubit->entangled_partner = qubit; - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_TRUE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureX(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); -} - -TEST(StatQubitMeasurementTest, localZMeasurementWithoutError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - auto *another_qubit = new StatQubitTarget{}; - qubit->fillParams(); - another_qubit->fillParams(); - qubit->entangled_partner = another_qubit; - another_qubit->entangled_partner = qubit; - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); -} - -TEST(StatQubitMeasurementTest, localZMeasurementWithError) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - auto *another_qubit = new StatQubitTarget{}; - qubit->fillParams(); - another_qubit->fillParams(); - setParDouble(qubit, "z_measurement_error_rate", 0.99); - qubit->entangled_partner = another_qubit; - another_qubit->entangled_partner = qubit; - qubit->setMeasurementErrorModel(qubit->Measurement_error); - sim->registerComponent(qubit); - - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.7; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::MINUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_TRUE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); - - qubit->reset(); - another_qubit->reset(); - qubit->addZerror(); - qubit->addXerror(); - rng->doubleValue = 0.3; - EXPECT_EQ(qubit->localMeasureZ(), quisp::types::EigenvalueResult::PLUS_ONE); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(another_qubit->god_err.has_x_error); - EXPECT_FALSE(another_qubit->god_err.has_z_error); -} - -} // end namespace diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_memory_error_test.cc b/quisp/modules/QNIC/StationaryQubit/StationaryQubit_memory_error_test.cc deleted file mode 100644 index 0cde3292b..000000000 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_memory_error_test.cc +++ /dev/null @@ -1,546 +0,0 @@ -#include -#include -#include -#include -#include "StationaryQubit.h" -#include "omnetpp/simtime.h" - -using namespace quisp::modules; -using namespace quisp::modules::common; -using namespace quisp_test; -namespace { -class Strategy : public TestComponentProviderStrategy { - public: - Strategy() : backend(new MockQuantumBackend()) {} - ~Strategy() {} - IQuantumBackend *getQuantumBackend() override { return backend; } - MockQuantumBackend *backend; -}; - -class StatQubitTarget : public StationaryQubit { - public: - using StationaryQubit::applyMemoryError; - using StationaryQubit::initialize; - using StationaryQubit::par; - StatQubitTarget() : StationaryQubit() { - setComponentType(new TestModuleType("test qubit")); - provider.setStrategy(std::make_unique()); - } - void reset() { - setFree(true); - updated_time = SimTime(0); - no_density_matrix_nullptr_entangled_partner_ok = true; - } - void fillParams() { - // see networks/omnetpp.ini - setParDouble(this, "emission_success_probability", 0.5); - setParDouble(this, "memory_x_error_rate", 1.11111111e-7); - setParDouble(this, "memory_y_error_rate", 1.11111111e-7); - setParDouble(this, "memory_z_error_rate", 1.11111111e-7); - setParDouble(this, "memory_energy_excitation_rate", 0.000198); - setParDouble(this, "memory_energy_relaxation_rate", 0.00000198); - setParDouble(this, "memory_completely_mixed_rate", 0); - - setParDouble(this, "h_gate_error_rate", 1. / 2000); - setParDouble(this, "h_gate_x_error_ratio", 0); - setParDouble(this, "h_gate_z_error_ratio", 0); - setParDouble(this, "h_gate_y_error_ratio", 0); - - setParDouble(this, "x_gate_error_rate", 1. / 2000); - setParDouble(this, "x_gate_x_error_ratio", 0); - setParDouble(this, "x_gate_z_error_ratio", 0); - setParDouble(this, "x_gate_y_error_ratio", 0); - - setParDouble(this, "z_gate_error_rate", 1. / 2000); - setParDouble(this, "z_gate_x_error_ratio", 0); - setParDouble(this, "z_gate_z_error_ratio", 0); - setParDouble(this, "z_gate_y_error_ratio", 0); - - setParDouble(this, "cnot_gate_error_rate", 1. / 2000); - setParDouble(this, "cnot_gate_ix_error_ratio", 1); - setParDouble(this, "cnot_gate_xi_error_ratio", 1); - setParDouble(this, "cnot_gate_xx_error_ratio", 1); - setParDouble(this, "cnot_gate_iz_error_ratio", 1); - setParDouble(this, "cnot_gate_zi_error_ratio", 1); - setParDouble(this, "cnot_gate_zz_error_ratio", 1); - setParDouble(this, "cnot_gate_iy_error_ratio", 1); - setParDouble(this, "cnot_gate_yi_error_ratio", 1); - setParDouble(this, "cnot_gate_yy_error_ratio", 1); - - setParDouble(this, "x_measurement_error_rate", 1. / 2000); - setParDouble(this, "y_measurement_error_rate", 1. / 2000); - setParDouble(this, "z_measurement_error_rate", 1. / 2000); - - setParInt(this, "stationary_qubit_address", 1); - setParInt(this, "node_address", 1); - setParInt(this, "qnic_address", 1); - setParInt(this, "qnic_type", 0); - setParInt(this, "qnic_index", 0); - setParDouble(this, "emission_jittering_standard_deviation", 0.5); - } -}; - -TEST(StatQubitMemoryErrorTest, do_nothing) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - sim->registerComponent(qubit); - - qubit->callInitialize(); - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - - // if current time and updated_time are same, do nothing - EXPECT_EQ(qubit->updated_time, SimTime(0)); - sim->setSimTime(SimTime(0, SIMTIME_US)); - qubit->applyMemoryError(); - - EXPECT_EQ(qubit->updated_time, SimTime(0, SIMTIME_US)); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); -} -TEST(StatQubitMemoryErrorTest, update_timestamp) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - sim->registerComponent(qubit); - - qubit->callInitialize(); - qubit->reset(); - EXPECT_EQ(qubit->updated_time, SimTime(0)); - sim->setSimTime(SimTime(1, SIMTIME_US)); - qubit->applyMemoryError(); - EXPECT_EQ(qubit->updated_time, SimTime(1, SIMTIME_US)); -} -TEST(StatQubitMemoryErrorTest, apply_memory_error_no_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - - // Initial_condition << 1, 0, 0, 0, 0, 0, 0; - // this means take 1st row of MemoryTransitionMatrix - // ceiled values should be: - // No error= 0.5, X error = 0.6, Z error = 0.7, Y error = 0.8, Excitation = 0.9, Relaxation = 1.0 - setParDouble(qubit, "memory_x_error_rate", .1); - setParDouble(qubit, "memory_y_error_rate", .1); - setParDouble(qubit, "memory_z_error_rate", .1); - setParDouble(qubit, "memory_energy_excitation_rate", .1); - setParDouble(qubit, "memory_energy_relaxation_rate", .1); - setParDouble(qubit, "memory_completely_mixed_rate", 0); - sim->registerComponent(qubit); - - qubit->callInitialize(); - sim->setSimTime(SimTime(1, SIMTIME_US)); - - // X error - qubit->reset(); - rng->doubleValue = 0.55; - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Z error - rng->doubleValue = 0.65; - qubit->reset(); - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Y error - rng->doubleValue = 0.75; - qubit->reset(); - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Excitation error - rng->doubleValue = 0.85; - qubit->reset(); - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Relaxation error - rng->doubleValue = 0.95; - qubit->reset(); - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); -} - -TEST(StatQubitMemoryErrorTest, apply_memory_error_x_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - - // Initial_condition << 0, 1, 0, 0, 0, 0, 0; - // this means take 2nd row of MemoryTransitionMatrix - // ceiled values should be: - // No error= 0.1, X error = 0.6, Z error = 0.7, Y error = 0.8, Excitation = 0.9, Relaxation = 1.0 - setParDouble(qubit, "memory_x_error_rate", .1); - setParDouble(qubit, "memory_y_error_rate", .1); - setParDouble(qubit, "memory_z_error_rate", .1); - setParDouble(qubit, "memory_energy_excitation_rate", .1); - setParDouble(qubit, "memory_energy_relaxation_rate", .1); - setParDouble(qubit, "memory_completely_mixed_rate", 0); - sim->registerComponent(qubit); - qubit->callInitialize(); - sim->setSimTime(SimTime(1, SIMTIME_US)); - - // X error - qubit->reset(); - qubit->god_err.has_x_error = true; - rng->doubleValue = 0.55; - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Z error - rng->doubleValue = 0.65; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Y error - rng->doubleValue = 0.75; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Excitation error - rng->doubleValue = 0.85; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Relaxation error - rng->doubleValue = 0.95; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); -} - -TEST(StatQubitMemoryErrorTest, apply_memory_error_z_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - - // Initial_condition << 0, 0, 1, 0, 0, 0, 0; - // this means take 3rd row of MemoryTransitionMatrix - // ceiled values should be: - // No error= 0.1, X error = 0.6, Z error = 0.7, Y error = 0.8, Excitation = 0.9, Relaxation = 1.0 - setParDouble(qubit, "memory_x_error_rate", .1); - setParDouble(qubit, "memory_y_error_rate", .1); - setParDouble(qubit, "memory_z_error_rate", .1); - setParDouble(qubit, "memory_energy_excitation_rate", .1); - setParDouble(qubit, "memory_energy_relaxation_rate", .1); - setParDouble(qubit, "memory_completely_mixed_rate", 0); - sim->registerComponent(qubit); - qubit->callInitialize(); - sim->setSimTime(SimTime(1, SIMTIME_US)); - - // X error - qubit->reset(); - qubit->god_err.has_x_error = true; - rng->doubleValue = 0.55; - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Z error - rng->doubleValue = 0.65; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Y error - rng->doubleValue = 0.75; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Excitation error - rng->doubleValue = 0.85; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Relaxation error - rng->doubleValue = 0.95; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); -} - -TEST(StatQubitMemoryErrorTest, apply_memory_error_y_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - - // Initial_condition << 0, 0, 0, 1, 0, 0, 0; - // this means take 4th row of MemoryTransitionMatrix - // ceiled values should be: - // No error= 0.1, X error = 0.2, Z error = 0.3, Y error = 0.8, Excitation = 0.9, Relaxation = 1.0 - setParDouble(qubit, "memory_x_error_rate", .1); - setParDouble(qubit, "memory_y_error_rate", .1); - setParDouble(qubit, "memory_z_error_rate", .1); - setParDouble(qubit, "memory_energy_excitation_rate", .1); - setParDouble(qubit, "memory_energy_relaxation_rate", .1); - setParDouble(qubit, "memory_completely_mixed_rate", 0); - sim->registerComponent(qubit); - qubit->callInitialize(); - sim->setSimTime(SimTime(1, SIMTIME_US)); - - // X error - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - rng->doubleValue = 0.15; - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Z error - rng->doubleValue = 0.25; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Y error - rng->doubleValue = 0.5; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - qubit->applyMemoryError(); - EXPECT_TRUE(qubit->god_err.has_x_error); - EXPECT_TRUE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Excitation error - rng->doubleValue = 0.85; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Relaxation error - rng->doubleValue = 0.95; - qubit->reset(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); -} - -TEST(StatQubitMemoryErrorTest, apply_memory_error_excitation_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - - // Initial_condition << 0, 0, 0, 0, 1, 0, 0; - // this means take 5th row of MemoryTransitionMatrix - // ceiled values should be: - // No error= 0.1, X error = 0.2, Z error = 0.3, Y error = 0.8, Excitation = 0.9, Relaxation = 1.0 - setParDouble(qubit, "memory_x_error_rate", .1); - setParDouble(qubit, "memory_y_error_rate", .1); - setParDouble(qubit, "memory_z_error_rate", .1); - setParDouble(qubit, "memory_energy_excitation_rate", .1); - setParDouble(qubit, "memory_energy_relaxation_rate", .1); - setParDouble(qubit, "memory_completely_mixed_rate", 0); - sim->registerComponent(qubit); - qubit->callInitialize(); - sim->setSimTime(SimTime(1, SIMTIME_US)); - - // X error - qubit->reset(); - qubit->god_err.has_excitation_error = true; - rng->doubleValue = 0.15; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Z error - rng->doubleValue = 0.25; - qubit->reset(); - qubit->god_err.has_excitation_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Y error - rng->doubleValue = 0.5; - qubit->reset(); - qubit->god_err.has_excitation_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Excitation error - rng->doubleValue = 0.85; - qubit->reset(); - qubit->god_err.has_excitation_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Relaxation error - rng->doubleValue = 0.95; - qubit->reset(); - qubit->god_err.has_excitation_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); -} - -TEST(StatQubitMemoryErrorTest, apply_memory_error_relaxation_error) { - auto *sim = prepareSimulation(); - auto *rng = useTestRNG(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - - // Initial_condition << 0, 0, 0, 0, 0, 1, 0; - // this means take 6th row of MemoryTransitionMatrix - // ceiled values should be: - // No error= 0, X error = 0, Z error = 0, Y error = 0, Excitation = 0.1, Relaxation = 1.0 - setParDouble(qubit, "memory_x_error_rate", .1); - setParDouble(qubit, "memory_y_error_rate", .1); - setParDouble(qubit, "memory_z_error_rate", .1); - setParDouble(qubit, "memory_energy_excitation_rate", .1); - setParDouble(qubit, "memory_energy_relaxation_rate", .1); - setParDouble(qubit, "memory_completely_mixed_rate", 0); - sim->registerComponent(qubit); - qubit->callInitialize(); - sim->setSimTime(SimTime(1, SIMTIME_US)); - - // Excitation error - rng->doubleValue = 0.05; - qubit->reset(); - qubit->god_err.has_relaxation_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_TRUE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); - - // Relaxation error - rng->doubleValue = 0.95; - qubit->reset(); - qubit->god_err.has_relaxation_error = true; - qubit->applyMemoryError(); - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_TRUE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); -} - -} // namespace diff --git a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_test.cc b/quisp/modules/QNIC/StationaryQubit/StationaryQubit_test.cc index 0c61d86ea..9d720003c 100644 --- a/quisp/modules/QNIC/StationaryQubit/StationaryQubit_test.cc +++ b/quisp/modules/QNIC/StationaryQubit/StationaryQubit_test.cc @@ -1,40 +1,55 @@ #include "StationaryQubit.h" +#include #include #include #include #include +#include +#include +#include #include - +#include "backends/Backends.h" +#include "backends/ErrorTracking/Configuration.h" +#include "backends/interfaces/IConfiguration.h" +#include "backends/interfaces/IQuantumBackend.h" +#include "omnetpp/cmessage.h" +#include "test_utils/Simulation.h" +#include "test_utils/UtilFunctions.h" +#include "test_utils/mock_backends/MockQuantumBackend.h" + +using namespace testing; using namespace quisp::modules; using namespace quisp::modules::common; using namespace quisp_test; using namespace Eigen; +using namespace omnetpp; +using quisp::backends::ErrorTrackingConfiguration; +using quisp::messages::PhotonicQubit; namespace { class Strategy : public TestComponentProviderStrategy { public: - Strategy() : backend(new MockQuantumBackend()) {} + Strategy(IQuantumBackend *backend) : backend(backend) {} ~Strategy() {} IQuantumBackend *getQuantumBackend() override { return backend; } - MockQuantumBackend *backend; + IQuantumBackend *backend; }; class StatQubitTarget : public StationaryQubit { public: - using StationaryQubit::getErrorMatrix; - using StationaryQubit::getQuantumState; + using StationaryQubit::backend; + using StationaryQubit::finish; + using StationaryQubit::handleMessage; using StationaryQubit::initialize; using StationaryQubit::par; - StatQubitTarget() : StationaryQubit() { + using StationaryQubit::prepareBackendQubitConfiguration; + StatQubitTarget(IQuantumBackend *backend) : StationaryQubit() { setComponentType(new TestModuleType("test qubit")); - provider.setStrategy(std::make_unique()); - } - void reset() { - setFree(true); - updated_time = SimTime(0); - no_density_matrix_nullptr_entangled_partner_ok = true; + provider.setStrategy(std::make_unique(backend)); + toLensGate = new TestGate(this, "tolens_quantum_port$o"); } + void reset() { setFree(true); } void fillParams() { // see networks/omnetpp.ini setParDouble(this, "emission_success_probability", 0.5); @@ -82,202 +97,195 @@ class StatQubitTarget : public StationaryQubit { setParInt(this, "qnic_index", 0); setParDouble(this, "emission_jittering_standard_deviation", 0.5); } -}; - -TEST(StatQubitTest, initialize_memory_transition_matrix) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - setParDouble(qubit, "memory_x_error_rate", .011); - setParDouble(qubit, "memory_y_error_rate", .012); - setParDouble(qubit, "memory_z_error_rate", .013); - setParDouble(qubit, "memory_energy_excitation_rate", .014); - setParDouble(qubit, "memory_energy_relaxation_rate", .015); - setParDouble(qubit, "memory_completely_mixed_rate", 0); - sim->registerComponent(qubit); - qubit->callInitialize(); - auto mat = qubit->Memory_Transition_matrix; - - // each element means: "Clean Xerror Zerror Yerror Excited Relaxed Mixed" - Eigen::RowVectorXd row0(7); - double sigma = .011 + .013 + .012 + .014 + .015; - row0 << 1 - sigma, .011, .013, .012, .014, .015, .0; - ASSERT_EQ(mat.row(0), row0); - - Eigen::RowVectorXd row1(7); - row1 << .011, 1 - sigma, .012, .013, .014, .015, .0; - ASSERT_EQ(mat.row(1), row1); - - Eigen::RowVectorXd row2(7); - row2 << .013, .012, 1 - sigma, .011, .014, .015, .0; - ASSERT_EQ(mat.row(2), row2); - - Eigen::RowVectorXd row3(7); - row3 << .012, .013, .011, 1 - sigma, .014, .015, .0; - ASSERT_EQ(mat.row(3), row3); - - Eigen::RowVectorXd row4(7); - row4 << 0, 0, 0, 0, 1 - .015, .015, .0; - ASSERT_EQ(mat.row(4), row4); + TestGate *toLensGate; + cGate *gate(const char *gatename, int index = -1) override { + if (strcmp("tolens_quantum_port$o", gatename) != 0) { + throw std::runtime_error("unexpected gate name"); + } + return toLensGate; + } +}; - Eigen::RowVectorXd row5(7); - row5 << 0, 0, 0, 0, .014, 1 - .014, .0; - ASSERT_EQ(mat.row(5), row5); +class StatQubitTest : public ::testing::Test { + protected: + void SetUp() { + sim = prepareSimulation(); + backend = new MockQuantumBackend(); + qubit = new StatQubitTarget(backend); + qubit->fillParams(); + sim->registerComponent(qubit); + } + void TearDown() { delete backend; } - Eigen::RowVectorXd row6(7); - row6 << 0, 0, 0, 0, .014, .015, 1 - (.014 + .015); - ASSERT_EQ(mat.row(6), row6); -} + StatQubitTarget *qubit; + MockQuantumBackend *backend; + simulation::TestSimulation *sim; +}; -TEST(StatQubitTest, setFree) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - sim->registerComponent(qubit); - qubit->fillParams(); +TEST_F(StatQubitTest, init) { + auto *backend_qubit = new MockBackendQubit(); + auto *config = new IConfiguration(); + EXPECT_CALL(*backend, getDefaultConfiguration()).WillOnce(Return(ByMove(std::unique_ptr(config)))); + EXPECT_CALL(*backend, createQubit(NotNull(), NotNull())).WillOnce(Return(backend_qubit)); + EXPECT_CALL(*backend_qubit, setFree()).WillOnce(Return()); qubit->callInitialize(); - qubit->god_err.has_x_error = true; - qubit->god_err.has_z_error = true; - qubit->god_err.has_excitation_error = true; - qubit->god_err.has_relaxation_error = true; - qubit->god_err.has_completely_mixed_error = true; - - qubit->setFree(true); - EXPECT_EQ(qubit->updated_time, simTime()); - auto last_updated_at = qubit->updated_time; - sim->setSimTime(10); - EXPECT_EQ(qubit->updated_time, last_updated_at); - qubit->setFree(true); - EXPECT_EQ(qubit->updated_time, simTime()); - - // check the qubit reset properly - EXPECT_FALSE(qubit->god_err.has_x_error); - EXPECT_FALSE(qubit->god_err.has_z_error); - EXPECT_FALSE(qubit->god_err.has_excitation_error); - EXPECT_FALSE(qubit->god_err.has_relaxation_error); - EXPECT_FALSE(qubit->god_err.has_completely_mixed_error); + delete backend_qubit; } -TEST(StatQubitTest, setFreeUpdatesTime) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - sim->registerComponent(qubit); - qubit->fillParams(); - qubit->callInitialize(); - - qubit->setFree(true); - EXPECT_EQ(qubit->updated_time, simTime()); - - auto last_updated_at = qubit->updated_time; - sim->setSimTime(10); - EXPECT_EQ(qubit->updated_time, last_updated_at); - - qubit->setFree(true); - EXPECT_EQ(qubit->updated_time, simTime()); +TEST_F(StatQubitTest, errorTrackingQubitConfigurationOverwrite) { + auto *config = new ErrorTrackingConfiguration(); + setParDouble(qubit, "cnot_gate_error_rate", 0.01); + setParDouble(qubit, "cnot_gate_ix_error_ratio", 0.02); + setParDouble(qubit, "cnot_gate_xi_error_ratio", 0.03); + setParDouble(qubit, "cnot_gate_xx_error_ratio", 0.04); + setParDouble(qubit, "cnot_gate_iz_error_ratio", 0.05); + setParDouble(qubit, "cnot_gate_zi_error_ratio", 0.06); + setParDouble(qubit, "cnot_gate_zz_error_ratio", 0.07); + setParDouble(qubit, "cnot_gate_iy_error_ratio", 0.08); + setParDouble(qubit, "cnot_gate_yi_error_ratio", 0.09); + setParDouble(qubit, "cnot_gate_yy_error_ratio", 0.10); + + setParDouble(qubit, "h_gate_error_rate", 0.11); + setParDouble(qubit, "h_gate_x_error_ratio", 0.12); + setParDouble(qubit, "h_gate_y_error_ratio", 0.13); + setParDouble(qubit, "h_gate_z_error_ratio", 0.14); + + setParDouble(qubit, "x_gate_error_rate", 0.15); + setParDouble(qubit, "x_gate_x_error_ratio", 0.16); + setParDouble(qubit, "x_gate_y_error_ratio", 0.17); + setParDouble(qubit, "x_gate_z_error_ratio", 0.18); + + setParDouble(qubit, "z_gate_error_rate", 0.19); + setParDouble(qubit, "z_gate_x_error_ratio", 0.20); + setParDouble(qubit, "z_gate_y_error_ratio", 0.21); + setParDouble(qubit, "z_gate_z_error_ratio", 0.22); + + setParDouble(qubit, "x_measurement_error_rate", 0.23); + setParDouble(qubit, "y_measurement_error_rate", 0.24); + setParDouble(qubit, "z_measurement_error_rate", 0.25); + + setParDouble(qubit, "memory_x_error_rate", 0.26); + setParDouble(qubit, "memory_y_error_rate", 0.27); + setParDouble(qubit, "memory_z_error_rate", 0.28); + setParDouble(qubit, "memory_energy_excitation_rate", 0.29); + setParDouble(qubit, "memory_energy_relaxation_rate", 0.30); + setParDouble(qubit, "memory_completely_mixed_rate", 0.31); + + EXPECT_NE(config->cnot_gate_err_rate, qubit->par("cnot_gate_error_rate").doubleValue()); + EXPECT_NE(config->cnot_gate_ix_err_ratio, qubit->par("cnot_gate_ix_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_xi_err_ratio, qubit->par("cnot_gate_xi_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_xx_err_ratio, qubit->par("cnot_gate_xx_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_iz_err_ratio, qubit->par("cnot_gate_iz_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_zi_err_ratio, qubit->par("cnot_gate_zi_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_zz_err_ratio, qubit->par("cnot_gate_zz_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_iy_err_ratio, qubit->par("cnot_gate_iy_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_yi_err_ratio, qubit->par("cnot_gate_yi_error_ratio").doubleValue()); + EXPECT_NE(config->cnot_gate_yy_err_ratio, qubit->par("cnot_gate_yy_error_ratio").doubleValue()); + + EXPECT_NE(config->h_gate_err_rate, qubit->par("h_gate_error_rate").doubleValue()); + EXPECT_NE(config->h_gate_x_err_ratio, qubit->par("h_gate_x_error_ratio").doubleValue()); + EXPECT_NE(config->h_gate_y_err_ratio, qubit->par("h_gate_y_error_ratio").doubleValue()); + EXPECT_NE(config->h_gate_z_err_ratio, qubit->par("h_gate_z_error_ratio").doubleValue()); + + EXPECT_NE(config->x_gate_err_rate, qubit->par("x_gate_error_rate").doubleValue()); + EXPECT_NE(config->x_gate_x_err_ratio, qubit->par("x_gate_x_error_ratio").doubleValue()); + EXPECT_NE(config->x_gate_y_err_ratio, qubit->par("x_gate_y_error_ratio").doubleValue()); + EXPECT_NE(config->x_gate_z_err_ratio, qubit->par("x_gate_z_error_ratio").doubleValue()); + + EXPECT_NE(config->z_gate_err_rate, qubit->par("z_gate_error_rate").doubleValue()); + EXPECT_NE(config->z_gate_x_err_ratio, qubit->par("z_gate_x_error_ratio").doubleValue()); + EXPECT_NE(config->z_gate_y_err_ratio, qubit->par("z_gate_y_error_ratio").doubleValue()); + EXPECT_NE(config->z_gate_z_err_ratio, qubit->par("z_gate_z_error_ratio").doubleValue()); + + EXPECT_NE(config->measurement_x_err_rate, qubit->par("x_measurement_error_rate").doubleValue()); + EXPECT_NE(config->measurement_y_err_rate, qubit->par("y_measurement_error_rate").doubleValue()); + EXPECT_NE(config->measurement_z_err_rate, qubit->par("z_measurement_error_rate").doubleValue()); + + EXPECT_NE(config->memory_x_err_rate, qubit->par("memory_x_error_rate").doubleValue()); + EXPECT_NE(config->memory_y_err_rate, qubit->par("memory_y_error_rate").doubleValue()); + EXPECT_NE(config->memory_z_err_rate, qubit->par("memory_z_error_rate").doubleValue()); + EXPECT_NE(config->memory_excitation_rate, qubit->par("memory_energy_excitation_rate").doubleValue()); + EXPECT_NE(config->memory_relaxation_rate, qubit->par("memory_energy_relaxation_rate").doubleValue()); + EXPECT_NE(config->memory_completely_mixed_rate, qubit->par("memory_completely_mixed_rate").doubleValue()); + + // usually qubit->backend is assigned during initialize() + qubit->backend = backend; + + EXPECT_CALL(*backend, getDefaultConfiguration()).WillOnce(Return(ByMove(std::unique_ptr(config)))); + auto new_conf = qubit->prepareBackendQubitConfiguration(true); + + EXPECT_EQ(config->cnot_gate_err_rate, qubit->par("cnot_gate_error_rate").doubleValue()); + EXPECT_EQ(config->cnot_gate_ix_err_ratio, qubit->par("cnot_gate_ix_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_xi_err_ratio, qubit->par("cnot_gate_xi_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_xx_err_ratio, qubit->par("cnot_gate_xx_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_iz_err_ratio, qubit->par("cnot_gate_iz_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_zi_err_ratio, qubit->par("cnot_gate_zi_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_zz_err_ratio, qubit->par("cnot_gate_zz_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_iy_err_ratio, qubit->par("cnot_gate_iy_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_yi_err_ratio, qubit->par("cnot_gate_yi_error_ratio").doubleValue()); + EXPECT_EQ(config->cnot_gate_yy_err_ratio, qubit->par("cnot_gate_yy_error_ratio").doubleValue()); + + EXPECT_EQ(config->h_gate_err_rate, qubit->par("h_gate_error_rate").doubleValue()); + EXPECT_EQ(config->h_gate_x_err_ratio, qubit->par("h_gate_x_error_ratio").doubleValue()); + EXPECT_EQ(config->h_gate_y_err_ratio, qubit->par("h_gate_y_error_ratio").doubleValue()); + EXPECT_EQ(config->h_gate_z_err_ratio, qubit->par("h_gate_z_error_ratio").doubleValue()); + + EXPECT_EQ(config->x_gate_err_rate, qubit->par("x_gate_error_rate").doubleValue()); + EXPECT_EQ(config->x_gate_x_err_ratio, qubit->par("x_gate_x_error_ratio").doubleValue()); + EXPECT_EQ(config->x_gate_y_err_ratio, qubit->par("x_gate_y_error_ratio").doubleValue()); + EXPECT_EQ(config->x_gate_z_err_ratio, qubit->par("x_gate_z_error_ratio").doubleValue()); + + EXPECT_EQ(config->z_gate_err_rate, qubit->par("z_gate_error_rate").doubleValue()); + EXPECT_EQ(config->z_gate_x_err_ratio, qubit->par("z_gate_x_error_ratio").doubleValue()); + EXPECT_EQ(config->z_gate_y_err_ratio, qubit->par("z_gate_y_error_ratio").doubleValue()); + EXPECT_EQ(config->z_gate_z_err_ratio, qubit->par("z_gate_z_error_ratio").doubleValue()); + + EXPECT_EQ(config->measurement_x_err_rate, qubit->par("x_measurement_error_rate").doubleValue()); + EXPECT_EQ(config->measurement_y_err_rate, qubit->par("y_measurement_error_rate").doubleValue()); + EXPECT_EQ(config->measurement_z_err_rate, qubit->par("z_measurement_error_rate").doubleValue()); + + EXPECT_EQ(config->memory_x_err_rate, qubit->par("memory_x_error_rate").doubleValue()); + EXPECT_EQ(config->memory_y_err_rate, qubit->par("memory_y_error_rate").doubleValue()); + EXPECT_EQ(config->memory_z_err_rate, qubit->par("memory_z_error_rate").doubleValue()); + EXPECT_EQ(config->memory_excitation_rate, qubit->par("memory_energy_excitation_rate").doubleValue()); + EXPECT_EQ(config->memory_relaxation_rate, qubit->par("memory_energy_relaxation_rate").doubleValue()); + EXPECT_EQ(config->memory_completely_mixed_rate, qubit->par("memory_completely_mixed_rate").doubleValue()); } -TEST(StatQubitTest, addXError) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - sim->registerComponent(qubit); - EXPECT_FALSE(qubit->god_err.has_x_error); - qubit->addXerror(); - EXPECT_TRUE(qubit->god_err.has_x_error); - qubit->addXerror(); - EXPECT_FALSE(qubit->god_err.has_x_error); +TEST_F(StatQubitTest, emissionFailedPhotonLost) { + sim->setContext(qubit); + auto *msg = new PhotonicQubit(); + qubit->emission_success_probability = 0; + EXPECT_EQ(qubit->toLensGate->messages.size(), 0); + qubit->handleMessage(msg); + EXPECT_EQ(qubit->toLensGate->messages.size(), 1); + auto *new_msg = qubit->toLensGate->messages.at(0); + ASSERT_NE(new_msg, nullptr); + EXPECT_NE(new_msg, msg); + + auto *photon = dynamic_cast(new_msg); + ASSERT_NE(photon, nullptr); + EXPECT_TRUE(photon->getPhotonLost()); } -TEST(StatQubitTest, addZError) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - sim->registerComponent(qubit); - EXPECT_FALSE(qubit->god_err.has_z_error); - qubit->addZerror(); - EXPECT_TRUE(qubit->god_err.has_z_error); - qubit->addZerror(); - EXPECT_FALSE(qubit->god_err.has_z_error); +TEST_F(StatQubitTest, emissionSuccess) { + sim->setContext(qubit); + auto *msg = new PhotonicQubit(); + qubit->emission_success_probability = 1; + EXPECT_EQ(qubit->toLensGate->messages.size(), 0); + qubit->handleMessage(msg); + EXPECT_EQ(qubit->toLensGate->messages.size(), 1); + auto *new_msg = qubit->toLensGate->messages.at(0); + ASSERT_NE(new_msg, nullptr); + + auto *photon = dynamic_cast(new_msg); + ASSERT_NE(photon, nullptr); + EXPECT_FALSE(photon->getPhotonLost()); } -TEST(StatQubitTest, getErrorMatrixTest) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - qubit->fillParams(); - sim->registerComponent(qubit); - qubit->callInitialize(); - Matrix2cd err; - - err = qubit->getErrorMatrix(qubit); - EXPECT_EQ(Matrix2cd::Identity(), err); - - Matrix2cd Z(2, 2); - Z << 1, 0, 0, -1; - qubit->addZerror(); - err = qubit->getErrorMatrix(qubit); - EXPECT_EQ(Z, err); - qubit->setFree(true); - - Matrix2cd X(2, 2); - X << 0, 1, 1, 0; - qubit->addXerror(); - err = qubit->getErrorMatrix(qubit); - EXPECT_EQ(X, err); - qubit->setFree(true); - - Matrix2cd Y(2, 2); - Y << 0, Complex(0, -1), Complex(0, 1), 0; - qubit->addXerror(); - qubit->addZerror(); - err = qubit->getErrorMatrix(qubit); - EXPECT_EQ(Y, err); - qubit->setFree(true); +TEST_F(StatQubitTest, finish) { + ASSERT_NO_THROW({ qubit->finish(); }); } -TEST(StatQubitTest, getQuantumState) { - auto *sim = prepareSimulation(); - auto *qubit = new StatQubitTarget{}; - auto *partner_qubit = new StatQubitTarget{}; - sim->registerComponent(qubit); - sim->registerComponent(partner_qubit); - qubit->fillParams(); - qubit->callInitialize(); - partner_qubit->fillParams(); - partner_qubit->callInitialize(); - qubit->setEntangledPartnerInfo(partner_qubit); - - quantum_state state; - - state = qubit->getQuantumState(); - Vector4cd state_vector(4); - state_vector << 1 / sqrt(2), 0, 0, 1 / sqrt(2); - Matrix4cd dm(4, 4); - dm = state_vector * state_vector.adjoint(); - EXPECT_EQ(dm, state.state_in_density_matrix); - EXPECT_EQ(state_vector, state.state_in_ket); - - qubit->addXerror(); - state = qubit->getQuantumState(); - state_vector << 0, 1 / sqrt(2), 1 / sqrt(2), 0; - dm = state_vector * state_vector.adjoint(); - EXPECT_EQ(dm, state.state_in_density_matrix); - EXPECT_EQ(state_vector, state.state_in_ket); - qubit->addXerror(); - - partner_qubit->addXerror(); - state = qubit->getQuantumState(); - state_vector << 0, 1 / sqrt(2), 1 / sqrt(2), 0; - dm = state_vector * state_vector.adjoint(); - EXPECT_EQ(dm, state.state_in_density_matrix); - EXPECT_EQ(state_vector, state.state_in_ket); - partner_qubit->addXerror(); - - qubit->addZerror(); - state = qubit->getQuantumState(); - state_vector << 1 / sqrt(2), 0, 0, -1 / sqrt(2); - dm = state_vector * state_vector.adjoint(); - EXPECT_EQ(dm, state.state_in_density_matrix); - EXPECT_EQ(state_vector, state.state_in_ket); - qubit->addZerror(); -} } // namespace diff --git a/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.cc b/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.cc index f06b14ce5..96cc508eb 100644 --- a/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.cc +++ b/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.cc @@ -43,7 +43,7 @@ void HardwareMonitor::initialize(int stage) { initial.total_count = 0; Pauli.X << 0, 1, 1, 0; - Pauli.Y << 0, Complex(0, -1), Complex(0, 1), 0; + Pauli.Y << 0, std::complex(0, -1), std::complex(0, 1), 0; Pauli.Z << 1, 0, 0, -1; Pauli.I << 1, 0, 0, 1; @@ -371,11 +371,11 @@ void HardwareMonitor::finish() { Bellpair_Z << 1 / sqrt(2), 0, 0, -1 / sqrt(2); Matrix4cd density_matrix_Z = Bellpair_Z * Bellpair_Z.adjoint(); double Zerr_rate = (extended_density_matrix_reconstructed.real() * density_matrix_Z.real()).trace(); - Complex checkZ = Bellpair_Z.adjoint() * extended_density_matrix_reconstructed * Bellpair_Z; + std::complex checkZ = Bellpair_Z.adjoint() * extended_density_matrix_reconstructed * Bellpair_Z; EV << "Zerr = " << Zerr_rate << " or, " << checkZ.real() << "+" << checkZ.imag() << "\n"; Vector4cd Bellpair_Y; - Bellpair_Y << 0, Complex(0, 1 / sqrt(2)), Complex(0, -1 / sqrt(2)), 0; + Bellpair_Y << 0, std::complex(0, 1 / sqrt(2)), std::complex(0, -1 / sqrt(2)), 0; Matrix4cd density_matrix_Y = Bellpair_Y * Bellpair_Y.adjoint(); double Yerr_rate = (extended_density_matrix_reconstructed.real() * density_matrix_Y.real()).trace(); EV << "Yerr = " << Yerr_rate << "\n"; diff --git a/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.h b/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.h index 343886cd7..b6fed2b83 100644 --- a/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.h +++ b/quisp/modules/QRSA/HardwareMonitor/HardwareMonitor.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace quisp::modules { @@ -33,6 +34,14 @@ class HardwareMonitor : public IHardwareMonitor { utils::ComponentProvider provider; private: + // Matrices of single qubit errors. Used when conducting tomography. + struct SingleQubitError { + Eigen::Matrix2cd X; // double 2*2 matrix + Eigen::Matrix2cd Y; // complex double 2*2 matrix + Eigen::Matrix2cd Z; + Eigen::Matrix2cd I; + }; + int my_address; // number of qnics connected to stand alone HOM or internal hom in the neighbor. @@ -59,7 +68,7 @@ class HardwareMonitor : public IHardwareMonitor { cModule *getQnic(int qnic_index, QNIC_type qnic_type); NeighborTable neighbor_table; raw_data *tomography_data; - single_qubit_error Pauli; + SingleQubitError Pauli; TomographyOutcomeTable *temporal_tomography_output; // qnic address -> partner . count_id . outcome LinkCostMap *tomography_runningtime_holder; diff --git a/quisp/modules/QRSA/RealTimeController/RealTimeController.cc b/quisp/modules/QRSA/RealTimeController/RealTimeController.cc index 63b117105..cc53f9e8b 100644 --- a/quisp/modules/QRSA/RealTimeController/RealTimeController.cc +++ b/quisp/modules/QRSA/RealTimeController/RealTimeController.cc @@ -45,17 +45,7 @@ void RealTimeController::applyZGate(qrsa::IQubitRecord *const qubit_record) { } void RealTimeController::assertNoEntanglement(qrsa::IQubitRecord *const qubit_record) { auto *qubit = provider.getStationaryQubit(qubit_record); - if (qubit->entangled_partner == nullptr && qubit->Density_Matrix_Collapsed(0, 0).real() == -111 && !qubit->no_density_matrix_nullptr_entangled_partner_ok) { - error("something went wrong"); - } - if (qubit->entangled_partner != nullptr) { - if (qubit->entangled_partner->entangled_partner == nullptr) { - error("1. Entanglement tracking is not doing its job. in update resource E.S."); - } - if (qubit->entangled_partner->entangled_partner != qubit) { - error("2. Entanglement tracking is not doing its job. in update resource E.S."); - } - } + qubit->assertEntangledPartnerValid(); } } // namespace modules } // namespace quisp diff --git a/quisp/modules/QRSA/RuleEngine/RuleEngine.cc b/quisp/modules/QRSA/RuleEngine/RuleEngine.cc index 427f953b2..d98dd3135 100644 --- a/quisp/modules/QRSA/RuleEngine/RuleEngine.cc +++ b/quisp/modules/QRSA/RuleEngine/RuleEngine.cc @@ -500,25 +500,7 @@ void RuleEngine::freeFailedQubits_and_AddAsResource(int destAddr, int internal_q // Keep the entangled qubits auto *qubit_record = qnic_store->getQubitRecord(qnic_type, qnic_index, it->second.qubit_index); IStationaryQubit *qubit = provider.getStationaryQubit(qubit_record); - - // if the partner is null, not correct - if (qubit->entangled_partner != nullptr) { - if (qubit->entangled_partner->entangled_partner == nullptr) { - // my instance is null (no way) - error("1. Entanglement tracking is not doing its job."); - } - if (qubit->entangled_partner->entangled_partner != qubit) { - // partner's qubit doesn't point this qubit -> wrong - error("2. Entanglement tracking is not doing its job."); - } - } - - if (qubit->entangled_partner == nullptr && qubit->Density_Matrix_Collapsed(0, 0).real() == -111 && !qubit->no_density_matrix_nullptr_entangled_partner_ok) { - EV << "entangle partner null?" << qubit->entangled_partner << " == nullptr?\n"; - EV << "density matrix collapsed?" << qubit->Density_Matrix_Collapsed(0, 0).real() << "==-111?\n"; - EV << "here should be true" << qubit->no_density_matrix_nullptr_entangled_partner_ok << "\n"; - error("RuleEngine. Ebit succeed. but wrong"); - } + qubit->assertEntangledPartnerValid(); // Add qubit as available resource between NeighborQNodeAddress. bell_pair_store.insertEntangledQubit(neighborQNodeAddress, qubit_record); } diff --git a/quisp/modules/QRSA/RuleEngine/RuntimeCallback.h b/quisp/modules/QRSA/RuleEngine/RuntimeCallback.h index 0fbf3c153..97a6a3763 100644 --- a/quisp/modules/QRSA/RuleEngine/RuntimeCallback.h +++ b/quisp/modules/QRSA/RuleEngine/RuntimeCallback.h @@ -225,39 +225,9 @@ struct RuntimeCallback : public quisp::runtime::Runtime::ICallBack { return qubit->action_index; } - void hackSwappingPartners(IQubitRecord *const left_qubit_rec, IQubitRecord *const right_qubit_rec) override { - // HACK: this comes from the original SwappingAction.cc - // manipulate entangled partners to reproduce the situation of entanglement swapping - // this will be not used if we implement more realistic qubit backend - auto *left_qubit = provider.getStationaryQubit(left_qubit_rec); - auto *right_qubit = provider.getStationaryQubit(right_qubit_rec); - auto left_partner_qubit = left_qubit->entangled_partner; - auto right_partner_qubit = right_qubit->entangled_partner; - if (right_partner_qubit == nullptr) throw std::runtime_error("invalid right partner qubit"); - if (left_partner_qubit == nullptr) throw std::runtime_error("invalid left partner qubit"); - right_partner_qubit->setEntangledPartnerInfo(left_partner_qubit); - left_partner_qubit->setEntangledPartnerInfo(right_partner_qubit); - - // HACK: this is also comes from the original SwappingAction.cc - // at the both partner nodes, they need know which qubits are swapped. - // so here these qubit indices are stored and later sendSwappingResults method uses it - // this must be tracked in another way because we can't know these information - // from the actual qubits in real world - right_qubit_index = right_partner_qubit->stationary_qubit_address; - left_qubit_index = left_partner_qubit->stationary_qubit_address; - } + void hackSwappingPartners(IQubitRecord *const left_qubit_rec, IQubitRecord *const right_qubit_rec) override {} - void hackBreakEntanglement(IQubitRecord *qubit) override { - auto *stat_qubit = rule_engine->provider.getStationaryQubit((qubit)); - // HACK: comes from the original PurifyAction.cc. - // we're freeing the qubit but its entangled_partner will be freed later. - // to pass the validation in RuleEngine::freeFailedQubits_and_AddAsResource for next round, - // break the entanglement manually. - if (stat_qubit->entangled_partner != nullptr && stat_qubit->entangled_partner->entangled_partner != nullptr) { - stat_qubit->entangled_partner->no_density_matrix_nullptr_entangled_partner_ok = true; - stat_qubit->entangled_partner->entangled_partner = nullptr; - } - }; + void hackBreakEntanglement(IQubitRecord *qubit) override{}; std::string getNodeInfo() override { std::stringstream ss; diff --git a/quisp/modules/common_types.h b/quisp/modules/common_types.h index 086134816..649e8ccac 100644 --- a/quisp/modules/common_types.h +++ b/quisp/modules/common_types.h @@ -10,7 +10,9 @@ using QNicType = int; using QubitIndex = int; using QubitId = std::tuple; using IBackendQubit = quisp::backends::IQubit; +using quisp::backends::ErrorTrackingBackend; +using quisp::backends::ErrorTrackingConfiguration; +using quisp::backends::IConfiguration; +using quisp::backends::IQuantumBackend; using quisp::backends::IQubitId; -using IQuantumBackend = quisp::backends::IQuantumBackend; -using ErrorTrackingBackend = quisp::backends::ErrorTrackingBackend; } // namespace quisp::modules::common diff --git a/quisp/runtime/types.h b/quisp/runtime/types.h index 8e79ba75b..ab551c394 100644 --- a/quisp/runtime/types.h +++ b/quisp/runtime/types.h @@ -23,7 +23,7 @@ using String = std::string; using IQubitRecord = quisp::modules::qrsa::IQubitRecord; /// @brief measurement outcome for Instructions. -using MeasurementOutcome = quisp::modules::measurement_outcome; +using MeasurementOutcome = quisp::backends::MeasurementOutcome; /// @brief alias for omnetpp's simulation time. using Time = omnetpp::SimTime; diff --git a/quisp/test_utils/TestUtils.h b/quisp/test_utils/TestUtils.h index 8f6e1e543..96bf954f0 100644 --- a/quisp/test_utils/TestUtils.h +++ b/quisp/test_utils/TestUtils.h @@ -8,6 +8,7 @@ #include "StaticEnv.h" #include "TestComponentProviderStrategy.h" #include "UtilFunctions.h" +#include "mock_backends/MockBackendQubit.h" #include "mock_backends/MockQuantumBackend.h" #include "mock_modules/MockHardwareMonitor.h" #include "mock_modules/MockQubit.h" @@ -21,6 +22,7 @@ namespace quisp_test { // use these functions and classes in your unit test. using gate::TestGate; +using mock_backends::MockBackendQubit; using mock_backends::MockQuantumBackend; using mock_modules::hardware_monitor::MockHardwareMonitor; using mock_modules::qnic_store::MockQNicStore; diff --git a/quisp/test_utils/mock_backends/MockBackendQubit.h b/quisp/test_utils/mock_backends/MockBackendQubit.h new file mode 100644 index 000000000..f858cff1b --- /dev/null +++ b/quisp/test_utils/mock_backends/MockBackendQubit.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include +#include +#include "backends/interfaces/IQubit.h" +#include "gmock/gmock-function-mocker.h" +namespace quisp_test::mock_backends { +class MockBackendQubit : public quisp::backends::abstract::IQubit { + public: + MOCK_METHOD(void, setFree, (), (override)); + MOCK_METHOD(void, setEntangledPartner, (IQubit * partner_qubit), (override)); +}; +} // namespace quisp_test::mock_backends diff --git a/quisp/test_utils/mock_backends/MockQuantumBackend.h b/quisp/test_utils/mock_backends/MockQuantumBackend.h index 2a9a7b1a3..9637afc97 100644 --- a/quisp/test_utils/mock_backends/MockQuantumBackend.h +++ b/quisp/test_utils/mock_backends/MockQuantumBackend.h @@ -7,12 +7,17 @@ namespace quisp_test::mock_backends { using quisp::modules::common::IBackendQubit; +using quisp::modules::common::IConfiguration; using quisp::modules::common::IQuantumBackend; using quisp::modules::common::IQubitId; class MockQuantumBackend : public IQuantumBackend { public: MOCK_METHOD(IBackendQubit *, getQubit, (const IQubitId *), (override)); + MOCK_METHOD(IBackendQubit *, createQubit, (const IQubitId *, std::unique_ptr configuration), (override)); + MOCK_METHOD(IBackendQubit *, createQubit, (const IQubitId *), (override)); + MOCK_METHOD(void, deleteQubit, (const IQubitId *), (override)); MOCK_METHOD(const SimTime &, getSimTime, (), (override)); MOCK_METHOD(void, setSimTime, (SimTime time), (override)); + MOCK_METHOD(std::unique_ptr, getDefaultConfiguration, (), (const, override)); }; } // namespace quisp_test::mock_backends diff --git a/quisp/test_utils/mock_modules/MockQubit.h b/quisp/test_utils/mock_modules/MockQubit.h index ce10a33cc..f7bef609b 100644 --- a/quisp/test_utils/mock_modules/MockQubit.h +++ b/quisp/test_utils/mock_modules/MockQubit.h @@ -4,13 +4,17 @@ #include #include #include +#include "backends/Backends.h" #include "modules/QNIC.h" +#include "modules/QNIC/StationaryQubit/IStationaryQubit.h" #include "modules/QRSA/RuleEngine/BellPairStore/BellPairStore.h" namespace quisp_test { namespace mock_modules { namespace stationary_qubit { +using quisp::backends::IQubit; +using quisp::backends::IQubitId; using quisp::modules::IStationaryQubit; using quisp_test::utils::setParBool; using quisp_test::utils::setParDouble; @@ -20,6 +24,8 @@ class MockQubit : public IStationaryQubit { public: using IStationaryQubit::initialize; using IStationaryQubit::par; + IStationaryQubit *entangled_partner; + MOCK_METHOD(void, emitPhoton, (int pulse), (override)); MOCK_METHOD(void, setFree, (bool consumed), (override)); MOCK_METHOD(quisp::types::MeasureZResult, correlationMeasureZ, (), (override)); @@ -30,8 +36,6 @@ class MockQubit : public IStationaryQubit { MOCK_METHOD(quisp::types::EigenvalueResult, localMeasureZ, (), (override)); MOCK_METHOD(bool, Xpurify, (IStationaryQubit *), (override)); MOCK_METHOD(bool, Zpurify, (IStationaryQubit *), (override)); - MOCK_METHOD(void, addXerror, (), (override)); - MOCK_METHOD(void, addZerror, (), (override)); MOCK_METHOD(void, Z_gate, (), (override)); MOCK_METHOD(void, X_gate, (), (override)); MOCK_METHOD(void, Hadamard_gate, (), (override)); @@ -39,14 +43,9 @@ class MockQubit : public IStationaryQubit { MOCK_METHOD(void, Lock, (unsigned long rs_id, int rule_id, int action_id), (override)); MOCK_METHOD(void, Unlock, (), (override)); MOCK_METHOD(bool, isLocked, (), (override)); - MOCK_METHOD(quisp::modules::measurement_outcome, measure_density_independent, (), (override)); - MOCK_METHOD(void, setCompletelyMixedDensityMatrix, (), (override)); + MOCK_METHOD(quisp::types::MeasurementOutcome, measure_density_independent, (), (override)); MOCK_METHOD(void, setEntangledPartnerInfo, (IStationaryQubit *), (override)); - MOCK_METHOD(quisp::types::EigenvalueResult, measureX, (), (override)); - MOCK_METHOD(quisp::types::EigenvalueResult, measureY, (), (override)); - MOCK_METHOD(quisp::types::EigenvalueResult, measureZ, (), (override)); - MOCK_METHOD(void, cnotGate, (IStationaryQubit * control_qubit), (override)); MOCK_METHOD(void, hadamardGate, (), (override)); MOCK_METHOD(void, zGate, (), (override)); @@ -55,17 +54,17 @@ class MockQubit : public IStationaryQubit { MOCK_METHOD(void, sdgGate, (), (override)); MOCK_METHOD(void, excite, (), (override)); MOCK_METHOD(void, relax, (), (override)); + MOCK_METHOD(void, assertEntangledPartnerValid, (), (override)); + MOCK_METHOD(IQubit *const, getEntangledPartner, (), (const, override)); + MOCK_METHOD(IQubit *const, getBackendQubitRef, (), (const, override)); + MOCK_METHOD(int, getPartnerStationaryQubitAddress, (), (const, override)); MockQubit() : IStationaryQubit() { setComponentType(new module_type::TestModuleType("test qubit")); } MockQubit(quisp::modules::QNIC_type _type, quisp::modules::QNicIndex _qnic_index) : MockQubit() { qnic_type = _type; qnic_index = _qnic_index; } - void reset() { - setFree(true); - updated_time = SimTime(0); - no_density_matrix_nullptr_entangled_partner_ok = true; - } + void reset() { setFree(true); } void fillParams() { // see networks/omnetpp.ini setParDouble(this, "emission_success_probability", 0.5); @@ -119,10 +118,6 @@ class MockQubit : public IStationaryQubit { setParBool(this, "god_excitation_error", false); setParBool(this, "god_relaxation_error", false); setParBool(this, "is_busy", false); - setParInt(this, "god_entangled_stationary_qubit_address", 0); - setParInt(this, "god_entangled_node_address", 0); - setParInt(this, "god_entangled_qnic_address", 0); - setParInt(this, "god_entangled_qnic_type", 0); setParDouble(this, "fidelity", -1.0); } };