1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
// Copyright 2019 Q1t BV
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A simple, efficient, quantum computer simulator.
//!
//! Overview
//! ========
//!
//! q1tsim is a simulator library for a quantum computer, written in Rust. Its goal
//! is to be an easy to use, efficient simulator for the development and testing of
//! quantum algorithms.
//!
//! Features
//! ========
//! * Easy implementation and simulation of quantum circuits
//! * Supports the creation of arbitrary quantum gates
//! * Most common quantum gates already included
//! * Measurement in `X`, `Y`, or `Z` basis
//! * Possibility of measurement without affecting the quantum state
//! * Creation of histograms of measurement results over multiple runs
//! * Operations conditional on classical values
//! * Export of circuits to Open QASM and c-QASM for running your programs on other computers or simulators
//! * Export of circuits to LaTeX, for drawing pictures of your circuit
//! * Efficient simulation of stabilizer circuits
//!
//! Usage
//! =====
//! To use q1tsim in your Rust application, add the following to your `Cargo.toml` file:
//!
//! ```toml
//! [dependencies]
//! q1tsim = "0.3"
//! ```
//!
//! As an example, here is a 3-qubit quantum Fourier transform of the |000⟩ quantum
//! state:
//! ```
//! use q1tsim::circuit::Circuit;
//! use q1tsim::gates::{CS, CT, Swap};
//!
//! fn main()
//! {
//!     // The number of times this circuit is evaluated
//!     let nr_runs = 8192;
//!
//!     // Create a quantum circuit with 3 quantum bits and 3 classical (measurement)
//!     // bits. The circuit starts by default with all quantum bits in the |0⟩
//!     // state, so in this case |000⟩.
//!     let mut circuit = Circuit::new(3, 3);
//!
//!     // Set up a 3-qubit quantum Fourier transform
//!     // There is no predefined method on Circuit that implements a controlled
//!     // `S` or `T` gate, so we use the `add_gate()` method for those.
//!     circuit.h(2);
//!     circuit.add_gate(CS::new(), &[1, 2]);
//!     circuit.add_gate(CT::new(), &[0, 2]);
//!     circuit.h(1);
//!     circuit.add_gate(CS::new(), &[0, 1]);
//!     circuit.h(0);
//!     circuit.add_gate(Swap::new(), &[0, 2]);
//!
//!     // Measure all quantum bits in the Pauli `Z` basis
//!     circuit.measure_all(&[0, 1, 2]);
//!
//!     // Actually calculate the resulting quantum state, and perform the
//!     // measurements, averaging over `nr_runs` runs.
//!     circuit.execute(nr_runs);
//!
//!     // And print the results.
//!     let hist = circuit.histogram_string().unwrap();
//!     for (bits, count) in hist.iter()
//!     {
//!         println!("{}: {}", bits, count);
//!     }
//! }
//! ```
//! The result should be a more or less equal distribution over the eight possible
//! states (000, 001, ..., 111).
//!
//! Creating a circuit
//! ==================
//! Struct [Circuit](circuit/struct.Circuit.html) is the main structure used
//! in creating a quantum program. The basic layout of a program to create
//! a quantum circuit, execute it, and collect the results, is as follows:
//! ```
//! use q1tsim::circuit::Circuit;
//!
//! // Create a new circuit with `nr_qbits` quantum bits and `nr_cbits`
//! // classical bits
//! let nr_qbits = 2;
//! let nr_cbits = 2;
//! let mut circuit = Circuit::new(nr_qbits, nr_cbits);
//!
//! // Add operations on the circuit. In this case, a Hadamard transform on the
//! // first bit, followwed by a CNOT gate with the first bit as control and
//! // the second bit as target.
//! circuit.h(0);
//! circuit.cx(0, 1);
//!
//! // Add a measurement of the resulting quantum state. This measures the first
//! // qbit into classical bit 0, and the second qbit into classical bit 1.
//! circuit.measure_all(&[0, 1]);
//!
//! // Now execute the circuit, averaging measurements over `nr_runs` runs
//! // of the circuit.
//! let nr_runs = 1024;
//! circuit.execute(nr_runs);
//!
//! // And finally collect the results. The `histogram_vec()` method returns a
//! // vector with at each index `i` the number if times the measurement returned
//! // `i` in the classical register.
//! let hist = circuit.histogram_vec();
//! ```
//! Since version 0.3, many of the methods on `Circuit` will return a `Result`,
//! possibly containing an error code (e.g. if invalid bit numbers are used).
//! Checking the result of each modification of the circuit quickly becomes
//! tedious, so the [circuit](macro.circuit.html) macro was added that can make
//! multiple method calls and immediately returns on the first error encountered
//! (or returns `Ok(())` if all calls were successful). With this, the previous
//! program can be written as
//! ```rust
//! # #[macro_use] extern crate q1tsim; fn main() {
//! let nr_qbits = 2;
//! let nr_cbits = 2;
//! let mut circuit = circuit!(nr_qbits, nr_cbits, {
//!     h(0);
//!     cx(0, 1);
//!     measure_all(&[0, 1]);
//! }).expect("Failed to build circuit");
//!
//! let nr_runs = 1024;
//! circuit.execute(nr_runs);
//! let hist = circuit.histogram_vec();
//! # }
//!```
//!
//! Custom gates
//! ============
//! Using the [Circuit::add_gate()](circuit/struct.Circuit.html#method.add_gate)
//! method, arbitrary gates can be added to a circuit. You can define your own
//! custom gates by implementing the [Gate](gates/trait.Gate.html) trait. To
//! implement this trait, the type should implement at least the
//! [description()](gates/trait.Gate.html#tymethod.description),
//! [nr_affected_bits()](gates/trait.Gate.html#tymethod.nr_affected_bits),
//! and [matrix()](gates/trait.Gate.html#tymethod.matrix) methods. The
//! `description()` method should return a short textual identifier or label
//! for the gate, while `nr_affected_bits()` returns the number of qubits on
//! which the gate operates. The `matrix()` method should return a matrix of size
//! `2`<sup>`n`</sup>`×2`<sup>`n`</sup>, where `n` is the number of affected bits,
//! that describes the unitary transformation that the gate implements. An example
//! of a simple custom gate that rotates the `|01⟩` and `|10⟩` components of
//! a pair of qubits, is given below:
//! ```
//! use ndarray::array;
//! use q1tsim::ExportGate;
//!
//! #[derive(ExportGate)]
//! struct Mix
//! {
//!    alpha: f64
//! }
//!
//! impl q1tsim::gates::Gate for Mix
//! {
//!     fn description(&self) -> &str { "M" }
//!     fn nr_affected_bits(&self) -> usize { 2 }
//!     fn matrix(&self) -> q1tsim::cmatrix::CMatrix
//!     {
//!         let o = q1tsim::cmatrix::COMPLEX_ONE;
//!         let z = q1tsim::cmatrix::COMPLEX_ZERO;
//!         let c = self.alpha.cos() * o;
//!         let s = self.alpha.sin() * o;
//!         array![
//!             [o, z,  z, z],
//!             [z, c, -s, z],
//!             [z, s,  c, z],
//!             [z, z,  z, o]
//!         ]
//!     }
//! }
//! ```
//! Types implementing the `Gate` trait may optionally also implement the
//! [apply()](gates/trait.Gate.html#method.apply) family of methods if a more
//! optimal implementation than simply multiplying by its associated matrix can
//! be found.
//!
//! Exporting gates and circuits
//! ============================
//! The discerning reader may have notices the `#[derive(ExportGate)]` statement
//! on the custom gate in the listing above. This makes the type use the default
//! implementations of the export functions for a gate. Currently, there are
//! three traits for exporting a gate:
//! - [OpenQasm](export/trait.OpenQasm.html) for exporting a gate to OpenQasm code.
//! - [CQasm](export/trait.CQasm.html) for exporting a gate to c-Qasm code.
//! - [Latex](export/trait.Latex.html) for exporting a gate to LaTeX.
//!
//! You can use the default implementation for each of these traits by deriving
//! them, e.g.
//! ```
//! use q1tsim::OpenQasm;
//! use q1tsim::gates::Gate;
//!
//! #[derive(OpenQasm)]
//! struct MySpecialGate {}
//!
//! impl Gate for MySpecialGate {
//!     /* ... */
//!     # fn description(&self) -> &str { "" }
//!     # fn nr_affected_bits(&self) -> usize { 0 }
//!     # fn matrix(&self) -> q1tsim::cmatrix::CMatrix { q1tsim::cmatrix::CMatrix::zeros((0,0)) }
//! }
//! ```
//! The default implementations for OpenQasm and CQasm simply return an error,
//! since there is no way [^no_qasm] to know how to encode a custom gate
//! in these formats. The default implementation for the LaTeX export simply draws
//! a rectangular box with the gate description inside. As seen before, if you
//! want to use default definitions for all export traits, derive from `ExportGate`.
//!
//! Note that to use a gate type in a circuit, it must be exportable, so an
//! implementation for the export traits must be defined for your custom type,
//! either through deriving or by providing your own implementation.
//!
//! [^no_qasm]: No reasonable way at least. Technically, we could take the matrix
//! for the gate, decompose it into primitive gates, and export the corresponding
//! code.
//!
//! Stabilizer circuits
//! ===================
//! Stabilizer circuits are circuits that can be expressed entirely in terms of
//! the Clifford gates `H`, `S`, and `CX`, and qubit measurements. Since version
//! 0.4.0, `q1tsim` can simulate these circuits much more efficiently than
//! general circuits. If you have a custom gate type that can be represented
//! in terms of Clifford gates, and wish to use it with the stabilizer backend,
//! you should override the default implementations of the
//! [is_stabilizer()](gates/trait.Gate.html#method.is_stabilizer) and
//! [conjugate()](gates/trait.Gate.html#method.conjugate) methods. As an example,
//! the implementation for a hypothetical `HX` gate that first performs a Hadamard
//! transform, followed by an `X` gate, could look like
//! ```
//! use q1tsim::stabilizer::PauliOp;
//! use q1tsim::gates::Gate;
//!
//! struct HX {}
//!
//! impl Gate for HX {
//!     # fn description(&self) -> &str { "" }
//!     # fn nr_affected_bits(&self) -> usize { 0 }
//!     # fn matrix(&self) -> q1tsim::cmatrix::CMatrix { q1tsim::cmatrix::CMatrix::zeros((0,0)) }
//!     fn is_stabilizer(&self) -> bool
//!     {
//!         true
//!     }
//!
//!     fn conjugate(&self, ops: &mut [PauliOp]) -> q1tsim::error::Result<bool>
//!     {
//!         let (op, sign) = match ops[0]
//!             {
//!                 PauliOp::I => (PauliOp::I, false),
//!                 PauliOp::Z => (PauliOp::X, true),
//!                 PauliOp::X => (PauliOp::Z, false),
//!                 PauliOp::Y => (PauliOp::Y, false)
//!             };
//!         ops[0] = op;
//!         Ok(sign)
//!     }
//!
//!     /* ... */
//! }
//! ```

#[macro_use] extern crate ndarray;
#[cfg(test)] #[macro_use] extern crate matches;

#[macro_use] pub mod cmatrix;
#[macro_use] pub mod gates;
pub mod circuit;
pub mod error;
pub mod ffi;
pub mod export;
pub mod permutation;
pub mod qustate;
pub mod vectorstate;
pub mod stabilizer;

mod idhash;
mod support;
#[cfg(test)] mod stats;

pub use q1tsim_derive::*;