Wolfram Quantum Computation Framework

Mads Bahrami and Nikolay Murzin

quantum@wolfram.com

Paclet installation

Deployed version:

PacletInstall["Wolfram/QuantumFramework"]

Development version:

PacletInstall["https://wolfr.am/DevWQCF",ForceVersionInstall->True]

Get the paclet

<<Wolfram`QuantumFramework`

QuantumCircuitOperator

A quantum circuit is composition of quantum operators acting on a quantum state, representing a step-wise transformation of quantum system
QuantumCircuitOperator[{op1,op1,op2}] a list of operators (either complete form, or shorthand)
QuantumCircuitOperator[{“named_circuit”,...}] a named-circuit
QuantumCircuitOperator[...][] a circuit acting on its corresponding register state

QuantumCircuitOperator["X"]

QuantumCircuitOperator["XYZ"]

QuantumCircuitOperator[{"X"->2}]

QuantumCircuitOperator[{"X"->2,"H","Z"->2}]

QuantumCircuitOperator[{"CNOT"}]

QuantumCircuitOperator[{"CNOT"->{2,1}}]

QuantumCircuitOperator[{"X"->2,"H","Z"->2}]["Operators"]

QuantumCircuitOperator[{"X"->2,"H","Z"->2}]["CircuitOperator"]

QuantumCircuitOperator[{"H","CNOT",Sqrt@"X","Barrier","RootSWAP",{"R",θ,"X"->1,"Y"->2},{"Permutation",Cycles[{{1,2}}]},"Barrier",QuantumChannel[{"BitFlip",p}],"Barrier",{1},{2}}]

%["Operators"]

QuantumOperators

The most important pattern to remember is QuantumOperator[arg,order]

QuantumOperator["X"]

Note by default, the order is set as {1}, or {1,2}, or {1,2,...} (depending on the operator)

QuantumOperator["SWAP"]

QuantumOperator[{"Permutation",Cycles[{{1,2}}]}]

QuantumCircuitOperator[QuantumOperator[{"Permutation",Cycles[{{1,2}}]}]]["Diagram"]

QuantumOperator["SWAP"]==QuantumOperator[{"Permutation",Cycles[{{1,2}}]}]

QuantumOperator["SWAP",{2,3}]

QuantumOperator["X",{1,2}]==QuantumOperator["X"]@QuantumOperator["X",{2}]==QuantumTensorProduct[QuantumOperator["X"],QuantumOperator["X"]]

A little but of cheating: visualizing them two swaps with different orders
Wait for it, we will discuss about circuits soon

QuantumCircuitOperator[{"SWAP","SWAP"->{2,3}}]["Diagram"]

Some arithmetic/operations on operators:

Exp[-I θ/2 QuantumOperator["X"]]

%==QuantumOperator[{"RX",θ}]

Sqrt[QuantumOperator["X"]]

%==QuantumOperator["SX"]

QuantumCircuitOperator[{"X"->{1,2},Sqrt["X"]}]["Diagram"]

QuantumOperator["T"+"X"]

%==QuantumOperator["T"]+QuantumOperator["X"]

QuantumOperator["YY"+"XX"+"ZZ"]

QuantumOperator["XX"+"YY"+"ZZ"]==Total[QuantumOperator/@{"XX","YY","ZZ"}]

QuantumOperator[{"R",θ,"XX"+"YY"+"ZZ"}]

FullSimplify[%==QuantumOperator[{"R",θ,"XX"}]@QuantumOperator[{"R",θ,"YY"}]@QuantumOperator[{"R",θ,"ZZ"}]]

One can define controlled-operators with many control and target

ctrl1={2};
ctrl0={4,5};
cu=QuantumOperator[{"C",{"X"->{1},"Y"->{3}},ctrl1,ctrl0}]

QuantumCircuitOperator[cu]["Diagram"]

Ising-type of interactions and their Trotter-Suzuki decomposition (4th order)

op=Table[QuantumOperator["XX",{i,i+1}],{i,5}];

qc=QuantumCircuitOperator[{"Trotterization",op,4,1}];

qc["Diagram","ShowGateLabels"->False]

#["Label"]&/@qc["Operators"]

An operator is a tensor flow with input and output:

QuantumOperator["H",{2,3}]["Diagram"]

Named-circuits

QuantumCircuitOperator["Bell"]["Diagram"]

QuantumCircuitOperator["Toffoli"]["Diagram"]

QuantumCircuitOperator["Fourier"]["Diagram"]

QuantumCircuitOperator[{"Fourier",5}]["Diagram"]

QuantumCircuitOperator[{"PhaseEstimation",QuantumOperator[{"Phase",2π/5}],3}]["Diagram"]

QuantumCircuitOperator[{"BernsteinVazirani","101"}]["Diagram"]

QuantumCircuitOperator[{"Graph",RandomGraph[{4,5}]}]["Diagram"]

