Safe Haskell | None |
---|

This module provides a user-friendly interface to building quantum circuits out of classical functions on booleans. It is based on lower-level functionality provided by Quipper.Utils.Template.

Technically, the only functions to be used in this module are

, a specialized version of `decToCircMonad`

, and
`decToMonad`

. The only useful datatype here is `unpack`

.`BoolParam`

One should not have to directly use the other things: they are only for the internal use of Template Haskell to build quantum circuits out of classical computation on booleans.

Note: in the following, we write circuits in ASCII form. The following conventions are used. They are extended in obvious ways when applicable (e.g. when writing a ternary gate).

---- : wire 0 |-- : initialize an ancilla |0> --| 0 : terminate an ancilla, asserting it was |0> +--+ -| |- : a unary gate +--+ +--+ -| |- | | : a binary gate -| |- +--+ -- -- X : swap gate -- -- --x-- | : controlled-not, applying NOT on the bottom wire if the top one is |1> --N-- --o-- | : controlled-not, applying NOT on the bottom wire if the top one is |0> --N--

## Synopsis

- data BoolParam
- newBool :: BoolParam -> Bool
- template_PFalse :: Circ BoolParam
- template_PTrue :: Circ BoolParam
- decToCircMonad :: Q [Dec] -> Q [Dec]
- template_newBool :: Circ (BoolParam -> Circ Qubit)
- template_False :: Circ Qubit
- template_True :: Circ Qubit
- template_not :: Circ (Qubit -> Circ Qubit)
- template_symb_ampersand_symb_ampersand_ :: Circ (Qubit -> Circ (Qubit -> Circ Qubit))
- template_symb_vbar_symb_vbar_ :: Circ (Qubit -> Circ (Qubit -> Circ Qubit))
- template_bool_xor :: Circ (Qubit -> Circ (Qubit -> Circ Qubit))
- template_if :: QData b => Circ Qubit -> Circ b -> Circ b -> Circ b
- template_symb_equal_symb_equal_ :: QEq qa => Circ (qa -> Circ (qa -> Circ Qubit))
- class CircLiftingUnpack packed unpacked | packed -> unpacked, unpacked -> packed where

# Overview

Using the tool

designed in Quipper.Utils.Template, we
can easily generate quantum circuits. Indeed, suppose that we are given the classical oracle `decToMonad`

toyOracle :: Bool -> Bool toyOracle a = f (g a) (h a)

for some `g,h :: Bool -> Bool`

and `f :: Bool -> Bool -> Bool`

. If
*g* and *h* are given by quantum circuits of the form

+-----+ input ---| |-- input wire, assumed to be not modified by the box | | 0 |-| |--- output (was ancilla wire) +-----+

and if *f* is given by

+-----+ input ---| |-- was input 1, assumed to be not modified | | input ---| |-- was input 2, assumed to be not modified | | 0 |--| |-- output (was ancilla wire), +-----+

we can compositionally generate a circuit `C`

for *toyOracle* as follows.

+---+ +---+ input ---| |-- -----------------| |-- (output of g) | g | X +---+ | | 0 |--| |-- --| |--- ------| f |-- (output of h) +---+ | h | X | | (I) 0 |------------| |--- - ----| |-- (output of f) +---+ X +---+ 0 |- ----------- (input of g)

Note that the resulting circuit is a classical, reversible circuit
(more precisely, the circuit defines a one-to-one function). In
order to obtain a reversible quantum circuit, one should then apply
the function

to get the following (we
keep the same convention of wires as in the definition of `classical_to_reversible`

`C`

):

+---+ +---+ input--| |-----| |-- still the input | | | | 0 |--| |-----| |--| 0 | C | | D | (II) 0 |--| |--x--| |--| 0 | | | | | 0 |--| |--|--| |--| 0 +---+ | +---+ | output wire---N--------------.

Here `D`

is the inverse of `C`

. We now have a circuit of the
canonical form, computing and then uncomputing its ancillas:

+-----------+ a --| |- a | toyOracle | z --| |- z + (f (g a) (h a)) +-----------+

# A type of boolean parameters

During the construction of a quantum circuit from
classical code, the type `Bool`

is mapped to the type
`Qubit`

. However, it is also sometimes useful to specify boolean
parameters to be used during circuit generation (for example, in
the BWT algorithm, the color is a parameter). For this purpose, we
provide a new type `BoolParam`

, which is identical to `Bool`

in
most respects, except that it is not mapped to `Qubit`

during
circuit generation.

A custom-design boolean type, not modified by circuit generation.

template_PFalse :: Circ BoolParam Source #

Lifted version of PFalse.

template_PTrue :: Circ BoolParam Source #

Lifted version of PTrue.

# Lifting classical functions to circuits

The main tool for transforming a classical computation into a
quantum circuit is the function

. It inputs the
syntax tree of a classical function, and outputs the syntax tree of
a corresponding quantum circuit. The type `decToCircMonad`

