Skip to content

Commit

Permalink
Merge pull request #467 from sfc-aqua/connect-backend-and-stationary-…
Browse files Browse the repository at this point in the history
…qubit-rebased

Connect backend and stationary qubit (new)
  • Loading branch information
Naphann authored Jan 20, 2023
2 parents 454fcd9 + 78f5e34 commit d66ab32
Show file tree
Hide file tree
Showing 42 changed files with 1,621 additions and 3,293 deletions.
10 changes: 10 additions & 0 deletions quisp/backends/Backends.h
Original file line number Diff line number Diff line change
@@ -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
50 changes: 48 additions & 2 deletions quisp/backends/ErrorTracking/Backend.cc
Original file line number Diff line number Diff line change
@@ -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<IRandomNumberGenerator> rng) : current_time(SimTime()), rng(std::move(rng)) {}
ErrorTrackingBackend::ErrorTrackingBackend(std::unique_ptr<IRandomNumberGenerator> rng, std::unique_ptr<ErrorTrackingConfiguration> configuration)
: current_time(SimTime()), rng(std::move(rng)) {
config = std::move(configuration);
}
ErrorTrackingBackend::ErrorTrackingBackend(std::unique_ptr<IRandomNumberGenerator> rng, std::unique_ptr<ErrorTrackingConfiguration> 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<IConfiguration> 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<ErrorTrackingQubit>(id, this);

IConfiguration* raw_conf = conf.release();
ErrorTrackingConfiguration* et_conf = dynamic_cast<ErrorTrackingConfiguration*>(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<ErrorTrackingConfiguration>(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<IConfiguration> ErrorTrackingBackend::getDefaultConfiguration() const {
// copy the default backend configuration for each qubit
return std::make_unique<ErrorTrackingConfiguration>(*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(); }

Expand Down
17 changes: 16 additions & 1 deletion quisp/backends/ErrorTracking/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
#include <memory>
#include <unordered_map>

#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;
Expand All @@ -18,9 +21,19 @@ using omnetpp::SimTime;

class ErrorTrackingBackend : public IQuantumBackend {
public:
ErrorTrackingBackend(std::unique_ptr<IRandomNumberGenerator> rng);
class ICallback {
public:
virtual ~ICallback() {}
virtual void willUpdate(ErrorTrackingBackend& backend) = 0;
};
ErrorTrackingBackend(std::unique_ptr<IRandomNumberGenerator> rng, std::unique_ptr<ErrorTrackingConfiguration> configuration);
ErrorTrackingBackend(std::unique_ptr<IRandomNumberGenerator> rng, std::unique_ptr<ErrorTrackingConfiguration> configuration, ICallback* callback);
~ErrorTrackingBackend();
IQubit* createQubit(const IQubitId* id, std::unique_ptr<IConfiguration> conf) override;
IQubit* createQubit(const IQubitId* id) override;
IQubit* getQubit(const IQubitId* id) override;
void deleteQubit(const IQubitId* id) override;
std::unique_ptr<IConfiguration> getDefaultConfiguration() const override;
const SimTime& getSimTime() override;
void setSimTime(SimTime time) override;
double dblrand();
Expand All @@ -29,6 +42,8 @@ class ErrorTrackingBackend : public IQuantumBackend {
std::unordered_map<const IQubitId*, std::unique_ptr<ErrorTrackingQubit>, IQubitId::Hash, IQubitId::Pred> qubits;
SimTime current_time;
const std::unique_ptr<IRandomNumberGenerator> rng;
std::unique_ptr<ErrorTrackingConfiguration> config;
ICallback* callback = nullptr;
};

} // namespace quisp::backends::error_tracking
150 changes: 146 additions & 4 deletions quisp/backends/ErrorTracking/Backend_test.cc
Original file line number Diff line number Diff line change
@@ -1,30 +1,78 @@
#include "Backend.h"
#include <cxxabi.h>
#include <gtest/gtest.h>
#include <omnetpp.h>
#include "../interfaces/IRandomNumberGenerator.h"
#include "Configuration.h"
#include "Qubit.h"
#include "backends/interfaces/IConfiguration.h"
#include "test.h"

namespace {
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<IRandomNumberGenerator> rng, std::unique_ptr<ErrorTrackingConfiguration> 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<Backend>(std::unique_ptr<IRandomNumberGenerator>(rng));
backend = std::make_unique<EtBackend>(std::unique_ptr<IRandomNumberGenerator>(rng), std::make_unique<ErrorTrackingConfiguration>());
}
TestRNG* rng;
std::unique_ptr<Backend> backend;
std::unique_ptr<EtBackend> 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);
Expand All @@ -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<IConfiguration>(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<ErrorTrackingConfiguration>(*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<TestEtQubit*>(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
53 changes: 53 additions & 0 deletions quisp/backends/ErrorTracking/Configuration.h
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit d66ab32

Please sign in to comment.