Skip to content

Commit

Permalink
remove AbstractError, add superop to QuantumError
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseclectic committed Aug 1, 2019
1 parent 2f88f31 commit 2d32a6a
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 113 deletions.
76 changes: 0 additions & 76 deletions src/noise/abstract_error.hpp

This file was deleted.

3 changes: 0 additions & 3 deletions src/noise/noise_model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
#include "framework/types.hpp"
#include "framework/rng.hpp"
#include "framework/circuit.hpp"
#include "noise/abstract_error.hpp"

// For JSON parsing of specific error types
#include "noise/quantum_error.hpp"
#include "noise/readout_error.hpp"

Expand Down
133 changes: 108 additions & 25 deletions src/noise/quantum_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#ifndef _aer_noise_quantum_error_hpp_
#define _aer_noise_quantum_error_hpp_

#include "noise/abstract_error.hpp"
#include "simulators/superoperator/superoperator_state.hpp"

namespace AER {
namespace Noise {
Expand All @@ -27,27 +27,39 @@ namespace Noise {
// Quantum error class that can model any error that is expressed as a
// qobj instruction acting on qubits.

class QuantumError : public AbstractError {
class QuantumError {
public:

// Methods for sampling
enum class Method {standard, superop};

// Alias for return type
using NoiseOps = std::vector<Operations::Op>;

//-----------------------------------------------------------------------
// Error base required methods
// Sampling method
//-----------------------------------------------------------------------

// Sample a noisy implementation of op
NoiseOps sample_noise(const reg_t &qubits,
RngEngine &rng) const override;
RngEngine &rng,
Method method = Method::standard) const;

// Load a QuantumError object from a JSON Error object
void load_from_json(const json_t &js) override;
// Return the opset for the quantum error
const Operations::OpSet& opset() const {return opset_;}

// Return the superoperator matrix representation of the error.
// If the error cannot be converted to a superoperator and error
// will be raised.
const cmatrix_t& superoperator() const;

//-----------------------------------------------------------------------
// Additional class methods
// Initialization
//-----------------------------------------------------------------------

// Load a QuantumError object from a JSON Error object
void load_from_json(const json_t &js);

// Sets the sub-circuits and probabilities to be sampled from.
// The length of the circuits vector and probability vector must be equal.
void set_circuits(const std::vector<NoiseOps> &circuits,
Expand All @@ -58,12 +70,35 @@ class QuantumError : public AbstractError {
// non-kraus subcircuits.
void set_from_kraus(const std::vector<cmatrix_t> &mats);

// Compute the superoperator representation of the quantum error
void compute_superoperator();

//-----------------------------------------------------------------------
// Utility
//-----------------------------------------------------------------------

// Set number of qubits or memory bits for error
inline void set_num_qubits(uint_t num_qubits) {num_qubits_ = num_qubits;}

// Get number of qubits or memory bits for error
inline uint_t get_num_qubits() const {return num_qubits_;}

// Set the sampled errors to be applied after the original operation
inline void set_errors_after() {errors_after_op_ = true;}

// Set the sampled errors to be applied before the original operation
inline void set_errors_before() {errors_after_op_ = false;}

// Returns true if the errors are to be applied after the operation
inline bool errors_after() const {return errors_after_op_;}

// Set threshold for checking probabilities and matrices
void set_threshold(double);

const Operations::OpSet& opset() const {return opset_;}

protected:
// Number of qubits sthe error applies to
uint_t num_qubits_ = 0;

// Probabilities, first entry is no-error (identity)
rvector_t probabilities_;
//std::discrete_distribution<uint_t> probabilities_;
Expand All @@ -76,37 +111,56 @@ class QuantumError : public AbstractError {

// threshold for validating if matrices are unitary
double threshold_ = 1e-10;

// Superoperator matrix representation of the error
cmatrix_t superoperator_;

// flag for where errors should be applied relative to the sampled op
bool errors_after_op_ = true;
};

//-------------------------------------------------------------------------
// Implementation: Mixed unitary error subclass
//-------------------------------------------------------------------------


QuantumError::NoiseOps QuantumError::sample_noise(const reg_t &qubits,
RngEngine &rng) const {
RngEngine &rng,
Method method) const {
if (qubits.size() < get_num_qubits()) {
std::stringstream msg;
msg << "QuantumError: qubits size (" << qubits.size() << ")";
msg << " < error qubits (" << get_num_qubits() << ").";
throw std::invalid_argument(msg.str());
}
auto r = rng.rand_int(probabilities_);
// Check for invalid arguments
if (r + 1 > circuits_.size()) {
std::stringstream msg;
msg << "QuantumError: probability outcome (" << r << ")";
msg << " is greater than number of circuits (" << circuits_.size() << ").";
throw std::invalid_argument(msg.str());
}
NoiseOps noise_ops = circuits_[r];
// Add qubits to noise op commands;
for (auto &op : noise_ops) {
// Update qubits based on position in qubits list
for (size_t q=0; q < op.qubits.size(); q++) {
op.qubits[q] = qubits[op.qubits[q]];
switch (method) {
case Method::superop: {
// Truncate qubits to size of the actual error
reg_t op_qubits = qubits;
op_qubits.resize(get_num_qubits());
auto op = Operations::make_superop(op_qubits, superoperator());
return NoiseOps({op});
}
default: {
auto r = rng.rand_int(probabilities_);
// Check for invalid arguments
if (r + 1 > circuits_.size()) {
std::stringstream msg;
msg << "QuantumError: probability outcome (" << r << ")";
msg << " is greater than number of circuits (" << circuits_.size() << ").";
throw std::invalid_argument(msg.str());
}
NoiseOps noise_ops = circuits_[r];
// Add qubits to noise op commands;
for (auto &op : noise_ops) {
// Update qubits based on position in qubits list
for (size_t q=0; q < op.qubits.size(); q++) {
op.qubits[q] = qubits[op.qubits[q]];
}
}
return noise_ops;
}
}
return noise_ops;
}

void QuantumError::set_threshold(double threshold) {
Expand Down Expand Up @@ -259,6 +313,35 @@ void QuantumError::set_from_kraus(const std::vector<cmatrix_t> &mats) {
}


const cmatrix_t& QuantumError::superoperator() const {
// Check the superoperator is actually computed
// If not raise an exception
if (superoperator_.empty()) {
throw std::runtime_error("QuantumError: superoperator is empty.");
}
return superoperator_;
}


void QuantumError::compute_superoperator() {
// Initialize superoperator matrix to correct size
size_t dim = 1 << (2 * get_num_qubits());
superoperator_.initialize(dim, dim);
// We use the superoperator simulator state to do this
QubitSuperoperator::State<> superop;
for (size_t j=0; j<circuits_.size(); j++ ){
// Initialize identity superoperator
superop.initialize_qreg(get_num_qubits());
// Apply each gate in the circuit
// We don't need output data or RNG for this
OutputData data;
RngEngine rng;
superop.apply_ops(circuits_[j], data, rng);
superoperator_ += probabilities_[j] * superop.qreg().matrix();
}
}


void QuantumError::load_from_json(const json_t &js) {
rvector_t probs;
JSON::get_value(probs, "probabilities", js);
Expand Down
34 changes: 25 additions & 9 deletions src/noise/readout_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
#ifndef _aer_noise_readout_error_hpp_
#define _aer_noise_readout_error_hpp_

#include "noise/abstract_error.hpp"

namespace AER {
namespace Noise {

Expand All @@ -26,31 +24,49 @@ namespace Noise {



class ReadoutError : public AbstractError {
class ReadoutError {
public:

// Alias for return type
using NoiseOps = std::vector<Operations::Op>;

//-----------------------------------------------------------------------
// Error base required methods
// Error sampling
//-----------------------------------------------------------------------

// Sample a noisy implementation of op
NoiseOps sample_noise(const reg_t &memory,
RngEngine &rng) const override;

// Load a ReadoutError object from a JSON Error object
void load_from_json(const json_t &js) override;
RngEngine &rng) const;

//-----------------------------------------------------------------------
// Additional class methods
// Initialization
//-----------------------------------------------------------------------

// Load a ReadoutError object from a JSON Error object
void load_from_json(const json_t &js);

// Set the default assignment probabilities for measurement of each qubit
// Each vector is a list of probabilities {P(0|q), P(1|q), ... P(n-1|q)}
// For the no-error case this list viewed as a matrix should be an
// identity matrix
void set_probabilities(const std::vector<rvector_t> &probs);

//-----------------------------------------------------------------------
// Utility
//-----------------------------------------------------------------------

// Set number of qubits or memory bits for error
inline void set_num_qubits(uint_t num_qubits) {num_qubits_ = num_qubits;}

// Get number of qubits or memory bits for error
inline uint_t get_num_qubits() const {return num_qubits_;}

protected:

// Number of qubits/memory bits the error applies to
uint_t num_qubits_ = 0;

// Vector of assignment probability vectors
std::vector<rvector_t> assignment_probabilities_;

// threshold for checking probabilities
Expand Down

0 comments on commit 2d32a6a

Please sign in to comment.