`Bool`

is mapped to
`Qubit`

; the type `BoolParam`

is unchanged; and each function *f* :
*a* → *b* is mapped to a function *f'* : *a'* → `Circ`

*b'*,
where *a'* and *b'* are the translations of the types *a* and *b*,
respectively.

Most of the work is done by the lower-level function

from the module Quipper.Utils.Template.
This lower-level function knows how to deal with many usual
constructs of the Haskell language, such as function applications,
lambda-abstractions, let-assignments, case-distinctions, and so
on. However, `decToMonad`

does not by default know how to deal
with the base cases, i.e., how to extract quantum circuits from
specific term constants such as `decToMonad`

, `&&`

, etc.`||`

The purpose of the remainder of this module is to do just that. For
every constant or function `XXX`

that one may want to use in a
classical program, we provide an implementation `template_XXX`

as a
quantum circuit. We refer to `template_XXX`

as the "lifted"
version of `XXX`

. The function

is a version of
`decToCircMonad`

that knows about these liftings.`decToMonad`

decToCircMonad :: Q [Dec] -> Q [Dec] Source #

Input the syntax tree of a classical function, and output the
syntax tree of a corresponding quantum function. The type `Bool`

is
mapped to `Qubit`

; the type `BoolParam`

is unchanged; and and each
function *f* : *a* → *b* is mapped to a function *f'* : *a'* →
`Circ`

*b'*, where *a'* and *b'* are the translations of the types
*a* and *b*, respectively. The function `decToCircMonad`

knows
about many built-in operations such as

and `&&`

, whose
circuit translations are defined below.`||`

# Syntactic sugar

Quipper comes equipped with syntactic sugar to ease
the use of the

function.`decToCircMonad`

Although the code

$( decToCircMonad [d| f x = ... |] )

is valid, it is possible to use the special keyword
`build_circuit`

, as follows:

build_circuit f x = ...

This code is equivalent to

f x = ... $( decToCircMonad [d| f x = ... |] )

In other words, it generates both a function `f`

of type `a -> ...`

and an object `template_f`

of type `Circ (a -> Circ ...)`

.

The following spellings are recognized:

build_circuit f x y z = ...

build_circuit f x y z = ...

build_circuit f :: a -> ... f x y z = ...

# Circuits for specific operations

## Boolean parameters

template_newBool :: Circ (BoolParam -> Circ Qubit) Source #

Lifted version of `newBool`

:

newBool :: BoolParam -> Bool.

Depending on the boolean parameter, the circuit is either

0 |--

or

1 |--

## Boolean constants

## Unary boolean operations

## Binary boolean operations

template_symb_ampersand_symb_ampersand_ :: Circ (Qubit -> Circ (Qubit -> Circ Qubit)) Source #

Lifted version of `&&`

:

(&&) :: Bool -> Bool -> Bool.

The circuit is

a -----x--- | b -----x--- | 0 |--N------- output: a and b.

template_symb_vbar_symb_vbar_ :: Circ (Qubit -> Circ (Qubit -> Circ Qubit)) Source #

Lifted version of `||`

:

(||) :: Bool -> Bool -> Bool.

The circuit is

a -----o--- | b -----o--- | 1 |--N------- output: a or b.

template_bool_xor :: Circ (Qubit -> Circ (Qubit -> Circ Qubit)) Source #

Lifted version of `bool_xor`

:

bool_xor :: Bool -> Bool -> Bool.

The circuit is

a -----x------- | b -----|---x--- | | 0 |--N---N------ output: a xor b.

## The if-then-else operation

The last term we need to build is

, a term
describing the if-then-else construct as a circuit.`template_if`

template_if :: QData b => Circ Qubit -> Circ b -> Circ b -> Circ b Source #

Lifted version of the `if-then-else`

construction:

if-then-else :: Bool -> b -> b -> b

We only allow first-order terms in the "then" and "else" clauses. The circuit is:

q -----x---o--- | | a -----x---|--- | | b -----|---x--- | | 0 |--N---N-------- wire output of the function.

## Equality test

template_symb_equal_symb_equal_ :: QEq qa => Circ (qa -> Circ (qa -> Circ Qubit)) Source #

Lifted version of the `==`

operator:

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

# Generic unpacking

class CircLiftingUnpack packed unpacked | packed -> unpacked, unpacked -> packed where Source #

The `decToCircMonad`

function produces (and also requires)
functions with somewhat unwieldy types. The `CircLiftingUnpack`

class defines generic functions for unpacking these types into a
more useable format, and for packing them back.

For example,

unpacks into
the type `Circ`

(qa -> `Circ`

(qb -> `Circ`

qd))`qa -> qb -> `

.`Circ`

qd

Note that `pack`

and `unpack`

do not in general form an
isomorphism, just a retraction of the packed type onto the unpacked
type.

## Instances

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') # | |