Safe Haskell | None |
---|

This module provides functions and operators that are "generic"
on quantum data. We say that a function is generic if it works at
any quantum data type, rather than just a specific type such as
`Qubit`

. For example, the generic function `qinit`

can be used to
initialize a qubit from a boolean, or a pair of qubits from a pair
of booleans, or a list of qubits from a list of booleans, and so
forth.

Some functions are also generic in the *number* of arguments they
take, in addition to the type of the arguments.

## Synopsis

- qinit :: QShape ba qa ca => ba -> Circ qa
- qterm :: QShape ba qa ca => ba -> qa -> Circ ()
- qdiscard :: QData qa => qa -> Circ ()
- cinit :: QShape ba qa ca => ba -> Circ ca
- cterm :: QShape ba qa ca => ba -> ca -> Circ ()
- cdiscard :: CData ca => ca -> Circ ()
- qc_init :: QCData qc => BType qc -> Circ qc
- qc_init_with_shape :: QCData qc => qc -> BType qc -> Circ qc
- qc_term :: QCData qc => BType qc -> qc -> Circ ()
- qc_discard :: QCData qc => qc -> Circ ()
- measure :: QShape ba qa ca => qa -> Circ ca
- prepare :: QShape ba qa ca => ca -> Circ qa
- qc_measure :: QCData qc => qc -> Circ (QCType Bit Bit qc)
- qc_prepare :: QCData qc => qc -> Circ (QCType Qubit Qubit qc)
- global_phase_anchored :: QCData qc => Double -> qc -> Circ ()
- map_hadamard :: QData qa => qa -> Circ qa
- map_hadamard_at :: QData qa => qa -> Circ ()
- swap :: QCData qc => qc -> qc -> Circ (qc, qc)
- swap_at :: QCData qc => qc -> qc -> Circ ()
- controlled_not :: QCData qc => qc -> qc -> Circ (qc, qc)
- controlled_not_at :: QCData qc => qc -> qc -> Circ ()
- bool_controlled_not :: QCData qc => qc -> BType qc -> Circ qc
- bool_controlled_not_at :: QCData qc => qc -> BType qc -> Circ ()
- qmultinot :: QData qa => qa -> Circ qa
- qmultinot_at :: QData qa => qa -> Circ ()
- qc_copy_fun :: QCData qc => qc -> Circ (qc, qc)
- qc_uncopy_fun :: QCData qc => qc -> qc -> Circ qc
- qc_copy :: QCData qc => qc -> Circ qc
- qc_uncopy :: QCData qc => qc -> qc -> Circ ()
- cgate_if :: CData ca => Bit -> ca -> ca -> Circ ca
- circ_if :: CData ca => Bit -> Circ ca -> Circ ca -> Circ ca
- named_gate :: QData qa => String -> qa -> Circ qa
- named_gate_at :: QData qa => String -> qa -> Circ ()
- named_rotation :: QData qa => String -> Timestep -> qa -> Circ qa
- named_rotation_at :: QData qa => String -> Timestep -> qa -> Circ ()
- extended_named_gate :: (QData qa, QData qb) => String -> qa -> qb -> Circ qa
- extended_named_gate_at :: (QData qa, QData qb) => String -> qa -> qb -> Circ ()
- dynamic_lift :: QShape ba qa ca => ca -> Circ ba
- mapUnary :: QData qa => (Qubit -> Circ Qubit) -> qa -> Circ qa
- mapBinary :: QData qa => (Qubit -> Qubit -> Circ (Qubit, Qubit)) -> qa -> qa -> Circ (qa, qa)
- mapBinary_c :: QShape ba qa ca => (Qubit -> Bit -> Circ (Qubit, Bit)) -> qa -> ca -> Circ (qa, ca)
- map2Q :: QData qa => ((Qubit, Qubit) -> Circ Qubit) -> (qa, qa) -> Circ qa
- qc_mapBinary :: QCData qc => (Qubit -> Qubit -> Circ (Qubit, Qubit)) -> (Bit -> Bit -> Circ (Bit, Bit)) -> qc -> qc -> Circ (qc, qc)
- qubits_of_qdata :: QData qa => qa -> [Qubit]
- qdata_of_qubits :: QData qa => qa -> [Qubit] -> qa
- endpoints_of_qcdata :: QCData qc => qc -> [Endpoint]
- qcdata_of_endpoints :: QCData qc => qc -> [Endpoint] -> qc
- qc_false :: QCData qc => qc -> BType qc
- qshape :: QData qa => BType qa -> qa
- qc_bind :: QCData qc => qc -> QCType a b qc -> Bindings a b
- qc_unbind :: QCData qc => Bindings a b -> qc -> QCType a b qc
- (.&&.) :: (ControlSource a, ControlSource b) => a -> b -> ControlList
- (.==.) :: QCData qc => qc -> BType qc -> ControlList
- (./=.) :: QCLeaf q => q -> Bool -> ControlList
- encapsulate_generic :: QCData x => ErrMsg -> (x -> Circ y) -> x -> (x, BCircuit, y)
- encapsulate_generic_in_namespace :: QCData x => ErrMsg -> (x -> Circ y) -> x -> Circ (x, BCircuit, y)
- unencapsulate_generic :: (QCData x, QCData y) => (x, BCircuit, y) -> x -> Circ y
- encapsulate_dynamic :: QCData x => (x -> Circ y) -> x -> (x, DBCircuit y)
- unencapsulate_dynamic :: (QCData x, QCData y) => (x, DBCircuit y) -> x -> Circ y
- 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_xt
- 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_xt
- reverse_simple :: (QCData_Simple x, QCData y, TupleOrUnary xt x, QCurry x_y x y) => x_y -> y -> Circ xt
- 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_xt
- reverse_generic_endo :: (QCData x, TupleOrUnary xt x, QCurry x_xt x xt) => x_xt -> x_xt
- reverse_generic_imp :: (QCData x, QCurry x__ x ()) => x__ -> x__
- reverse_endo_if :: (QCData x, TupleOrUnary xt x, QCurry x_xt x xt) => Bool -> x_xt -> x_xt
- reverse_imp_if :: (QCData qa, QCurry fun qa ()) => Bool -> fun -> fun
- class QCurry fun args res | fun -> args res, args res -> fun where
- transform_unary_dynamic_shape :: (QCData x, QCData y, x' ~ QCType a b x, y' ~ QCType a b y, Monad m) => DynamicTransformer m a b -> (x -> Circ y) -> x -> x' -> m y'
- transform_unary_dynamic :: (QCData x, QCData y) => DynamicTransformer Circ Qubit Bit -> (x -> Circ y) -> x -> Circ y
- transform_unary :: (QCData x, QCData y) => Transformer Circ Qubit Bit -> (x -> Circ y) -> x -> Circ y
- transform_generic :: (QCData x, QCData y, QCurry qfun x y) => Transformer Circ Qubit Bit -> qfun -> qfun
- transform_unary_shape :: (QCData x, QCData y, x' ~ QCType a b x, y' ~ QCType a b y, Monad m) => Transformer m a b -> (x -> Circ y) -> x -> x' -> m y'
- 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''
- with_ancilla_init :: QShape a qa ca => a -> (qa -> Circ b) -> Circ b
- with_ancilla_list :: Int -> (Qulist -> Circ a) -> Circ a
- with_computed_fun :: (QCData x, QCData y) => x -> (x -> Circ y) -> (y -> Circ (y, b)) -> Circ (x, b)
- with_computed :: QCData x => Circ x -> (x -> Circ b) -> Circ b
- with_basis_change :: Circ () -> Circ b -> Circ b
- with_classical_control :: QCData qa => Bit -> String -> qa -> (qa -> Circ qa) -> Circ qa
- provide_subroutine_generic :: (QCData x, QCData y) => ErrMsg -> BoxId -> Bool -> (x -> Circ y) -> x -> Circ ()
- box :: (QCData qa, QCData qb, QCurry qa_qb qa qb) => String -> qa_qb -> qa_qb
- nbox :: QCData qa => String -> Integer -> (qa -> Circ qa) -> qa -> Circ qa
- box_loopM :: (Integral int, QCData qa) => String -> int -> qa -> (qa -> Circ qa) -> Circ qa
- loopM_boxed_if :: (Integral int, QCData qa) => Bool -> String -> int -> qa -> (qa -> Circ qa) -> Circ qa
- inline_subroutine :: BoxId -> Namespace -> [Endpoint] -> Circ [Endpoint]

