Skip to content

QuantumSavory/PyQDecoders.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A Julia meta-package for accessing the python libraries pymatching (for MWPM-like decoders) and ldpc (for BP-like decoders).

How to use

pymatching

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

ldpc

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])

fusion-blossom

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]

pecos

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}}])

panqec

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]

mwpf

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)>)

Contributors 3

  •  
  •  
  •  

Languages