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

Safe HaskellNone

Quipper.Labels

Contents

Description

This module provides functionality for labelling endpoints in wires. The goal is to achieve two things:

  • Label qubits individually. For example, we would like to label three qubits (a, b, c) as "a", "b", and "c", respectively.
  • Label data structures all at once. For example, if a=[x,y,z] is a piece of quantum data, and we label this data structure "a", then the individual qubits will be labelled: x = a[0], y = a[1], z = a[2].

We can also combine both methods to arbitrary nesting levels. For example, we can label (([x,y,z], t), [u,v,w]) as ("a", ["u", "v", "w"]), to get the labelling x = a[0,0], y = a[0,1], z = a[0,2], t = a[1], u = u, v = v, w = w.

Synopsis

Helper functions

Indices

type IndexList = (String, [String])Source

An index list is something that can be appended to a string. We consider subscript indices of the form "[i]", dotted indices of the form ".i", and perhaps arbitrary suffixes. A complication is that we want consecutive subscript indices to be combined, as in "[i,j,k]". We therefore need a special data structure to hold an index list "under construction".

An index list consists of a string and a list of current subscripts. For efficiency, the list of subscripts is reversed, i.e., the most recent subscript is at the head of the list.

indexlist_format :: IndexList -> StringSource

Convert an index list to a string.

indexlist_empty :: IndexListSource

The empty index list.

indexlist_subscript :: IndexList -> String -> IndexListSource

Append a subscript to an index list.

indexlist_dotted :: IndexList -> String -> IndexListSource

Append a dotted index to an index list.

The LabelMonad monad

newtype LabelMonad a Source

A monad to provide a convenient syntax for specifying Labelable instances. Computations in this monad have access to a read-only "current index list", and they output a binding from wires to strings.

Constructors

LabelMonad 

labelmonad_get_indexlist :: LabelMonad IndexListSource

Get the current string and index.

labelmonad_put_binding :: Wire -> String -> LabelMonad ()Source

Output a binding for a label

labelmonad_with_indexlist :: IndexList -> LabelMonad a -> LabelMonad aSource

Run a subcomputation with a new current index list.

labelmonad_run :: LabelMonad () -> Map Wire StringSource

Extract a labelling from a label monad computation. This is the run function of the label monad.

Formatting of labels

label_wire :: Wire -> String -> LabelMonad ()Source

Label a wire with the given name, using the current index.

with_index :: String -> LabelMonad () -> LabelMonad ()Source

Run a subcomputation with a subscript index appended to the current index list. Sample usage:

 with_index "0" $ do
   <<<labelings>>>

with_dotted_index :: String -> LabelMonad () -> LabelMonad ()Source

Run a subcomputation with a dotted index appended to the current index list. Sample usage:

 with_dotted_index "left" $ do
   <<<labelings>>>

indexed :: LabelMonad () -> String -> LabelMonad ()Source

Like with_index, except the order of the arguments is reversed. This is intended to be used as an infix operator:

 <<<labeling>>> `indexed` "0"

dotted_indexed :: LabelMonad () -> String -> LabelMonad ()Source

Like with_dotted_index, except the order of the arguments is reversed. This is intended to be used as an infix operator:

 <<<labeling>>> `dotted_indexed` "left"

label_empty :: LabelMonad ()Source

Do nothing.

The Labelable type class

class Labelable a s whereSource

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.

Methods

label_rec :: a -> s -> LabelMonad ()Source

Recursively label a data structure with the given format.

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) 

mklabel :: Labelable a s => a -> s -> [(Wire, String)]Source

Given a data structure and a format, return a list of labelled wires.

High-level functions

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.

Defining new Labelable instances

A Labelable instance should be defined for each new instance of QCData. The general idea is that the structure of the label should exactly follow the structure of the data being labeled, except that at any level the label can be a string (which will then be decorated with appropriate subscripts for each leaf in the data structure).