QuantumCircuitOperator[{"Grover",a&&b&&!c||d&&!(a||b)}]["Diagram"]

QuantumBasis

If not specified, we automatically treat everything in the computational basis. 
Important patterns to remember:
QauntumBasis[{n1,n2,...}]
QuantumBasis[n,m]
QuantumBasis[asso]

QuantumBasis[3]

QuantumBasis[2,3]

QuantumBasis[{3,2,5}]

QuantumBasis[<|"up"->{1,1},"down"->{1,-I}|>]

There are also many named basis

QuantumBasis["Schwinger"]

QuantumState

The most important pattern to remember is QuantumBasis[arg,qb], with qb defining the basis (if not specified, will be treated automatically as computational basis, given dimensions of arg 
arg: a list of amplitudes, or density matrix, or named-states

QuantumState[{1,I}]

QuantumState[{1,I,3},3]

Note padding when qb is not specified

QuantumState[{1,I,3}]

named-states

QuantumState["RandomPure",3]

state=QuantumState[{"Werner",p,2}]

Some arithmetic with states

x QuantumState[{a,b}]+y QuantumState[{c,d}]

Basis transformation: a state defined in the computational basis, then transformed into Pauli-X basis

state=QuantumState["RandomPure"];
QuantumState[state,"X"]

there are couple of functions one can apply on quantum states
QuantumPartialTrace
QuantumDistance
QuantumEntangledQ
QuantumEntanglementMonotone

QuantumPartialTrace[state,{2}]["Formula"]//Simplify

For example, Werner states with p>=1/2 are not entangled, while p<1/2 are

QuantumEntangledQ@QuantumState[{"Werner",1/2,2}]

QuantumEntangledQ@QuantumState[{"Werner",1/4,2}]

QuantumEntangledQ[QuantumState["GHZ"]]

QuantumEntangledQ[QuantumState["GHZ"],{{1},{2}}]

Concurrence (default), EntanglementEntropy, LogNegativity, Negativity, {“RenyiEntropy”,α}, Realignment

QuantumEntanglementMonotone[QuantumState[{"Werner",1/4,2}]]

QuantumEntanglementMonotone[QuantumState[{"Werner",1/4,2}],"LogNegativity"]

There are lots of interesting properties one can get from a quantum state:
StateVector, DensityMatrix, Tensor, Norm, TraceNorm, Transpose, SchmidtBasis, Conjugate, Transpose (and partial transpose), Purify (and Unpurify), Bend (Unbend), Bipartition

QuantumState["RandomMixed"]["Properties"]

Note some of these properties return eg a numerical value (Entropy) and some returns a quantum state (Transpose, or Bipartition)

Generate a random pure state of 2-qubits:

r=QuantumState[{"RandomPure",2}]

Decompose it (iteration of Schmidt decomposition, until getting separable terms; ie no entanglement)

r["Decompose"]

Map[#["Formula"]&,%,{2}]

Similar operator, but final terms are still 2-qubit states (but separable)

#["Formula"]&/@r["Disentangle"]

r=QuantumState["RandomMixed",{3}]

r["Purify"]

Note partial tracing over ancillary qudit returns the original state

QuantumPartialTrace[%,{2}]==r

Permute:

QuantumState[{a1,a2,a3,a4}]["Permute",Cycles[{{1,2}}]]

Note an operation can be defined by states (|a><b| format of QM) or an operator (difference in our framework: input/output qudits)

proj=QuantumState["PhiPlus"]["Projector"]
op=QuantumState["PhiPlus"]["Operator"]

r=QuantumState[{"RandomPure",2}];

proj[r]==QuantumState["PhiPlus"]

op[r]==QuantumState["PhiPlus"]

Note quantum state is a tensor flow with no input and one or more output (depending on the number of qudits)

QuantumState["1"]["Diagram"]

QuantumState["12"]["Diagram"]

QuantumMeasurementOperator

Either usual PVMs or generic POVMs
Think of it very similar to quantum operator (given basis, and order)

qm=QuantumMeasurementOperator[{1,3}][QuantumState[{"RandomPure",3}]]

qm["ProbabilityPlot"]

qm["Probabilities"]

qm["StateAssociation"]

QuantumMeasurementOperator[{1,2,3}][QuantumState[{"RandomPure",3}]]

%["ProbabilityPlot"]

POVM:

states={QuantumState[-(1/2){1,(Sqrt[3])}],QuantumState[-(1/2){1,-(Sqrt[3])}],QuantumState["0"]};
{e1,e2,e3}=(2/3)#["Operator"]&/@states;
povm={e1,e2,e3};

PositiveSemidefiniteMatrixQ[#["Matrix"]]&/@povm

Total[povm]==QuantumOperator["I"]

qm=QuantumMeasurementOperator[povm][QuantumState["RandomPure"]]

qm["ProbabilityPlot"]