From f87ce77682bb889087897cb91a20554150a1cff5 Mon Sep 17 00:00:00 2001 From: Joschka Roffe Date: Fri, 17 Nov 2023 10:43:05 +0000 Subject: [PATCH] updating union find syntax --- docs/source/quantum_decoder.ipynb | 41 ++++++++++++++----- python_test/test_qcodes.py | 4 +- python_test/test_scratch.py | 2 +- .../ldpc/belief_find_decoder/__init__.pyi | 16 +++++--- .../_belief_find_decoder.pxd | 2 +- .../_belief_find_decoder.pyx | 35 ++++++++++++---- .../ldpc/union_find_decoder/__init__.pyi | 4 +- .../_union_find_decoder.pxd | 2 +- .../_union_find_decoder.pyx | 10 ++--- 9 files changed, 79 insertions(+), 37 deletions(-) diff --git a/docs/source/quantum_decoder.ipynb b/docs/source/quantum_decoder.ipynb index a144cff..bbed9ba 100644 --- a/docs/source/quantum_decoder.ipynb +++ b/docs/source/quantum_decoder.ipynb @@ -58,18 +58,30 @@ "\n", "The belief propagation + union-find decoder (belief-find) is an alternative to BP+OSD for decoding quantum LDPC codes. Belief-find first attempts to solve the decoding using belief propagation. If this fails, a union-find decoder is run as a post-processor using the output of BP to guide cluster growth. The `LDPC` package implements two versions of belief-find:\n", "\n", - "1) **Peeling belief-find**. This approach uses a peeling decoder to solve the local decoding problem on each code. Peeling uinon-find is limited to decoding codes that have point like syndromes. e.g, the surface and toric codes. The peeling version of union-find decoder was first proposed by Delfosse & Nickerson in (https://arxiv.org/abs/1709.06218). Peeling belief-find was first proposed and implemented by Oscar Higgott (https://arxiv.org/abs/2203.04948).\n", + "1) **Peeling belief-find**. This approach uses a peeling decoder to solve the local decoding problem in each cluster. Peeling uinon-find is limited to decoding codes that have point like syndromes. e.g, the surface and toric codes. The peeling version of union-find decoder was first proposed by Delfosse & Nickerson in (https://arxiv.org/abs/1709.06218). Peeling belief-find was first proposed and implemented by Oscar Higgott (https://arxiv.org/abs/2203.04948).\n", "\n", "2) **Cluster-inversion belief-find**. This approach solves the local decoding problem on each cluster using matrix inverison. Cluster-inversion union find can be applied to any quantum LDPC code. Matrix inversion find was first proposed by Delfosse et al. (https://arxiv.org/abs/2103.08049), and later improved by Berent et al. (https://arxiv.org/abs/2209.01180). As far as I am aware, the `LDPCv2` has the first implementation of cluster-inversion belief-find.\n", "\n", - "The `LDPC` implementation of belief-find inherits from the `ldpc.BpDecoder` class. Examples of belief-find in use are given below:" + "The `LDPC` implementation of belief-find inherits from the `ldpc.BpDecoder` class.\n", + "\n", + "An example of the cluster-inversion belief-find decoder is below:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Syndrome: [1 0 0 1 0]\n", + "Decoding: [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 0 0]\n", + "Decoding syndrome: [1 0 0 1 0]\n" + ] + } + ], "source": [ "import numpy as np\n", "import ldpc.codes\n", @@ -84,7 +96,7 @@ " bp_method = 'product_sum',\n", " max_iter = 7,\n", " schedule = 'serial',\n", - " matrix_solve = True, # If set to True, union-find clusters are solved by matrix inversion\n", + " uf_method = \"inversion\", # Union-find clusters are solved by matrix inversion\n", " bits_per_step = 1 ## this is the number of bits by which clusters are expanded in each growth step \n", " )\n", "\n", @@ -101,12 +113,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The peeling version of belief-find can be activated by setting `matrix_solve=False`. This method only works for parity check matrix that yield point-like syndromes. An example of using peeling belief-find on the repetition code is show below:" + "The peeling version of belief-find can be activated by setting `uf_method=\"peeling\"`. This method only works for parity check matrix that yield point-like syndromes. An example of using peeling belief-find on the repetition code is show below:" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -123,7 +135,7 @@ " bp_method = 'product_sum',\n", " max_iter = 7,\n", " schedule = 'serial',\n", - " matrix_solve = False, # If matrix_solve is set to False, union-find clusters are solved using a peeling decoder\n", + " uf_method = \"peeling\", # If uf_method is set to False, union-find clusters are solved using a peeling decoder\n", " bits_per_step = 1 ## this is the number of bits by which clusters are expanded in each growth step \n", " )\n", "\n" @@ -131,15 +143,15 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Decoding: [1 1 1 1 1 1 0 0 0 0 0 0 1 0 0]\n", - "Decoding syndrome: [0 0 0 0 0 1 0 0 0 0 0 1 1 0 1]\n" + "Decoding: [0 0 0 1 0 1 0 1 0 1 0 0 0 0 1]\n", + "Decoding syndrome: [0 0 1 1 1 1 1 1 1 1 0 0 0 1 1]\n" ] } ], @@ -152,6 +164,13 @@ "decoding_syndrome = H@decoding % 2\n", "print(f\"Decoding syndrome: {decoding_syndrome}\")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/python_test/test_qcodes.py b/python_test/test_qcodes.py index ff8a69a..423c835 100644 --- a/python_test/test_qcodes.py +++ b/python_test/test_qcodes.py @@ -74,7 +74,7 @@ def test_400_16_6_hgp(): decoder = BpOsdDecoder(hx, error_rate=error_rate, max_iter=5, bp_method="ps", schedule="parallel", osd_method = "osd0") ler, min_logical, speed = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Prod-sum osd-0 parallel schedule") - decoder = BeliefFindDecoder(hx, error_rate=error_rate, max_iter=5, bp_method="ms", ms_scaling_factor=0.625, schedule="parallel", matrix_solve=True, bits_per_step=1) + decoder = BeliefFindDecoder(hx, error_rate=error_rate, max_iter=5, bp_method="ms", ms_scaling_factor=0.625, schedule="parallel", uf_method="inversion", bits_per_step=1) ler, min_logical, speed = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Belief-find parallel schedule") @@ -102,5 +102,5 @@ def test_toric_20(): decoder = BpOsdDecoder(hx, error_rate=error_rate, max_iter=5, bp_method="ps", schedule="parallel", osd_method = "osd0") ler, min_logical, speed = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Prod-sum osd-0 parallel schedule") - decoder = BeliefFindDecoder(hx, error_rate=error_rate, max_iter=5, bp_method="ms", ms_scaling_factor=0.625, schedule="parallel", matrix_solve=False, bits_per_step=1) + decoder = BeliefFindDecoder(hx, error_rate=error_rate, max_iter=5, bp_method="ms", ms_scaling_factor=0.625, schedule="parallel", uf_method="peeling", bits_per_step=1) ler, min_logical, speed = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Belief-find parallel schedule") \ No newline at end of file diff --git a/python_test/test_scratch.py b/python_test/test_scratch.py index 44bd125..3e4569e 100644 --- a/python_test/test_scratch.py +++ b/python_test/test_scratch.py @@ -40,7 +40,7 @@ bp_method = 'product_sum', max_iter = 1, schedule = 'serial', - matrix_solve = True, # If matrix_solve is set to False, union-find clusters are solved using a peeling decoder + uf_method = True, # If uf_method is set to False, union-find clusters are solved using a peeling decoder bits_per_step = 1 ## this is the number of bits by which clusters are expanded in each growth step ) diff --git a/src_python/ldpc/belief_find_decoder/__init__.pyi b/src_python/ldpc/belief_find_decoder/__init__.pyi index b4ea528..44d230c 100644 --- a/src_python/ldpc/belief_find_decoder/__init__.pyi +++ b/src_python/ldpc/belief_find_decoder/__init__.pyi @@ -7,7 +7,7 @@ class BeliefFindDecoder(BpDecoderBase): The BeliefFindDecoder is designed to decode binary linear codes by initially attempting BP decoding, and if that fails, it falls back to the Union Find Decoder algorithm. The UFD algorithm is based on the principles outlined in https://arxiv.org/abs/1709.06218, with an option to utilise a more general version as described in - https://arxiv.org/abs/2103.08049 for LDPC codes by setting `matrix_solve=True`. + https://arxiv.org/abs/2103.08049 for LDPC codes by setting `uf_method=True`. Parameters ---------- @@ -33,9 +33,10 @@ class BeliefFindDecoder(BpDecoderBase): serial_schedule_order : Optional[List[int]], optional A list of integers specifying the serial schedule order. Must be of length equal to the block length of the code, by default None. - matrix_solve : bool, optional - If set to True, implements the more general version of union find as described in - https://arxiv.org/abs/2103.08049 for LDPC codes, by default True. + uf_method : str, optional + The method used to solve the local decoding problem in each cluster. Choose from: 1) 'inversion' or 2) 'peeling'. + By default set to 'inversion'. The 'peeling' method is only suitable for LDPC codes with point like syndromes. + The inversion method can be applied to any parity check matrix. bits_per_step : int, optional Specifies the number of bits added to the cluster in each step of the UFD algorithm. If no value is provided, this is set the block length of the code. @@ -43,7 +44,7 @@ class BeliefFindDecoder(BpDecoderBase): ----- The `BeliefFindDecoder` class leverages soft information outputted by the BP decoder to guide the cluster growth in the UFD algorithm. The number of bits added to the cluster in each step is controlled by the `bits_per_step` parameter. - The `matrix_solve` parameter activates a more general version of the UFD algorithm suitable for LDPC codes when set to True. + The `uf_method` parameter activates a more general version of the UFD algorithm suitable for LDPC codes when set to True. """ @@ -70,3 +71,8 @@ class BeliefFindDecoder(BpDecoderBase): If the length of the input syndrome is not equal to the length of the code. """ + + @property + def uf_method(self): + @uf_method.setter + def uf_method(self, uf_method: str): \ No newline at end of file diff --git a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd index a88912e..85e02fe 100644 --- a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd +++ b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd @@ -21,7 +21,7 @@ cdef class BeliefFindDecoder(BpDecoderBase): cdef uf_decoder_cpp* ufd cdef vector[uint8_t] bf_decoding cdef vector[uint8_t] residual_syndrome - cdef bool matrix_solve + cdef str uf_method cdef int bits_per_step diff --git a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx index 1124fc9..c8ddf8b 100644 --- a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx +++ b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx @@ -11,7 +11,7 @@ cdef class BeliefFindDecoder(BpDecoderBase): The BeliefFindDecoder is designed to decode binary linear codes by initially attempting BP decoding, and if that fails, it falls back to the Union Find Decoder algorithm. The UFD algorithm is based on the principles outlined in https://arxiv.org/abs/1709.06218, with an option to utilise a more general version as described in - https://arxiv.org/abs/2103.08049 for LDPC codes by setting `matrix_solve=True`. + https://arxiv.org/abs/2103.08049 for LDPC codes by setting `uf_method=True`. Parameters ---------- @@ -37,9 +37,10 @@ cdef class BeliefFindDecoder(BpDecoderBase): serial_schedule_order : Optional[List[int]], optional A list of integers specifying the serial schedule order. Must be of length equal to the block length of the code, by default None. - matrix_solve : bool, optional - If set to True, implements the more general version of union find as described in - https://arxiv.org/abs/2103.08049 for LDPC codes, by default True. + uf_method : str, optional + The method used to solve the local decoding problem in each cluster. Choose from: 1) 'inversion' or 2) 'peeling'. + By default set to 'inversion'. The 'peeling' method is only suitable for LDPC codes with point like syndromes. + The inversion method can be applied to any parity check matrix. bits_per_step : int, optional Specifies the number of bits added to the cluster in each step of the UFD algorithm. If no value is provided, this is set the block length of the code. @@ -47,18 +48,18 @@ cdef class BeliefFindDecoder(BpDecoderBase): ----- The `BeliefFindDecoder` class leverages soft information outputted by the BP decoder to guide the cluster growth in the UFD algorithm. The number of bits added to the cluster in each step is controlled by the `bits_per_step` parameter. - The `matrix_solve` parameter activates a more general version of the UFD algorithm suitable for LDPC codes when set to True. + The `uf_method` parameter activates a more general version of the UFD algorithm suitable for LDPC codes when set to True. """ def __cinit__(self, pcm: Union[np.ndarray, scipy.sparse.spmatrix], error_rate: Optional[float] = None, error_channel: Optional[List[float]] = None, max_iter: Optional[int] = 0, bp_method: Optional[str] = 'minimum_sum', ms_scaling_factor: Optional[float] = 1.0, schedule: Optional[str] = 'parallel', omp_thread_count: Optional[int] = 1, - random_schedule_seed: Optional[int] = 0, serial_schedule_order: Optional[List[int]] = None, matrix_solve: bool = True, bits_per_step:int = 0, input_vector_type: str = "syndrome"): + random_schedule_seed: Optional[int] = 0, serial_schedule_order: Optional[List[int]] = None, uf_method: str = True, bits_per_step:int = 0, input_vector_type: str = "syndrome"): self.MEMORY_ALLOCATED=False self.ufd = new uf_decoder_cpp(self.pcm[0]) self.bf_decoding.resize(self.n) #C vector for the bf decoding self.residual_syndrome.resize(self.m) #C vector for the bf decoding - self.matrix_solve = matrix_solve + self.uf_method = uf_method if bits_per_step == 0: self.bits_per_step = pcm.shape[1] else: @@ -114,9 +115,9 @@ cdef class BeliefFindDecoder(BpDecoderBase): for i in range(self.n): out[i] = self.bpd.decoding[i] if not self.bpd.converge: - if self.matrix_solve: + if self.uf_method == "inversion": self.ufd.decoding = self.ufd.matrix_decode(self._syndrome, self.bpd.log_prob_ratios,self.bits_per_step) - else: + elif self.uf_method == "peeling": self.ufd.decoding = self.ufd.peel_decode(self._syndrome, self.bpd.log_prob_ratios,self.bits_per_step) for i in range(self.n): # self.bf_decoding[i] = self.ufd.decoding[i]^self.bpd.decoding[i] @@ -124,5 +125,21 @@ cdef class BeliefFindDecoder(BpDecoderBase): return out + + @property + def uf_method(self): + return self.uf_method + + @uf_method.setter + def uf_method(self, uf_method: str): + if uf_method.lower() in ["inversion", "invert", "matrix"]: + self.uf_method = "inversion" + elif uf_method.lower() in ["peeling", "peel"]: + self.uf_method = "peeling" + else: + raise ValueError(f"Invalid UF method: {uf_method}. Must be one of 'inversion' or 'peeling'.") + + + # def maximum_cluster_size(self): # return self.ufd.maximum_cluster_size[0], self.ufd.maximum_cluster_size[1] \ No newline at end of file diff --git a/src_python/ldpc/union_find_decoder/__init__.pyi b/src_python/ldpc/union_find_decoder/__init__.pyi index 0d4164f..a49fe1d 100644 --- a/src_python/ldpc/union_find_decoder/__init__.pyi +++ b/src_python/ldpc/union_find_decoder/__init__.pyi @@ -5,14 +5,14 @@ class UnionFindDecoder: A decoder class that implements the Union Find Decoder (UFD) algorithm to decode binary linear codes. The decoder operates on a provided parity-check matrix (PCM) and can function with or without soft information from a channel. The UFD algorithm can be run in two modes: matrix solve and peeling, controlled by the - `matrix_solve` flag. + `uf_method` flag. Parameters ---------- pcm : Union[np.ndarray, spmatrix] The parity-check matrix (PCM) of the code. This should be either a dense matrix (numpy ndarray) or a sparse matrix (scipy sparse matrix). - matrix_solve : bool, optional + uf_method : bool, optional If True, the decoder operates in matrix solve mode. If False, it operates in peeling mode. Default is False. """ diff --git a/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd b/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd index 9249d3e..0bcce64 100644 --- a/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd +++ b/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd @@ -25,5 +25,5 @@ cdef class UnionFindDecoder(): cdef BpSparse* pcm cdef vector[uint8_t] _syndrome cdef vector[double] uf_llrs - cdef bool matrix_solve + cdef bool uf_method cdef int bits_per_step \ No newline at end of file diff --git a/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx b/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx index 361ccb0..304bb9f 100644 --- a/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx +++ b/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx @@ -48,19 +48,19 @@ cdef class UnionFindDecoder: A decoder class that implements the Union Find Decoder (UFD) algorithm to decode binary linear codes. The decoder operates on a provided parity-check matrix (PCM) and can function with or without soft information from a channel. The UFD algorithm can be run in two modes: matrix solve and peeling, controlled by the - `matrix_solve` flag. + `uf_method` flag. Parameters ---------- pcm : Union[np.ndarray, spmatrix] The parity-check matrix (PCM) of the code. This should be either a dense matrix (numpy ndarray) or a sparse matrix (scipy sparse matrix). - matrix_solve : bool, optional + uf_method : bool, optional If True, the decoder operates in matrix solve mode. If False, it operates in peeling mode. Default is False. """ - def __cinit__(self, pcm: Union[np.ndarray, spmatrix], matrix_solve: bool = False): + def __cinit__(self, pcm: Union[np.ndarray, spmatrix], uf_method: str = False): self.MEMORY_ALLOCATED=False @@ -78,7 +78,7 @@ cdef class UnionFindDecoder: self.ufd = new uf_decoder_cpp(self.pcm[0]) self._syndrome.resize(self.m) #C vector for the syndrome self.uf_llrs.resize(self.n) #C vector for the log-likehood ratios - self.matrix_solve = matrix_solve + self.uf_method = uf_method self.MEMORY_ALLOCATED=True def __del__(self): @@ -142,7 +142,7 @@ cdef class UnionFindDecoder: else: self.bits_per_step = bits_per_step - if self.matrix_solve: + if self.uf_method: if llrs is not None: self.ufd.decoding = self.ufd.matrix_decode(self._syndrome, self.uf_llrs,self.bits_per_step) else: