Skip to content

Commit

Permalink
Merge pull request #49 from a-barlow/release-0.5.2
Browse files Browse the repository at this point in the history
Release 0.5.2
  • Loading branch information
a-barlow committed May 9, 2024
2 parents 6799f17 + 0eb4bbb commit 0225c03
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 48 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,32 @@

This file logs the versions of quantr.

## 0.5.2 - Review of docs and minor code improvements

The README was updated to give credit to another quantum circuit
simulator implemented in Rust:
[Spinoza](https://github.com/QuState/spinoza). Although yet used by the
current authors, the Spinoza project is more developed and mature than
quantr, and looks to be a good Rust alternative!

The LICENSES were updated to reflect the use of the
[fastrand](https://crates.io/crates/fastrand.) crate that is a
dependency of quantr. This was implemented in update 0.4.1; although
this wasn't stated in the licensing at the time, the fastrand crate was
implicitly being used under the MIT licence.

Several unnecessary calls of `ProductState::to_string` through it's
trait implementation were made in printing macros, and are now removed.

Features:

- The `IntoIter` trait was implemented for `ProductState`, which
produces an iterator of the qubits that represent the state, from left
to right in braket notation.
- `Circuit::get_toggle_progress` has been added, which returns if the
circuit has been set to print explicit simulation progress, set by
`Circuit::toggle_simulation_progress`.

## 0.5.1 - Review of docs and deprecated const functions

See the previous update, 0.5.0, for why some functions were promoted to
Expand Down
13 changes: 7 additions & 6 deletions COPYRIGHT.txt
Expand Up @@ -6,16 +6,17 @@ found in the root directory of this repository.

This text file details the licences that are applied to this project as a
consequence of using:
- the rand crate (version 0.8.5);
- the fastrand crate (version 2.1.0);
- the Rust language; and
- the standard libraries of the Rust language.

As the owner of quantr, I have chosen to use the rand crate, Rust language and
its standard library under the MIT licence. The licence can be found at
http://opensource.org/licenses/MIT or within this file under the header
"MIT licence".
As the owner of quantr, I have chosen to use the fastrand crate, Rust
language and its standard library under the MIT licence. The licence can
be found at http://opensource.org/licenses/MIT or within this file under
the header "MIT licence".

Details of the rand crate can be found at https://crates.io/crates/rand.
Details of the fastrand crate can be found at
https://crates.io/crates/fastrand.

The repository for the Rust language and its standard libraries,
can be found at https://github.com/rust-lang/, which contains the licences
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "quantr"
version = "0.5.1"
version = "0.5.2"
edition = "2021"
license = "EUPL-1.2"
readme = "README.md"
Expand All @@ -9,7 +9,7 @@ categories = ["science", "simulation"]
authors = ["Andrew Barlow <a.barlow.dev@gmail.com>"]
repository = "https://github.com/a-barlow/quantr"
homepage = "https://a-barlow.github.io/quantr-book"
description = "Readily create, simulate and print quantum circuits."
description = "Create and simulate gate-based quantum circuits."

[dependencies]
fastrand = "^2.0.1"
fastrand = "2.1.0"
4 changes: 2 additions & 2 deletions QUICK_START.md
Expand Up @@ -229,7 +229,7 @@ fn main() {
if let Ok(Measurement::Observable(bin_count)) = circuit.repeat_measurement(500) {
println!("\n[Observable] Bin count of observed states.");
for (state, count) in bin_count {
println!("|{}> observed {} times", state.to_string(), count);
println!("|{}> observed {} times", state, count);
}
}

Expand All @@ -238,7 +238,7 @@ fn main() {
{
println!("\n[Non-Observable] The amplitudes of each state in the final superposition.");
for (state, amplitude) in output_super_position.into_iter() {
println!("|{}> : {}", state.to_string(), amplitude);
println!("|{}> : {}", state, amplitude);
}
}
}
Expand Down
35 changes: 18 additions & 17 deletions README.md
@@ -1,7 +1,7 @@
# quantr

[![Crates.io](https://img.shields.io/crates/v/quantr?style=flat-square&color=%23B94700)](https://crates.io/crates/quantr)
[![Static Badge](https://img.shields.io/badge/version%20-%201.75.0%20-%20white?style=flat-square&logo=rust&color=%23B94700)](https://releases.rs/)
[![Static Badge](https://img.shields.io/badge/version%20-%201.77.2%20-%20white?style=flat-square&logo=rust&color=%23B94700)](https://releases.rs/)
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/a-barlow/quantr/rust.yml?style=flat-square&label=tests&color=%2349881B)](https://github.com/a-barlow/quantr/actions/workflows/rust.yml)
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/a-barlow/quantr/rust_dev.yml?style=flat-square&label=tests%20(dev)&color=%2349881B)](https://github.com/a-barlow/quantr/actions/workflows/rust_dev.yml)
[![docs.rs](https://img.shields.io/docsrs/quantr?style=flat-square&color=%2349881B)](https://crates.io/crates/quantr)
Expand All @@ -16,10 +16,10 @@
> [other simulations](#other-quantum-computer-simulators) if you are
> intending to use quantr for projects.
A Rust library crate that builds, prints and simulates a quantum
computer.
A Rust library crate that builds, prints and simulates quantum gate
based circuits.

This crate allows the user to build a quantum circuit by adding columns
This crate allows the user to build quantum circuits by adding columns
of gates via various methods. Once the circuit has been built, then it
can be simulated, which attaches the register |00..0> resulting in a
superposition that can be measured.
Expand All @@ -36,17 +36,12 @@ implementation of Grover's algorithm.
where the latter is still possible to retrieve.
- Prints the circuit diagram to the terminal, or saves it to a text
file, as a UTF-8 string.
- Custom gates can be implemented easily by giving their explicit linear
- Custom gates can be implemented easily by giving their explicit
mappings on product states. This allows the user to avoid representing
the gates as matrices.
- Attempts to minimise memory consumption by not using matrices nor
sparse matrices, but instead uses functions to represent the linear
mapping of gates. For the number of qubits in a circuit, `n`, the
estimated memory that is required for quantr to simulate the circuit
when `n >= 16` is approximately the size of the state vector itself in
Rust, `2**(n-6) KiB`. For `n < 16`, the memory required is less than
`1 MiB`.
- Can simulate circuits up to ~18 qubits within a reasonable time.
- Custom gates do not have to be unitary, allowing for any quantum
channel to be implemented.
- Can simulate circuits up to ~16 qubits within a reasonable time.
- Only safe Rust code is used, and the only dependency is the
[fastrand](https://crates.io/crates/fastrand) crate and its
sub-dependencies.
Expand Down Expand Up @@ -96,7 +91,8 @@ guide](QUICK_START.md).

### Limitations (currently)

- **No noise** consideration, or ability to introduce noise.
- **No noise** consideration, however this could be (albeit tediously)
implemented through the custom gates.
- **No parallelisation** option.
- **No ability to add classical wires** nor gates that measure a
single wire of a quantum circuit.
Expand All @@ -118,15 +114,17 @@ nodes to define gates (such as the CNot and Toffoli gates), it must be
defined so that the most far right state of the product state, is
assumed to be the gate that is 'activated'. In general, it is better to
assume that the custom function doesn't define control nodes, but rather
it extends the dimension of the function's domain. Lastly, the custom
enum does not check if the mapping is unitary.
it extends the dimension of the function's domain. Lastly, it should be
noted that there are no checks on the custom gate for being a valid
quantum channel.

### Documentation

> [The Quantr Book](https://a-barlow.github.io/quantr-book/) is planned
> to serve as extended documentation to quantr, such as explaining the
> motivations behind chosen algorithms. For now, it only contains the
> start guide.
> start guide, and some preliminary results of the memory efficiency of
> quantr.
For the online code documentation, please refer to
[crates.io](https://crates.io/crates/quantr). This can also be built and
Expand All @@ -135,6 +133,9 @@ moving into the directory, and running `cargo doc --open`.

### Other quantum computer simulators

Another, and more stable, quantum circuit simulator written in Rust is
[Spinoza](https://github.com/QuState/spinoza).

The website [Are We Quantum Yet](https://arewequantumyet.github.io)
(checked 24/10/23) lists all things quantum computing in Rust.

Expand Down
2 changes: 1 addition & 1 deletion examples/custom_gate.rs
Expand Up @@ -36,7 +36,7 @@ fn main() -> Result<(), Box<dyn Error>> {
if let Ok(Measurement::Observable(bin_count)) = qc.repeat_measurement(50) {
println!("\nStates observed over 50 measurements:");
for (states, count) in bin_count.into_iter() {
println!("|{}> : {}", states.to_string(), count);
println!("|{}> : {}", states, count);
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/generalised_control_not_gate.rs
Expand Up @@ -40,7 +40,7 @@ fn main() -> Result<(), Box<dyn Error>> {
if let Ok(Measurement::Observable(bin_count)) = qc.repeat_measurement(50) {
println!("\nStates observed over 50 measurements:");
for (states, count) in bin_count.into_iter() {
println!("|{}> : {}", states.to_string(), count);
println!("|{}> : {}", states, count);
}
}

Expand Down
4 changes: 2 additions & 2 deletions examples/grovers.rs
Expand Up @@ -53,7 +53,7 @@ fn main() -> Result<(), Box<dyn Error>>{
if let Ok(Measurement::Observable(bin_count)) = circuit.repeat_measurement(500) {
println!("[Observable] Bin count of observed states.");
for (state, count) in bin_count {
println!("|{}> observed {} times", state.to_string(), count);
println!("|{}> observed {} times", state, count);
}
}

Expand All @@ -62,7 +62,7 @@ fn main() -> Result<(), Box<dyn Error>>{
{
println!("\n[Non-Observable] The amplitudes of each state in the final superposition.");
for (state, amplitude) in output_super_position.into_iter() {
println!("|{}> : {}", state.to_string(), amplitude);
println!("|{}> : {}", state, amplitude);
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/qft.rs
Expand Up @@ -37,7 +37,7 @@ fn main() -> Result<(), Box<dyn Error>> {
if let Ok(Measurement::NonObservable(final_sup)) = qc.get_superposition() {
println!("\nThe final superposition is:");
for (state, amplitude) in final_sup.into_iter() {
println!("|{}> : {}", state.to_string(), amplitude);
println!("|{}> : {}", state, amplitude);
}
}

Expand Down
35 changes: 26 additions & 9 deletions src/circuit.rs
Expand Up @@ -98,6 +98,22 @@ impl<'a> Circuit<'a> {
self.num_qubits
}

/// Returns if the circuit will print explicit simulatin output set
/// by [Circuit::toggle_simulation_progress].
///
/// # Example
/// ```
/// use quantr::{Circuit};
///
/// let mut quantum_circuit = Circuit::new(2).unwrap();
/// assert_eq!(quantum_circuit.get_toggle_progress(), false);
/// quantum_circuit.toggle_simulation_progress();
/// assert_eq!(quantum_circuit.get_toggle_progress(), true);
/// ```
pub fn get_toggle_progress(&self) -> bool {
self.config_progress
}

/// Returns the vector of gates that have been added to the circuit.
///
/// It is a flattened vector which is buffered with identity gates.
Expand Down Expand Up @@ -380,7 +396,7 @@ impl<'a> Circuit<'a> {
///
/// // Simulates the circuit:
/// // |0> -------
/// // |0> -- H --
/// // |0> -------
/// // |0> -- H --
/// ````
pub fn simulate(&mut self) {
Expand Down Expand Up @@ -468,13 +484,14 @@ impl<'a> Circuit<'a> {
}
}

/// Returns a `HashMap` that containes the number of times the corresponding state was observed over
/// `n` measurements of the superpositions.
/// Returns a `HashMap` that contains the number of times the corresponding state was observed over
/// `n` measurements of the superpositions (shots).
///
/// Explicitly, this performs repeated measurements where a register is attached to the circuit,
/// the resulting superposition measured, and then the reduced state recorded. If the HashMap does not
/// include a product state, then it was not observed over the `n` measurements. This method
/// requires that the circuit has already been simulated by calling [Circuit::simulate].
/// the resulting superposition measured in the computational basis, and then the reduced state
/// recorded. If the HashMap does not include a product state, then it was not observed over the
/// `n` measurements. This method requires that the circuit has already been simulated by calling
/// [Circuit::simulate].
///
/// # Example
/// ```
Expand All @@ -489,7 +506,7 @@ impl<'a> Circuit<'a> {
/// println!("State | Number of Times Observed");
/// if let Ok(Observable(bin_count)) = circuit.repeat_measurement(500) {
/// for (state, observed_count) in bin_count {
/// println!("|{}> : {}", state.to_string(), observed_count);
/// println!("|{}> : {}", state, observed_count);
/// }
/// }
///
Expand All @@ -499,7 +516,7 @@ impl<'a> Circuit<'a> {
/// ```
pub fn repeat_measurement(
&self,
number_iterations: usize,
shots: usize,
) -> QResultConst<Measurement<HashMap<ProductState, usize>>> {
match &self.output_state {
Some(super_position) => {
Expand All @@ -511,7 +528,7 @@ impl<'a> Circuit<'a> {

let mut bin_count: HashMap<ProductState, usize> = Default::default();

for _ in 0..number_iterations {
for _ in 0..shots {
let mut cummalitive: f64 = 0f64;
let dice_roll: f64 = fastrand::f64();
for (state_label, probability) in &probabilities {
Expand Down
11 changes: 6 additions & 5 deletions src/circuit/simulation.rs
Expand Up @@ -138,11 +138,12 @@ impl<'a> Circuit<'a> {
let mut swapped_state: ProductState = prod_state.clone();
swapped_state.insert_qubits(state.qubits.as_slice(), gate_positions.as_slice());

if let Some(existing_amp) = mapped_states.get(&swapped_state) {
mapped_states.insert(swapped_state, existing_amp.add(state_amp.mul(amp)));
} else {
mapped_states.insert(swapped_state, state_amp.mul(amp));
}
mapped_states
.entry(swapped_state)
.and_modify(|existing_amp| {
*existing_amp = existing_amp.add(state_amp.mul(amp));
})
.or_insert(state_amp.mul(amp));
}
}
}
1 change: 1 addition & 0 deletions src/circuit/states.rs
Expand Up @@ -32,6 +32,7 @@ mod super_positions;
mod super_positions_unchecked;

pub use product_states::ProductState;
pub use product_states::ProductStateIter;
pub use qubit::Qubit;
pub use super_position_iter::SuperPositionIterator;
pub use super_positions::SuperPosition;

0 comments on commit 0225c03

Please sign in to comment.