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

how to interpret the matching into a correction as which data qubits are producing errors. #56

Closed
XiangYZhg opened this issue Jan 19, 2023 · 8 comments

Comments

@XiangYZhg
Copy link

Hi,

I am using the package to decode an unrotated SC. I used the function of "decode_to_matched_dets_dict" to get the minimum weight perfect match, which shows the pairs of detectors. However, if I wanted to know what is the shortest path between a pair of detectors to get the data qubits that the path passing through, what would be the function suggested? I have searched the document and found nothing related though. I am presuming maybe I should write it on my own?

Thanks!

@oscarhiggott
Copy link
Owner

There are a few approaches:

  1. The easiest/best is generally to combine stim and pymatching. That way you just write the circuit for your unrotated SC, and the simulation and decoding is all automated. Is there a reason you can't do this here?
  2. If you want to use the pymatching API directly (e.g. give a custom matching graph), for QEC it's generally best to use matching.decode (or matching.decode_batch). matching.decode returns a bitstring prediction (a binary numpy array). If an edge e contains index i in its fault_ids attribute, then if e is flipped in the matching, element prediction[i] is flipped. Thus prediction[i] gives the parity of the number of edges in the solution that contain i in their fault_ids attribute. A fault_id can correspond to a single qubit (e.g. X) error, which is what I think you're looking for, or it can correspond to a logical observable (this is how stim/sinter uses it). Perhaps the documentation for this could be better, with more examples. I'll leave this issue open for now until I do that.
  3. If you want to know the edges given as pairs of detectors, rather than using their fault_ids, you could use the decode_to_edges_array method released yesterday in v2.1.0. This is different to decode_to_matched_dets_dict, which instead gives the endpoints (detection events) of paths in the matching. Also it gives it as an array not a dict, but I could add a dict version if that's useful. Generally option (1) and/or (2) will be much faster than this approach though. For example, you might want to do sparse binary matrix multiplication to check for a logical error, which is implicit or fast with (1) or (2), but is slow in this approach (3).
  4. I'm planning to add methods to the Python API for finding shortest paths between nodes (see issue Add shortest paths methods #49). In your case, this would give you the same information as (3).

Hope this helps!

@XiangYZhg
Copy link
Author

Hi Oscar,

Thank you so much for the reply. It's really helpful, particularly the third point.
1.Regarding the first point, maybe I have a misunderstanding here. I am using stim and pymatching together. It works perfectly if the target is to predict the logical observable. But I am expecting to get the detailed errors as what qubits might have flipped.
2. For the second point, I have run matching.decode over a stim circuit, but the result given by the function just reflects the logical observable. I guess the reason is that in the course of building the matching graph, fault_ids are not really specified except for the logical one.

@oscarhiggott
Copy link
Owner

Ah I see, so you're interested in inspecting which specific error mechanisms have occurred. I agree that you can't get that information from matching.decode when the decoder is configured to use logical observables as fault_ids. One other thing you can do is use the stim detector error model to construct a sparse check matrix and numpy array of priors. You can then sample from the priors yourself in numpy, and when you use the check matrix and log ratio of the priors to construct the pymatching.Matching, each column of the check matrix is assigned a fault id. So with this hack you can inspect what was sampled and decoded (in the basis of detectors, rather than circuit elements). This won't be as fast as using stim for simulation, though.

@XiangYZhg
Copy link
Author

Ah I see, so you're interested in inspecting which specific error mechanisms have occurred. I agree that you can't get that information from matching.decode when the decoder is configured to use logical observables as fault_ids. One other thing you can do is use the stim detector error model to construct a sparse check matrix and numpy array of priors. You can then sample from the priors yourself in numpy, and when you use the check matrix and log ratio of the priors to construct the pymatching.Matching, each column of the check matrix is assigned a fault id. So with this hack you can inspect what was sampled and decoded (in the basis of detectors, rather than circuit elements). This won't be as fast as using stim for simulation, though.

I can roughly capture the idea. But could you shed more lights on "priors"? I don't what the meaning of the word in the context.

@oscarhiggott
Copy link
Owner

By priors I just mean the probabilities of the error mechanisms given knowledge of the error model, but not the syndrome. E.g. for this detector error model (DEM):

error(0.01) D0
error(0.02) D0 D1
error(0.015) D1 D2 L0
error(0.03) D2

by a prior for an error mechanism I'm referring to the error probability assigned to it in the DEM. If you assign an index to each error mechanism in the DEM (e.g. its row number), you can store the priors as a numpy array, and have a check matrix H representing detectors (e.g. each column is an error mechanism, each row is a detector, H[i,j]=1 iff error mechanism j flips detector i). Likewise, you can construct a logical observables matrix L (where L[i,j]=1 iff error mechanism j flips observable i). You should use scipy.sparse.csc_matrix not dense, but e.g. here it would be:

priors = [0.01, 0.02, 0.015, 0.03]
H = [[1, 1, 0, 0],
     [0, 1, 1, 0],
     [0, 0, 1, 1]]
L = [[0, 0, 1, 0]]

You can construct a pymatching.Matching using check matrix H with weights log((1-priors)/priors). You can sample bitstrings from the priors distribution, and check for logical errors using L.

@oscarhiggott
Copy link
Owner

(But I'm not sure what you're trying to do precisely, so if you don't care about speed then maybe decode_to_edges_array already does all you need)

@XiangYZhg
Copy link
Author

(But I'm not sure what you're trying to do precisely, so if you don't care about speed then maybe decode_to_edges_array already does all you need)

Yah, decode_to_edges_array is indeed enough for my case since speed doesn't bother me. But I would love to investigate the check-matrix idea if the performance becomes an issue in the future. Thanks for all the helps and explanation Oscar. I will leave you to decide if the issue should be closed or not, although I've got what I am looking for.

@oscarhiggott
Copy link
Owner

Ok great, I'll close the issue in that case, since I already have an open issue to add more documentation

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

No branches or pull requests

2 participants