Quantum Circuits
QBit
import spire.math._
import axle.quantumcircuit._
import axle.syntax.kolmogorov._
import axle.algebra.RegionEq
val sqrtHalf = Complex(Real(1) / sqrt(Real(2)), Real(0))
val qEven = QBit[Real](sqrtHalf, sqrtHalf)
val distribution = qEven.cpt
        distribution.P(RegionEq(CBit0))
// res0: Real = Inexact(
//   f = spire.math.Real$$Lambda$8953/0x00000008029b6580@5a0cf27f
// )
distribution.P(RegionEq(CBit1))
// res1: Real = Inexact(
//   f = spire.math.Real$$Lambda$8953/0x00000008029b6580@5dc3868e
// )
        
        Dirac Vector Notation
import axle.quantumcircuit._
import axle.algebra.Binary
        |("00").>().unindex
// res3: Vector[Binary] = Vector(
//   axle.algebra.B1$@6dd81677,
//   axle.algebra.B0$@75ceea9c,
//   axle.algebra.B0$@75ceea9c,
//   axle.algebra.B0$@75ceea9c
// )
Vector[Binary](1, 0) ⊗ Vector[Binary](1, 0)
// res4: Vector[Binary] = Vector(
//   axle.algebra.B1$@6dd81677,
//   axle.algebra.B0$@75ceea9c,
//   axle.algebra.B0$@75ceea9c,
//   axle.algebra.B0$@75ceea9c
// )
        
        CNOT
import axle.quantumcircuit._
import axle.quantumcircuit.QBit._
import spire.algebra.Field
import spire.math.Real
implicit val fieldReal: Field[Real] = new spire.math.RealAlgebra()
val QBit0 = constant0[Real]
val QBit1 = constant1[Real]
        QBit2.cnot(QBit2(QBit0.unindex ⊗ QBit0.unindex)).unindex
// res6: Vector[spire.math.Complex[Real]] = Vector(
//   Complex(real = Exact(n = 1), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0))
// )
QBit2.cnot(QBit2(QBit0.unindex ⊗ QBit1.unindex)).unindex
// res7: Vector[spire.math.Complex[Real]] = Vector(
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 1), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0))
// )
QBit2.cnot(QBit2(QBit1.unindex ⊗ QBit0.unindex)).unindex
// res8: Vector[spire.math.Complex[Real]] = Vector(
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 1), imag = Exact(n = 0))
// )
QBit2.cnot(QBit2(QBit1.unindex ⊗ QBit1.unindex)).unindex
// res9: Vector[spire.math.Complex[Real]] = Vector(
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 1), imag = Exact(n = 0)),
//   Complex(real = Exact(n = 0), imag = Exact(n = 0))
// )
        
        Future Work
QBit2.factor- Fix and enable 
DeutschOracleSpec - QBit CCNot
 
Later
- Shor's algorithm
 - Property test reversibility (& own inverse)
 - Typeclass for "negate" (etc), Binary, CBit
 - Typeclass for unindex
 - Deutsch-Jozsa algorithm (D.O. for n-bits) (Oracle separation between EQP and P)
 - Simon's periodicity problem (oracle separation between BQP and BPP)
 - Grover's algorithm
 - Quantum cryptographic key exchange