Skip to content

BertrandBev/Dagger

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Dagger

A quantum computing language, a virtual machine and an interactive book

Website shields.io

Philosophy

Dagger provides a user-friendly language that handles both classical and quantum-specific operations in harmony, making it easier to learn the basics of quantum computing and quantum algorithms through an interactive and intuitive experience.

Compiler

The Dagger compiler is written entirely in Rust. It features a custom lexer, a recursive-descent parser, and a two-pass AST-traversing compiler that emits Dagger Bytecode, which is then executed by the QVM. The compiler itself can be compiled to common Rust targets as well as WebAssembly (WASM) for use in web applications, as shown in the book.

The strong typing enforces type consistency across all common types as well as quantum primitives (gates and state registers), specifically checking for qubit size matching.

VM

The Dagger VM is a lean, stack-based virtual machine implemented in Rust. It offers full debugger support, including breakpoints, code stepping, call stack unwinding, and optional symbol expansion. All primitive operations are natively compiled, and quantum-specific operations are supported by nalgebra.

The language

Dagger is a minimalistic, imperative, strongly-typed language with first-class support for quantum computing primitives. Its syntax is inspired by Rust

It supports the following primitives

Primitives

type size description
bit 1 boolean container
i64 8 64-bit integer
f64 8 64-bit floating point number
c32 8 32-bit floating point complex number
str 8 string pointer
gate 8 quantum gate pointer
qubit 8 quantum register pointer
// Types are inferred, therefore explicit types are optionnal
let a: bit = 1b;
let b: c32 = 1 + 2i;
let c: str = "quantum";

Arrays

Fixed-size array of any type can be declared and accessed. They live on the stack, an therefore have no overhead

let a: [i64; 3] = [1, 2, 3];
let b: [[bit; 2]; 2] = [[1b, 0b], [0b, 1b]];

Quantum primitives

Quantum registered are declared using the ket notation, and are auto-normalized on assignment. When combined together through a kronecker product, a larger quantum register is created, and operands are turned into pointer into that larger register. Pointers into quantum registers can be taken using a multi-index notation: x[i0,i1,..];

let x: qubit = |10;
let y: qubit = |0⟩ + |1;
let xy = x * y; // Kronecker product
// Now x points to xy[0,1], and y points to xy[2];
// We may create a pointer into that larger state by using multi pointer notation
let z = xy[0,2];

Quantum operators and observables (typed "gates") can be declared from arrays using the std lib function to_gate. Input array must be square and hermitian (square matrix that is equal to its own conjugate transpose). Additionally, the std lib features various usual gates.

let CNot: gate<2> = std::to_gate([[0b, 1b], [1b, 0b]]);
let CNot = std::CNot; // Already in the stdlib

Standard library

The stdlib contains a few useful constants and functions, invoked through the namespace std::*.

VM functions

  • print(fmt: str, ...args): Standard output formatted print
  • assert(a: bool): Runtime assert

Math functions

Numeric types include i64, f64 and c32

  • sqrt(x: num) -> num: square root
  • sin(x: num) -> num: sine
  • cos(x: num) -> num: cosine
  • abs(x: num) -> num: absolute value
  • pow(x: num, p: num) -> num: x^p
  • min(a: num, b: num) -> num: minimum of the two values
  • max(a: num, b: num) -> num: maximum of the two values
  • rand() -> f64: random number between 0 (inclusive) and 1 (exclusive)

Quantum gates

  • I: single qubit identity gate
  • X, Y, Z: Pauli gates
  • S: Phase gate
  • T: pi/8 z-rotation gate
  • CNot: two qubit CNot gate (w/ first as control)
  • CZ:
  • Swap: two qubit swap gate
  • CCNot: Troffoli gate

Quantum functions

  • normalize(x: qubit | gate): normalize a state register or a gate
  • to_gate(arr: [[c32; N]; N]) -> gate<N>: create a quantum gate from an hermitian array
  • meas(x: qubit) -> [bit; N]: measure a state register in the computational basis (Pauli Z), collapsing it to one of its eigenvectors, and return the collapsed eigenvector bit array
  • meas_observable(O: gate, x: qubit) -> f64: mesure the state x with the provided observable, collapsing it to one of its eigenvectors, and return the measured observable eigenvalue
  • map_to_uf(map: [bit; N]) -> gate<sqrt(N)>: create a binary quantum oracle from a mapping
  • hadamard(n: N) -> gate<N>: create a N qubit hadamard gate
  • identity(n: N) -> gate<N>: create a N qubit identity gate
  • kronecker(a: gate<A>, b: gate<B>) -> gate<A + B>: compute the kronecker product of the two gates
  • kronecker_exp(a: gate<A>, n: N) -> gate<A^N>: compute the kronecker exponent of a gate

About

|ψ⟩ A quantum computing language, a virtual machine and an interactive book

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published