# Generic gates

## Initialization and termination

qinit :: QShape ba qa ca => ba -> Circ qa Source #

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]

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 qc Source #

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 qc Source #

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.

## Measurement and preparation

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 `prepare`

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

## Global phase 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).

## Mapped gates

map_hadamard :: QData qa => qa -> Circ qa Source #

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`

.

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.

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.

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 qc Source #

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*.

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

Negate all qubits in a quantum data structure.

## Copying and uncopying

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 qc Source #

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

qc_copy :: QCData qc => qc -> Circ qc Source #

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

## Classical gates

cgate_if :: CData ca => Bit -> ca -> ca -> Circ ca Source #

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 ca Source #

`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.

## Named gates

named_gate :: QData qa => String -> qa -> Circ qa Source #

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 qa Source #

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 qa Source #

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 ba Source #

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.

# Mapping

mapUnary :: QData qa => (Qubit -> Circ Qubit) -> qa -> Circ qa Source #

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.

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

Map a binary qubit circuit to every pair of qubits in the quantum data-type. It is a run-time error if the two structures do not have the same size.

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.

# Conversion to lists

The functions in this section can be used to convert quantum data structures to and from lists. Do not use them! The conversion is unsafe in the same way pointers to void are unsafe in the C programming language. There is almost always a better and more natural way to accomplish what you need to do.

