Belief propagation (BP) decoding
To decode using belief propagation, first load an instance of the ldpc.BpDecoder class.
[1]:
import numpy as np
import ldpc.codes
from ldpc import BpDecoder
H=ldpc.codes.rep_code(3) #parity check matrix for the length-3 repetition code
n=H.shape[1] #the codeword length
bpd = BpDecoder(
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'
)
Received vector decoding
Given a corrupted codeword, the bp_decoder.decode will provide an estimate of its unerrored form. For example, consider the case where we are encoding via a three-bit repetition code:
[2]:
codeword=np.array([1,1,1])
If the above codeword is subject to an error on its first bit the received vector is given by
[3]:
received_vector=np.array([0,1,1])
The above vector can be corrected using the bp_decoder.decode as follows:
[4]:
decoded_codeword=bpd.decode(received_vector)
print(decoded_codeword)
[1 1 1]
Syndrome decoding
In syndrome decoding, the error syndrome is input to bp_decoder.decode function. This is useful in settings where the codeword cannot be directly measured. eg. in quantum error correction. The output of the syndrome recovery is an estimate of the error.
[5]:
H=ldpc.codes.rep_code(3) #parity check matrix for the length-3 repetition code
n=H.shape[1] #the codeword length
bpd = BpDecoder(
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'
)
error = np.array([0,1,0])
syndrome = H@error %2 # the syndrome of the error
decoding=bpd.decode(syndrome)
print(f"Error: {error}")
print(f"Syndrome: {syndrome}")
print(f"Decoding: {decoding}")
Error: [0 1 0]
Syndrome: [1 1]
Decoding: [0 1 0]
Assymetric error channels
If the code bits are subject to different error rates, an error_channel vector can be provided instead of the error rate. The error channel specifies the probability of an error on each code bit. For example, consider the case below
[6]:
bpd=BpDecoder(
H,
max_iter=n,
bp_method="product_sum",
error_channel=[0.1,0,0.1] #channel probability probabilities. Will overide error rate.
)
error=np.array([1,0,1])
syndrome=H@error%2
decoding=bpd.decode(syndrome)
print(f"Error: {error}")
print(f"Syndrome: {syndrome}")
print(f"Decoding: {decoding}")
Error: [1 0 1]
Syndrome: [1 1]
Decoding: [1 0 1]
Example: error correction over the binary symmetric channel
[7]:
import numpy as np
from ldpc.codes import rep_code
from ldpc import BpDecoder
n=13
error_rate=0.3
runs=5
H=rep_code(n)
#BP decoder class. Make sure this is defined outside the loop
bpd=BpDecoder(H,error_rate=error_rate,max_iter=n,bp_method="product_sum")
error=np.zeros(n).astype(int) #error vector
for _ in range(runs):
for i in range(n):
if np.random.random()<error_rate:
error[i]=1
else: error[i]=0
syndrome=H@error %2 #calculates the error syndrome
print(f"Error: {error}")
print(f"Syndrome: {syndrome}")
decoding=bpd.decode(syndrome)
print(f"Decoding: {decoding}\n")
Error: [1 0 1 0 0 0 1 1 1 1 0 1 0]
Syndrome: [1 1 1 0 0 1 0 0 0 1 1 1]
Decoding: [0 1 0 1 1 1 0 0 0 0 1 0 1]
Error: [0 0 0 0 0 0 0 0 1 0 0 0 0]
Syndrome: [0 0 0 0 0 0 0 1 1 0 0 0]
Decoding: [0 0 0 0 0 0 0 0 1 0 0 0 0]
Error: [0 0 0 0 1 0 1 1 1 1 1 0 1]
Syndrome: [0 0 0 1 1 1 0 0 0 0 1 1]
Decoding: [1 1 1 1 0 1 0 0 0 0 0 1 0]
Error: [0 0 1 0 0 0 0 0 1 1 1 0 1]
Syndrome: [0 1 1 0 0 0 0 1 0 0 1 1]
Decoding: [0 0 1 0 0 0 0 0 1 1 1 0 1]
Error: [0 0 1 0 0 0 1 1 0 0 0 0 1]
Syndrome: [0 1 1 0 0 1 0 1 0 0 0 1]
Decoding: [0 0 1 0 0 0 1 1 0 0 0 0 1]
Serial or Parallel Schedules
LDPCv2 has the option to switch between ‘parallel’ and ‘serial’ deocoding schedules. The default option is the parallel schedule. Serial scheduling can lead to better convergence in certain circumstances. Serial scheduling can be activated as follows:
[8]:
H=ldpc.codes.rep_code(3) #parity check matrix for the length-3 repetition code
n=H.shape[1] #the codeword length
bpd = BpDecoder(
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',
schedule = "serial" # the BP schedule
)
error = np.array([0,1,0])
syndrome = H@error %2 # the syndrome of the error
decoding=bpd.decode(syndrome)
print(f"Error: {error}")
print(f"Syndrome: {syndrome}")
print(f"Decoding: {decoding}")
Error: [0 1 0]
Syndrome: [1 1]
Decoding: [0 1 0]
Monte-Carlo Simulation Class
The ldpc.monte_carlo_simulation.MonteCarloBscSimulation provides a convenient way of testing the performance of binary linear codes over the binary symmetric channel.
[8]:
import numpy as np
import ldpc.codes
from ldpc import BpDecoder
from ldpc.monte_carlo_simulation import MonteCarloBscSimulation
import ldpc.code_util
H = np.array([[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1],
[1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0],
[1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0]])
n,k,d = ldpc.code_util.compute_code_parameters(H)
print(f"[n={n}, k={k}, d={d}]")
error_rate = 0.01
dec = BpDecoder(H, error_rate=error_rate, max_iter = 0, bp_method="minimum_sum")
mc_sim = MonteCarloBscSimulation(H, error_rate = error_rate, target_run_count=10000, Decoder = dec, tqdm_disable=True)
mc_sim.run()
[n=14, k=5, d=5]
[8]:
{'logical_error_rate': 0.0019,
'logical_error_rate_eb': 0.0004354756020720334,
'error_rate': 0.01,
'run_count': 10000,
'fail_count': 19}
[ ]: