Skip to content

Commit

Permalink
Merge pull request #16 from a-barlow/release-0.2.2
Browse files Browse the repository at this point in the history
Release 0.2.2
  • Loading branch information
a-barlow committed Oct 20, 2023
2 parents 8b562f9 + 4a015c6 commit 2b66e2c
Show file tree
Hide file tree
Showing 7 changed files with 392 additions and 264 deletions.
54 changes: 35 additions & 19 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,21 @@

This file logs the versions of quantr.

## 0.2.2 - Fixing the `Printer` and pushing of custom functions

Additions:

- A usage section in the README.md; displaying a small snippet of quantr
code.

Fixes:

- Custom gates added to columns were not automatically pushed so that
they were isolated.
- The `Printer` struct now prints double gates, triple gates and custom
gates correctly, in addition to adjusting to the circuit diagram for
variable length of the gate names.

## 0.2.1 - Fixed `Circuit::repeat_measurement`

Fix:
Expand All @@ -13,15 +28,14 @@ Fix:

Features:

- Gates with multiple control nodes are now automatically pushed to
columns where they are isolated. This automatic pushing occurs when
the user attempts to add several multi-control node gates at the same
time via the methods that append gates to the circuit.
- All methods and initialisations of structs return a
`Result<_,QuantError>`.
- Gates with multiple control nodes (multi-control gates) are now
automatically pushed to columns so that they are isolated. This
automatic pushing occurs when the user attempts to add several
multi-control gates at the same time via the methods that append gates
to the circuit.
- The documentation has been re-shuffled for the `circuit` module, where
they are now ordered in such a way that they are most likely to be
used.
the methods are now in order of when they would be used in a
simulation of a circuit.
- Compiled with Rust 1.72.1.

Breaking changes:
Expand All @@ -31,22 +45,24 @@ Breaking changes:
- A circuit now has an upper bound of 50 qubits (although, much less is
recommended due to incomplete optimisations).
- The following methods have now been made unavailable to the user:
- `States::insert_qubits`
- `States::num_qubits`
- `States::get`
- `States::comp_basis`
- `States::binary_basis`
- `ProductStates::insert_qubits`
- `ProductStates::num_qubits`
- `ProductStates::get`
- `ProductStates::comp_basis`
- `ProductStates::binary_basis`
- The following methods have been removed:
- `States::as_hash_string`
- `SuperPosition::as_hash_string`
- The following methods have been renamed:
- `States::as_hash` -> `States::as_hash_map`
- `States::get_amp_from_pos` -> `States::get_amplitude`
- `States::get_amp_from_state` -> `States::get_amplitude_from_state`
- `QuantrError` is no longer accessible nor referenced in documentation.
- `SuperPosition::as_hash` -> `States::as_hash_map`
- `SuperPosition::get_amp_from_pos` -> `States::get_amplitude`
- `SuperPosition::get_amp_from_state` ->
`States::get_amplitude_from_state`
- `QuantrError` is no longer accessible to the user.

Additions:

- Unit tests for adding multiple gates with multiple control nodes.
- Unit tests for adding multiple multi-control gates.
- Unit tests for user validation of various methods.

## 0.1.2 - CZ and Swap gate confusion

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
@@ -1,14 +1,14 @@
[package]
name = "quantr"
version = "0.2.1"
version = "0.2.2"
edition = "2021"
license = "EUPL-1.2"
readme = "README.md"
keywords = ["quantum", "computer", "simulator", "circuit", "qubit"]
categories = ["science", "simulation"]
authors = ["Andrew Barlow <a.barlow.dev@gmail.com>"]
repository = "https://github.com/a-barlow/quantr"
homepage = "https://github.com/a-barlow/quantr"
homepage = "https://a-barlow.github.io/quantr-book"
description = "Readily create, simulate and print quantum circuits."

