```{-|
-Module      : Operations.QuantumOperations
-Description : Quantum Operations
-Copyright   : (c) Mihai Sebastian Ardelean, 2018
-Maintainer  : ardeleanasm@gmail.com
-Portability : POSIX
-}
module Operations.QuantumOperations
(
QubitOperations(..)
, GateOperations(..)
) where

import Numeric.LinearAlgebra hiding ( (|>) )

import Quantum.Qubits
import Core.QOperationsInternal(entangleTwoQubits
,applyGate
,outerProduct
,multiply
,kron)
import Quantum.Gates

-- | Class QubitOperations used to define common operations that can be made with 'Quantum.Qubits.Qubit'
class QubitOperations a where
{-|
- entangle function is used to perform the Kronecker product between two qubits.

>>>entangle qZero qOne
(4><1)
[ 0.0 :+ 0.0
, 1.0 :+ 0.0
, 0.0 :+ 0.0
, 0.0 :+ 0.0 ]
-}
entangle::a->a->a

{-|
-|> function is used to apply a gate on a qubit

>>>qZero |> hGate
(2><1)
[ 0.7071067811865475 :+ 0.0
, 0.7071067811865475 :+ 0.0 ]
-}
(|>)::a->Gate->a

{-|
-|><| function represents the outer product.

>>>qZero |><| qZero
(2><2)
[ 1.0 :+ 0.0, 0.0 :+ 0.0
, 0.0 :+ 0.0, 0.0 :+ 0.0 ]
-}
(|><|)::a->a->Gate

{-|
-mul function is used to multiply the states with a constant.

>>>qZero * 5
(2><1)
[ 5.0 :+ 0.0, 0.0 :+ 0.0
, 0.0 :+ 0.0, 0.0 :+ 0.0 ]
-}
(*)::a->Complex Double->a

-- | QubitOperations instance for 'Quantum.Qubits.Qubit'
instance QubitOperations Qubit where
entangle = entangleTwoQubits
(|>)=flip applyGate
(|><|)=outerProduct
(*)=multiply

-- | Class GateOperations used to define common operations that can be made with 'Quantum.Gates.Gate'
class GateOperations a where

{-|
- Kronecker product operator is used to create gates that can be used on multiple qubits

>>>hGate <*> hGate
(4><4)
[ 0.4999999999999999 :+ 0.0,    0.4999999999999999 :+ 0.0,    0.4999999999999999 :+ 0.0,    0.4999999999999999 :+ 0.0
, 0.4999999999999999 :+ 0.0, (-0.4999999999999999) :+ 0.0,    0.4999999999999999 :+ 0.0, (-0.4999999999999999) :+ 0.0
, 0.4999999999999999 :+ 0.0,    0.4999999999999999 :+ 0.0, (-0.4999999999999999) :+ 0.0, (-0.4999999999999999) :+ 0.0
, 0.4999999999999999 :+ 0.0, (-0.4999999999999999) :+ 0.0, (-0.4999999999999999) :+ 0.0,    0.4999999999999999 :+ 0.0 ]}
-}
(<*>)::a->a->a

-- | GateOperations instance for 'Quantum.Gates.Gate'
instance GateOperations Gate where
(<*>)=kron

```