Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Feature propagatable error gens #435

Draft
wants to merge 12 commits into
base: develop
Choose a base branch
from

Conversation

sserita
Copy link
Contributor

@sserita sserita commented May 1, 2024

This is a draft PR for integrating @ashenmill's work on end-of-circuit error generators, which will probably be paired with some sort of STIM forward simulator support.

I'm opening this PR early so that I can comment on specific lines of code.

def com(p1,p2):
P1 = pyGSTiPauli_2_stimPauli(p1)
P2=pyGSTiPauli_2_stimPauli(p2)
P3=P1*P2-P2*P1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ashenmill Is there a specific version of STIM that is required for this? I tried subtracting PauliString objects like this on stim 1.13.0 and got unsupported operand type. Negation and addition do exist, but addition seems to just be concatenation. Am I missing something?

wT=ErG1.getWeight()*ErG2.getWeight()*weightFlip*BCHweight

if ErG1.getType()=='H' and ErG2.getType()=='H':
pVec=com(ErG1.getP1() , ErG2.getP2())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not be ErG2.getP1()? Hamiltonian error generators should only have one basis element, right?

in this function, if the weight is needed please store paulistring::weight prior to applying this function
'''
def stimPauli_2_pyGSTiPauli(pauliString):
return str(pauliString)[1:].replace('_',"I")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line may fail if there is a complex phase because you would need to remove 2 characters.

MultiGate: lets the code know
returns: list of propagatableerrorgens
'''
def ErrorPropagator(circ,errorModel,MultiGateDict={},BCHOrder=1,BCHLayerwise=False,NonMarkovian=False,MultiGate=False,ErrorLayerDef=False):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick note to future us to remove this mutable default arg for MultiGateDict.

Copy link
Contributor Author

@sserita sserita left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting some discrepancies between the notes and code. It doesn't really matter if we know the code is correct, but we will eventually want some documentation for this so ensuring the notes match is probably a good step.

pVec=com(ErG2.getP1() , ErG1.getP1())
errorGens.append( propagatableerrorgen( 'C' , [ErG2.getP1() , pVec[1]] , -1j*wT *pVec[0] ) )

elif ErG1.getType()=='H' and ErG2.getType()=='C':
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes have this as

$$\large [H_P, C_{A,B}] = iC_{[A,P],B} + iC_{[P,B],A} $$

but what is coded is

$$\large [H_P, C_{A,B}] = iC_{[A,P],B} + iC_{\textcolor{red}{[B,P]},A} $$

I think the swapped order of the commutator introduces a sign difference, right? Which is correct?

elif ErG1.getType()=='C' and ErG2.getType()=='H':
errorGens = commute_errors(ErG2,ErG1,weightFlip=-1.0,BCHweight=BCHweight)

elif ErG1.getType()=='H' and ErG2.getType()=='A':
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar as [H,C]. The notes have

$$\large [H_P, A_{A,B}] = -iA_{[A,P],B} - iA_{A,[P,B]} $$

but coded is

$$\large [H_P, A_{A,B}] = -iA_{\textcolor{red}{[P,A]},B} - iA_{A,[P,B]} $$

Again, we have comm order swap in the first term with a potential sign difference. Which is correct?

errorGens = commute_errors(ErG2,ErG1,weightFlip=-1.0,BCHweight=BCHweight)

elif ErG1.getType()=='S' and ErG2.getType()=='S':
errorGens.append( propagatableerrorgen('H', ErG1.getP1(),0 ))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we add what looks like a dummy H label?

elif ErG1.getType()=='S' and ErG2.getType()=='S':
errorGens.append( propagatableerrorgen('H', ErG1.getP1(),0 ))

elif ErG1.getType()=='S' and ErG2.getType()=='C':
Copy link
Contributor Author

@sserita sserita May 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes have

$$\large [S_P, C_{A,B}] = -iA_{AP,BP} -iA_{PB,AP} -\frac{i}{2}\big(A_{{A,B}P,P} + A_{P,P{A,B}}\big) $$

but code is

