quipper-0.7: An embedded, scalable functional programming language for quantum computing.

Safe HaskellNone

Quipper

Contents

Description

This is the main export module for Quipper, collecting everything that Quipper applications need. This is Quipper's "public" interface.

Synopsis

The Circ monad

data Circ a Source

The Circ monad encapsulates the type of quantum operations. For example, a quantum operation that inputs two Qubits and outputs a Qubit and a Bit has the following type:

 (Qubit, Qubit) -> Circ (Qubit, Bit)

Instances

Monad Circ 
Functor Circ 
Applicative Circ 
QCurry (Circ b) () b 
CircLiftingUnpack (Circ [a]) (Circ [a]) 
CircLiftingUnpack (Circ ()) (Circ ()) 
CircLiftingUnpack (Circ (a, b)) (Circ (a, b)) 
CircLiftingUnpack (Circ (a, b, c)) (Circ (a, b, c)) 
CircLiftingUnpack (Circ (a, b, c, d)) (Circ (a, b, c, d)) 
CircLiftingUnpack (Circ (a, b, c, d, e)) (Circ (a, b, c, d, e)) 
CircLiftingUnpack (Circ (a, b, c, d, e, f)) (Circ (a, b, c, d, e, f)) 
CircLiftingUnpack (Circ (a, b, c, d, e, f, g)) (Circ (a, b, c, d, e, f, g)) 
CircLiftingUnpack (Circ Qubit) (Circ Qubit) 
CircLiftingUnpack (Circ b) b' => CircLiftingUnpack (Circ (a -> Circ b)) (a -> b') 

Basic types

data Bit Source

The type of run-time classical bits (i.e., boolean wires in a circuit).

type Qulist = [Qubit]Source

Synonym for a qubit list, for convenience.

type Bitlist = [Bit]Source

Synonym for a bit list, for convenience.

Basic gates

This section contains various elementary gates that can be used as building blocks for constructing circuits.

type Timestep = DoubleSource

A time step is a small floating point number used as a parameter to certain gates, such as rotation gates or the [exp −iZt] gate.

Reversible gates in functional style

The gates in this section are in "functional" style, which means that they return something. For example, the qnot gate consumes a Qubit, performs an operation, and outputs a new Qubit. The gates should be used like this:

 output <- qnot input

or, for a binary gate:

 (out0, out1) <- gate_W in0 in1

For each of these gates, we also provide a version in imperative style, see Reversible gates in imperative style below.

qnot :: Qubit -> Circ QubitSource

Apply a NOT gate to a qubit.

hadamard :: Qubit -> Circ QubitSource

Apply a Hadamard gate.

gate_H :: Qubit -> Circ QubitSource

An alternate name for the Hadamard gate.

gate_X :: Qubit -> Circ QubitSource

Apply a Pauli X gate.

gate_Y :: Qubit -> Circ QubitSource

Apply a Pauli Y gate.

gate_Z :: Qubit -> Circ QubitSource

Apply a Pauli Z gate.

gate_S :: Qubit -> Circ QubitSource

Apply a Clifford S-gate.

gate_S_inv :: Qubit -> Circ QubitSource

Apply the inverse of an S-gate.

gate_T :: Qubit -> Circ QubitSource

Apply a T = √S gate.

gate_T_inv :: Qubit -> Circ QubitSource

Apply the inverse of a T-gate.

gate_E :: Qubit -> Circ QubitSource

Apply a Clifford E = HS[sup 3]ω[sup 3] gate.

[image E.png]

This gate is the unique Clifford operator with the properties E³ = I, EXE⁻¹ =Y, EYE⁻¹ =Z, and EZE⁻¹ =X. It is a convenient gate for calculations. For example, every Clifford operator can be uniquely written of the form

  • E[sup a]X[sup b]S[sup c]ω[sup d],

where a, b, c, and d are taken modulo 3, 2, 4, and 8, respectively.

gate_E_inv :: Qubit -> Circ QubitSource

Apply the inverse of an E-gate.

gate_omega :: Qubit -> Circ QubitSource

Apply the scalar ω = [exp iπ/4], as a single-qubit gate.

gate_V :: Qubit -> Circ QubitSource

Apply a V = √X gate. This is by definition the following gate (see also Nielsen and Chuang, p.182):

[image V.png]

gate_V_inv :: Qubit -> Circ QubitSource

Apply the inverse of a V-gate.

expZt :: Timestep -> Qubit -> Circ QubitSource

Apply an [exp −iZt] gate. The timestep t is a parameter.

rGate :: Int -> Qubit -> Circ QubitSource

Apply a rotation by angle 2πi/2[sup n] about the z-axis.

[image rGate.png]

gate_W :: Qubit -> Qubit -> Circ (Qubit, Qubit)Source

Apply a W gate. The W gate is self-inverse and diagonalizes the SWAP gate.

[image W.png]

The arguments are such that

 gate_W |0〉 |0〉 = |00〉
 gate_W |0〉 |1〉 = (|01〉+|10〉) / √2
 gate_W |1〉 |0〉 = (|01〉-|10〉) / √2
 gate_W |1〉 |1〉 = |11〉.

In circuit diagrams, W[sub 1] denotes the "left" qubit, and W[sub 2] denotes the "right" qubit.

gate_iX :: Qubit -> Circ QubitSource

Apply an iX gate. This gate is used similarly to the Pauli X gate, but with two advantages:

  • the doubly-controlled iX gate can be implemented in the Clifford+T gate base with T-count 4 (the doubly-controlled X gate requires T-count 7);
  • the iX-gate has determinant 1, and therefore an n-times controlled iX gate can be implemented in the Clifford+T gate base with no ancillas.

In particular, the iX gate can be used to implement an additional control with T-count 8, like this:

[image iX.png]

gate_iX_inv :: Qubit -> Circ QubitSource

Apply a −iX gate. This is the inverse of gate_iX.

global_phase :: Double -> Circ ()Source

Apply a global phase change [exp iπt], where typically t ∈ [0,2]. This gate is uninteresting if not controlled; however, it has non-trivial effect if it is used as a controlled gate.

global_phase_anchored :: QCData qc => Double -> qc -> Circ ()Source

Like global_phase, except the gate is also "anchored" at a qubit, a bit, or more generally at some quantum data. The anchor is only used as a hint for graphical display. The gate, which is a zero-qubit gate, will potentially be displayed near the anchor(s).

qmultinot :: QData qa => qa -> Circ qaSource

Negate all qubits in a quantum data structure.

cnot :: Bit -> Circ BitSource

Apply a NOT gate to a classical bit.

swap :: QCData qc => qc -> qc -> Circ (qc, qc)Source

Apply a swap gate to two qubits. More generally, apply swap gates to every corresponding pair of qubits in two pieces of quantum data.

Reversible gates in imperative style

The gates in this section are in "imperative" style, which means that they operate on a qubit "in place" and do not return anything. The gates should be used like this:

 qnot_at q

or, for a binary gate:

 gate_W_at q0 q1

For each of these gates, we also provide a version in functional style, see Reversible gates in functional style above.

qnot_at :: Qubit -> Circ ()Source

Apply a NOT gate to a qubit.

hadamard_at :: Qubit -> Circ ()Source

Apply a Hadamard gate.

gate_H_at :: Qubit -> Circ ()Source

An alternate name for the Hadamard gate.

gate_X_at :: Qubit -> Circ ()Source

Apply a Pauli X gate.

gate_Y_at :: Qubit -> Circ ()Source

Apply a Pauli Y gate.

gate_Z_at :: Qubit -> Circ ()Source

Apply a Pauli Z gate.

gate_S_at :: Qubit -> Circ ()Source

Apply a Clifford S-gate.

gate_S_inv_at :: Qubit -> Circ ()Source

Apply the inverse of an S-gate.

gate_T_at :: Qubit -> Circ ()Source

Apply a T = √S gate.

gate_T_inv_at :: Qubit -> Circ ()Source

Apply the inverse of a T-gate.

gate_E_at :: Qubit -> Circ ()Source

Apply a Clifford E = HS[sup 3]ω[sup 3] gate.

[image E.png]

This gate is the unique Clifford operator with the properties E³ = I, EXE⁻¹ =Y, EYE⁻¹ =Z, and EZE⁻¹ =X. It is a convenient gate for calculations. For example, every Clifford operator can be uniquely written of the form

  • E[sup a]X[sup b]S[sup c]ω[sup d],

where a, b, c, and d are taken modulo 3, 2, 4, and 8, respectively.

gate_E_inv_at :: Qubit -> Circ ()Source

Apply the inverse of an E-gate.

gate_omega_at :: Qubit -> Circ ()Source

Apply the scalar ω = [exp iπ/4], as a single-qubit gate.

gate_V_at :: Qubit -> Circ ()Source

Apply a V = √X gate. This is by definition the following gate (see also Nielsen and Chuang, p.182):

[image V.png]

gate_V_inv_at :: Qubit -> Circ ()Source

Apply the inverse of a V-gate.

expZt_at :: Timestep -> Qubit -> Circ ()Source

Apply an [exp −iZt] gate. The timestep t is a parameter.

rGate_at :: Int -> Qubit -> Circ ()Source

Apply a rotation by angle 2πi/2[sup n] about the z-axis.

[image rGate.png]

gate_W_at :: Qubit -> Qubit -> Circ ()Source

Apply a W gate. The W gate is self-inverse and diagonalizes the SWAP gate.

[image W.png]

The arguments are such that

 gate_W |0〉 |0〉 = |00〉
 gate_W |0〉 |1〉 = (|01〉+|10〉) / √2
 gate_W |1〉 |0〉 = (|01〉-|10〉) / √2
 gate_W |1〉 |1〉 = |11〉.

In circuit diagrams, W[sub 1] denotes the "left" qubit, and W[sub 2] denotes the "right" qubit.

gate_iX_at :: Qubit -> Circ ()Source

Apply an iX gate. This gate is used similarly to the Pauli X gate, but with two advantages:

  • the doubly-controlled iX gate can be implemented in the Clifford+T gate base with T-count 4 (the doubly-controlled X gate requires T-count 7);
  • the iX-gate has determinant 1, and therefore an n-times controlled iX gate can be implemented in the Clifford+T gate base with no ancillas.

In particular, the iX gate can be used to implement an additional control with T-count 8, like this:

[image iX.png]

gate_iX_inv_at :: Qubit -> Circ ()Source

Apply a −iX gate. This is the inverse of gate_iX_at.

qmultinot_at :: QData qa => qa -> Circ ()Source

Negate all qubits in a quantum data structure.

cnot_at :: Bit -> Circ ()Source

Apply a NOT gate to a classical bit.

swap_at :: QCData qc => qc -> qc -> Circ ()Source

Apply a swap gate to two qubits. More generally, apply swap gates to every corresponding pair of qubits in two pieces of quantum data.

Gates for state preparation and termination

qinit :: QShape ba qa ca => ba -> Circ qaSource

Initialize a qubit from a boolean parameter. More generally, initialize a data structure of qubits from a corresponding data structure of boolean parameters. Examples:

 q <- qinit False
 (q0, q1) <- qinit (True, False)
 [q0, q1, q2] <- qinit [True, False, True]

qterm :: QShape ba qa ca => ba -> qa -> Circ ()Source

Terminate a qubit, asserting its state to equal the boolean parameter. More generally, terminate a data structure of qubits, asserting that their state is as given by a data structure of booleans parameters. Examples:

 qterm False q
 qterm (False, False) (q0, q1)
 qterm [False, False, False] [q0, q1, q2]

In some cases, it is permissible for some aspect of the parameter's shape to be underspecified, e.g., a longer than necessary list, or an integer of indeterminate length. It is therefore possible, for example, to write:

 qterm 17 qa          -- when qa :: QDInt,
 qterm [False..] qa   -- when qa :: [Qubit].

The rules for when a boolean argument can be "promoted" in this way are specific to each individual data type.

qdiscard :: QData qa => qa -> Circ ()Source

Discard a qubit, ignoring its state. This can leave the quantum system in a mixed state, so is not a reversible operation. More generally, discard all the qubits in a quantum data structure. Examples:

 qdiscard q
 qdiscard (q0, q1)
 qdiscard [q0, q1, q2]

cinit :: QShape ba qa ca => ba -> Circ caSource

Initialize a Bit (boolean input) from a Bool (boolean parameter). More generally, initialize the a data structure of Bits from a corresponding data structure of Bools. Examples:

 b <- cinit False
 (b0, b1) <- cinit (True, False)
 [b0, b1, b2] <- cinit [True, False, True]

cterm :: QShape ba qa ca => ba -> ca -> Circ ()Source

Terminate a Bit, asserting its state to equal the given Bool. More generally, terminate a data structure of Bits, asserting that their state is as given by a data structure of Bools. Examples:

 cterm False b
 cterm (False, False) (b0, b1)
 cterm [False, False, False] [b0, b1, b2]

In some cases, it is permissible for some aspect of the parameter's shape to be underspecified, e.g., a longer than necessary list, or an integer of indeterminate length. It is therefore possible, for example, to write:

 cterm 17 ca          -- when ca :: CInt,
 cterm [False..] ca   -- when ca :: [Bit].

The rules for when a boolean argument can be "promoted" in this way are specific to each individual data type.

cdiscard :: CData ca => ca -> Circ ()Source

Discard a Bit, ignoring its state. This can leave the system in a mixed state, so is not a reversible operation. More generally, discard all the Bits in a data structure. Examples:

 cdiscard b
 cdiscard (b0, b1)
 cdiscard [b0, b1, b2]

qc_init :: QCData qc => BType qc -> Circ qcSource

Heterogeneous version of qinit. Please note that the type of the result of this function cannot be inferred from the type of the argument. For example,

 x <- qc_init False

is ambiguous, unless it can be inferred from the context whether x is a Bit or a Qubit. If the type cannot be inferred from the context, it needs to be stated explicitly, like this:

 x <- qc_init False :: Circ Qubit

Alternatively, qc_init_with_shape can be used to fix a specific type.

qc_init_with_shape :: QCData qc => qc -> BType qc -> Circ qcSource

A version of qc_init that uses a shape type parameter. The first argument is the shape type parameter, and the second argument is a data structure containing boolean initializers. The shape type argument determines which booleans are used to initialize qubits, and which ones are used to initialize classical bits.

Example:

 (x,y) <- qc_init_with_shape (bit,[qubit]) (True, [False,True])

This will assign to x a classical bit initialized to 1, and to y a list of two qubits initialized to |0〉 and |1〉, respectively.

qc_term :: QCData qc => BType qc -> qc -> Circ ()Source

Heterogeneous version of qterm.

qc_discard :: QCData qc => qc -> Circ ()Source

Heterogeneous version of qdiscard.

measure :: QShape ba qa ca => qa -> Circ caSource

Measure a Qubit, resulting in a Bit. More generally, measure all the Qubits in a quantum data structure, resulting in a corresponding data structure of Bits. This is not a reversible operation. Examples:

 b <- measure q
 (b0, b1) <- measure (q0, q1)
 [b0, b1, b2] <- measure [q0, q1, q2]

prepare :: QShape ba qa ca => ca -> Circ qaSource

Prepare a Qubit initialized from a Bit. More generally, prepare a data structure of Qubits, initialized from a corresponding data structure of Bits. Examples:

 q <- prepare b
 (q0, q1) <- prepare (b0, b1)
 [q0, q1, q2] <- prepare [b0, b1, b2]

qc_measure :: QCData qc => qc -> Circ (QCType Bit Bit qc)Source

Heterogeneous version of measure. Given a heterogeneous data structure, measure all of its qubits, and leave any classical bits unchanged.

qc_prepare :: QCData qc => qc -> Circ (QCType Qubit Qubit qc)Source

Heterogeneous version of measure. Given a heterogeneous data structure, prepare qubits from all classical bits, and leave any qubits unchanged.

Gates for classical circuits

The gates in this section are for constructing classical circuits. None of these gates alter or discard their inputs; each gate produces a new wire holding the output of the gate.

cgate_xor :: [Bit] -> Circ BitSource

Return the "exclusive or" of a list of bits.

cgate_eq :: Bit -> Bit -> Circ BitSource

Test equality of two bits, and return True iff they are equal.

cgate_not :: Bit -> Circ BitSource

Return the negation of its input. Note that unlike cnot or cnot_at, this gate does not alter its input, but returns a newly created bit.

cgate_and :: [Bit] -> Circ BitSource

Return the conjunction of a list of bits.

cgate_or :: [Bit] -> Circ BitSource

Return the disjunction of a list of bits.

cgate_if :: CData ca => Bit -> ca -> ca -> Circ caSource

If a is True, return a copy of b, else return a copy of c. Here b and c can be any data structures consisting of Bits, but b and c must be of the same type and shape (for example, if they are lists, they must be of equal length). Examples:

 output <- cgate_if a b c
 (out0, out1) <- cgate_if a (b0, b1) (c0, c1)
 [out0, out1, out2] <- cgate_if a [b0, b1, b2] [c0, c1, c2]

circ_if :: CData ca => Bit -> Circ ca -> Circ ca -> Circ caSource

circ_if is an if-then-else function for classical circuits. It is a wrapper around cgate_if, intended to be used like this:

 result <- circ_if <<<condition>>> (
   <<then-part>>>
   )(
   <<<else-part>>>
   )

Unlike cgate_if, this is a meta-operation, i.e., the bodies of the "then" and "else" parts can be circuit building operations.

What makes this different from the usual boolean "if-then-else" is that the condition is of type Bit, i.e., it is only known at circuit execution time. Therefore the generated circuit contains both the "then" and "else" parts, suitably controlled. Precondition: the "then" and "else" parts must be of the same type and shape.

User-defined gates

named_gate :: QData qa => String -> qa -> Circ qaSource

Define a new functional-style gate of the given name. Usage:

 my_unary_gate :: Qubit -> Circ Qubit
 my_unary_gate = named_gate "Q"
 my_binary_gate :: (Qubit, Qubit) -> Circ (Qubit, Qubit)
 my_binary_gate = named_gate "R"

This defines a new unary gate and a new binary gate, which will be rendered as Q and R, respectively, in circuit diagrams.

named_gate_at :: QData qa => String -> qa -> Circ ()Source

Define a new imperative-style gate of the given name. Usage:

 my_unary_gate_at :: Qubit -> Circ ()
 my_unary_gate_at = named_gate_at "Q"
 my_binary_gate_at :: (Qubit, Qubit) -> Circ ()
 my_binary_gate_at = named_gate_at "R"

This defines a new unary gate and a new binary gate, which will be rendered as Q and R, respectively, in circuit diagrams.

named_rotation :: QData qa => String -> Timestep -> qa -> Circ qaSource

Define a new functional-style gate of the given name, and parameterized by a real-valued parameter. This is typically used for rotations or phase gates that are parameterized by an angle. The name can contain '%' as a place holder for the parameter. Usage:

 my_unary_gate :: Qubit -> Circ Qubit
 my_unary_gate = named_rotation "exp(-i%Z)" 0.123
 my_binary_gate :: TimeStep -> (Qubit, Qubit) -> Circ (Qubit, Qubit)
 my_binary_gate t = named_rotation "Q(%)" t

named_rotation_at :: QData qa => String -> Timestep -> qa -> Circ ()Source

Define a new imperative-style gate of the given name, and parameterized by a real-valued parameter. This is typically used for rotations or phase gates that are parameterized by an angle. The name can contain '%' as a place holder for the parameter. Usage:

 my_unary_gate_at :: Qubit -> Circ ()
 my_unary_gate_at = named_rotation "exp(-i%Z)" 0.123
 my_binary_gate_at :: TimeStep -> (Qubit, Qubit) -> Circ ()
 my_binary_gate_at t = named_rotation "Q(%)" t

extended_named_gate :: (QData qa, QData qb) => String -> qa -> qb -> Circ qaSource

Define a new functional-style gate of the given name. Like named_gate, except that the generated gate is extended with "generalized controls". The generalized controls are additional inputs to the gate that are guaranteed not to be modified if they are in a computational basis state. They are rendered in a special way in circuit diagrams. Usage:

 my_new_gate :: (Qubit,Qubit) -> Qubit -> Circ (Qubit,Qubit)
 my_new_gate = extended_named_gate "Q"

This defines a new gate with name Q, two inputs, and one generalized input.

extended_named_gate_at :: (QData qa, QData qb) => String -> qa -> qb -> Circ ()Source

Like extended_named_gate, except defines an imperative style gate. Usage:

 my_new_gate_at :: (Qubit,Qubit) -> Qubit -> Circ ()
 my_new_gate_at = extended_named_gate_at "Q"

This defines a new gate with name Q, two inputs, and one generalized input.

Dynamic lifting

dynamic_lift :: QShape ba qa ca => ca -> Circ baSource

Convert a Bit (boolean circuit output) to a Bool (boolean parameter). More generally, convert a data structure of Bits to a corresponding data structure of Bools.

For use in algorithms that require the output of a measurement to be used as a circuit-generation parameter. This is the case, for example, for sieving methods, and also for some iterative algorithms.

Note that this is not a gate, but a meta-operation. The input consists of classical circuit endpoints (whose values are known at circuit execution time), and the output is a boolean parameter (whose value is known at circuit generation time).

The use of this operation implies an interleaving between circuit execution and circuit generation. It is therefore a (physically) expensive operation and should be used sparingly. Using the dynamic_lift operation interrupts the batch mode operation of the quantum device (where circuits are generated ahead of time), and forces interactive operation (the quantum device must wait for the next portion of the circuit to be generated). This operation is especially expensive if the current circuit contains unmeasured qubits; in this case, the qubits must be preserved while the quantum device remains on standby.

Also note that this operation is not supported in all contexts. It is an error, for example, to use this operation in a circuit that is going to be reversed, or in the body of a boxed subroutine. Also, not all output devices (such as circuit viewers) support this operation.

Other circuit-building functions

qinit_plusminus :: Bool -> Circ QubitSource

Generate a new qubit initialized to |+〉 when b=False and |−〉 when b=True.

qinit_of_char :: Char -> Circ QubitSource

Generate a new qubit initialized to one of |0〉, |1〉, |+〉, |−〉, depending on a character c which is '0', '1', '+', or '-'.

qinit_of_string :: String -> Circ [Qubit]Source

Generate a list of qubits initialized to a sequence of |0〉, |1〉, |+〉, |−〉, defined by a string argument e.g. "00+0+++".

map_hadamard :: QData qa => qa -> Circ qaSource

Apply a Hadamard gate to every qubit in a quantum data structure.

map_hadamard_at :: QData qa => qa -> Circ ()Source

Imperative version of map_hadamard.

controlled_not :: QCData qc => qc -> qc -> Circ (qc, qc)Source

Apply a controlled-not gate to every corresponding pair of quantum or classical bits in two pieces of QCData. The first argument is the target and the second the (positive) control.

For now, we require both pieces of QCData to have the same type, i.e., classical bits can be controlled only by classical bits and quantum bits can be controlled only by quantum bits.

Example:

 ((a',b'), (x,y)) <- controlled_not (a,b) (x,y)

is equivalent to

 a' <- qnot a `controlled` x
 b' <- qnot b `controlled` y

controlled_not_at :: QCData qc => qc -> qc -> Circ ()Source

Imperative version of controlled_not. Apply a controlled-not gate to every corresponding pair of quantum or classical bits in two pieces of QCData. The first argument is the target and the second the (positive) control.

bool_controlled_not :: QCData qc => qc -> BType qc -> Circ qcSource

A version of controlled_not where the control consists of boolean data. Example:

 bool_controlled_not (q, r, s) (True, True, False)

negates q and r, but not s.

bool_controlled_not_at :: QCData qc => qc -> BType qc -> Circ ()Source

A version of controlled_not_at where the control consists of boolean data. Example:

 bool_controlled_not_at (q, r, s) (True, True, False)

negates q and r, but not s.

qc_copy :: QCData qc => qc -> Circ qcSource

Create a fresh copy of a piece of quantum data. Note: copying is performed via a controlled-not operation, and is not cloning. This is similar to qc_copy_fun, except it returns only the copy, and not the original.

qc_uncopy :: QCData qc => qc -> qc -> Circ ()Source

"Uncopy" a piece of quantum data; i.e. terminate copy, assuming it's a copy of orig. This is the inverse of qc_copy, in the sense that the following sequence of instructions behaves like the identity function:

 b <- qc_copy a
 qc_uncopy a b

qc_copy_fun :: QCData qc => qc -> Circ (qc, qc)Source

Initialize a new piece of quantum data, as a copy of a given piece. Returns both the original and the copy.

qc_uncopy_fun :: QCData qc => qc -> qc -> Circ qcSource

Given two pieces of quantum data, assumed equal (w.r.t. the computational basis), terminate the second piece (and return the first, unmodified). This is the inverse of qc_copy_fun, in the sense that the following sequence of instructions behaves like the identity function:

 (orig, copy) <- qc_copy_fun orig
 orig <- qc_uncopy_fun orig copy

mapUnary :: QData qa => (Qubit -> Circ Qubit) -> qa -> Circ qaSource

Map a single qubit gate across every qubit in the data structure.

mapBinary :: QData qa => (Qubit -> Qubit -> Circ (Qubit, Qubit)) -> qa -> qa -> Circ (qa, qa)Source

Map a binary gate across every corresponding pair of qubits in two quantum data structures of equal shape.

mapBinary_c :: QShape ba qa ca => (Qubit -> Bit -> Circ (Qubit, Bit)) -> qa -> ca -> Circ (qa, ca)Source

Like mapBinary, except the second data structure is classical.

qc_mapBinary :: QCData qc => (Qubit -> Qubit -> Circ (Qubit, Qubit)) -> (Bit -> Bit -> Circ (Bit, Bit)) -> qc -> qc -> Circ (qc, qc)Source

Heterogeneous version of mapBinary. Map a binary gate f across every corresponding pair of qubits, and a binary gate g across every corresponding pair of bits, in two quantum data structures of equal shape.

Notation for controls

Some gates can be controlled by a condition involving one of more "control" qubits and/or classical bits at circuit execution time. Such gates can also be controlled by boolean conditions that are known at circuit generation time (in which case the gate will not be generated when the control condition is false). This section provides a convenient and flexible syntax for specifying controls.

In Quipper, controls can be written in a way that is reminiscent of (a restricted set of) ordinary boolean expressions. Here are some examples:

 q1 .==. 0 .&&. q2 .==. 1   for Qubits q1, q2
 q .&&. p                   means  q .==. 1  .&&.  p .==. 1
 qx .==. 5                  for a QDInt qx
 q1 .==. 0 .&&. z <= 7      combines quantum and classical controls
 q ./=. b                   the negation of q .==. b;
                            here b is a boolean.
 [p,q,r,s]                  a list of positive controls
 [(p, True), (q, False), (r, False), (s, True)]
                            a list of positive and negative controls

Among these infix operators, (.&&.) binds more weakly than (.==.), (./=.).

Controls can be attached to a gate by means of the infix operator controlled:

 gate `controlled` <<controls>>   

class ControlSource a whereSource

A "control source" is anything that can be used as a control on a gate. The most common way to construct a control source is by using the .==., ./=., and .&&. operators. In addition, we provide the following instances:

  • Bool. A boolean condition that is known at circuit generation time can be used as a control, which is then either trivial (the gate is generated) or inconsistent (the gate is not generated).
  • Wire. This includes the type Bit (for a classical execution-time control) and Qubit (for a quantum control). A wire can be used as a shorthand notation for a positive control on that wire.
  • ControlList. A control list is Quipper's internal representation of a control condition, and is trivially a control source.
  • A list of control sources can be used as a control source.

Methods

to_control :: a -> ControlListSource

Convert a condition to a control.

data ControlList Source

A ControlList is Quipper's internal representation of the type of conjunctive controls, i.e., controls that can be constructed using the .==., ./=., and .&&. operators.

(.&&.) :: (ControlSource a, ControlSource b) => a -> b -> ControlListSource