In practice, there are two cases to consider: adding a new QCData constructor, and adding a new atomic QCData.

New QCshape constructors

Consider the case of a new QCData constructor:

 instance (QCData a) => QCData (Constructor a).

There are two required Labelable instances. The first instance deals with a label that is a string, and takes the following form:

 instance (Labelable a String) => Labelable (Constructor a) String where
   label_rec as s = do
     label_rec <<<a1>>> s `indexed` <<<index1>>>
     ...
     label_rec <<<an>>> s `indexed` <<<indexn>>>

Here, a[sub 1]...a[sub n] are the components of the data structure, and index[sub 1]...index[sub n/] are the corresponding subscripts. The function indexed appends a subscript of the form "[i]". There is a similar function dotted_indexed, which appends a subscript of the form ".i".

The second required instance deals with a label that is a data structure of the same shape as the data being labeled. It takes the form:

 instance (Labelable a s) => Labelable (Constructor a) (Constructor s) where
   label_rec as ss idx = do
     label_rec <<<a1>>> <<<s1>>>
     ...
     label_rec <<<an>>> <<<sn>>>

Here, a[sub 1]...a[sub n] are the components of the data structure, and s[sub 1]...s[sub n] are the corresponding components of the label.

Example

As a concrete example, consider a constructor

 data MaybeTwo a = One a | Two a a
 instance (QCData a) => QCData (MaybeTwo a)

The following instance declarations would be appropriate:

 instance (Labelable a String) => Labelable (MaybeTwo a) String where
    label_rec (One x) s =
      with_dotted_index "one" $ do
        label_rec x s
    label_rec (Two x y) s =
      with_dotted_index "two" $ do
        label_rec x s `indexed` "0"
        label_rec y s `indexed` "1"

 instance (Labelable a s) => Labelable (MaybeTwo a) (MaybeTwo s) where
    label_rec (One x) (One s) = label_rec x s
    label_rec (Two x y) (Two s t) = do
      label_rec x s
      label_rec y t
    label_rec _ _ = return ()  -- fail silently

With this example, the commands

 mklabel (One x) "s"
 mklabel (Two y z) "s"

produce the respective labelings

 x -> s.one
 y -> s.two[0]
 z -> s.two[1]
New atomic QCShape

Consider the case of a new atomic QCData instance:

 instance QCData (Atomic x).

We usually need a Labelable instance for the cases x=Qubit and x=Bit. This should be done uniformly, by using the QCLeaf type class. The instance takes the following form:

 instance QCLeaf x => Labelable (Atomic x) String where
   label_rec a s = do
     label_rec <<<a1>>> s `indexed` <<<index1>>>
     ...
     label_rec <<<an>>> s `indexed` <<<indexn>>>

Here, a[sub 1]...a[sub n] are the components of the data structure, and index[sub 1]...index[sub n/] are the corresponding subscripts. It is up to the designer of the data structure to decide what are "components" and how they should be labelled. On or more layers of string or numeric indices can be added as appropriate.

Example

Consider the following sample atomic quantum data. A real number consists of an exponent, a sign, and a list of digits.

 data MyReal x = MyReal Int x [x]
 instance QCLeaf x => QCData (MyReal x)

The following instance declaration would be appropriate:

 instance QCLeaf x => Labelable (MyReal x) String where
    label_rec (MyReal exp sign digits) s = do
      label_rec sign s `dotted_indexed` "sign"
      with_dotted_index "digit" $ do
        sequence_ [ label_rec d s `indexed` show i | (d,i) <- zip digits [-exp..] ]

With this example, the command

 mklabel (MyReal 2 x [y0, y1, y2, y3]) "s"

produces the labeling

 x  -> "s.sign"
 y0 -> "s.digit[-2]"
 y1 -> "s.digit[-1]"
 y2 -> "s.digit[0]"
 y3 -> "s.digit[1]"

Note that we could have also used the default labeling for the members of a list, but in this case, it was convenient to use a custom labeling.