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

module Quipper (
  -- * The Circ monad  
  Circ(..),
  
  -- * Basic types
  Qubit,
  Bit,
  Qulist,
  Bitlist,
  
  -- * Basic gates
  -- $BASIC
  Timestep,
  
  -- $FUNCTIONAL_ANCHOR
  
  -- ** Reversible gates in functional style
  -- $FUNCTIONAL
  qnot,
  hadamard,
  gate_H,
  gate_X,
  gate_Y,
  gate_Z,
  gate_S,
  gate_S_inv,
  gate_T,
  gate_T_inv,
  gate_E,
  gate_E_inv,
  gate_omega,
  gate_V,
  gate_V_inv,
  expZt,
  rGate,
  gate_W,
  gate_iX,
  gate_iX_inv,
  global_phase,
  global_phase_anchored,
  qmultinot,
  cnot,
  swap,
  
  -- $IMPERATIVE_ANCHOR
  
  -- ** Reversible gates in imperative style 
  -- $IMPERATIVE 
  qnot_at,
  hadamard_at,
  gate_H_at,
  gate_X_at,
  gate_Y_at,
  gate_Z_at,
  gate_S_at,
  gate_S_inv_at,
  gate_T_at,
  gate_T_inv_at,
  gate_E_at,
  gate_E_inv_at,
  gate_omega_at,
  gate_V_at,
  gate_V_inv_at,
  expZt_at,
  rGate_at,
  gate_W_at,
  gate_iX_at,
  gate_iX_inv_at,
  qmultinot_at,
  cnot_at,
  swap_at,
  
  -- ** Gates for state preparation and termination
  qinit,
  qterm,
  qdiscard,
  cinit,
  cterm,
  cdiscard,
  qc_init,
  qc_init_with_shape,
  qc_term,
  qc_discard,
  measure,
  prepare,
  qc_measure,
  qc_prepare,
  
  -- ** Gates for classical circuits
  -- $CLASSICAL
  cgate_xor,  
  cgate_eq,
  cgate_not,
  cgate_and,
  cgate_or,
  cgate_if,
  circ_if,
  
  -- ** User-defined gates
  named_gate,
  named_gate_at,
  named_rotation,
  named_rotation_at,
  extended_named_gate,
  extended_named_gate_at,
  
  -- ** Dynamic lifting
  dynamic_lift,
  
  -- * Other circuit-building functions
  qinit_plusminus,
  qinit_of_char,
  qinit_of_string,
  map_hadamard,
  map_hadamard_at,
  controlled_not,
  controlled_not_at,
  bool_controlled_not,
  bool_controlled_not_at,
  qc_copy,
  qc_uncopy,
  qc_copy_fun,
  qc_uncopy_fun,
  mapUnary,
  mapBinary,
  mapBinary_c,
  qc_mapBinary,
  
  -- * Notation for controls
  -- $CONTROLS
  ControlSource(..),
  ControlList,
  (.&&.), 
  (.==.), 
  (./=.),
  controlled,
  
  -- * Signed items
  Signed(..),
  from_signed,
  get_sign,
  
  -- * Comments and labelling
  comment,
  label,
  comment_with_label,
  without_comments,
  Labelable,
  
  -- * Hierarchical circuits
  box,
  nbox,
  box_loopM,
  loopM_boxed_if,

  -- * Block structure
  -- $BLOCK
  
  -- ** Ancillas
  -- $WITHANCILLA
  with_ancilla,
  with_ancilla_list,
  with_ancilla_init,
  -- ** Automatic uncomputing
  with_computed_fun,
  with_computed,
  with_basis_change,
  -- ** Controls
  with_controls,
  with_classical_control,
  without_controls,
  without_controls_if,
  -- ** Loops
  for,
  endfor,
  foreach,
  loop,
  loop_with_index,
  loopM,
  loop_with_indexM,
  
  -- * Operations on circuits
  -- ** Reversing
  reverse_generic,
  reverse_simple,
  reverse_generic_endo,
  reverse_generic_imp,
  reverse_generic_curried,
  reverse_simple_curried,
  reverse_endo_if,
  reverse_imp_if,
  
  -- ** Printing
  Format (..),
  FormatStyle(..),
  format_enum,
  print_unary,
  print_generic,
  print_simple,
  print_of_document,
  print_of_document_custom,
  
  -- ** Classical circuits  
  classical_to_cnot,
  classical_to_quantum,
  -- ** Ancilla uncomputation
  classical_to_reversible,
  
  -- * Circuit transformers
  -- $TRANSFORMATION
  
  -- ** User-definable transformers
  Transformer,
  T_Gate(..),
  -- ** Pre-defined transformers
  identity_transformer,
  -- ** An example transformer
  -- $TRANSEXAMPLE
  
  -- ** Applying transformers to circuits
  transform_generic,
  transform_generic_shape,
  
  -- ** Auxiliary type definitions
  InverseFlag,
  NoControlFlag,
  B_Endpoint(..),
  Endpoint,
  Ctrls,  

  -- * Automatic circuit generation from classical code
  -- $TEMPLATE
  module Quipper.CircLifting,
  module Libraries.Template,

  -- * Extended quantum data types
  -- ** Homogeneous quantum data types
  QShape,
  QData,
  CData,
  BData,
  
  -- ** Heterogeneous quantum data types
  QCData,
  QCDataPlus,
  
  -- ** Shape-related operations
  -- $SHAPE
  bit,
  qubit,
  qshape,
  qc_false,
  
  -- ** Quantum type classes
  -- $QCLASSES
  QEq (..),
  QOrd (..),
  q_lt,
  q_gt,
  q_le,
  q_ge,
  
  ) where


import Quipper.Monad
import Quipper.Generic
import Quipper.QData
import Quipper.QClasses
import Quipper.Control
import Quipper.CircLifting
import Quipper.Transformer (T_Gate(..), Transformer, Ctrls, B_Endpoint(..))
import Quipper.Circuit (InverseFlag, NoControlFlag, from_signed, get_sign)
import Quipper.Classical
import Quipper.Printing
import Quipper.Labels

import Libraries.Template
import Libraries.Auxiliary

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

-- $FUNCTIONAL_ANCHOR #FUNCTIONAL#

-- $FUNCTIONAL
-- 
-- 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 <#IMPERATIVE Reversible gates in imperative style> below.

-- $IMPERATIVE_ANCHOR #IMPERATIVE#

-- $IMPERATIVE
-- 
-- 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 <#FUNCTIONAL Reversible gates in functional style> above.

-- * Snippets of additional documentation lifted from import modules:

-- $CLASSICAL
--
-- 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.

-- $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>>   

-- $BLOCK
-- 
-- 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.

-- $WITHANCILLA 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.

-- $TEMPLATE
-- 
-- 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.

-- $TRANSFORMATION
-- 
-- 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/).
-- @

-- $TRANSEXAMPLE
-- 
-- 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

-- $QCLASSES
--
-- 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.

-- $SHAPE 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.