$$\large [S_P, C_{A,B}] = -iA_{\textcolor{red}{PA},BP} -iA_{PB,\textcolor{red}{PA}} -\frac{i}{2}\big(A_{{A,B}P,P} + A_{P,P{A,B}}\big) $$

Similar to the commutators, this change in multiplication could come with a sign change (depending on whether $[P,A] = 0$ and $[P,B] = 0$).
(Also we are computing ${A,B}$ twice).

errorGens.append( propagatableerrorgen( 'C', [pVec1[1], pVec2[1]] , -1j*wT*pVec1[0]*pVec2[0]))
pVec1 = com(ErG2.getP1() , ErG2.getP2())
pVec2 = com(ErG1.getP1(),pVec1[1])
errorGens.append( propagatableerrorgen( 'A', [ErG1.getP1(), pVec2[1]] ,-.5*wT*pVec1[0]*pVec2[0]))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note has $\frac{i}{2}$ for this weight but here it is just $\frac{1}{2}$.

elif ErG1.getType() == 'A' and ErG1.getType() == 'S':
errorGens = commute_errors(ErG2,ErG1,weightFlip=-1.0,BCHweight=BCHweight)

elif ErG1.getType() == 'C' and ErG2.getType() == 'C':
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, I'll just say that this is way more readable with the intermediate variables. It would be even more readable if pVec* were named things like AP or acomAB or things like that.

Note has

$$\large \begin{align*} [C_{A,B}, C_{P,Q}] &= -i\big(A_{AP,QB} + A_{AQ,BP} - A_{BP,QA} - A_{BQ,PA}\big)\\ &-\frac{i}{2}\big(A_{[P,{A,B}],Q} + A_{[Q,{A,B}],P} + A_{[{P,Q},A],B} + A_{[{P,Q},B],A}\big)\\ &+\frac{i}{4}H_{[{A,B},{P,Q}]} \end{align*} $$

but coded up is

$$\large \begin{align*} [C_{A,B}, C_{P,Q}] &= -i\big(A_{AP,QB} + A_{AQ,\textcolor{red}{PB}} \textcolor{red}{+} A_{BP,QA} \textcolor{red}{+} A_{BQ,PA}\big)\\ &-\frac{i}{2}\big(A_{[P,{A,B}],Q} + A_{[Q,{A,B}],P} + A_{[{P,Q},A],B} + A_{[{P,Q},B],A}\big)\\ &+\frac{i}{4}H_{[{A,B},{P,Q}]} \end{align*} $$

Which is correct? (Also we are recomputing anticommutators)

pVec1=com(P,Q)
pVec2=com(A,B)
pVec3=com(pVec1[1],pVec2[1])
errorGens.append( propagatableerrorgen('H',[pVec3[1]] ,.25*wT*pVec1[0]*pVec2[0]*pVec3[0]))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes have a factor of $\frac{i}{4}$ but this is just $\frac{1}{4}$.

errorGens.append( propagatableerrorgen('C', [pVec2[1] , Q ], .5*1j*wT*pVec1[0]*pVec2[0] ))
pVec1 = acom(A,B)
pVec2 =com(Q,pVec1[1])
errorGens.append( propagatableerrorgen('C',[pVec2[1],P ],-.5*1j*wT*pVec1[0]*pVec2[0] ))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes have $-\frac{1}{2}$ but @ashenmill confirmed that the coded $-\frac{i}{2}$ is correct.

@sserita
Copy link
Contributor Author

sserita commented May 6, 2024

FYI, I have split off another branch from this called feature-nonstim-BCH-tools. The key difference is that the BCH tools in the branch will a) not rely on STIM and b) use existing label classes + defaultdicts to avoid the need to subclass out PropagatableErrorgen.

I'm not planning to make tools that cover all of the functionality Ashe covered, so likely some merge will be required, but I think my branch will have a pretty good idea of what these tools might look like when they are finally merged. I hope this will be at least a good discussion point for us in a week. :)

Added Analytic Propagation
Created an initial implementation of the error_gen Object initial implementation.  Also merged a few functions from the ml branch for compressed sensing purposes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants