A Julia meta-package for accessing the python libraries pymatching
(for MWPM-like decoders) and ldpc
(for BP-like decoders).
The python pymatching module is immediately available:
julia> using PyQDecoders
julia> PyQDecoders.pm
Python: <module 'pymatching' from ...>
Running the example from pymatching
's original Readme:
julia> using PyQDecoders: sps, np, pm
julia> H = sps.csc_matrix(
[1 1 0 0 0;
0 1 1 0 0;
0 0 1 1 0;
0 0 0 1 1])
Python:
<4x5 sparse matrix of type '<class 'numpy.int64'>'
with 8 stored elements in Compressed Sparse Column format>
julia> weights = [4, 3, 2, 3, 4]
5-element Vector{Int64}:
4
3
2
3
4
julia> matching = pm.Matching(H, weights=weights)
Python: <pymatching.Matching object with 4 detectors, 1 boundary node, and 5 edges>
julia> prediction = matching.decode([0, 1, 0, 1])
Python: array([0, 0, 1, 1, 0], dtype=uint8)
julia> prediction, solution_weight = matching.decode([0, 1, 0, 1], return_weight=true);
julia> prediction
Python: array([0, 0, 1, 1, 0], dtype=uint8)
julia> solution_weight
Python: 5.0
The python ldpc module is immediately available:
julia> using PyQDecoders
julia> PyQDecoders.ldpc
Python: <module 'ldpc' from ...>
Running the example from ldpc
's original Readme:
julia> using PyQDecoders: sps, np, ldpc
julia> H = ldpc.codes.rep_code(3) # parity check matrix for the length-3 repetition code
Python:
array([[1, 1, 0],
[0, 1, 1]])
julia> n = H.shape[1] # the codeword length, same as `size(H, 2)`
Python: 3
julia> bpd = ldpc.bp_decoder(
H, # the parity check matrix
error_rate=0.1, # the error rate on each bit
max_iter=n, # the maximum iteration depth for BP
bp_method="product_sum", # BP method. The other option is `minimum_sum'
channel_probs=[nothing] # channel probability probabilities. Will override error rate.
)
Python: <ldpc.bp_decoder.bp_decoder object at 0x...>
julia> error = [0,1,0]
3-element Vector{Int64}:
0
1
0
julia> using PythonCall: PyArray
julia> syndrome = PyArray(H)*error .% 2
2-element Vector{Int64}:
1
1
julia> decoding = bpd.decode(np.array(syndrome))
Python: array([0, 1, 0])
The python fusion-blossom module is immediately available:
julia> using PyQDecoders
julia> PyQDecoders.fb
Python: <module 'fusion_blossom' from ...>
Running the example from fusion-blossom
's original example qec codes demo:
julia> using PyQDecoders: fb;
julia> code = fb.CodeCapacityPlanarCode(d=11, p=0.05, max_half_weight=500);
julia> syndrome = code.generate_random_errors(seed=1000);
julia> initializer = code.get_initializer();
julia> solver = fb.SolverSerial(initializer);
julia> solver.solve(syndrome);
julia> subgraph = solver.subgraph();
julia> println("Minimum Weight Parity Subgraph (MWPS): ", subgraph)
Minimum Weight Parity Subgraph (MWPS): [14, 24, 26, 34, 66, 68, 93, 107, 144, 159, 161, 169]
The python pecos module is immediately available:
julia> using PyQDecoders
julia> PyQDecoders.pecos
Python: <module 'pecos' from ...>
Running the example from pecos
's original example
on 2D version of minimum-weight-perfect-matching decoder:
julia> using PyQDecoders: pecos, pecosdecoders
julia> depolar = pecos.error_gens.DepolarGen(model_level="code_capacity");
julia> surface = pecos.qeccs.Surface4444(distance=3);
julia> logic = pecos.circuits.LogicalCircuit();
julia> logic.append(surface.gate("ideal init |0>"));
julia> logic.append(surface.gate("I", num_syn_extract=1));
julia> circ_runner = pecos.circuit_runners.Standard(seed=1);
julia> state = pecos.simulators.SparseSim(surface.num_qudits);
julia> decode = pecosdecoders.MWPM2D(surface).decode;
julia> meas, err = circ_runner.run(state, logic, error_gen=depolar, error_params=Dict("p" => 0.1));
julia> print("Measurement outcomes (syndrome):", meas)
Measurement outcomes (syndrome):{(1, 0, 7): {3: 1, 5: 1, 15: 1}}
julia> print("Errors introduced:", err)
Errors introduced:{(1, 0, 0): {'after': QuantumCircuit(params={'circuit_type': 'faults'}, ticks=[{'Z': {4}, 'X': {10}}])}}
julia> recovery_circuit = decode(meas);
julia> print("Recovery circuit from MWPM2D decoder:", recovery_circuit)
Recovery circuit from MWPM2D decoder:QuantumCircuit([{'Z': {4}, 'X': {10}}])
The python panqec module is immediately available:
julia> using PyQDecoders
julia> PyQDecoders.panqec
Python: <module 'panqec' from ...>
Running the example from panqec
original tutorial:
julia> using PyQDecoders: panqec, panqecdecoders
julia> Toric2DCode = panqec.codes.Toric2DCode;
julia> PauliErrorModel = panqec.error_models.PauliErrorModel;
julia> MatchingDecoder = panqecdecoders.MatchingDecoder;
julia> code = Toric2DCode(4)
julia> error_model = PauliErrorModel(0.2, 0.3, 0.5)
julia> p = 0.1
julia> decoder = MatchingDecoder(code, error_model, p)
julia> errors = error_model.generate(code, p)
julia> syndrome = code.measure_syndrome(errors)
julia> println("Errors: ", errors)
Errors: [0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
julia> println("Syndrome: ", syndrome)
Syndrome: [0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0]
The python mwpf module is immediately available:
julia> using PyQDecoders
julia> PyQDecoders.mwpf
Python: <module 'mwpf' from ...>
Running the example from mwpf
's original Readme:
julia> using PyQDecoders: mwpf
julia> HyperEdge = mwpf.HyperEdge;
julia> SolverInitializer = mwpf.SolverInitializer;
julia> SolverSerialJointSingleHair = mwpf.SolverSerialJointSingleHair;
julia> SyndromePattern = mwpf.SyndromePattern;
julia> vertex_num = 4;
julia> weighted_edges = [
HyperEdge([0, 1], 100), # [vertices], weight
HyperEdge([1, 2], 100),
HyperEdge([2, 3], 100),
HyperEdge([0], 100), # boundary vertex
HyperEdge([0, 1, 2], 60), # hyperedge
];
julia> initializer = SolverInitializer(vertex_num, weighted_edges);
julia> hyperion = SolverSerialJointSingleHair(initializer);
julia> syndrome = [0, 1, 3];
julia> hyperion.solve(SyndromePattern(syndrome));
julia> hyperion_subgraph = hyperion.subgraph();
julia> println("Hyperion Subgraph: ", hyperion_subgraph)
Hyperion Subgraph: [2, 4]
julia> _, bound = hyperion.subgraph_range();
julia> println("Subgraph Range: ", (bound.lower, bound.upper))
Subgraph Range: (<py OrderedFloat(160.0)>, <py OrderedFloat(160.0)>)