[dependencies]
Expand Down
70 changes: 60 additions & 10 deletions README.md
Expand Up @@ -15,16 +15,17 @@ test](https://github.com/a-barlow/quantr/workflows/cargo%20test/badge.svg)](http
> [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 a quantum
computer.

This crate allows the user to build a quantum circuit 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
can be simulated, which attaches the register |00..0> resulting in a
superposition that can be measured.

For a brief example of using quantr, see the
[quick start guide](QUICK_START.md) which walks through an
implementation of the Grover's algorithm.
implementation of Grover's algorithm.

### Defining features

Expand All @@ -35,18 +36,67 @@ implementation of the Grover's algorithm.
- 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
mappings on states. This allows the user to avoid representing the
gates as matrices.
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, and instead uses functions to represent the linear
sparse matrices, but instead uses functions to represent the linear
mapping of gates.
- Only safe Rust code is used, and the only dependency is the
[rand](https://docs.rs/rand/latest/rand/) crate.


### Usage

An example of simulating and printing a two qubit circuit:

```rust
use quantr::circuit::{Circuit, StandardGate, printer::Printer,
Measurement::Observable};

fn main() {

let mut quantum_circuit: Circuit = Circuit::new(2).unwrap();

quantum_circuit
.add_gates(vec![StandardGate::H, StandardGate::H])
.unwrap();
quantum_circuit
.add_gate(StandardGate::CNot(0), 1)
.unwrap();

let mut printer = Printer::new(&quantum_circuit);
printer.print_diagram();
// The above prints the following:
// ┏━━━┓
// ┨ H ┠──█──
// ┗━━━┛ │
//
// ┏━━━┓┏━┷━┓
// ┨ H ┠┨ X ┠
// ┗━━━┛┗━━━┛

quantum_circuit.simulate();

// Below prints the number of times that each state was observered
// over 500 measurements of superpositions.

if let Observable(bin_count) = quantum_circuit.repeat_measurement(500).unwrap() {
println!("[Observable] Bin count of observed states.");
for (state, count) in bin_count {
println!("|{}> observed {} times", state.as_string(), count);
}
}

}
```

A more detailed example of using quantr is given in the [quick start
guide](QUICK_START.md).

### Limitations (currently)

- There is **no noise** consideration, or ability to introduce noise.
- There is **no ability to add classical circuits**.
- There is **no ability to add classical wires**.
- The circuit size has an **upper bound of 50 qubits**. Although, due to
incomplete optimisations, it's recommended that the circuit size
should be much less.
Expand Down Expand Up @@ -90,9 +140,9 @@ computing in Rust.

A useful and very practical simulator for learning quantum computing is
[Quirk](https://algassert.com/quirk). It's a real-time online simulator
that interfaces via drag-and-drop gates. Note that Quirk uses the
reverse ordering of labelling their states from the quantum circuit as
defined here.
that interfaces via drag-and-drop gates. Note that the labelling of the
states in the computational basis in Quirk is reversed when compared to
quantr's labelling of such states.

### Licence

Expand Down
33 changes: 24 additions & 9 deletions src/circuit.rs
Expand Up @@ -112,9 +112,28 @@ pub enum StandardGate<'a> {
Custom(fn(ProductState) -> SuperPosition, &'a [usize], String),
}

impl<'a> StandardGate<'a> {
// Retreives the list of nodes within a gate.
fn get_nodes(&self) -> Option<Vec<usize>> {
match self {
StandardGate::Id
| StandardGate::H
| StandardGate::X
| StandardGate::Y
| StandardGate::Z => None,
StandardGate::CNot(c)
| StandardGate::Swap(c)
| StandardGate::CZ(c)
| StandardGate::CY(c) => Some(vec![*c]),
StandardGate::Toffoli(c1, c2) => Some(vec![*c1, *c2]),
StandardGate::Custom(_, nodes, _) => Some(nodes.to_vec()),
}
}
}

/// For identifying which gates are single, double etc.
#[derive(Debug)]
enum GateSize {
#[derive(Debug, Clone)]
pub(crate) enum GateSize {
Single,
Double,
Triple,
Expand Down Expand Up @@ -310,7 +329,7 @@ impl<'a> Circuit<'a> {
} else {
for (pos, gate) in gates.iter().enumerate() {
match Self::classify_gate_size(gate) {
GateSize::Double | GateSize::Triple => {
GateSize::Double | GateSize::Triple | GateSize::Custom => {
let mut temp_vec = vec![StandardGate::Id; gates.len()];
temp_vec[pos] = gate.clone();
extended_vec.extend(temp_vec);
Expand Down Expand Up @@ -589,7 +608,7 @@ impl<'a> Circuit<'a> {
// Helps in constructing a bundle. This ultimately makes the match statements more concise.
// Maybe best to see if this can be hardcoded in before hand; that is the bundles are added to
// the circuit instead?
fn classify_gate_size(gate: &StandardGate) -> GateSize {
pub(crate) fn classify_gate_size(gate: &StandardGate) -> GateSize {
match gate {
StandardGate::Id
| StandardGate::H
Expand Down Expand Up @@ -799,11 +818,7 @@ mod tests {
}

fn equal_within_error(num: f64, compare_num: f64) -> bool {
if num < compare_num + ERROR_MARGIN && num > compare_num - ERROR_MARGIN {
true
} else {
false
}
num < compare_num + ERROR_MARGIN && num > compare_num - ERROR_MARGIN
}

fn compare_circuit(quantum_circuit: Circuit, correct_register: &[Complex<f64>]) {
Expand Down

0 comments on commit 2b66e2c

Please sign in to comment.