This is an infix operator to concatenate two controls, forming their logical conjunction.

(.==.) :: QCData qc => qc -> BType qc -> ControlListSource

(qx .==. x): a control which is true just if quantum data qx is in the specified state x.

(./=.) :: QCLeaf q => q -> Bool -> ControlListSource

The notation (q ./=. x) is shorthand for (q .==. not x), when x is a boolean parameter.

Unlike .==., which is defined for any shape of quantum data, ./=. is only defined for a single control bit or qubit.

controlled :: ControlSource c => Circ a -> c -> Circ aSource

An infix operator to apply the given controls to a gate:

 gate `controlled` <<controls>>

It also works with functional-style gates:

 result <- gate `controlled` <<controls>>

The infix operator is left associative, so it can be applied multiple times:

 result <- gate `controlled` <<controls1>> `controlled` <<controls2>>

The latter is equivalent to

 result <- gate `controlled` <<controls1>> .&&. <<controls2>>

Signed items

data Signed a Source

A signed item of type a. Signed x True represents a positive item, and Signed x False represents a negative item.

When used with wires in a circuit, a positive sign is used to represent a positive control, i.e., a filled dot, and a negative sign is used to represent a negative control, i.e., an empty dot.

Constructors

Signed a Bool 

from_signed :: Signed a -> aSource

Extract the underlying item of a signed item.

get_sign :: Signed a -> BoolSource

Extract the sign of a signed item: True is positive, and False is negative.

Comments and labelling

comment :: String -> Circ ()Source

Insert a comment in the circuit. This is not a gate, and has no effect, except to mark a spot in the circuit. How the comment is displayed depends on the printing backend.

label :: Labelable qa labels => qa -> labels -> Circ ()Source

Label qubits in the circuit. This is not a gate, and has no effect, except to make the circuit more readable. How the labels are displayed depends on the printing backend. This can take several different forms. Examples:

Label q as q and r as r:

 label (q,r) ("q", "r")

Label a, b, and c as a, b, and c, respectively:

 label [a,b,c] ["a", "b", "c"]

Label q as x[0] and r as x[1]:

 label (q,r) "x"

Label a, b, and c as x[0], x[1], x[2]:

 label [a,b,c] "x"

comment_with_label :: Labelable qa labels => String -> qa -> labels -> Circ ()Source

Combine comment and label in a single command.

without_comments :: Circ a -> Circ aSource

Disable labels and comments for a block of code. The intended usage is like this:

 without_comments $ do {
   <<<code block>>>
 }

This is sometimes useful in situations where code is being re-used, for example when one function is implemented in terms of another, but should not inherit comments from it. It is also useful in the definition of recursive function, where a comment should only be applied at the outermost level. Finally, it can be used to suppress comments from parts of circuits for presentation purposes.

class Labelable a s Source

Labelable a s means that a is a data structure that can be labelled with the format s. A "format" is a string, or a data structure with strings at the leaves.

Instances

Labelable Char String 
Labelable Double String 
Labelable Float String 
Labelable Int String 
Labelable Integer String 
Labelable () String 
Labelable () () 
Labelable Bit String 
Labelable Qubit String 
Labelable a String => Labelable [a] String 
Labelable a String => Labelable (Signed a) String 
Labelable a s => Labelable [a] [s] 
Labelable a String => Labelable (Signed a) (Signed String) 
(Labelable a String, Labelable b String) => Labelable (a, b) String 
(Labelable a String, Labelable b String) => Labelable (B_Endpoint a b) String 
(Labelable a sa, Labelable b sb) => Labelable (a, b) (sa, sb) 
(Labelable a s, Labelable b t) => Labelable (B_Endpoint a b) (B_Endpoint s t) 
(Labelable a String, Labelable b String, Labelable c String) => Labelable (a, b, c) String 
(Labelable a sa, Labelable b sb, Labelable c sc) => Labelable (a, b, c) (sa, sb, sc) 
(Labelable a String, Labelable b String, Labelable c String, Labelable d String) => Labelable (a, b, c, d) String 
(Labelable a sa, Labelable b sb, Labelable c sc, Labelable d sd) => Labelable (a, b, c, d) (sa, sb, sc, sd) 
(Labelable a String, Labelable b String, Labelable c String, Labelable d String, Labelable e String) => Labelable (a, b, c, d, e) String 
(Labelable a sa, Labelable b sb, Labelable c sc, Labelable d sd, Labelable e se) => Labelable (a, b, c, d, e) (sa, sb, sc, sd, se) 
(Labelable a String, Labelable b String, Labelable c String, Labelable d String, Labelable e String, Labelable f String) => Labelable (a, b, c, d, e, f) String 
(Labelable a sa, Labelable b sb, Labelable c sc, Labelable d sd, Labelable e se, Labelable f sf) => Labelable (a, b, c, d, e, f) (sa, sb, sc, sd, se, sf) 
(Labelable a String, Labelable b String, Labelable c String, Labelable d String, Labelable e String, Labelable f String, Labelable g String) => Labelable (a, b, c, d, e, f, g) String 
(Labelable a sa, Labelable b sb, Labelable c sc, Labelable d sd, Labelable e se, Labelable f sf, Labelable g sg) => Labelable (a, b, c, d, e, f, g) (sa, sb, sc, sd, se, sf, sg) 
(Labelable a String, Labelable b String, Labelable c String, Labelable d String, Labelable e String, Labelable f String, Labelable g String, Labelable h String) => Labelable (a, b, c, d, e, f, g, h) String 
(Labelable a sa, Labelable b sb, Labelable c sc, Labelable d sd, Labelable e se, Labelable f sf, Labelable g sg, Labelable h sh) => Labelable (a, b, c, d, e, f, g, h) (sa, sb, sc, sd, se, sf, sg, sh) 
(Labelable a String, Labelable b String, Labelable c String, Labelable d String, Labelable e String, Labelable f String, Labelable g String, Labelable h String, Labelable i String) => Labelable (a, b, c, d, e, f, g, h, i) String 
(Labelable a sa, Labelable b sb, Labelable c sc, Labelable d sd, Labelable e se, Labelable f sf, Labelable g sg, Labelable h sh, Labelable i si) => Labelable (a, b, c, d, e, f, g, h, i) (sa, sb, sc, sd, se, sf, sg, sh, si) 
(Labelable a String, Labelable b String, Labelable c String, Labelable d String, Labelable e String, Labelable f String, Labelable g String, Labelable h String, Labelable i String, Labelable j String) => Labelable (a, b, c, d, e, f, g, h, i, j) String 
(Labelable a sa, Labelable b sb, Labelable c sc, Labelable d sd, Labelable e se, Labelable f sf, Labelable g sg, Labelable h sh, Labelable i si, Labelable j sj) => Labelable (a, b, c, d, e, f, g, h, i, j) (sa, sb, sc, sd, se, sf, sg, sh, si, sj) 

Hierarchical circuits

box :: (QCData qa, QCData qb, QCurry qa_qb qa qb) => String -> qa_qb -> qa_qbSource

A generic interface for wrapping a circuit-generating function into a boxed and named subroutine. This takes a name and a circuit-generating function, and returns a new circuit-generating function of the same type, but which inserts a boxed subroutine instead of the actual body of the subroutine.

It is intended to be used like this:

 somefunc :: Qubit -> Circ Qubit
 somefunc a = do ...
 
 somefunc_boxed :: Qubit -> Circ Qubit
 somefunc_boxed = box "somefunc" somefunc

Here, the type of somefunc is just an example; this could indeed be a function with any number and type of arguments, as long as the arguments and return type are quantum data.

It is also possible to inline the box operator directly, in which case it should be done like this:

 somefunc :: Qubit -> Circ Qubit
 somefunc = box "somefunc" $ \a -> do ...

Note: The box operator wraps around a complete function, including all of its arguments. It would be incorrect to apply the box operator after some quantum variables have already been defined. Thus, the following is incorrect:

 incorrect_somefunc :: Qubit -> Circ Qubit
 incorrect_somefunc a = box "somefunc" $ do ...

It is the user's responsibility not to use the same name for different subroutines. If box is called more than once with the same name and shape of input, Quipper assumes, without checking, that they are subsequent calls to the same subroutine.

The type of the box operator is overloaded and quite difficult to read. It can have for example the following types:

 box :: String -> (Qubit -> Circ Qubit) -> (Qubit -> Circ Qubit)
 box :: String -> (QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt)) -> (QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt))

nbox :: QCData qa => String -> Integer -> (qa -> Circ qa) -> qa -> Circ qaSource

A version of box with iteration. The second argument is an iteration count.

This can only be applied to functions of a single argument, where the input and output types are the same.

box_loopM :: (Integral int, QCData qa) => String -> int -> qa -> (qa -> Circ qa) -> Circ qaSource

A version of nbox with same type as loopM.

loopM_boxed_if :: (Integral int, QCData qa) => Bool -> String -> int -> qa -> (qa -> Circ qa) -> Circ qaSource

A version of loopM that will be boxed conditionally on a boolean condition. Typical usage:

 loopM_boxed_if (s > 1) "name" s x $ \x -> do
   <<<body>>>
   return x

Block structure

The following are higher-order functions that provide a way to structure quantum programs into blocks. A block can contain local ancillas or local controls.

Ancillas

The use of the with_ancilla family of operators is preferable to using qinit and qterm directly. In particular, it is possible to add controls to a block created with one of the with_ancilla family of operators, whereas qinit and qterm, when used individually, cannot be controlled.

