From 1bbc96d65499971935c98c65a21176f73b3dc1fa Mon Sep 17 00:00:00 2001 From: Andrew Barlow Date: Fri, 19 Jan 2024 12:08:52 +0000 Subject: [PATCH 1/7] Edit public interface and error propagation The public interface with quantr has now been made completely safe (so the user cannot destrouy asssumptions essential for the simualtion of the circuit), in addition to adding an extra error struct to handle constant errors. This will allow some functions to be made constant. Signed-off-by: Andrew Barlow --- CHANGELOG.md | 37 +++++++++++++++++++++++- examples/custom_gate.rs | 6 ++-- examples/generalised_control_not_gate.rs | 6 ++-- examples/grovers.rs | 9 +++--- examples/qft.rs | 6 ++-- src/circuit.rs | 37 ++++++++++-------------- src/circuit/states/product_states.rs | 12 ++++---- src/circuit/states/super_positions.rs | 13 ++++----- src/error.rs | 35 ++++++++++++---------- src/lib.rs | 1 - tests/grovers.rs | 8 ++--- tests/qft.rs | 6 ++-- 12 files changed, 106 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf90fa9..875c2d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ This file logs the versions of quantr. +## 0.5.0 - Finalising Interface + +Following this update, interfacing with quantr can now be done safely, +as to not allow the user to destroy any assumptions made from building +the circuit. In this update, that meant making the final public fields +private for the `Circuit` struct. + +Breaking changes: + +- Removed `QuantrError` from public interface. This is no longer + required, as it can used through it's implementation of the + `std::errorError` trait. +- All fields of `Circuit` are now private; that is `num_qubits` and + `circuit_gates`. These two can still be accessed through + `Circuit::get_num_qubits` and `Circuit::get_gates` respectively. +- The argument of `Circuit::get_num_qubits` now only borrows the + circuit, instead of consuming it (which was a mistake in the 0.4.1 + release). + +Internal improvements: + +- Added `QuantrErrorConst` that consumes a `&str`. This can be used for + constant strings (error messages) and so enabling some functions to + become constant. + ## 0.4.1 - More optimisations Edited the README to include "No parallelisation" to limitations, and @@ -9,6 +34,16 @@ reduced the tractable number of qubit simulations to 18. There has also been a large overhaul of the code to increase maintainability. Some common mistakes were also fixed with the help of `cargo clippy`. +Features: + +- `Circuit::get_num_qubits`, this is to replace the `num_qubits` field + that will be made private in the next major update. However, the + argument consumes the circuit which was a mistake. This will be fixed + in the next major update too. This returns the number of qubits of the + circuit. +- `Circuit::get_gates`, returns the vector of gates that represent the + quantum circuit. This will replace the `circuit_gates` field. + Change of dependency: - The `rand` crate has been swapped with `fastrand` which decreases @@ -20,7 +55,7 @@ Optimisations: arguments changed so that the `kronecker_prod` is not used; increasing speed for multi gate processing. - The main simulating algorithm has been updated to increase it's speed, - mostly bypassing computations that are uneeded, for instance product + mostly bypassing computations that are unneeded, for instance product state qubits are flipped only if they are indeed different. Deprecated features: diff --git a/examples/custom_gate.rs b/examples/custom_gate.rs index e37481e..c43fd16 100644 --- a/examples/custom_gate.rs +++ b/examples/custom_gate.rs @@ -10,12 +10,14 @@ // Shows the use of `Gate::Custom` in implementing the CCC-not gate. +use std::error::Error; + use quantr::{ states::{ProductState, Qubit, SuperPosition}, - Circuit, Gate, Measurement, Printer, QuantrError, + Circuit, Gate, Measurement, Printer, }; -fn main() -> Result<(), QuantrError> { +fn main() -> Result<(), Box> { let mut qc: Circuit = Circuit::new(4)?; // Build a circuit using a CCC-not gate, placing the control nodes on positions 0, 1, 2 and diff --git a/examples/generalised_control_not_gate.rs b/examples/generalised_control_not_gate.rs index 4ecee71..eb668e4 100644 --- a/examples/generalised_control_not_gate.rs +++ b/examples/generalised_control_not_gate.rs @@ -11,14 +11,16 @@ //! This example is a copy of `example/custom_gate.rs`, but instead uses a custom function that //! showcases a controlled not gate which generalises the number of control nodes. +use std::error::Error; + use quantr::{ states::{ProductState, Qubit, SuperPosition}, - Circuit, Gate, Measurement, Printer, QuantrError, + Circuit, Gate, Measurement, Printer, }; const CIRCUIT_SIZE: usize = 6; -fn main() -> Result<(), QuantrError> { +fn main() -> Result<(), Box> { let mut qc: Circuit = Circuit::new(CIRCUIT_SIZE)?; // Multi-controlled gate used here. diff --git a/examples/grovers.rs b/examples/grovers.rs index e7d8dad..0b6fa33 100644 --- a/examples/grovers.rs +++ b/examples/grovers.rs @@ -8,16 +8,17 @@ * Author: Andrew Rowan Barlow */ -// A 3 qubit circuit that implementes Grovers algorithm. The oracle target the states |110> and -// |111>. This example will also print the circuit, and show the simulaion in real time. +// A 3 qubit circuit that implements Grovers algorithm. The oracle target the states |110> and +// |111>. This example will also print the circuit, and show the simulation in real time. // // This example will print a bin count of measured states from 500 repeated simulations, and the // superposition itself. -use quantr::{Circuit, Gate, Measurement, Printer, QuantrError}; +use quantr::{Circuit, Gate, Measurement, Printer}; +use std::error::Error; #[rustfmt::skip] -fn main() -> Result<(), QuantrError>{ +fn main() -> Result<(), Box>{ let mut circuit = Circuit::new(3)?; // Kick state into superposition of equal weights diff --git a/examples/qft.rs b/examples/qft.rs index 1c817b5..0fba49e 100644 --- a/examples/qft.rs +++ b/examples/qft.rs @@ -13,12 +13,14 @@ // // To define the custom function, a new circuit is initialised and simulated. +use std::error::Error; + use quantr::{ states::{ProductState, SuperPosition}, - Circuit, Gate, Measurement, Printer, QuantrError, + Circuit, Gate, Measurement, Printer, }; -fn main() -> Result<(), QuantrError> { +fn main() -> Result<(), Box> { let mut qc: Circuit = Circuit::new(3)?; // Apply qft diff --git a/src/circuit.rs b/src/circuit.rs index 344764a..bd9bf9e 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -12,8 +12,9 @@ #![allow(deprecated)] use super::circuit::gate::{GateCategory, GateInfo}; +use crate::error::{QuantrError, QuantrErrorConst}; use crate::states::{ProductState, SuperPosition}; -use crate::{Gate, QuantrError}; +use crate::Gate; use std::collections::HashMap; use std::iter::zip; @@ -24,6 +25,7 @@ mod standard_gate_ops; pub mod states; pub(crate) type QResult = Result; +pub(crate) type QResultConst = Result; // The tolerance for declaring non-zero amplitudes. const ZERO_MARGIN: f64 = 1e-7; @@ -41,15 +43,8 @@ pub enum Measurement { /// A quantum circuit where gates can be appended and then simulated to measure resulting /// superpositions. pub struct Circuit<'a> { - #[deprecated( - note = "This field will be made private to the user, where it will be given pub(crate) status in the next major update. Use Circuit::get_gates instead." - )] - // Change this to Vec in next major update. - pub circuit_gates: Vec>, - #[deprecated( - note = "This field will be made private to the user, where it will be given pub(crate) status in the next major update. Use Circuit::get_num_qubits instead." - )] - pub num_qubits: usize, + circuit_gates: Vec>, + num_qubits: usize, output_state: Option, register: Option, config_progress: bool, @@ -68,10 +63,10 @@ impl<'a> Circuit<'a> { /// // Initialises a 3 qubit circuit. /// let quantum_circuit: Circuit = Circuit::new(3).unwrap(); /// ``` - pub fn new(num_qubits: usize) -> QResult> { + pub const fn new(num_qubits: usize) -> QResultConst> { if num_qubits == 0 { - return Err(QuantrError { - message: String::from("The initiliased circuit must have at least one wire."), + return Err(QuantrErrorConst { + message: "The initiliased circuit must have at least one wire.", }); } @@ -94,7 +89,7 @@ impl<'a> Circuit<'a> { /// let quantum_circuit: Circuit = Circuit::new(3).unwrap(); /// assert_eq!(quantum_circuit.get_num_qubits(), 3usize); /// ``` - pub fn get_num_qubits(self) -> usize { + pub const fn get_num_qubits(&self) -> usize { self.num_qubits } @@ -456,12 +451,12 @@ impl<'a> Circuit<'a> { /// // |000> : 0 - 0.71...i /// // |001> : 0 + 0.71...i /// ``` - pub fn get_superposition(&self) -> QResult> { + pub const fn get_superposition(&self) -> QResultConst> { match &self.output_state { Some(super_position) => Ok(Measurement::NonObservable(super_position)), None => { - Err(QuantrError { - message: "The circuit has not been simulated. Call Circuit::simulate before calling this method, Circuit::get_superposition.".to_string(), + Err(QuantrErrorConst { + message: "The circuit has not been simulated. Call Circuit::simulate before calling this method, Circuit::get_superposition.", }) } } @@ -499,10 +494,10 @@ impl<'a> Circuit<'a> { pub fn repeat_measurement( &self, number_iterations: usize, - ) -> QResult>> { + ) -> QResultConst>> { match &self.output_state { Some(super_position) => { - // Peform bin count of states + // Perform bin count of states let mut probabilities: HashMap = Default::default(); for (key, value) in super_position.to_hash_map() { probabilities.insert(key, value.abs_square()); @@ -527,8 +522,8 @@ impl<'a> Circuit<'a> { Ok(Measurement::Observable(bin_count)) }, None => { - Err(QuantrError { - message: "The circuit has not been simulated. Call Circuit::simulate before calling this method, Circuit::repeat_measurement.".to_string(), + Err(QuantrErrorConst { + message: "The circuit has not been simulated. Call Circuit::simulate before calling this method, Circuit::repeat_measurement.", }) }, } diff --git a/src/circuit/states/product_states.rs b/src/circuit/states/product_states.rs index 915d7ae..f3f1cbe 100644 --- a/src/circuit/states/product_states.rs +++ b/src/circuit/states/product_states.rs @@ -8,9 +8,9 @@ * Author: Andrew Rowan Barlow */ -use crate::circuit::QResult; +use crate::circuit::{QResult, QResultConst}; +use crate::error::{QuantrError, QuantrErrorConst}; use crate::states::Qubit; -use crate::QuantrError; /// A product state in the computational basis. #[derive(Clone, Hash, PartialEq, Eq, Debug)] @@ -32,12 +32,10 @@ impl ProductState { /// /// let prod: ProductState = ProductState::new(&[Qubit::One, Qubit::Zero]).unwrap(); // |10> /// ``` - pub fn new(product_state: &[Qubit]) -> QResult { + pub fn new(product_state: &[Qubit]) -> QResultConst { if product_state.is_empty() { - return Err(QuantrError { - message: String::from( - "The slice of qubits is empty, it needs to at least have one element.", - ), + return Err(QuantrErrorConst { + message: "The slice of qubits is empty, it needs to at least have one element.", }); } Ok(ProductState { diff --git a/src/circuit/states/super_positions.rs b/src/circuit/states/super_positions.rs index a230b87..2d3f84e 100644 --- a/src/circuit/states/super_positions.rs +++ b/src/circuit/states/super_positions.rs @@ -8,9 +8,10 @@ * Author: Andrew Rowan Barlow */ -use crate::circuit::{HashMap, QResult, ZERO_MARGIN}; +use crate::circuit::{HashMap, QResult, QResultConst, ZERO_MARGIN}; use crate::complex_re; -use crate::{states::ProductState, Complex, QuantrError, COMPLEX_ZERO}; +use crate::error::{QuantrError, QuantrErrorConst}; +use crate::{states::ProductState, Complex, COMPLEX_ZERO}; /// A superposition of [ProductState]s. #[derive(PartialEq, Debug, Clone)] @@ -33,10 +34,10 @@ impl SuperPosition { /// /// assert_eq!(&complex_re_array![1f64, 0f64, 0f64, 0f64], superpos.get_amplitudes()); /// ``` - pub fn new(prod_dimension: usize) -> QResult { + pub fn new(prod_dimension: usize) -> QResultConst { if prod_dimension == 0 { - return Err(QuantrError { - message: String::from("The number of qubits must be non-zero."), + return Err(QuantrErrorConst { + message: "The number of qubits must be non-zero.", }); } @@ -69,7 +70,6 @@ impl SuperPosition { let length = amplitudes.len(); if (length & (length - 1)) != 0 { - // return Err(QuantrError { message: String::from( "The length of the array must be of the form 2**n where n is an integer.", @@ -244,7 +244,6 @@ impl SuperPosition { Ok(self) } - #[inline] fn equal_within_error(num: f64, compare_num: f64) -> bool { num < compare_num + ZERO_MARGIN && num > compare_num - ZERO_MARGIN } diff --git a/src/error.rs b/src/error.rs index 580f0a3..5418c2d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,22 +18,6 @@ pub struct QuantrError { pub(crate) message: String, } -impl QuantrError { - /// Returns the error message. - /// - /// # Example - /// ``` - /// use quantr::Circuit; - /// - /// if let Err(quantr_err) = Circuit::new(0) { - /// assert_eq!("The initiliased circuit must have at least one wire.", quantr_err.get_msg()); - /// } - /// ``` - pub fn get_msg(&self) -> &str { - &self.message - } -} - impl fmt::Display for QuantrError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "\x1b[91m[Quantr Error] {}\x1b[0m ", self.message) @@ -47,3 +31,22 @@ impl fmt::Debug for QuantrError { } impl Error for QuantrError {} + +/// Relays error messages resulting from quantr. +pub struct QuantrErrorConst { + pub(crate) message: &'static str, +} + +impl fmt::Display for QuantrErrorConst { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\x1b[91m[Quantr Error] {}\x1b[0m ", self.message) + } +} + +impl fmt::Debug for QuantrErrorConst { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self, f) + } +} + +impl Error for QuantrErrorConst {} diff --git a/src/lib.rs b/src/lib.rs index 1cd6b11..4f67b66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,4 +74,3 @@ pub use circuit::printer::Printer; pub use circuit::states; pub use circuit::{Circuit, Measurement}; pub use complex::{Complex, COMPLEX_ZERO}; -pub use error::QuantrError; diff --git a/tests/grovers.rs b/tests/grovers.rs index 39dbb17..b8de73b 100644 --- a/tests/grovers.rs +++ b/tests/grovers.rs @@ -8,17 +8,17 @@ * Author: Andrew Rowan Barlow */ -use quantr::{complex_re, Complex, QuantrError}; +use quantr::{complex_re, Complex}; use quantr::{ states::{ProductState, Qubit, SuperPosition}, Circuit, Gate, Measurement::{NonObservable, Observable}, }; -use std::f64::consts::FRAC_1_SQRT_2; +use std::{error::Error, f64::consts::FRAC_1_SQRT_2}; const ERROR_MARGIN: f64 = 0.00000001f64; #[test] -fn grovers_3qubit() -> Result<(), QuantrError> { +fn grovers_3qubit() -> Result<(), Box> { fastrand::seed(0); let mut circuit = Circuit::new(3)?; @@ -70,7 +70,7 @@ fn grovers_3qubit() -> Result<(), QuantrError> { } #[test] -fn x3sudoko() -> Result<(), QuantrError> { +fn x3sudoko() -> Result<(), Box> { fastrand::seed(0); let mut qc: Circuit = Circuit::new(10)?; diff --git a/tests/qft.rs b/tests/qft.rs index f75ee8a..ee30585 100644 --- a/tests/qft.rs +++ b/tests/qft.rs @@ -11,14 +11,14 @@ use quantr::{ complex, complex_im, complex_re, states::{ProductState, SuperPosition}, - Circuit, Complex, Gate, Measurement, QuantrError, + Circuit, Complex, Gate, Measurement, }; -use std::f64::consts::FRAC_1_SQRT_2; +use std::{error::Error, f64::consts::FRAC_1_SQRT_2}; const ERROR_MARGIN: f64 = 0.00000001f64; #[test] -fn simple_qft() -> Result<(), QuantrError> { +fn simple_qft() -> Result<(), Box> { fastrand::seed(0); let mut qc: Circuit = Circuit::new(3)?; From a310bd4bb060b1664f3aef34e788f7dcc128d73a Mon Sep 17 00:00:00 2001 From: Andrew Barlow Date: Fri, 19 Jan 2024 12:19:54 +0000 Subject: [PATCH 2/7] Implement std::Display trait for ProductState This automatically produces a to_string method for this ProductState, in addition to allowing more functionality when it is being written to the console. Signed-off-by: Andrew Barlow --- src/circuit/states/product_states.rs | 47 +++++++++++++++------------ src/circuit/states/super_positions.rs | 4 +-- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/circuit/states/product_states.rs b/src/circuit/states/product_states.rs index f3f1cbe..c7201cf 100644 --- a/src/circuit/states/product_states.rs +++ b/src/circuit/states/product_states.rs @@ -8,6 +8,8 @@ * Author: Andrew Rowan Barlow */ +use std::fmt; + use crate::circuit::{QResult, QResultConst}; use crate::error::{QuantrError, QuantrErrorConst}; use crate::states::Qubit; @@ -183,27 +185,6 @@ impl ProductState { self.qubits[qubit_number] } - /// Returns the labelling of the product state as a String. - /// - /// # Example - /// ``` - /// use quantr::states::{Qubit, ProductState}; - /// - /// let prod: ProductState = ProductState::new(&[Qubit::Zero, Qubit::One]).unwrap(); - /// - /// assert_eq!(String::from("01"), prod.to_string()); - /// ``` - #[allow(clippy::inherent_to_string)] - pub fn to_string(&self) -> String { - self.qubits - .iter() - .map(|q| match q { - Qubit::Zero => "0", - Qubit::One => "1", - }) - .collect::() - } - // Converts the computational basis labelling (a binary integer), into base 10. pub(super) fn comp_basis(&self) -> usize { self.qubits @@ -232,6 +213,30 @@ impl ProductState { } } +impl fmt::Display for ProductState { + /// Returns the labelling of the product state. + /// + /// # Example + /// ``` + /// use quantr::states::{Qubit, ProductState}; + /// + /// let prod: ProductState = ProductState::new(&[Qubit::Zero, Qubit::One]).unwrap(); + /// + /// assert_eq!(String::from("01"), prod.to_string()); + /// ``` + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let binary_string = self + .qubits + .iter() + .map(|q| match q { + Qubit::Zero => "0", + Qubit::One => "1", + }) + .collect::(); + write!(f, "{}", binary_string) + } +} + impl From for ProductState { /// Converts the [Qubit] to a [ProductState] struct. /// diff --git a/src/circuit/states/super_positions.rs b/src/circuit/states/super_positions.rs index 2d3f84e..fbe17ee 100644 --- a/src/circuit/states/super_positions.rs +++ b/src/circuit/states/super_positions.rs @@ -109,7 +109,7 @@ impl SuperPosition { let mut total_amplitude: f64 = 0f64; for (states, amplitude) in &hash_amplitudes { if states.num_qubits() != product_dim { - return Err(QuantrError { message: format!("The first state has product dimension of {}, whilst the state, |{}>, found as a key in the HashMap has dimension {}.", product_dim, states.to_string(), states.num_qubits()) }); + return Err(QuantrError { message: format!("The first state has product dimension of {}, whilst the state, |{}>, found as a key in the HashMap has dimension {}.", product_dim, states, states.num_qubits()) }); } total_amplitude += amplitude.abs_square(); } @@ -281,7 +281,7 @@ impl SuperPosition { let mut total_amplitude: f64 = 0f64; for (states, amplitude) in &litudes { if states.num_qubits() != product_size { - return Err(QuantrError { message: format!("The first state has product dimension of {}, whilst the state, |{}>, found as a key in the HashMap has dimension {}.", product_size, states.to_string(), states.num_qubits()) }); + return Err(QuantrError { message: format!("The first state has product dimension of {}, whilst the state, |{}>, found as a key in the HashMap has dimension {}.", product_size, states, states.num_qubits()) }); } total_amplitude += amplitude.abs_square(); } From 60c754b0de4d46abce4b297a24034857f3643a59 Mon Sep 17 00:00:00 2001 From: Andrew Barlow Date: Fri, 19 Jan 2024 12:50:09 +0000 Subject: [PATCH 3/7] Make const functions Signed-off-by: Andrew Barlow --- CHANGELOG.md | 3 +++ src/circuit.rs | 3 --- src/circuit/states/super_positions.rs | 28 +++++++++++---------------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 875c2d4..a003005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ private for the `Circuit` struct. Breaking changes: +- Changed return type of `states::super_positions::get_amplitude -> + Result, QuantrError>` to + `states::super_positions::get_amplitude -> Option>`. - Removed `QuantrError` from public interface. This is no longer required, as it can used through it's implementation of the `std::errorError` trait. diff --git a/src/circuit.rs b/src/circuit.rs index bd9bf9e..b583250 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -9,7 +9,6 @@ */ // Added only for silencing deprecated warnings for using public fields of `Circuit`. -#![allow(deprecated)] use super::circuit::gate::{GateCategory, GateInfo}; use crate::error::{QuantrError, QuantrErrorConst}; @@ -275,7 +274,6 @@ impl<'a> Circuit<'a> { Ok(()) } - // need to implement all other gates, in addition to checking that it's within circuit size! fn has_overlapping_controls_and_target(gates: &[Gate], circuit_size: usize) -> QResult<()> { for (pos, gate) in gates.iter().enumerate() { if let Some(nodes) = gate.get_nodes() { @@ -300,7 +298,6 @@ impl<'a> Circuit<'a> { } // Find if there are any repeating values in array, O(n) - // The initialisation of the circuit guarantees the max circuit size. fn contains_repeating_values(num_qubits: usize, array: &[usize]) -> bool { let mut counter: Vec = vec![false; num_qubits]; for j in array { diff --git a/src/circuit/states/super_positions.rs b/src/circuit/states/super_positions.rs index fbe17ee..faaf823 100644 --- a/src/circuit/states/super_positions.rs +++ b/src/circuit/states/super_positions.rs @@ -61,19 +61,18 @@ impl SuperPosition { /// /// assert_eq!(&complex_re_array![1f64, 0f64, 0f64, 0f64], superpos.get_amplitudes()); /// ``` - pub fn new_with_amplitudes(amplitudes: &[Complex]) -> QResult { + pub fn new_with_amplitudes(amplitudes: &[Complex]) -> QResultConst { if !Self::equal_within_error(amplitudes.iter().map(|x| x.abs_square()).sum::(), 1f64) { - return Err(QuantrError { - message: String::from("Slice given to set amplitudes in super position does not conserve probability, the absolute square sum of the coefficents must be one."), + return Err(QuantrErrorConst { + message: "Slice given to set amplitudes in super position does not conserve probability, the absolute square sum of the coefficents must be one.", }); } let length = amplitudes.len(); if (length & (length - 1)) != 0 { - return Err(QuantrError { - message: String::from( + return Err(QuantrErrorConst { + message: "The length of the array must be of the form 2**n where n is an integer.", - ), }); } @@ -126,7 +125,8 @@ impl SuperPosition { }) } - /// Retrieves the coefficient of the product state in the computational basis given by the list index. + /// Retrieves the coefficient of the product state in the computational basis given by the list index. Returns `None` if the + /// index is greater than the product dimension of the superposition. /// /// # Example /// ``` @@ -137,14 +137,8 @@ impl SuperPosition { /// /// assert_eq!(complex_re!(1f64), superpos.get_amplitude(1).unwrap()); /// ``` - pub fn get_amplitude(&self, pos: usize) -> QResult> { - if pos >= self.amplitudes.len() { - let length = self.amplitudes.len(); - Err(QuantrError { message: format!("Failed to retrieve amplitude from list. Index given was, {pos}, which is greater than length of list, {length}."), - }) - } else { - Ok(*self.amplitudes.get(pos).unwrap()) - } + pub fn get_amplitude(&self, pos: usize) -> Option> { + self.amplitudes.get(pos).cloned() } /// Returns the number of qubits that each product state in the super position is composed of by using the Kronecker product. @@ -158,7 +152,7 @@ impl SuperPosition { /// /// assert_eq!(2, superpos.get_num_qubits()); /// ``` - pub fn get_num_qubits(&self) -> usize { + pub const fn get_num_qubits(&self) -> usize { self.product_dim } @@ -209,7 +203,7 @@ impl SuperPosition { if 2usize << (prod_state.qubits.len() - 1) != self.amplitudes.len() { return Err(QuantrError { message: format!("Unable to retreive product state, |{:?}> with dimension {}. The superposition is a linear combination of states with different dimension. These dimensions should be equal.", prod_state.to_string(), prod_state.num_qubits()),}); } - Ok(*self.amplitudes.get(prod_state.comp_basis()).unwrap()) + Ok(self.amplitudes[prod_state.comp_basis()]) } /// Returns a new superposition in the computational basis. From df8d24c4a5cf63e349d1f133bbb77855f8eb6e40 Mon Sep 17 00:00:00 2001 From: Andrew Barlow Date: Fri, 19 Jan 2024 12:59:01 +0000 Subject: [PATCH 4/7] Bump copyright to 2024 Signed-off-by: Andrew Barlow --- src/circuit.rs | 2 +- src/circuit/gate.rs | 2 +- src/circuit/printer.rs | 2 +- src/circuit/simulation.rs | 2 +- src/circuit/standard_gate_ops.rs | 2 +- src/circuit/states.rs | 2 +- src/circuit/states/product_states.rs | 2 +- src/circuit/states/qubit.rs | 2 +- src/circuit/states/super_position_iter.rs | 2 +- src/circuit/states/super_positions.rs | 2 +- src/circuit/states/super_positions_unchecked.rs | 2 +- src/complex.rs | 2 +- src/error.rs | 2 +- src/lib.rs | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index b583250..6cc0ae6 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/gate.rs b/src/circuit/gate.rs index 66f4ac9..ba2d207 100644 --- a/src/circuit/gate.rs +++ b/src/circuit/gate.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/printer.rs b/src/circuit/printer.rs index 5f3ab4a..79ed303 100644 --- a/src/circuit/printer.rs +++ b/src/circuit/printer.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/simulation.rs b/src/circuit/simulation.rs index 473b173..0789f5b 100644 --- a/src/circuit/simulation.rs +++ b/src/circuit/simulation.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/standard_gate_ops.rs b/src/circuit/standard_gate_ops.rs index cdccf47..7ad1c49 100644 --- a/src/circuit/standard_gate_ops.rs +++ b/src/circuit/standard_gate_ops.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/states.rs b/src/circuit/states.rs index 02b5454..861915c 100644 --- a/src/circuit/states.rs +++ b/src/circuit/states.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/states/product_states.rs b/src/circuit/states/product_states.rs index c7201cf..06fbfba 100644 --- a/src/circuit/states/product_states.rs +++ b/src/circuit/states/product_states.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/states/qubit.rs b/src/circuit/states/qubit.rs index e0f1e4d..d3be660 100644 --- a/src/circuit/states/qubit.rs +++ b/src/circuit/states/qubit.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/states/super_position_iter.rs b/src/circuit/states/super_position_iter.rs index 1c3aaa8..5907e58 100644 --- a/src/circuit/states/super_position_iter.rs +++ b/src/circuit/states/super_position_iter.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/states/super_positions.rs b/src/circuit/states/super_positions.rs index faaf823..d7695af 100644 --- a/src/circuit/states/super_positions.rs +++ b/src/circuit/states/super_positions.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/circuit/states/super_positions_unchecked.rs b/src/circuit/states/super_positions_unchecked.rs index 35cee3b..b8e147c 100644 --- a/src/circuit/states/super_positions_unchecked.rs +++ b/src/circuit/states/super_positions_unchecked.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/complex.rs b/src/complex.rs index c70a14a..409a0db 100644 --- a/src/complex.rs +++ b/src/complex.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/error.rs b/src/error.rs index 5418c2d..a1bd103 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is diff --git a/src/lib.rs b/src/lib.rs index 4f67b66..3f6e47c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Andrew Rowan Barlow. Licensed under the EUPL-1.2 +* Copyright (c) 2024 Andrew Rowan Barlow. Licensed under the EUPL-1.2 * or later. You may obtain a copy of the licence at * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12. A copy * of the EUPL-1.2 licence in English is given in LICENCE.txt which is From 501cc95b46495377b81d4ccb284f2404401935cf Mon Sep 17 00:00:00 2001 From: Andrew Barlow Date: Fri, 19 Jan 2024 13:19:58 +0000 Subject: [PATCH 5/7] Update docs and error interface Errors have been made publicly availble again, however the fields cannot be altered. The error can be used through the error trait. Signed-off-by: Andrew Barlow --- CHANGELOG.md | 14 ++++++++++---- src/circuit/states/super_positions.rs | 5 ++--- src/error.rs | 2 +- src/lib.rs | 4 ++++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a003005..c126385 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,20 +14,26 @@ Breaking changes: - Changed return type of `states::super_positions::get_amplitude -> Result, QuantrError>` to `states::super_positions::get_amplitude -> Option>`. -- Removed `QuantrError` from public interface. This is no longer - required, as it can used through it's implementation of the - `std::errorError` trait. - All fields of `Circuit` are now private; that is `num_qubits` and `circuit_gates`. These two can still be accessed through `Circuit::get_num_qubits` and `Circuit::get_gates` respectively. - The argument of `Circuit::get_num_qubits` now only borrows the circuit, instead of consuming it (which was a mistake in the 0.4.1 release). +- Removed `QuantrError` fields from public interface. +- The following functions have changed their returning error type to + `QuantrErrorConst`: + - `Circuit::new` + - `Circuit::get_superposition` + - `Circuit::repeat_measurement` + - `states::SuperPosition::new` + - `states::SuperPosition::new_with_amplitudes` + - `states::ProductState::new` Internal improvements: - Added `QuantrErrorConst` that consumes a `&str`. This can be used for - constant strings (error messages) and so enabling some functions to + constant strings (error messages) and so enables some functions to become constant. ## 0.4.1 - More optimisations diff --git a/src/circuit/states/super_positions.rs b/src/circuit/states/super_positions.rs index d7695af..8f655e6 100644 --- a/src/circuit/states/super_positions.rs +++ b/src/circuit/states/super_positions.rs @@ -71,8 +71,7 @@ impl SuperPosition { let length = amplitudes.len(); if (length & (length - 1)) != 0 { return Err(QuantrErrorConst { - message: - "The length of the array must be of the form 2**n where n is an integer.", + message: "The length of the array must be of the form 2**n where n is an integer.", }); } @@ -203,7 +202,7 @@ impl SuperPosition { if 2usize << (prod_state.qubits.len() - 1) != self.amplitudes.len() { return Err(QuantrError { message: format!("Unable to retreive product state, |{:?}> with dimension {}. The superposition is a linear combination of states with different dimension. These dimensions should be equal.", prod_state.to_string(), prod_state.num_qubits()),}); } - Ok(self.amplitudes[prod_state.comp_basis()]) + Ok(self.amplitudes[prod_state.comp_basis()]) } /// Returns a new superposition in the computational basis. diff --git a/src/error.rs b/src/error.rs index a1bd103..4cf1535 100644 --- a/src/error.rs +++ b/src/error.rs @@ -32,7 +32,7 @@ impl fmt::Debug for QuantrError { impl Error for QuantrError {} -/// Relays error messages resulting from quantr. +/// Relays constant error messages resulting from quantr. pub struct QuantrErrorConst { pub(crate) message: &'static str, } diff --git a/src/lib.rs b/src/lib.rs index 3f6e47c..e113cba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,9 @@ //! [Circuit::repeat_measurement], where a new register is attached before each measurement. Or, the //! explicit superposition can be retrieved using [Circuit::get_superposition]. //! +//! All errors resulting from the incorrect use of quantr are propagated by [QuantrError] and +//! [QuantrErrorConst]. +//! //! More complex examples can be found in the `examples` folder within this repository. //! //! # Example @@ -74,3 +77,4 @@ pub use circuit::printer::Printer; pub use circuit::states; pub use circuit::{Circuit, Measurement}; pub use complex::{Complex, COMPLEX_ZERO}; +pub use error::{QuantrError, QuantrErrorConst}; From bc4d213b804949a0311c166b8e357e96e34afabc Mon Sep 17 00:00:00 2001 From: Andrew Barlow Date: Fri, 19 Jan 2024 13:21:38 +0000 Subject: [PATCH 6/7] Bump cargo version Signed-off-by: Andrew Barlow --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1dc4ce6..ef283e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quantr" -version = "0.4.1" +version = "0.5.0" edition = "2021" license = "EUPL-1.2" readme = "README.md" From 28d6af7a7825017ee380bbf17821af5d4774f2dc Mon Sep 17 00:00:00 2001 From: Andrew Barlow Date: Fri, 19 Jan 2024 13:45:56 +0000 Subject: [PATCH 7/7] Make quantr errors private Signed-off-by: Andrew Barlow --- CHANGELOG.md | 4 +++- src/lib.rs | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c126385..eb3b812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,9 @@ Breaking changes: - The argument of `Circuit::get_num_qubits` now only borrows the circuit, instead of consuming it (which was a mistake in the 0.4.1 release). -- Removed `QuantrError` fields from public interface. +- Removed `QuantrError` from the public interface. Now, it has to be + used through it's trait `std::error::Error`. See `examples` and the + `main()` function return type. - The following functions have changed their returning error type to `QuantrErrorConst`: - `Circuit::new` diff --git a/src/lib.rs b/src/lib.rs index e113cba..14a76a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,8 +28,8 @@ //! [Circuit::repeat_measurement], where a new register is attached before each measurement. Or, the //! explicit superposition can be retrieved using [Circuit::get_superposition]. //! -//! All errors resulting from the incorrect use of quantr are propagated by [QuantrError] and -//! [QuantrErrorConst]. +//! All errors resulting from the incorrect use of quantr are propagated by `QuantrError` and +//! `QuantrErrorConst` that implement the [std::error::Error] trait. //! //! More complex examples can be found in the `examples` folder within this repository. //! @@ -77,4 +77,3 @@ pub use circuit::printer::Printer; pub use circuit::states; pub use circuit::{Circuit, Measurement}; pub use complex::{Complex, COMPLEX_ZERO}; -pub use error::{QuantrError, QuantrErrorConst};