Details: evaluation

Having defined the quotient algebra, there can be an additional equivalence relation on the monomials when they are evaluated. This depends on the variant of the NC hierarchy in use. Let us reuse the CHSH example, and for simplicity, we define A(x) and B(y) as quotient monomials.

import net.alasc.symdpoly._
import net.alasc.symdpoly.examples.quantum.CHSH.{Free, Quantum}
def A(x: Int) = Quantum.quotient(Free.A(x))
def B(y: Int) = Quantum.quotient(Free.B(y))

Original NPA hierarchy and real-valued variant

For the original NPA hierarchy, there are no additional equivalences.

scala> val L1 = Quantum.eigenvalueEvaluator()
L1: net.alasc.symdpoly.evaluation.Evaluator.Aux[net.alasc.symdpoly.quotient.MonoDef.<refinement>.type] = ScratchEigenvalueEvaluator(false,Grp())

scala> L1(A(0)*A(1)).toString
res0: String = L([A(0) A(1)])

scala> L1(A(1)*A(0)).toString
res1: String = L([A(1) A(0)])

However, sometimes we know that real moment matrices are sufficient to express the optimum. Thus, we can state that we evaluate polynomials over pure states, and that L(x) = L(x.adjoint); as L is a *-homomorphism (i.e. L(x.adjoint) = L(x).adjoint), the resulting coefficients will be real.

scala> val L2 = Quantum.eigenvalueEvaluator(real = true)
L2: net.alasc.symdpoly.evaluation.Evaluator.Aux[net.alasc.symdpoly.quotient.MonoDef.<refinement>.type] = ScratchEigenvalueEvaluator(true,Grp())

scala> L2(A(0)*A(1)).toString
res2: String = L([A(0) A(1)])

scala> L2(A(1)*A(0)).toString
res3: String = L([A(0) A(1)])

scala> L2(A(0)*A(1)*B(0)*B(1)).toString
res4: String = L([A(0) A(1) B(0) B(1)])

scala> L2(A(1)*A(0)*B(0)*B(1)).toString
res5: String = L([A(0) A(1) B(1) B(0)])

scala> L2(A(0)*A(1)*B(1)*B(0)).toString
res6: String = L([A(0) A(1) B(1) B(0)])

scala> L2(A(1)*A(0)*B(1)*B(0)).toString
res7: String = L([A(0) A(1) B(0) B(1)])

PPT constraints

We can also require PPT constraints, i.e. equivalence of monomials under partial transposition. The user specifies the families of operators that commute.

scala> val L3 = Quantum.pptEvaluator(Free.A, Free.B)
L3: net.alasc.symdpoly.evaluation.Evaluator.Aux[net.alasc.symdpoly.quotient.MonoDef.<refinement>.type] = net.alasc.symdpoly.evaluation.PPTEvaluator@3332d53c

scala> L3(A(0)*A(1)*B(0)*B(1)).toString
res8: String = L([A(0) A(1) B(0) B(1)])

scala> L3(A(1)*A(0)*B(0)*B(1)).toString
res9: String = L([A(0) A(1) B(0) B(1)])

scala> L3(A(0)*A(1)*B(1)*B(0)).toString
res10: String = L([A(0) A(1) B(0) B(1)])

scala> L3(A(1)*A(0)*B(1)*B(0)).toString
res11: String = L([A(0) A(1) B(0) B(1)])

scala> import net.alasc.symdpoly.examples.quantum.Sliwa.{Free => SliwaFree, Quotient => SliwaQuotient}
import net.alasc.symdpoly.examples.quantum.Sliwa.{Free=>SliwaFree, Quotient=>SliwaQuotient}

scala> val L3bis = SliwaQuotient.pptEvaluator(SliwaFree.A, SliwaFree.B ++ SliwaFree.C)
L3bis: net.alasc.symdpoly.evaluation.Evaluator.Aux[net.alasc.symdpoly.quotient.MonoDef.<refinement>.type] = net.alasc.symdpoly.evaluation.PPTEvaluator@7d3663d1

Trace optimization

It is also possible to use cyclic equivalency, corresponding to trace optimization of polynomials.

scala> val L4 = Free.traceEvaluator(real = true)
L4: net.alasc.symdpoly.evaluation.Evaluator.Aux[net.alasc.symdpoly.examples.quantum.CHSH.Free.type] = TraceEvaluator(true,Grp())

scala> L4(Free.A(0)*Free.A(1)*Free.B(0)*Free.B(1)).toString
res12: String = L(A(0) A(1) B(0) B(1))

scala> L4(Free.A(1)*Free.A(0)*Free.B(0)*Free.B(1)).toString
res13: String = L(A(0) A(1) B(1) B(0))

scala> L4(Free.A(0)*Free.A(1)*Free.B(1)*Free.B(0)).toString
res14: String = L(A(0) A(1) B(1) B(0))

scala> L4(Free.A(1)*Free.A(0)*Free.B(1)*Free.B(0)).toString
res15: String = L(A(0) A(1) B(0) B(1))

Note: the use of trace optimization with rewriting rules has not yet been proven sound.