qubits_of_qdata :: QData qa => qa -> [Qubit] Source #

Return the list of qubits representing the given quantum data. The qubits are ordered in some fixed, but arbitrary way. It is guaranteed that two pieces of qdata of the same given shape will be ordered in the same way. No other property of the order is guaranteed, In particular, the order may change without notice from one version of Quipper to the next.

qdata_of_qubits :: QData qa => qa -> [Qubit] -> qa Source #

Take a specimen piece of quantum data to specify the "shape"
desired (length of lists, etc); then reads the given list of qubits
in as a piece of quantum data of the same shape. The ordering of
the input qubits is the same as `qubits_of_qdata`

produces for the
given shape.

A "length mismatch" error occurs if the list does not have exactly the required length.

endpoints_of_qcdata :: QCData qc => qc -> [Endpoint] Source #

Return the list of endpoints that form the leaves of the given
`QCData`

. The leaves are ordered in some fixed, but arbitrary
way. It is guaranteed that two pieces of data of the same given
shape will be ordered in the same way. No other property of the
order is guaranteed. In particular, the order may change without notice from
one version of Quipper to the next.

qcdata_of_endpoints :: QCData qc => qc -> [Endpoint] -> qc Source #

Take a specimen piece of `QCData`

to specify the "shape"
desired (length of lists, etc); then reads the given list of
endpoints in as a piece of quantum data of the same shape. The
ordering of the input endpoints equals that produced by
`endpoints_of_qcdata`

for the given shape.

A "length mismatch" error occurs if the list does not have
exactly the required length. A "shape mismatch" error occurs if
the list contains a `Qubit`

when a `Bit`

was expected, or vice versa.

# Shape related operations

qc_false :: QCData qc => qc -> BType qc Source #

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

.

qshape :: QData qa => BType qa -> qa Source #

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

.

# Bindings

qc_bind :: QCData qc => qc -> QCType a b qc -> Bindings a b Source #

Take two pieces of quantum data of the same shape (the first of which consists of wires of a low-level circuit) and create bindings.

qc_unbind :: QCData qc => Bindings a b -> qc -> QCType a b qc Source #

Apply bindings to a piece of quantum and/or classical data holding low-level wires, to get data of the same shape.

# Generic controls

The following functions define a convenient syntax for controls. With this, we can write controls in much the same way as one would write (a restricted class of) boolean expressions. 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 we can combine 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
`(.==.)`

, `(./=.)`

.

(.&&.) :: (ControlSource a, ControlSource b) => a -> b -> ControlList infixr 3 Source #

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

(.==.) :: QCData qc => qc -> BType qc -> ControlList infix 4 Source #

`(qx .==. x)`

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

# Generic encapsulation

An encapsulated circuit is a low-level circuit together with data structures holding the input endpoints and output endpoints. A circuit-generating function, with fully specified parameters, can be turned into an encapsulated circuit; conversely, an encapsulated circuit can be turned into a circuit-generating function. Thus, encapsulation and unencapsulation are the main interface for passing between high- and low-level data structures.

encapsulate_generic :: QCData x => ErrMsg -> (x -> Circ y) -> x -> (x, BCircuit, y) Source #

Extract an encapsulated circuit from a circuit-generating function. This requires a shape parameter.

encapsulate_generic_in_namespace :: QCData x => ErrMsg -> (x -> Circ y) -> x -> Circ (x, BCircuit, y) Source #

As `encapsulate_generic`

, but passes the current namespace
into the circuit-generating function, to save recomputing
shared subroutines

unencapsulate_generic :: (QCData x, QCData y) => (x, BCircuit, y) -> x -> Circ y Source #

Turn an encapsulated circuit back into a circuit-generating function.