with_ancilla :: (Qubit -> Circ a) -> Circ aSource

Convenient wrapper around qinit and qterm. This can be used to introduce an ancilla with a local scope, like this:

 with_ancilla $ \h -> do {
   <<<code block using ancilla h>>>
 }

The ancilla will be initialized to |0〉 at the beginning of the block, and it is the programmer's responsibility to ensure that it will be returned to state |0〉 at the end of the block.

A block created with with_ancilla is controllable, provided that the body is controllable.

with_ancilla_list :: Int -> (Qulist -> Circ a) -> Circ aSource

Like with_ancilla, but creates a list of n ancillas, all initialized to |0〉. Usage:

 with_ancilla_list n $ \a -> do {
   <<<code block using list of ancillas a>>>
 }

with_ancilla_init :: QShape a qa ca => a -> (qa -> Circ b) -> Circ bSource

Execute a block with local ancillas. Opens a block, initializing an ancilla with a specified classical value, and terminates it with the same value when the block closes. Note: it is the programmer's responsibility to return the ancilla to its original state at the end of the enclosed block. Usage:

 with_ancilla_init True $ \a -> do {
   <<<code block using ancilla a initialized to True>>>
 }
 with_ancilla_init [True,False,True] $ \a -> do {
   <<<code block using list of ancillas a initialized to [True,False,True]>>>
 }

Automatic uncomputing

with_computed_fun :: (QCData x, QCData y) => x -> (x -> Circ y) -> (y -> Circ (y, b)) -> Circ (x, b)Source

