microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
jan

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/noisy_simulator/src/lib.rs

200lines · modeblame

312af694orpuente-MS2 years ago1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! This crate contains the noisy simulator backend for the Q# language.
5//!
6//! It includes two simulators:
7//! - A density matrix simulator.
8//! - A state vector simulator.
9//!
10//! # Density matrix simulator
11//! The density matrix simulator is faster, since it evolves the entire probability space
12//! of the system as a whole, so you only need to run the simulation once, and take all
13//! the samples you need from the final density matrix. However, it is more memory intensive.
14//!
3a78aa85orpuente-MS2 years ago15//! A density matrix has 2 ^ (2 * `number_of_qubits`) complex numbers entries.
312af694orpuente-MS2 years ago16//! If each complex number is represented as two 64-bits floating point numbers,
3a78aa85orpuente-MS2 years ago17//! the density matrix will be 2 ^ (2 * `number_of_qubits`) * 16 bytes. E.g., a density
312af694orpuente-MS2 years ago18//! matrix representing a 20 qubits system will be 17592186044416 bytes, or 16.4 TB.
19//!
20//! # State vector simulator
3a78aa85orpuente-MS2 years ago21//! The state vector simulator allocates less memory, however if you want 1,000,000 shots
22//! of the circuit, you need to run the simulation 1,000,000 times.
23//! A state vector has 2 ^ (`number_of_qubits`) complex entries. So, a state vector of a 20
312af694orpuente-MS2 years ago24//! qubits system will be 16777216 bytes, or 16 MB.
25//!
26//! # Which one should I use?
27//! If you are interested in running many shots of the circuit it is better to use the
28//! density matrix simulator, as long as you have enough memory in your system (13 qubits or less).
29//!
30//! However if you are interested in a single or very few shots, you should use the state
31//! vector simulator.
32
33#![deny(missing_docs)]
34
35pub(crate) mod density_matrix_simulator;
36pub(crate) mod instrument;
37pub(crate) mod kernel;
38pub(crate) mod operation;
39pub(crate) mod state_vector_simulator;
40#[cfg(test)]
41pub(crate) mod tests;
42
43use nalgebra::{DMatrix, DVector};
44use num_complex::Complex;
45use thiserror::Error;
46
47// Re-exports.
48pub use {
49density_matrix_simulator::{DensityMatrix, DensityMatrixSimulator},
50instrument::Instrument,
51operation::Operation,
52state_vector_simulator::{StateVector, StateVectorSimulator},
53};
54
55/// A square matrix of `Complex<f64>`.
56pub type SquareMatrix = DMatrix<Complex<f64>>;
57/// A complex vector.
58pub type ComplexVector = DVector<Complex<f64>>;
59/// Error tolerance used in the simulators.
60pub(crate) const TOLERANCE: f64 = 1e-12;
61
62/// A trait representing a noisy quantum circuit simulator.
63pub trait NoisySimulator {
64/// State of the noisy simulator. Depending on the simulation method the state will be
65/// a `DensityMatrix` or a `StateVector`.
66type State;
67
68/// Creates a new `NoisySimulator`.
69fn new(number_of_qubits: usize) -> Self;
70
71/// Creates a new `NoisySimulator` with a given seed for its random number generator.
72fn new_with_seed(number_of_qubits: usize, seed: u64) -> Self;
73
74/// Apply an operation to the given qubit ids.
75fn apply_operation(&mut self, operation: &Operation, qubits: &[usize]) -> Result<(), Error>;
76
77/// Performs selective evolution under the given instrument.
78/// Returns the index of the observed outcome.
79///
80/// Use this method to perform measurements on the quantum system.
81fn sample_instrument(
82&mut self,
83instrument: &Instrument,
84qubits: &[usize],
85) -> Result<usize, Error>;
86
87/// Performs selective evolution under the given instrument using a custom random distribution.
88/// Returns the index of the observed outcome.
89///
90/// This method is used for testing and debugging purposes.
91fn sample_instrument_with_distribution(
92&mut self,
93instrument: &Instrument,
94qubits: &[usize],
95random_sample: f64,
96) -> Result<usize, Error>;
97
98/// Returns the `State` if the simulator is in a valid state.
99fn state(&self) -> Result<&Self::State, &Error>;
100
101/// Set state of the quantum system.
102fn set_state(&mut self, new_state: Self::State) -> Result<(), Error>;
103
104/// Return theoretical change in trace due to operations that have been applied so far
105/// In reality, the density matrix is always renormalized after instruments/operations
106/// have been applied.
107fn trace_change(&self) -> Result<f64, Error>;
108
109/// Set the trace of the quantum system.
110fn set_trace(&mut self, trace: f64) -> Result<(), Error>;
111}
112
113/// A noisy simulation error.
114#[derive(Clone, Debug, Error, PartialEq)]
115pub enum Error {
116/// Failure when building a `DensityMatrix` from raw data.
117#[error("error when building `DensityMatrix` from raw_data: {0}")]
118DensityMatrixTryFromError(String),
e39d888eConradJohnston10 months ago119/// Failure when building an instrument.
312af694orpuente-MS2 years ago120#[error("error when building instrument: {0}")]
121FailedToConstructInstrument(String),
122/// Failure when building an operation.
123#[error("error when building operation: {0}")]
124FailedToConstructOperation(String),
125/// Failure when sampling instrument outcome.
126#[error("numerical error: no outcome found when sampling instrument")]
127FailedToSampleInstrumentOutcome,
128/// Failure when sampling Kraus operators.
129#[error("numerical error: no outcome found when sampling Kraus operators")]
130FailedToSampleKrausOperators,
131/// Provided an invalid state when creating or setting the state of the simulator.
132#[error("provided an invalid state when creating or setting the state of the simulator: {0}")]
133InvalidState(String),
134/// `Matrix` ⋅ `Vector` multiplication mismatch.
e938e457orpuente-MS1 years ago135#[error(
136"matrix ⋅ vector multiplication mismatch; matrix is of dimension ({nrows}, {ncols}) but vector has {vec_dim} entries"
137)]
312af694orpuente-MS2 years ago138MatrixVecDimensionMismatch {
139/// Number of rows in the matrix.
140nrows: usize,
141/// Number of columns in the matrix.
142ncols: usize,
143/// Number of elements in the vector.
144vec_dim: usize,
145},
146/// State is not normalized.
147#[error("numerical error: trace should be between 0 and 1, but it is {0}")]
148NotNormalized(f64),
149/// A numerical error, such as a probability-0 event.
150#[error("numerical error: probability-0 event")]
151ProbabilityZeroEvent,
152/// A qubit-id is greater than the number of qubits the simulation supports.
153#[error("qubit id out of bounds: {0}")]
154QubitIdOutOfBounds(usize),
155/// Failure when building a `StateVector` from raw data.
156#[error("error when building `StateVector` from raw_data: {0}")]
157StateVectorTryFromError(String),
158/// Trace is not real
e938e457orpuente-MS1 years ago159#[error(
160"state trace should be real since it represents a probability, but its imaginary part is: {0}"
161)]
312af694orpuente-MS2 years ago162TraceIsNotReal(f64),
163}
164
165impl Error {
166const fn is_unrecoverable(&self) -> bool {
167matches!(
168self,
169Error::ProbabilityZeroEvent
170| Error::FailedToSampleInstrumentOutcome
171| Error::FailedToSampleKrausOperators
172)
173}
174}
175
176impl From<&Error> for Error {
177fn from(value: &Error) -> Self {
178value.clone()
179}
180}
181
182impl From<&mut Error> for Error {
183fn from(value: &mut Error) -> Self {
184value.clone()
185}
186}
187
188/// Handles errors in the simulator.
189/// If an error is unrecoverable, it will set the state of the simulator to that error,
190/// invalidating any further evolution of the quantum system.
191macro_rules! handle_error {
87b113ceOscar Puente9 months ago192($self:expr, $err:expr) => {{
312af694orpuente-MS2 years ago193if $err.is_unrecoverable() {
194$self.state = Err($err.clone());
195}
87b113ceOscar Puente9 months ago196return Err($err);
197}};
312af694orpuente-MS2 years ago198}
199
200pub(crate) use handle_error;