A dynamic encapsulated circuit is to an encapsulated circuit like a
`DBCircuit`

to a `BCircuit`

. The output is not a static circuit,
but an interactive computation expressed through the `ReadWrite`

monad, which can be run on a quantum device to get a static circuit
out.

encapsulate_dynamic :: QCData x => (x -> Circ y) -> x -> (x, DBCircuit y) Source #

Extract an encapsulated dynamic circuit from a circuit-generating function. This requires a shape parameter.

unencapsulate_dynamic :: (QCData x, QCData y) => (x, DBCircuit y) -> x -> Circ y Source #

Turn an encapsulated dynamic circuit back into a circuit-generating function.

This currently fails if the dynamic circuit contains output liftings, because the transformer interface has not yet been updated to work with dynamic circuits.

# Generic 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_xt Source #

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_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_xt Source #

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 :: (QCData_Simple x, QCData y, TupleOrUnary xt x, QCurry x_y x y) => x_y -> y -> Circ xt Source #

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_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_xt Source #

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_generic_endo :: (QCData x, TupleOrUnary xt x, QCurry x_xt x xt) => x_xt -> x_xt Source #

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_endo_if :: (QCData x, TupleOrUnary xt x, QCurry x_xt x xt) => Bool -> x_xt -> x_xt Source #

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 -> fun Source #

Conditional version of `reverse_generic_imp`

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

# The QCurry type class

class QCurry fun args res | fun -> args res, args res -> fun where Source #

The `QCurry`

type class is similar to the `Curry`

type class,
except that the result type is guarded by the `Circ`

monad. It
provides a family of type isomorphisms

fun ≅ args -> Circ res,

where

fun = a1 -> a2 -> ... -> an -> Circ res, args = (a1, (a2, (..., (an, ())))).

The benefit of having `Circ`

in the result type is that it ensures
that the result type is not itself a function type, and therefore
*fun* has a *unique* arity *n*. Then *args* and *res* are uniquely
determined by *fun*, which can be used to write higher-order
operators that consume *fun* of any arity and "do the right
thing".

# Generic circuit transformations

transform_unary_dynamic_shape :: (QCData x, QCData y, x' ~ QCType a b x, y' ~ QCType a b y, Monad m) => DynamicTransformer m a b -> (x -> Circ y) -> x -> x' -> m y' Source #

Like transform_unary_shape but for a dynamic transformer

transform_unary_dynamic :: (QCData x, QCData y) => DynamicTransformer Circ Qubit Bit -> (x -> Circ y) -> x -> Circ y Source #

Like transform_unary but for a dynamic transformer

transform_unary :: (QCData x, QCData y) => Transformer Circ Qubit Bit -> (x -> Circ y) -> x -> Circ y Source #

Apply the given transformer to a circuit.

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

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_unary_shape :: (QCData x, QCData y, x' ~ QCType a b x, y' ~ QCType a b y, Monad m) => Transformer m a b -> (x -> Circ y) -> x -> x' -> m y' 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.

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.

# Generic block structure

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

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]>>> }

with_ancilla_list :: Int -> (Qulist -> Circ a) -> Circ a Source #

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_computed_fun :: (QCData x, QCData y) => x -> (x -> Circ y) -> (y -> Circ (y, b)) -> Circ (x, b) Source #

: computes `with_computed_fun`

*x* *f* *g**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 b Source #

: performs `with_computed`

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

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*^{−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 b Source #

: performs a basis change,
then the `with_basis_change`

*basischange* *code**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>>>

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

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.

# Boxed subcircuits

provide_subroutine_generic :: (QCData x, QCData y) => ErrMsg -> BoxId -> Bool -> (x -> Circ y) -> x -> Circ () Source #

Bind a name to a function as a subroutine in the current namespace. This requires a shape argument, as well as complete parameters, so that it is uniquely determined which actual circuit will be the subroutine. It is an error to call that subroutine later with a different shape argument. It is therefore the user's responsibility to ensure that the name is unique to the subroutine, parameters, and shape.

This function does nothing if the name
already exists in the namespace; in particular, it does *not* check
whether the given function is equal to the stored subroutine.

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

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 qa Source #

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 qa Source #

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

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

inline_subroutine :: BoxId -> Namespace -> [Endpoint] -> Circ [Endpoint] Source #

Like `call_subroutine`

, except inline the subroutine body from
the given namespace, instead of inserting a subroutine call.

Implementation note: this currently copies *all* subroutine
definitions from the given namespace into the current namespace,
and not just the ones used by the current subroutine.

Implementation note: this currently only works on lists of endpoints.