with_computed_fun x f g: computes x' := f(x); then computes g(x'), which should be organized as a pair (x',y); then uncomputes x' back to x, and returns (x,y).

Important subtlety in usage: all quantum data referenced in f, even as controls, must be explicitly bound and returned by f, or the reversing may rebind it incorrectly. g, on the other hand, can safely refer to anything that is in scope outside the with_computed_fun.

with_computed :: QCData x => Circ x -> (x -> Circ b) -> Circ bSource

with_computed computation code: performs computation (with result x), then performs code x, and finally performs the reverse of computation, for example like this:

[image with_computed.png]

Both computation and code may refer to any qubits that exist in the current environment, and they may also create new qubits. computation may produce arbitrary garbage in addition to its output.

This is a very general but relatively unsafe operation. It is the user's responsibility to ensure that the computation can indeed be undone. In particular, if computation contains any initializations, then code must ensure that the corresponding assertions will be satisfied in computation[sup −1].

Related more specialized, but potentially safer, operations are:

  • with_basis_change, which is like with_computed, but assumes that computation is unitary, and
  • classical_to_reversible, which assumes that computation is classical (or pseudo-classical), and code is a simple copy-by-controlled-not operation.

with_basis_change :: Circ () -> Circ b -> Circ bSource

with_basis_change basischange code: performs a basis change, then the code, then the inverse of the basis change. Both basischange and code are in imperative style. It is the user's responsibility to ensure that the image of code is contained in the image of basischange, or else there will be unmet assertions or runtime errors. Usage:

 with_basis_change basischange $ do
   <<<code>>>

 where
   basischange = do
     <<<gates>>>

Controls

with_controls :: ControlSource c => c -> Circ a -> Circ aSource

A syntax for "if"-style (classical and quantum) controls. This can be used as follows:

 gate1
 with_controls <<controls>> $ do {
   gate2
   gate3
 }
 gate4

The specified controls will be applied to gate2 and gate3. It is an error to specify a control for a gate that cannot be controlled (such as measurement).

with_classical_control :: QCData qa => Bit -> String -> qa -> (qa -> Circ qa) -> Circ qaSource

Classical control on a function with same shape of input and output: if the control bit is true the function is fired, otherwise the identity map is used. Note: the constraint on the types is dynamically checked.

without_controls :: Circ a -> Circ aSource

Apply a block of gates while temporarily suspending the application of controls. This can be used to omit controls on gates where they are known to be unnecessary. This is a relatively low-level function and should not normally be called directly by user code. Instead, it is safer to use a higher-level function such as with_basis_change. However, the without_controls operator is useful in certain situations, e.g., it can be used to preserve the NoControlFlag when defining transformers.

Usage:

 without_controls $ do 
   <<code block>>

or:

 without_controls (gate)

Note that all controls specified in the surrounding code are disabled within the without_controls block. This is even true if the without_controls block appears in a subroutine, and the subroutine is later called in a controlled context. On the other hand, it is possible to specify controls inside the without_controls block. Consider this example:

 my_subcircuit = do
   gate1
   without_controls $ do {
     gate2
     gate3 `controlled` <<controls1>>
   }
   gate4

 my_circuit = do
   my_subcircuit `controlled` <<controls2>>

In this example, controls 1 will be applied to gate 3, controls 2 will be applied to gates 1 and 4, and no controls will be applied to gate 2.

without_controls_if :: NoControlFlag -> Circ a -> Circ aSource

Apply without_controls if NoControlFlag is True, otherwise do nothing.

Loops

for :: Monad m => Int -> Int -> Int -> (Int -> m ()) -> m ()Source

A "for" loop. Counts from a to b in increments of s.

Standard notation:

 for i = a to b by s do
   commands             
 end for

Our notation:

 for a b s $ \i -> do
   commands
 endfor

endfor :: Monad m => m ()Source

Mark the end of a "for"-loop. This command actually does nothing, but can be used to make the loop look prettier.

foreach :: Monad m => [a] -> (a -> m b) -> m ()Source

Iterate a parameter over a list of values. It can be used as follows:

 foreach [1,2,3,4] $ \n -> do
   <<<loop body depending on the parameter n>>>
 endfor

The loop body will get executed once for each n ∈ {1,2,3,4}.

loop :: (Eq int, Num int) => int -> t -> (t -> t) -> tSource

Iterate a function n times. Example:

 loop 3 x f = f (f (f x))

loop_with_index :: (Eq int, Num int) => int -> t -> (int -> t -> t) -> tSource

Like loop, but also pass a loop counter to the function being iterated. Example:

 loop_with_index 3 x f = f 2 (f 1 (f 0 x))

loopM :: (Eq int, Num int, Monad m) => int -> t -> (t -> m t) -> m tSource

Monadic version of loop.

loop_with_indexM :: (Eq int, Num int, Monad m) => int -> t -> (int -> t -> m t) -> m tSource

Monadic version of loop_with_index. Thus,

 loop_with_indexM 3 x0 f

will do the following:

 do
   x1 <- f 0 x0
   x2 <- f 1 x1
   x3 <- f 2 x2    
   return x3

Operations on circuits

Reversing

reverse_generic :: (QCData x, QCData y, TupleOrUnary xt x, QCurry x_y x y, Curry x_y_xt x (y -> Circ xt)) => x_y -> x_y_xtSource

Reverse a circuit-generating function. The reversed function requires a shape parameter, given as the input type of the original function.

The type of this highly overloaded function is quite difficult to read. It can have for example the following types:

 reverse_generic :: (QCData x, QCData y) => (x -> Circ y) -> x -> (y -> Circ x) 
 reverse_generic :: (QCData x, QCData y, QCData z) => (x -> y -> Circ z) -> x -> y -> (z -> Circ (x,y)) 

reverse_simple :: (QCData_Simple x, QCData y, TupleOrUnary xt x, QCurry x_y x y) => x_y -> y -> Circ xtSource

Like reverse_generic, but only works at simple types, and therefore requires no shape parameters. Typical type instances:

 reverse_simple :: (QCData_Simple x, QCData y) => (x -> Circ y) -> (y -> Circ x)
 reverse_simple :: (QCData_Simple x, QCData_Simple y, QCData z) => (x -> y -> Circ z) -> (z -> Circ (x,y))

reverse_generic_endo :: (QCData x, TupleOrUnary xt x, QCurry x_xt x xt) => x_xt -> x_xtSource

Like reverse_generic, but specialized to endomorphic circuits, i.e., circuits where the input and output have the same type (modulo possibly currying) and shape. In this case, unlike reverse_generic, no additional shape parameter is required, and the reversed function is curried if the original function was. Typical type instances:

 reverse_generic_endo :: (QCData x) => (x -> Circ x) -> (x -> Circ x)
 reverse_generic_endo :: (QCData x, QCData y) => (x -> y -> Circ (x,y)) -> (x -> y -> Circ (x,y))

reverse_generic_imp :: (QCData x, QCurry x__ x ()) => x__ -> x__Source

Like reverse_generic_endo, but applies to endomorphic circuits expressed in "imperative" style. Typical type instances:

 reverse_generic_endo :: (QCData x) => (x -> Circ ()) -> (x -> Circ ())
 reverse_generic_endo :: (QCData x, QCData y) => (x -> y -> Circ ()) -> (x -> y -> Circ ())

reverse_generic_curried :: (QCData x, QCData y, TupleOrUnary xt x, Tuple yt y, QCurry x_yt x yt, QCurry y_xt y xt, Curry x_y_xt x y_xt) => x_yt -> x_y_xtSource

Like reverse_generic, but takes functions whose output is a tuple, and curries the reversed function. Differs from reverse_generic in an example such as:

 f                         :: (x -> y -> Circ (z,w))
 reverse_generic f         :: x -> y -> ((z,w) -> Circ (x,y))
 reverse_generic_curried f :: x -> y -> (z -> w -> Circ (x,y))

Note: the output must be a n-tuple, where n = 0 or n ≥ 2. Applying this to a circuit whose output is a non-tuple type is a type error; in this case, reverse_generic should be used.

reverse_simple_curried :: (QCData_Simple x, QCData y, TupleOrUnary xt x, Tuple yt y, QCurry x_yt x yt, QCurry y_xt y xt) => x_yt -> y_xtSource

Like reverse_simple, but takes functions whose output is a tuple, and curries the reversed function. Typical type instance:

 reverse_simple_curried :: (QCData_Simple x, QCData y, QCData z) => (x -> Circ (y,z)) -> (y -> z -> Circ x)

Note: the output must be a n-tuple, where n = 0 or n ≥ 2. Applying this to a circuit whose output is a non-tuple type is a type error; in this case, reverse_generic should be used.

reverse_endo_if :: (QCData x, TupleOrUnary xt x, QCurry x_xt x xt) => Bool -> x_xt -> x_xtSource

Conditional version of reverse_generic_endo. Invert the endomorphic quantum circuit if the boolean is true; otherwise, insert the non-inverted circuit.

reverse_imp_if :: (QCData qa, QCurry fun qa ()) => Bool -> fun -> funSource

Conditional version of reverse_generic_imp. Invert the imperative style quantum circuit if the boolean is true; otherwise, insert the non-inverted circuit.

Printing

data Format Source

Available output formats.

Constructors

EPS

Encapsulated PostScript graphics.

PDF

Portable Document Format. One circuit per page.

PS

PostScript. One circuit per page.

ASCII

A textual representation of circuits.

Preview

Don't print anything, but preview directly on screen (requires the external program acroread).

GateCount

Print statistics on gate counts.

CustomStyle FormatStyle 

Instances

data FormatStyle Source

A data type that holds all the customizable parameters.

Constructors

FormatStyle 

Fields

renderformat :: RenderFormat

The RenderFormat to use.

backgroundcolor :: Color

The color of the background.

foregroundcolor :: Color

The color of the foreground (e.g. wires and gates).

linewidth :: Double

Line width.

coffs :: Double

Gap for double line representing classical bit.

dotradius :: Double

Radius of dots for "controlled" gates.

oplusradius :: Double

Radius of oplus for "not" gate.

xoff :: Double

Horizontal column width.

gatepad :: Double

Difference between width of box and width of label.

gateheight :: Double

Height of labelled box.

crossradius :: Double

Width and height of "cross" for swap gate.

stringbase :: Double

Vertical shift for text labels.

barwidth :: Double

Width of "bar" bar.

barheight :: Double

Height of "bar" bar.

dwidth :: Double

Width of "D" symbol.

dheight :: Double

Height of "D" symbol.

maxgatelabelwidth :: Double

Maximal width of a gate label.

maxlabelwidth :: Double

Maximal width of a wire label.

maxnumberwidth :: Double

Maximal width of a wire number.

gatefont :: Font

Font to use for labels on gates.

commentfont :: Font

Font to use for comments.

commentcolor :: Color

Color to use for comments.

labelfont :: Font

Font to use for labels.

labelcolor :: Color

Color to use for labels.

numberfont :: Font

Font to use for numbers.

numbercolor :: Color

Color to use for numbers.

subroutineshape :: Bool

Whether to label each subroutine call with shape parameters

Instances

format_enum :: [(String, Format)]Source

A mapping from lower-case strings (to be used, e.g., with command line options) to available formats.

print_unary :: QCData qa => Format -> (qa -> Circ b) -> qa -> IO ()Source

Print a circuit generating function to the specified format; this requires a shape parameter.

print_generic :: (QCData qa, QCurry qfun qa b, Curry fun qa (IO ())) => Format -> qfun -> funSource

Print a circuit generating function to the specified format. Unlike print_unary, this can be applied to a circuit-generating function in curried form with n arguments, for any n >= 0. It then requires n shape parameters.

The type of this heavily overloaded function is difficult to read. In more readable form, it has all of the following types:

 print_generic :: Format -> Circ qa -> IO ()
 print_generic :: (QCData qa) => Format -> (qa -> Circ qb) -> a -> IO ()
 print_generic :: (QCData qa, QCData qb) => Format -> (qa -> qb -> Circ qc) -> a -> b -> IO ()

and so forth.

print_simple :: (QCData qa, QCurry qfun qa b, Curry fun qa (IO ()), QCData_Simple qa) => Format -> qfun -> IO ()Source

Like print_generic, but only works at simple types, and therefore requires no shape parameters.

print_of_document :: Format -> Document a -> IO aSource

Print a document to the requested format, which must be one of PS, PDF, EPS, or Preview.

print_of_document_custom :: Custom -> Format -> Document a -> IO aSource

Like print_of_document, but also takes a Custom data structure.

Classical circuits

classical_to_cnot :: (QCData qa, QCData qb, QCurry qfun qa qb) => qfun -> qfunSource

Translate all classical gates in a circuit into equivalent controlled-not gates.

The type of this overloaded function is difficult to read. In more readable form, it has all of the following types:

 classical_to_cnot :: (QCData qa) => Circ qa -> Circ qa
 classical_to_cnot :: (QCData qa, QCData qb) => (qa -> Circ qb) -> (qa -> Circ qb)
 classical_to_cnot :: (QCData qa, QCData qb, QCData qc) => (qa -> qb -> Circ qc) -> (qa -> qb -> Circ qc)

and so forth.

classical_to_quantum :: (QCData qa, QCData qb, QCurry qfun qa qb, QCurry qfun' (QType qa) (QType qb)) => qfun -> qfun'Source

Replace all classical gates in a circuit by equivalent quantum gates.

The type of this overloaded function is difficult to read. In more readable form, it has all of the following types:

 classical_to_quantum :: (QCData qa) => Circ qa -> Circ (QType qa)
 classical_to_quantum :: (QCData qa, QCData qb) => (qa -> Circ qb) -> (QType qa -> Circ (QType qb))
 classical_to_quantum :: (QCData qa, QCData qb, QCData qc) => (qa -> qb -> Circ qc) -> (QType qa -> QType qb -> Circ (QType qc))

and so forth.

Ancilla uncomputation

classical_to_reversible :: (QCData qa, QCData qb) => (qa -> Circ qb) -> (qa, qb) -> Circ (qa, qb)Source

Generic function for turning a classical (or pseudo-classical) circuit into a reversible circuit. The input is a classical boolean function xf(x), given as a not necessarily reversible circuit (however, the circuit should be one-to-one, i.e., no "garbage" should be explicitly erased). The output is the corresponding reversible function (x,y) ↦ x,yf(x)). qa and qb can be any quantum data types. The function classical_to_reversible does not itself change classical bits to qubits; use classical_to_quantum for that.

Circuit transformers

Transformers are a very general way of defining mappings over circuits. Possible uses of this include:

  • gate transformations, where a whole circuit is transformed by replacing each kind of gate with another gate or circuit;
  • error correcting codes, where a whole circuit is transformed replacing each qubit by some fixed number of qubits, and each gate by a circuit; and
  • simulations, where a whole circuit is mapped to a semantic function by specifying a semantic function for each gate.

The interface is designed to allow the programmer to specify new transformers easily. To define a specific transformation, the programmer has to specify only three pieces of information:

  • Types a=⟦Qubit⟧ and b=⟦Bit⟧, to serve as semantic domains.
  • A monad m. This is to allow translations to have side effects if desired; one can use the identity monad otherwise.
  • For every gate G, a corresponding semantic function ⟦G⟧. The type of this function depends on what kind of gate G is. For example:
 If G :: Qubit -> Circ Qubit, then ⟦G⟧ :: a -> m a. 
 If G :: (Qubit, Bit) -> Circ (Bit, Bit), then ⟦G⟧ :: (a, b) -> m (b, b).

The programmer provides this information by defining a function of type Transformer m a b, see below. Once a particular transformer has been defined, it can then be applied to entire circuits. For example, for a circuit with 1 inputs and 2 outputs:

 If C :: Qubit -> (Qubit, Qubit), then ⟦C⟧ :: a -> m (a, a).

User-definable transformers

type Transformer m a b = forall x. T_Gate m a b x -> xSource

A circuit transformer is specified by defining a function of type Transformer m a b. This involves specifying a monad m, semantic domains a=⟦Qubit⟧ and b=⟦Bit⟧, and a semantic function for each gate, like this:

 my_transformer :: Transformer m a b
 my_transformer (T_Gate1 <parameters> f) = f $ <semantic function for gate 1>
 my_transformer (T_Gate2 <parameters> f) = f $ <semantic function for gate 2>
 my_transformer (T_Gate3 <parameters> f) = f $ <semantic function for gate 3>
 ...

data T_Gate m a b x Source

The type T_Gate is used to define case distinctions over gates in the definition of transformers. For each kind of gate X, it contains a constructor of the form (T_X f). Here, X identifies the gate, and f is a higher-order function to pass the translation of X to.

Constructors

T_QGate String Int Int InverseFlag NoControlFlag (([a] -> [a] -> Ctrls a b -> m ([a], [a], Ctrls a b)) -> x) 
T_QRot String Int Int InverseFlag Timestep NoControlFlag (([a] -> [a] -> Ctrls a b -> m ([a], [a], Ctrls a b)) -> x) 
T_GPhase Double NoControlFlag (([B_Endpoint a b] -> Ctrls a b -> m (Ctrls a b)) -> x) 
T_CNot NoControlFlag ((b -> Ctrls a b -> m (b, Ctrls a b)) -> x) 
T_CGate String NoControlFlag (([b] -> m (b, [b])) -> x) 
T_CGateInv String NoControlFlag ((b -> [b] -> m [b]) -> x) 
T_CSwap NoControlFlag ((b -> b -> Ctrls a b -> m (b, b, Ctrls a b)) -> x) 
T_QPrep NoControlFlag ((b -> m a) -> x) 
T_QUnprep NoControlFlag ((a -> m b) -> x) 
T_QInit Bool NoControlFlag (m a -> x) 
T_CInit Bool NoControlFlag (m b -> x) 
T_QTerm Bool NoControlFlag ((a -> m ()) -> x) 
T_CTerm Bool NoControlFlag ((b -> m ()) -> x) 
T_QMeas ((a -> m b) -> x) 
T_QDiscard ((a -> m ()) -> x) 
T_CDiscard ((b -> m ()) -> x) 
T_DTerm Bool ((b -> m ()) -> x) 
T_Subroutine BoxId InverseFlag NoControlFlag ControllableFlag [Wire] Arity [Wire] Arity RepeatFlag ((Namespace -> [B_Endpoint a b] -> Ctrls a b -> m ([B_Endpoint a b], Ctrls a b)) -> x) 
T_Comment String InverseFlag (([(B_Endpoint a b, String)] -> m ()) -> x) 

Instances

Show (T_Gate m a b x) 

Pre-defined transformers

identity_transformer :: Transformer Circ Qubit BitSource

The identity transformer. This just maps a low-level circuits to the corresponding circuit-generating function. It can also be used as a building block in other transformers, to define "catch-all" clauses for gates that don't need to be transformed.

An example transformer

The following is a short but complete example of how to write and use a simple transformer. As usual, we start by importing Quipper:

 import Quipper

We will write a transformer called sample_transformer, which maps every swap gate to a sequence of three controlled-not gates, and leaves all other gates unchanged. For convenience, Quipper pre-defines an identity_transformer, which can be used as a catch-all clause to take care of all the gates that don't need to be rewritten.

 mytransformer :: Transformer Circ Qubit Bit
 mytransformer (T_QGate "swap" 2 0 _ ncf f) = f $
   \[q0, q1] [] ctrls -> do
     without_controls_if ncf $ do
       with_controls ctrls $ do
         qnot_at q0 `controlled` q1
         qnot_at q1 `controlled` q0
         qnot_at q0 `controlled` q1
         return ([q0, q1], [], ctrls)
 mytransformer g = identity_transformer g

Note how Quipper syntax has been used to define the replacement circuit new_swap, consisting of three controlled-not gates. Also, since the original swap gate may have been controlled, we have added the additional controls with a with_controls operator. Finally, the without_controls_if operator ensures that if the NoControlFlag is set on the original swap gate, then it will also be set on the replacement circuit.

To try this out, we define some random circuit using swap gates:

 mycirc a b c d = do
   swap_at a b
   hadamard_at b
   swap_at b c `controlled` [a, d]
   hadamard_at c
   swap_at c d

To apply the transformer to this circuit, we use the generic operator transform_generic:

 mycirc2 = transform_generic mytransformer mycirc

Finally, we use a main function to display the original circuit and then the transformed one:

 main = do
   print_simple Preview mycirc
   print_simple Preview mycirc2

Applying transformers to circuits

transform_generic :: (QCData x, QCData y, QCurry qfun x y) => Transformer Circ Qubit Bit -> qfun -> qfunSource

Apply the given transformer to a circuit. Unlike transform_unary, this function can be applied to a circuit-generating function in curried form with n arguments, for any n ≥ 0.

The type of this heavily overloaded function is difficult to read. In more readable form, it has all of the following types:

 transform_generic :: (QCData x) => Transformer Circ Qubit Bit -> Circ x -> Circ x
 transform_generic :: (QCData x, QCData y) => Transformer Circ Qubit Bit -> (x -> Circ y) -> (x -> Circ y)
 transform_generic :: (QCData x, QCData y, QCData z) => Transformer Circ Qubit Bit -> (x -> y -> Circ z) -> (x -> y -> Circ z)

and so forth.

transform_generic_shape :: (QCData x, QCData y, QCurry qfun x y, Curry qfun' x' (m y'), Curry qfun'' x qfun', x' ~ QCType a b x, y' ~ QCType a b y, Monad m) => Transformer m a b -> qfun -> qfun''Source

Like transform_generic, but applies to arbitrary transformers of type

 Transformer m a b

instead of the special case

 Transformer Circ Qubit Bit.

This requires an additional shape argument.

The type of this heavily overloaded function is difficult to read. In more readable form, it has all of the following types:

 transform_generic :: (QCData x) => Transformer m a b -> Circ x -> m (QCData a b x)
 transform_generic :: (QCData x, QCData y) => Transformer m a b -> (x -> Circ y) -> x -> (QCData a b x -> m (QCData a b y))
 transform_generic :: (QCData x, QCData y, QCData z) => Transformer m a b -> (x -> y -> Circ z) -> x -> y -> (QCData a b x -> QCData a b y -> m (QCData a b z))

and so forth.

Auxiliary type definitions

type InverseFlag = BoolSource

A flag that, if True, indicates that the gate is inverted.

type NoControlFlag = BoolSource

A flag that, if True, indicates that the gate is controllable, but any further controls on the gate should be ignored. This is used, e.g., for circuits consisting of a basis change, some operation, and the inverse basis change. When controlling such a circuit, it is sufficient to control the middle operation, so the gates belonging to the basis change and its inverse will have the NoControlFlag set.

data B_Endpoint a b Source

An endpoint is either a qubit or a bit. In a transformer, we have ⟦Endpoint Qubit Bit⟧ = ⟦Qubit⟧ + ⟦Bit⟧. The type Endpoint a b is the same as Either a b, but we use more suggestive field names.

Constructors

Endpoint_Qubit a 
Endpoint_Bit b 

type Endpoint = B_Endpoint Qubit BitSource

An endpoint in a circuit. This is either a Qubit or a Bit.

type Ctrls a b = [Signed (B_Endpoint a b)]Source

A list of signed values of type ⟦Endpoint⟧. This type is an abbreviation defined for convenience.

Automatic circuit generation from classical code

The following two modules provide functions that are useful for automatic circuit generation from classical code. Please see Quipper.CircLifting for a more detailed explanation of how to use this feature.

Example

We give an example to illustrate what is meant by "lifting" a term to a monad. Consider the expression

 f = \g x -> g x x,

which has type

 f :: (a -> a -> b) -> (a -> b).

We can lift this to the IO monad by

  • converting the expression to an abstract syntax tree, using the special Template Haskell notation [nobr [| ... |]];
  • applying the expToMonad function;
  • converting the resulting abstract syntax tree back to a term, using the special Template Haskell notation [nobr $( ... )].

This allows us to write the following:

 f' = $( expToMonad "IO" [| \g x -> g x x |] ),

which has type

 f' :: IO ((a -> IO (a -> IO b)) -> IO (a -> IO b)),

and is in fact equivalent to

 f'' = return $ \g ->
         return $ \x -> do
           h <- g x
           y <- h x
           return y

General lifting functions

decToMonad :: String -> Q [Dec] -> Q [Dec]Source

Lift a list of declarations. The first argument is the name of the monad to lift into.

expToMonad :: String -> Q Exp -> Q ExpSource

Lift an expression. The first argument is the name of the monad to lift into.

Liftings of specific constants

List operations

template_symb_colon_ :: Monad m => m (a -> m ([a] -> m [a]))Source

Lifted version of '(:)' :: a -> [a] -> [a].

template_symb_obracket_symb_cbracket_ :: Monad m => m [a]Source

Lifted version of '[]' :: [a].

template_init :: Monad m => m ([a] -> m [a])Source

Lifted version of init :: [a] -> [a].

template_last :: Monad m => m ([a] -> m a)Source

Lifted version of last :: [a] -> [a].

template_symb_plus_symb_plus_ :: Monad m => m ([a] -> m ([a] -> m [a]))Source

Lifted version of '(++)' :: [a] -> [a] -> [a].

template_zip3 :: Monad m => m ([a] -> m ([b] -> m ([c] -> m [(a, b, c)])))Source

Lifted version of zip3.

template_foldl :: Monad m => m ((a -> m (b -> m a)) -> m (a -> m ([b] -> m a)))Source

lifted version of foldl

template_reverse :: Monad m => m ([a] -> m [a])Source

lifted version of reverse

template_zipWith :: Monad m => m ((a -> m (b -> m c)) -> m ([a] -> m ([b] -> m [c])))Source

lifted version of zipWith

template_fold_right_zip :: Monad m => m (((a, b, c) -> m (a, d)) -> m ((a, [b], [c]) -> m (a, [d])))Source

Lifted version of fold_right_zip

Other operations

template_symb_dollar_ :: Monad m => m ((a -> m b) -> m (a -> m b))Source

Lifted version of the combinator $.

template_error :: Monad m => m (String -> m a)Source

Lifted version of error :: String -> a. Using it will make the circuit generation fail with the error described in String.

template_snd :: Monad m => m ((a, b) -> m b)Source

Lifted version of snd :: (a,b) -> b

Extended quantum data types

Homogeneous quantum data types

class (QData qa, CType qa ~ ca, BType qa ~ ba) => QShape ba qa ca | ba -> qa, qa -> ca, ca -> baSource

The QShape class allows the definition of generic functions that can operate on quantum data of any "shape", for example, nested tuples or lists of qubits.

In general, there are three kinds of data: quantum inputs (such as Qubit), classical inputs (such as Bit), and classical parameters (such as Bool). For example, a Qubit can be initialized from a Bool; a Qubit can be measured, resulting in a Bit, etc. For this reason, the type class QShape establishes a relation between three types:

qa
A data structure having Qubit at the leaves.
ca
A data structure of the same shape as qa, having Bit at the leaves.
ba
A data structure of the same shape as qa, having Bool at the leaves.

Some functions input a classical parameter for the sole purpose of establishing the "shape" of a piece of data. The shape refers to qualities of a data structure, such as the length of a list, which are not uniquely determined by the type. For example, two different lists of length 5 have the same shape. When performing a generic operation, such as reversing a circuit, it is often necessary to specify the shape of the inputs, but not the actual inputs.

In the common case where one only needs to declare one of the types qa, ca, or ba, one of the simpler type classes QData, CData, or BData can be used.

Instances

(QData qa, ~ * (BType qa) ba, ~ * (CType qa) ca) => QShape ba qa ca 

class (qa ~ QType (CType qa), qa ~ QTypeB (BType qa), qa ~ QCType Qubit Bool qa, qa ~ QType qa, QCData qa, QCData (CType qa)) => QData qa Source

The QData type class contains homogeneous data types built up from leaves of type Qubit.

Instances

(~ * qa (QType (CType qa)), ~ * qa (QTypeB (BType qa)), ~ * qa (QCType Qubit Bool qa), ~ * qa (QType qa), QCData qa, QCData (CType qa)) => QData qa 

class (QData (QType ca), CType (QType ca) ~ ca) => CData ca Source

The CData type class contains homogeneous data types built up from leaves of type Bit.

Instances

(QData (QType ca), ~ * (CType (QType ca)) ca) => CData ca 

class (QData (QTypeB ba), BType (QTypeB ba) ~ ba) => BData ba Source

The BData type class contains homogeneous data types built up from leaves of type Bool.

Instances

(QData (QTypeB ba), ~ * (BType (QTypeB ba)) ba) => BData ba 

Heterogeneous quantum data types

class (Labelable qc String, Typeable qc, Show qc, Show (LType qc), qc ~ QCType Qubit Bit qc, CType (QType qc) ~ CType qc, BType (CType qc) ~ BType qc, QCType Int Bool (CType qc) ~ BType qc) => QCData qc Source

The QCData type class contains heterogeneous data types built up from leaves of type Qubit and Bit. It is the basis for several generic operations that apply to classical and quantum data, such as copying, transformers, simulation, and heterogeneous versions of qterm and qdiscard.

QCData and QData are interrelated, in the sense that the following implications hold:

 QData qa   implies   QCData qa
 CData ca   implies   QCData ca

Implications in the converse direction also hold whenever qc is a fixed known type:

 QCData qc   implies   QData (QType qc)
 QCData qc   implies   CData (CType qc)
 QCData qc   implies   BData (BType qc)

However, the type checker cannot prove the above implication in the case where qc is a type variable; for this, the more flexible (but more computationally expensive) QCDataPlus class can be used.

Instances

QCData Char 
QCData Double 
QCData Float 
QCData Int 
QCData Integer 
QCData () 
QCData Bit 
QCData Qubit 
QCData a => QCData [a] 
QCData a => QCData (Signed a) 
(QCData a, QCData b) => QCData (a, b) 
(QCData a, QCData b) => QCData (B_Endpoint a b) 
(QCData a, QCData b, QCData c) => QCData (a, b, c) 
(QCData a, QCData b, QCData c, QCData d) => QCData (a, b, c, d) 
(QCData a, QCData b, QCData c, QCData d, QCData e) => QCData (a, b, c, d, e) 
(QCData a, QCData b, QCData c, QCData d, QCData e, QCData f) => QCData (a, b, c, d, e, f) 
(QCData a, QCData b, QCData c, QCData d, QCData e, QCData f, QCData g) => QCData (a, b, c, d, e, f, g) 
(QCData a, QCData b, QCData c, QCData d, QCData e, QCData f, QCData g, QCData h) => QCData (a, b, c, d, e, f, g, h) 
(QCData a, QCData b, QCData c, QCData d, QCData e, QCData f, QCData g, QCData h, QCData i) => QCData (a, b, c, d, e, f, g, h, i) 
(QCData a, QCData b, QCData c, QCData d, QCData e, QCData f, QCData g, QCData h, QCData i, QCData j) => QCData (a, b, c, d, e, f, g, h, i, j) 

class (QCData qc, QData (QType qc)) => QCDataPlus qc Source

The QCDataPlus type class is almost identical to QCData, except that it contains one additional piece of information that allows the type checker to prove the implications

 QCDataPlus qc     implies   QShape (BType qc) (QType qc) (CType qc)
 QCDataPlus qc     implies   QData (QType qc)
 QCDataPlus qc     implies   CData (CType qc)
 QCDataPlus qc     implies   BData (BType qc)

This is sometimes useful, for example, in the context of a function that inputs a QCData, measures all the qubits, and returns a CData. However, the additional information for the type checker comes at a price, which is drastically increased compilation time. Therefore QCDataPlus should only be used when QCData is insufficient.

Instances

(QCData qc, QData (QType qc)) => QCDataPlus qc 

Shape-related operations

Some Quipper functions, such as print_generic, require a shape parameter. A shape parameter is a parameter passed to a function for the sole purpose of specifying the type or size of some data structure, without actually specifying any data. Example: given a circuit

 circuit :: ([Qubit], Bit) -> Circ Qubit,

the command

 print_generic Preview circuit ([qubit,qubit,qubit], bit)

tells Quipper to preview the circuit for a problem size of 3 qubits and 1 bit.

bit :: BitSource

A dummy term of type Bit. It can be used in shape parameters (e.g., qc_init), as well as shape type parameters (e.g., qcdata_mapM).

qubit :: QubitSource

A dummy term of type Qubit. It can be used in shape parameters (e.g., qc_init), as well as shape type parameters (e.g., qcdata_mapM).

qshape :: QData qa => BType qa -> qaSource

Return a quantum data structure of the given boolean shape, with every leaf initialized to the undefined dummy value qubit.

qc_false :: QCData qc => qc -> BType qcSource

Return a boolean data structure of the given shape, with every leaf initialized to False.

Quantum type classes

Haskell provides many convenient type classes: Eq, Ord, Num, etc. Quipper provides quantum analogues of some of these. For instance, Haskell’s Eq a has the method

 (==) :: a -> a -> Bool.  

Correspondingly, our QEq a qa ca has a method

 q_is_equal :: qa -> qa -> Circ (qa,qa,Qubit).  

Similarly, where Haskell’s Num class has methods +, *, signum, the class QNum has q_add, q_mult, q_signum, and so on. (QNum is defined in QuipperLib.Arith.)

All quantum type classes assume (a) that their instance types are QCData, and (b) that the corresponding classical parameter types are instances of the corresponding Haskell type classes.

Quantum type classes are designed to work well with the automatic circuit generation of Quipper.CircLifting: the methods of Haskell’s standard type classes are translated into their quantum analogues, where available.

class QCData qc => QEq qc whereSource

This is a quantum analogue of Haskell’s Eq type class. Default implementations are provided; by default, equality is bitwise equality of the underlying data structure. However, specific instances can provide custom implementations. In this case, q_is_equal is a minimal complete definition.

Methods

q_is_equal :: qc -> qc -> Circ (qc, qc, Qubit)Source

Test for equality.

q_is_not_equal :: qc -> qc -> Circ (qc, qc, Qubit)Source

Test for inequality.

Instances

QCData qc => QEq qc 

class (QEq qa, QData qa) => QOrd qa whereSource

This is a quantum analogue of Haskell's Ord type class. Its purpose is to define a total ordering on each of its instances. The functions in this class are assumed dirty in the sense that they do not uncompute ancillas, and some of the inputs may be returned as outputs. The functions are also assumed to be non-linear safe, i.e., they apply no gates to their inputs except as control sources. Minimal complete definition: q_less or q_greater. The default implementations of q_max and q_min assume that both arguments are of the same shape (for example, numbers of the same length).

Methods

q_less :: qa -> qa -> Circ QubitSource

Test for less than.

q_greater :: qa -> qa -> Circ QubitSource

Test for greater than.

q_leq :: qa -> qa -> Circ QubitSource

Test for less than or equal.

q_geq :: qa -> qa -> Circ QubitSource

Test for greater than or equal.

q_max :: qa -> qa -> Circ qaSource

Compute the maximum of two values.

q_min :: qa -> qa -> Circ qaSource

Compute the minimum of two values.

q_lt :: QOrd qa => qa -> qa -> Circ (qa, qa, Qubit)Source

q_lt qx qy: test whether qx < qy. A functionally typed wrapper for q_less.

q_gt :: QOrd qa => qa -> qa -> Circ (qa, qa, Qubit)Source

q_gt qx qy: test whether qx > qy. A functionally typed wrapper for q_greater.

q_le :: QOrd qa => qa -> qa -> Circ (qa, qa, Qubit)Source

q_le qx qy: test whether qxqy. A functionally typed wrapper for q_leq.

q_ge :: QOrd qa => qa -> qa -> Circ (qa, qa, Qubit)Source

q_ge qx qy: test whether qxqy. A functionally typed wrapper for q_geq.