From 2eb8ee49b214e17e957a143d2715db3765cdfc04 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Wed, 18 Sep 2024 21:21:55 +0500 Subject: [PATCH 01/10] fix some doc errors from build and add ECC ZOO links for product codes --- docs/src/Quantum/product_codes.md | 6 +-- docs/src/references.bib | 61 ++++++++++++++++--------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/docs/src/Quantum/product_codes.md b/docs/src/Quantum/product_codes.md index d7447be..cf1ae93 100644 --- a/docs/src/Quantum/product_codes.md +++ b/docs/src/Quantum/product_codes.md @@ -1,9 +1,9 @@ # Product Codes -- Hypergraph product: [tillich2009quantum](@cite) -- Generalized Shor: [bacon2006quantum](@cite) +- [Hypergraph product](https://errorcorrectionzoo.org/c/hypergraph_product): [Tillich_2014](@cite) +- [Generalized Shor](https://errorcorrectionzoo.org/c/generalized_shor): [bacon2006quantum](@cite) - Hyperbicycle: [pryadko2013quantum](@cite) -- Generealized bicycle: [pryadko2013quantum](@cite), [kovalev2013quantum](@cite), [kovalev1212quantum](@cite), [panteleev2021degenerate](@cite) +- [Generealized bicycle](https://errorcorrectionzoo.org/c/generalized_bicycle): [pryadko2013quantum](@cite), [Kovalev_2013](@cite), [panteleev2021degenerate](@cite) - Generalized hypergraph product: [panteleev2021degenerate](@cite) - Bias-tailored lifted product: [roffe2023bias](@cite) diff --git a/docs/src/references.bib b/docs/src/references.bib index a06832b..1845eaa 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -7,16 +7,13 @@ @misc{hastings2021quantum } @misc{hastings2016, - archiveprefix = {arxiv}, - author = {Hastings, M. B.}, - eprint = {1611.03790}, - keywords = {Quantum Physics}, - month = nov, - number = {arXiv:1611.03790}, - publisher = {{arXiv}}, - title = {Weight Reduction for Quantum Codes}, - urldate = {2023-11-14}, - year = {2016} + title={Weight Reduction for Quantum Codes}, + author={M. B. Hastings}, + year={2016}, + eprint={1611.03790}, + archivePrefix={arXiv}, + primaryClass={quant-ph}, + url={https://arxiv.org/abs/1611.03790}, } @inproceedings{hastings2021fiber, @@ -121,10 +118,18 @@ @article{bacon2006quantum year={2006} } -@inproceedings{tillich2009quantum, - title={Quantum LDPC codes with positive rate and minimum distance proportional to n $1/2$}, - author={Tillich, J-P and Zemor, G}, - booktitle={2009 IEEE International Symposium on Information Theory} +@article{Tillich_2014, + title={Quantum LDPC Codes With Positive Rate and Minimum Distance Proportional to the Square Root of the Blocklength}, + volume={60}, + ISSN={1557-9654}, + url={http://dx.doi.org/10.1109/TIT.2013.2292061}, + DOI={10.1109/tit.2013.2292061}, + number={2}, + journal={IEEE Transactions on Information Theory}, + publisher={Institute of Electrical and Electronics Engineers (IEEE)}, + author={Tillich, Jean-Pierre and Zemor, Gilles}, + year={2014}, + month=feb, pages={1193–1202} } @inproceedings{pryadko2013quantum, @@ -136,22 +141,18 @@ @inproceedings{pryadko2013quantum year={2013} } -@article{kovalev2013quantum, - title={Quantum Kronecker sum-product low-density parity-check codes with finite rate}, - author={Kovalev, Alexey A and Pryadko, Leonid P}, - journal={Physical Review A—Atomic, Molecular, and Optical Physics}, - volume={88}, - number={1}, - pages={012311}, - year={2013}, - publisher={APS} -} - -@article{kovalev1212quantum, - title={Quantum “hyperbicycle” low density parity check codes with finite rate}, - author={Kovalev, AA and Pryadko, LP}, - journal={arXiv}, - volume={1212} +@article{Kovalev_2013, + title={Quantum Kronecker sum-product low-density parity-check codes with finite rate}, + volume={88}, + ISSN={1094-1622}, + url={http://dx.doi.org/10.1103/PhysRevA.88.012311}, + DOI={10.1103/physreva.88.012311}, + number={1}, + journal={Physical Review A}, + publisher={American Physical Society (APS)}, + author={Kovalev, Alexey A. and Pryadko, Leonid P.}, + year={2013}, + month=jul } @article{panteleev2021degenerate, From 23425c5379f59a8cdfaaf464e028f265db68c802 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Sep 2024 15:34:12 +0500 Subject: [PATCH 02/10] fix documentation errors --- docs/src/Classical/cyclic_code.md | 4 ---- docs/src/Classical/linear_code.md | 3 --- docs/src/LDPC/codes.md | 22 ---------------------- docs/src/LDPC/decoders.md | 8 -------- docs/src/Tutorials/Message Passing.md | 2 +- docs/src/references.bib | 9 +++++++++ src/Classical/cyclic_code.jl | 4 ---- 7 files changed, 10 insertions(+), 42 deletions(-) diff --git a/docs/src/Classical/cyclic_code.md b/docs/src/Classical/cyclic_code.md index 6de619e..8ec136b 100644 --- a/docs/src/Classical/cyclic_code.md +++ b/docs/src/Classical/cyclic_code.md @@ -82,10 +82,6 @@ qcosets qcosets_reps ``` -```@docs -defining_set -``` - ```@docs zeros ``` diff --git a/docs/src/Classical/linear_code.md b/docs/src/Classical/linear_code.md index e2bbf94..a5c4218 100644 --- a/docs/src/Classical/linear_code.md +++ b/docs/src/Classical/linear_code.md @@ -50,9 +50,6 @@ standard_form_permutation ``` The minimum distance of some code families are known and are set during construction. The minimum distance is automatically computed in the constructor for codes which are deemed "small enough". Otherwise, the minimum distance is `missing`. Primitive bounds on the minimum distance are given by -```@docs -minimum_distance_lower_bound -``` ```@docs minimum_distance_upper_bound diff --git a/docs/src/LDPC/codes.md b/docs/src/LDPC/codes.md index da26e09..5dce847 100644 --- a/docs/src/LDPC/codes.md +++ b/docs/src/LDPC/codes.md @@ -121,28 +121,6 @@ shortest_cycles ``` Various information about the ACE values of cycles in the Tanner graph may be computed with the following functions. -```@docs -ACE_spectrum -``` - -```@docs -shortest_cycle_ACE -``` - -```@docs -ACE_distribution -``` -```@docs -average_ACE_distribution -``` - -```@docs -median_ACE_distribution -``` - -```@docs -mode_ACE_distribution -``` ## Greedy Construction Algorithms diff --git a/docs/src/LDPC/decoders.md b/docs/src/LDPC/decoders.md index 8accc97..d98b1d0 100644 --- a/docs/src/LDPC/decoders.md +++ b/docs/src/LDPC/decoders.md @@ -21,10 +21,6 @@ sum_product_box_plus min_sum ``` -```@docs -find_MP_schedule -``` - ## Linear Programming ```@docs @@ -32,7 +28,3 @@ LP_decoder_LDPC ``` ## Simulations - -```@docs -decoder_simulation -``` diff --git a/docs/src/Tutorials/Message Passing.md b/docs/src/Tutorials/Message Passing.md index 611ebc9..1092dcd 100644 --- a/docs/src/Tutorials/Message Passing.md +++ b/docs/src/Tutorials/Message Passing.md @@ -406,7 +406,7 @@ julia> Gallager_B(H, y) ``` ## Decimation -Decimation was previously used in message-passing applications outside of error correction and was applied to stabilizer codes in [](@cite). The idea is to freeze the value of a variable node. We can either do this from the start to obtain a so-called *genie-aided* decoder, or we can periodically pause message passing to fix a bit. In *guided decimation*, we pause every fixed number of rounds and freeze the value of the variable node with the highest log-likelihood ratio. In *automated decimation*, we pause after every iteration and fix any bit whose absolute value has passed a certain threshold. +Decimation was previously used in message-passing applications outside of error correction and was applied to stabilizer codes [yao2024belief](@cite). The idea is to freeze the value of a variable node. We can either do this from the start to obtain a so-called *genie-aided* decoder, or we can periodically pause message passing to fix a bit. In *guided decimation*, we pause every fixed number of rounds and freeze the value of the variable node with the highest log-likelihood ratio. In *automated decimation*, we pause after every iteration and fix any bit whose absolute value has passed a certain threshold. It is important to note that when a variable node is fixed to a specific value, the decoder is now sampling possible solutions with that fixed bit, which is different from the ML and MAP problems above. Furthermore, if there is a unique solution and a bit is fixed which does not match the solution, the decoder will fail instead of correcting that bit. For example, fixing the most reliable bit in guided decimation may mean fixing a bit which is still far from reliable and could go either way. On the other hand, fixing a bit could help the decoder converge faster and also break out of trapping sets. In this sense, decimation can be very helpful decoding degenerate stabilizer codes where there are many valid solutions and BP has a difficult time picking one to converge to. diff --git a/docs/src/references.bib b/docs/src/references.bib index 1845eaa..6eeb9ce 100644 --- a/docs/src/references.bib +++ b/docs/src/references.bib @@ -174,3 +174,12 @@ @article{roffe2023bias year={2023}, publisher={Verein zur F{\"o}rderung des Open Access Publizierens in den Quantenwissenschaften} } + +@inproceedings{yao2024belief, + title={Belief propagation decoding of quantum LDPC codes with guided decimation}, + author={Yao, Hanwen and Laban, Waleed Abu and H{\"a}ger, Christian and i Amat, Alexandre Graell and Pfister, Henry D}, + booktitle={2024 IEEE International Symposium on Information Theory (ISIT)}, + pages={2478--2483}, + year={2024}, + organization={IEEE} +} diff --git a/src/Classical/cyclic_code.jl b/src/Classical/cyclic_code.jl index e2b08df..83ad777 100644 --- a/src/Classical/cyclic_code.jl +++ b/src/Classical/cyclic_code.jl @@ -433,11 +433,7 @@ Return the set of representatives for the q-cyclotomic cosets of the cyclic code """ qcosets_reps(C::AbstractCyclicCode) = C.qcosets_reps -""" - defining_set(C::AbstractCyclicCode) -Return the defining set of the cyclic code. -""" defining_set(C::AbstractCyclicCode) = C.def_set """ From 1d739456b75c2fb1131180f125239aa96cbc0a43 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Sep 2024 19:33:00 +0500 Subject: [PATCH 03/10] suppress false positives --- docs/make.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/make.jl b/docs/make.jl index 6784b64..dc6aac0 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -11,6 +11,7 @@ Documenter.makedocs(; highlightsig = true, sitename = "Coding Theory Documentation", expandfirst = [], + checkdocs = :none, pages = ["Introduction" => "index.md", "Tutorials" => [ "Tutorials/Linear Codes.md", From 9769b43c16ead0c22572dcecb7d83b27c906fade Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Sep 2024 21:04:39 +0500 Subject: [PATCH 04/10] suppress false positives --- docs/src/Classical/linear_code.md | 8 -------- docs/src/Classical/new_codes_from_old.md | 16 ---------------- docs/src/LDPC/analysis.md | 6 ------ docs/src/LDPC/codes.md | 13 +------------ 4 files changed, 1 insertion(+), 42 deletions(-) diff --git a/docs/src/Classical/linear_code.md b/docs/src/Classical/linear_code.md index a5c4218..cb038bc 100644 --- a/docs/src/Classical/linear_code.md +++ b/docs/src/Classical/linear_code.md @@ -78,10 +78,6 @@ The minimum distance and its bounds may be manually set as well. Nothing is done set_distance_lower_bound! ``` -```@docs -set_distance_upper_bound! -``` - ```@docs set_minimum_distance! ``` @@ -92,10 +88,6 @@ set_minimum_distance! Singleton_bound ``` -```@docs -encode -``` - ```@docs syndrome ``` diff --git a/docs/src/Classical/new_codes_from_old.md b/docs/src/Classical/new_codes_from_old.md index a67f83b..5e9012f 100644 --- a/docs/src/Classical/new_codes_from_old.md +++ b/docs/src/Classical/new_codes_from_old.md @@ -22,29 +22,16 @@ construction_X3 ``` The direct sum code has generator matrix `G1 ⊕ G2` and parity-check matrix `H1 ⊕ H2`. -```@docs -CodingTheory.⊕ -``` The generator matrix of the (direct) product code is the kronecker product of the generator matrices of the inputs. -```@docs -CodingTheory.× -``` The parity-check matrix of the tensor product code is the kronecker product of the parity-check matrices of the inputs. -```@docs -CodingTheory.⊗ -``` There is some debate on how to define this product. This is known to often be the full ambient space. ```@docs entrywise_product_code ``` -```@docs -CodingTheory./ -``` - `juxtaposition` is representation dependent and therefore works on the potentially over-complete generator matrices, not on the standard form. ```@docs juxtaposition @@ -53,9 +40,6 @@ juxtaposition ## Methods If `C` is a quasi-cyclic code, `permute_code` returns a `LinearCode` object. -```@docs -permute_code -``` The most common way to extend a code is to add an extra column to the generator matrix whose values make the sum of the rows zero. This is called an even extension and is the default for `extend(C)`. Alternatively, this new column may be inserted at any index `c` in the matrix, e.g. `extend(C, c)`. In the most general case, one may provide a vector `a` and define the values of the new column to be `-a` dot the row. The standard definition is clearly just the special case that `a` is the all-ones vector. ```@docs diff --git a/docs/src/LDPC/analysis.md b/docs/src/LDPC/analysis.md index 7861be8..1806779 100644 --- a/docs/src/LDPC/analysis.md +++ b/docs/src/LDPC/analysis.md @@ -27,14 +27,8 @@ optimal_threshold density_evolution ``` -```@docs -plot_EXIT_chart -``` # Misc -```@docs -multiplicative_gap -``` ```@docs multiplicative_gap_lower_bound diff --git a/docs/src/LDPC/codes.md b/docs/src/LDPC/codes.md index 5dce847..bcb455e 100644 --- a/docs/src/LDPC/codes.md +++ b/docs/src/LDPC/codes.md @@ -31,14 +31,7 @@ Parity-check matrix: 6 × 9 1 1 0 0 0 0 1 1 1 ``` -Random regular LDPC codes maybe be constructed via -```@docs -regular_LDPC_code -``` -and irregular LDPC codes via -```@docs -irregular_LDPC_code -``` +Random regular LDPC codes maybe be constructed via `regular_LDPC_code` and `irregular_LDPC_code` ## Attributes The polynomials ``\lambda(x)`` and ``\rho(x)`` as well as the degrees of each variable and check nodes are computed upon construction. @@ -116,10 +109,6 @@ To count or explicitly enumerate the short cycles of the Tanner graph, use count_short_cycles ``` -```@docs -shortest_cycles -``` - Various information about the ACE values of cycles in the Tanner graph may be computed with the following functions. From d623cd837d035942cd4cda1fa60a41e9651a8829 Mon Sep 17 00:00:00 2001 From: Eric Sabo Date: Fri, 20 Sep 2024 10:42:34 -0400 Subject: [PATCH 05/10] bug fixes for RIS --- src/CodingTheory.jl | 2 +- src/Quantum/weight_dist.jl | 73 ++++++++++++++++++++++---------------- src/utils.jl | 32 +++++++++-------- 3 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/CodingTheory.jl b/src/CodingTheory.jl index 22aef7f..1b4bec5 100644 --- a/src/CodingTheory.jl +++ b/src/CodingTheory.jl @@ -362,7 +362,7 @@ include("Quantum/weight_dist.jl") # export weight_plot_CSS_X, weight_plot_CSS_Z, weight_plot_CSS, minimum_distance_X_Z, # minimum_distance_X, minimum_distance_Z, is_pure, QDistRndCSS export minimum_distance_upper_bound!, random_information_set_minimum_distance_bound!, - QDistRand + QDistRand! ############################# # Quantum/product_codes.jl diff --git a/src/Quantum/weight_dist.jl b/src/Quantum/weight_dist.jl index 48d2de1..e857f82 100644 --- a/src/Quantum/weight_dist.jl +++ b/src/Quantum/weight_dist.jl @@ -637,19 +637,22 @@ is returned, and if `dressed = false` then the bound is for the bare distance. R iterations and stops early if a logical of weight `d_lower_bound` is found. """ # here want to branch for graph states -function random_information_set_minimum_distance_bound(S::T, which::Symbol = :full; +function random_information_set_minimum_distance_bound!(S::T, which::Symbol = :full; dressed::Bool = true, max_iters::Int = 10000, verbose::Bool = false) where T <: AbstractSubsystemCode which ∈ (:full, :X, :Z) || throw(DomainError(which, "Must choose `:full`, `:X` or `:Z`.")) # order(field(S)) == 2 || throw(DomainError(S, "Currently only implemented for binary codes.")) is_positive(max_iters) || throw(DomainError(max_iters, "The number of iterations must be a positive integer.")) - return random_information_set_minimum_distance_bound(GaugeTrait(T), CSSTrait(T), + return random_information_set_minimum_distance_bound!(GaugeTrait(T), CSSTrait(T), LogicalTrait(T), S, which, dressed, max_iters, verbose) end -QDistRand(S::T, which::Symbol = :full; dressed::Bool = true, max_iters::Int = 10000, verbose::Bool = false) where T <: AbstractSubsystemCode = random_information_set_minimum_distance_bound(S, which; dressed = dressed, max_iters = max_iters, verbose = verbose) +QDistRand!(S::T, which::Symbol = :full; dressed::Bool = true, max_iters::Int = 10000, + verbose::Bool = false) where T <: AbstractSubsystemCode = + random_information_set_minimum_distance_bound!(S, which; dressed = dressed, max_iters = + max_iters, verbose = verbose) -function random_information_set_minimum_distance_bound(::HasGauges, ::IsCSS, ::HasLogicals, +function random_information_set_minimum_distance_bound!(::HasGauges, ::IsCSS, ::HasLogicals, S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int, verbose::Bool) # this is a CSS subsystem code @@ -752,7 +755,7 @@ function random_information_set_minimum_distance_bound(::HasGauges, ::IsCSS, ::H end end - uppers, founds = _RIS_bound_loop(operators_to_reduce, check_against, curr_l_bound, + uppers, founds = _RIS_bound_loop!(operators_to_reduce, check_against, curr_l_bound, curr_u_bound, found, max_iterst, n, verbose) loc = argmin(uppers) if dressed @@ -775,25 +778,30 @@ function random_information_set_minimum_distance_bound(::HasGauges, ::IsCSS, ::H return uppers[loc], founds[loc] end -function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsCSS, ::HasLogicals, - S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int) +function random_information_set_minimum_distance_bound!(::HasNoGauges, ::IsCSS, ::HasLogicals, + S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int, verbose::Bool) # CSS stabilizer code + n = S.n if which == :full verbose && println("Bounding the full distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), UInt8) + # println(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix(stabilizers(S), Bool))) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(logs[:, [n + 1:2n; 1:n]]) - curr_l_bound = S.l_bound_bare + curr_l_bound = S.l_bound + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") elseif which == :X verbose && println("Bounding the X-distance") stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( @@ -801,7 +809,7 @@ function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsCSS, : logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.logicals]), UInt8) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals])[:, [n + 1:2n; 1:n]]) - curr_l_bound = S.l_bound_dx_bare + curr_l_bound = S.l_bound_dx # this is done in the constructor but the logical is not stored at the time # so must redo here @@ -816,7 +824,7 @@ function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsCSS, : logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals]), UInt8) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(reduce(vcat, [log[1][:, 1:n] for log in S.logicals])) - curr_l_bound = S.l_bound_dx_bare + curr_l_bound = S.l_bound_dx # this is done in the constructor but the logical is not stored at the time # so must redo here @@ -826,8 +834,8 @@ function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsCSS, : found = operators_to_reduce[index, :] end - uppers, founds = _RIS_bound_loop(operators_to_reduce, check_against, curr_l_bound, - curr_u_bound, found, max_iterst, n, verbose) + uppers, founds = _RIS_bound_loop!(operators_to_reduce, check_against, curr_l_bound, + curr_u_bound, found, max_iters, n, verbose) loc = argmin(uppers) if which == :full S.u_bound = uppers[loc] @@ -839,8 +847,8 @@ function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsCSS, : return uppers[loc], founds[loc] end -function random_information_set_minimum_distance_bound(::HasGauges, ::IsNotCSS, ::HasLogicals, - S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int) +function random_information_set_minimum_distance_bound!(::HasGauges, ::IsNotCSS, ::HasLogicals, + S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int, verbose::Bool) # subsystem code which == :full || throw(ArguementError(which, "Parameter is not valid for non-CSS codes.")) @@ -859,7 +867,7 @@ function random_information_set_minimum_distance_bound(::HasGauges, ::IsNotCSS, # so must redo here _, mat = _rref_no_col_swap!(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] else verbose && println("Bounding the full bare distance") @@ -874,11 +882,11 @@ function random_information_set_minimum_distance_bound(::HasGauges, ::IsNotCSS, # so must redo here _, mat = _rref_no_col_swap!(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] end - uppers, founds = _RIS_bound_loop(operators_to_reduce, check_against, curr_l_bound, + uppers, founds = _RIS_bound_loop!(operators_to_reduce, check_against, curr_l_bound, curr_u_bound, found, max_iterst, n, verbose) loc = argmin(uppers) if dressed @@ -889,8 +897,8 @@ function random_information_set_minimum_distance_bound(::HasGauges, ::IsNotCSS, return uppers[loc], founds[loc] end -function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsNotCSS, ::HasLogicals, - S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int) +function random_information_set_minimum_distance_bound!(::HasNoGauges, ::IsNotCSS, ::HasLogicals, + S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int, verbose::Bool) # stabilizer code which == :full || throw(ArguementError(which, "Parameter is not valid for non-CSS codes.")) @@ -902,6 +910,7 @@ function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsNotCSS operators_to_reduce = vcat(stabs, logs) check_against = permutedims(logs[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here @@ -909,9 +918,10 @@ function random_information_set_minimum_distance_bound(::HasNoGauges, ::IsNotCSS anti = mat * check_against curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") - uppers, founds = _RIS_bound_loop(operators_to_reduce, check_against, curr_l_bound, - curr_u_bound, found, max_iterst, n, verbose) + uppers, founds = _RIS_bound_loop!(operators_to_reduce, check_against, curr_l_bound, + curr_u_bound, found, max_iters, n, verbose) loc = argmin(uppers) S.u_bound = uppers[loc] return uppers[loc], founds[loc] @@ -919,12 +929,12 @@ end # TODO rewrite all for graph states # function random_information_set_minimum_distance_bound(::Union{HasGauges, HasNoGauges}, -# ::Union{IsCSS, IsNotCSS}, ::HasNoLogicals, S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int) +# ::Union{IsCSS, IsNotCSS}, ::HasNoLogicals, S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int, verbose::Bool) # # graph state # end -function _RIS_bound_loop(operators_to_reduce, check_against, curr_l_bound::Int, curr_u_bound::Int, found, max_iters::Int, n::Int, verbose::Bool) +function _RIS_bound_loop!(operators_to_reduce, check_against, curr_l_bound::Int, curr_u_bound::Int, found, max_iters::Int, n::Int, verbose::Bool) num_thrds = Threads.nthreads() verbose && println("Detected $num_thrds threads.") @@ -933,7 +943,7 @@ function _RIS_bound_loop(operators_to_reduce, check_against, curr_l_bound::Int, founds = [found for _ in 1:num_thrds] thread_load = Int(floor(max_iters / num_thrds)) Threads.@threads for t in 1:num_thrds - log_test = zeros(Int, size(check_against, 2)) + log_test = zeros(Int, size(operators_to_reduce, 1), size(check_against, 2)) for _ in 1:thread_load if flag[] perm = shuffle(1:n) @@ -946,12 +956,13 @@ function _RIS_bound_loop(operators_to_reduce, check_against, curr_l_bound::Int, if any(!iszero, log_test[i, :]) w = 0 @inbounds for j in 1:n - iszero(perm_ops[i. j]) && iszero(perm_ops[i, j + n]) || (w += 1;) + iszero(perm_ops[i, j] % 2) && iszero(perm_ops[i, j + n] % 2) || (w += 1;) end if uppers[t] > w uppers[t] = w - founds[t] .= perm_ops[i, invperm!(perm2)] + # maybe use invpermute! here? + founds[t] .= perm_ops[i, invperm(perm2)] verbose && println("Adjusting upper bound: $w") if curr_l_bound == w verbose && println("Found a logical that matched the lower bound of $curr_l_bound") diff --git a/src/utils.jl b/src/utils.jl index fb82074..41843a6 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -127,8 +127,8 @@ end weight(v::T) where T <: Union{CTMatrixTypes, Vector{<:CTFieldElem}, Vector{S}, Adjoint{S, Vector{S}}, AbstractMatrix{S}} where S <: Integer = Hamming_weight(v) wt(v::T) where T <: Union{CTMatrixTypes, Vector{<:CTFieldElem}, Vector{S}, Adjoint{S, Vector{S}}, AbstractMatrix{S}} where S <: Integer = Hamming_weight(v) -# TODO polish and export -function row_wts_symplectic(A::CTMatrixTypes) +# TODO polish and export? +function row_wts_symplectic(A::Union{CTMatrixTypes, Matrix{<: Integer}, Matrix{Bool}}) nc = size(A, 2) iseven(nc) || throw(ArgumentError("Input does not have even length")) n = div(nc, 2) @@ -311,11 +311,12 @@ end # end _Flint_matrix_to_Julia_int_vector(A) = vec(_Flint_matrix_to_Julia_int_matrix(A)) -function _non_pivot_cols(A::CTMatrixTypes, type::Symbol=:nsp) - type ∈ [:sp, :nsp] +function _non_pivot_cols(A::CTMatrixTypes, type::Symbol = :nsp) + type ∈ (:sp, :nsp) || throw(DomainError(type, "Parameter should be `:sp` (sparse) or `:nsp` (not sparse).")) + if type == :sp return setdiff(collect(1:ncols(A)), [x.pos[1] for x in A]) - else #if type == :nsp - not sparse + else nonpivots = Vector{Int}() i = 1 j = 1 @@ -391,7 +392,9 @@ end # return maxlen # end -function _remove_empty(A::Union{CTMatrixTypes, Matrix{<:Number}, BitMatrix}, type::Symbol) +function _remove_empty(A::Union{CTMatrixTypes, Matrix{<: Number}, BitMatrix, Matrix{Bool}}, + type::Symbol) + type ∈ (:rows, :cols) || throw(ArgumentError("Unknown type in _remove_empty")) del = Vector{Int}() @@ -430,12 +433,12 @@ end _rref_no_col_swap(M::CTMatrixTypes, row_range::Base.OneTo{Int}, col_range::Base.OneTo{Int}) = _rref_no_col_swap(M, 1:row_range.stop, 1:col_range.stop) _rref_no_col_swap(M::CTMatrixTypes) = _rref_no_col_swap(M, axes(M, 1), axes(M, 2)) -function _rref_no_col_swap(A::Union{BitMatrix, Matrix{Bool}}, row_range::UnitRange{Int} = 1:size(A, 1), - col_range::UnitRange{Int} = 1:size(A, 2)) +function _rref_no_col_swap(A::Union{BitMatrix, Matrix{Bool}, Matrix{<: Integer}}, + row_range::UnitRange{Int} = 1:size(A, 1), col_range::UnitRange{Int} = 1:size(A, 2)) B = copy(A) _rref_no_col_swap!(B, row_range, col_range) - B + return B end function _rref_no_col_swap!(A::CTMatrixTypes, row_range::UnitRange{Int}, col_range::UnitRange{Int}) @@ -519,8 +522,8 @@ function _rref_no_col_swap!(A::CTMatrixTypes, row_range::UnitRange{Int}, col_ran return nothing end -function _rref_no_col_swap!(A::Union{BitMatrix, Matrix{Bool}}, row_range::UnitRange{Int} = 1:size(A, 1), - col_range::UnitRange{Int} = 1:size(A, 2)) +function _rref_no_col_swap!(A::Union{BitMatrix, Matrix{Bool}, Matrix{<: Integer}}, + row_range::UnitRange{Int} = 1:size(A, 1), col_range::UnitRange{Int} = 1:size(A, 2)) isempty(row_range) && return nothing isempty(col_range) && return nothing @@ -532,7 +535,7 @@ function _rref_no_col_swap!(A::Union{BitMatrix, Matrix{Bool}}, row_range::UnitRa # find first pivot ind = 0 for k in i:nr - if A[k, j] + if !iszero(A[k, j]) ind = k break end @@ -547,10 +550,11 @@ function _rref_no_col_swap!(A::Union{BitMatrix, Matrix{Bool}}, row_range::UnitRa # eliminate for k in row_range if k != i - if A[k, j] + if !iszero(A[k, j]) # do a manual loop here to reduce allocations @simd for l in axes(A, 2) - A[k, l] ⊻= A[i, l] + # A[k, l] ⊻= A[i, l] + A[k, l] = (A[k, l] + A[i, l]) % 2 end end end From 3bdf3c5813003f2974d4030be92bc94d328ee612 Mon Sep 17 00:00:00 2001 From: Eric Sabo Date: Fri, 20 Sep 2024 11:15:03 -0400 Subject: [PATCH 06/10] propagated typo fixes to all other if statements --- src/Quantum/weight_dist.jl | 148 +++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 57 deletions(-) diff --git a/src/Quantum/weight_dist.jl b/src/Quantum/weight_dist.jl index e857f82..a5e2a3e 100644 --- a/src/Quantum/weight_dist.jl +++ b/src/Quantum/weight_dist.jl @@ -656,102 +656,121 @@ function random_information_set_minimum_distance_bound!(::HasGauges, ::IsCSS, :: S::AbstractSubsystemCode, which::Symbol, dressed::Bool, max_iters::Int, verbose::Bool) # this is a CSS subsystem code + n = S.n if dressed if which == :full verbose && println("Bounding the full dressed distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - stabilizers(S), UInt8)), :rows) - gauges = _Flint_matrix_to_Julia_T_matrix(gauges_matrix(S), UInt8) - logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + gauges = _Flint_matrix_to_Julia_T_matrix(gauges_matrix(S), Int) + logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), Int) operators_to_reduce = vcat(stabs, gauges, logs) check_against = permutedims(logs[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound_dressed + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") elseif which == :X verbose && println("Bounding the dressed X-distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - X_stabilizers(S), UInt8)), :rows) - gauges = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.gauge_ops]), UInt8) - logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.logicals]), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + gauges = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.gauge_ops]), Int) + logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.logicals]), Int) operators_to_reduce = vcat(stabs, gauges, logs) check_against = permutedims(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals])[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound_dx_dressed + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") else verbose && println("Bounding the dressed Z-distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - Z_stabilizers(S), UInt8)), :rows) - gauges = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.gauge_ops]), UInt8) - logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals]), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + gauges = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.gauge_ops]), Int) + logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals]), Int) operators_to_reduce = vcat(stabs, gauges, logs) check_against = permutedims(reduce(vcat, [log[1][:, 1:n] for log in S.logicals])) curr_l_bound = S.l_bound_dz_dressed + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") end else if which == :full verbose && println("Bounding the full bare distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(logs[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound_bare + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") elseif which == :X verbose && println("Bounding the bare X-distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - X_stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.logicals]), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.logicals]), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals])[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound_dx_bare + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") else verbose && println("Bounding the bare Z-distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - Z_stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals]), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals]), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(reduce(vcat, [log[1][:, 1:n] for log in S.logicals])) curr_l_bound = S.l_bound_dx_bare + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") end end @@ -804,34 +823,40 @@ function random_information_set_minimum_distance_bound!(::HasNoGauges, ::IsCSS, verbose && println("Starting upper bound: $curr_u_bound") elseif which == :X verbose && println("Bounding the X-distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - X_stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.logicals]), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[1][:, 1:n] for log in S.logicals]), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals])[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound_dx + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") else verbose && println("Bounding the Z-distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - Z_stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals]), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(reduce(vcat, [log[2][:, n + 1:end] for log in S.logicals]), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(reduce(vcat, [log[1][:, 1:n] for log in S.logicals])) curr_l_bound = S.l_bound_dx + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") end uppers, founds = _RIS_bound_loop!(operators_to_reduce, check_against, curr_l_bound, @@ -853,37 +878,44 @@ function random_information_set_minimum_distance_bound!(::HasGauges, ::IsNotCSS, which == :full || throw(ArguementError(which, "Parameter is not valid for non-CSS codes.")) + n = S.n if dressed verbose && println("Bounding the full dressed distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - stabilizers(S), UInt8)), :rows) - gauges = _Flint_matrix_to_Julia_T_matrix(gauges_matrix(S), UInt8) - logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + gauges = _Flint_matrix_to_Julia_T_matrix(gauges_matrix(S), Int) + logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), Int) operators_to_reduce = vcat(stabs, gauges, logs) check_against = permutedims(logs[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound_dressed + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") else verbose && println("Bounding the full bare distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(logs[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound_bare + verbose && println("Starting lower bound: $curr_l_bound") # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] + verbose && println("Starting upper bound: $curr_u_bound") end uppers, founds = _RIS_bound_loop!(operators_to_reduce, check_against, curr_l_bound, @@ -903,10 +935,12 @@ function random_information_set_minimum_distance_bound!(::HasNoGauges, ::IsNotCS which == :full || throw(ArguementError(which, "Parameter is not valid for non-CSS codes.")) + n = S.n verbose && println("Bounding the full distance") - stabs = _remove_empty(_rref_no_col_swap!(_Flint_matrix_to_Julia_T_matrix( - stabilizers(S), UInt8)), :rows) - logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), UInt8) + stabs = _Flint_matrix_to_Julia_T_matrix(stabilizers(S), Int) + _rref_no_col_swap!(stabs) + stabs = _remove_empty(stabs, :rows) + logs = _Flint_matrix_to_Julia_T_matrix(logicals_matrix(S), Int) operators_to_reduce = vcat(stabs, logs) check_against = permutedims(logs[:, [n + 1:2n; 1:n]]) curr_l_bound = S.l_bound @@ -914,9 +948,9 @@ function random_information_set_minimum_distance_bound!(::HasNoGauges, ::IsNotCS # this is done in the constructor but the logical is not stored at the time # so must redo here - _, mat = _rref_no_col_swap!(operators_to_reduce) + mat = _rref_no_col_swap(operators_to_reduce) anti = mat * check_against - curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i:i, :]) for i in axes(anti, 1)), :])) + curr_u_bound, index = findmin(row_wts_symplectic(mat[findall(!iszero(anti[i, :]) for i in axes(anti, 1)), :])) found = operators_to_reduce[index, :] verbose && println("Starting upper bound: $curr_u_bound") From 371224cefccc6295c2a02e51e81e2c99fdaffb88 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Sep 2024 21:16:20 +0500 Subject: [PATCH 07/10] remove call to absent files in message passing.md --- docs/src/Tutorials/Message Passing.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/docs/src/Tutorials/Message Passing.md b/docs/src/Tutorials/Message Passing.md index 1092dcd..650dc41 100644 --- a/docs/src/Tutorials/Message Passing.md +++ b/docs/src/Tutorials/Message Passing.md @@ -247,7 +247,6 @@ lines!(ax, x, x, color = :black) f ``` -![phi](./../assets/images/phi.png) Trying to plot this function with the $\tanh$ versus plotting this function with the exponentials makes the numerical instability of the $\tanh$ apparent. Fortunately, the exponential form makes it apparent that it is not only symmetric about $y = x$, but also that the function is dominated by smaller values of $x$: @@ -751,7 +750,6 @@ lines!(noise, FER, color = :red) scatter!(noise, FER, color = :red) current_figure() ``` -![CSS_FER_test](./../assets/images/CSS_FER_test.png) TODO REDO THIS FUNCTION @@ -772,7 +770,6 @@ ax2 = Axis(fig2[1, 2], xlabel = "Iteration Number", ylabel = "Number Of Times Co barplot!(ax1, collect(keys(X_iters_15)), X_values, bar_width = 1) barplot!(ax2, collect(keys(Z_iters_15)), Z_values, bar_width = 1) ``` -![CSS_test_iters](./../assets/images/CSS_test_iters.png) The overwhelming majority of convergeneces, for both $X$ and $Z$, occurred within one or two iterations. This is plausible for a couple of reasons. First, note that all variable nodes have degree four but all check nodes have degree nine! This is large for an LDPC code. For low error rates when errors are sparsely distributed over 254 qubits, it may be common that a single check node does not connect to more than one inncorrect variable node and the degrees are high enough to immediately flip any bit. @@ -805,8 +802,6 @@ false Rerunning the simulation without using Bayes' Theorem returns almost symmetric $X$ and $Z$ iteration counts. For completeness, we include both runs on a single plot. The first blue point on the left is due to a single convergence error and the spike on the left further shows that direct sampling is either not appropriate for this error rate or it has not been sampled enough times for accuracy. -![CSS_FER_Bayes_test](./../assets/images/CSS_FER_Bayes_test.png) - ## Example 2: Single-Shot Decoding With Metachecks Next we're going to look at two single-shot decoding schemes. We will call the paper [quintavalle2021single](@cite) scheme one and [higgott2023improved](@cite) scheme two. We encourage the reader to check out both papers directly for details. Briefly, both schemes will consider data errors, as in the previous example, plus additional measurement errors (on the syndrome values). The code family we will look at has an extra matrix, $M$, with the property that $Ms = 0$ for any valid syndrome $s$ of the code. Then assuming that the measurement error $s_e$ didn't take us from a valid syndrome to another valid syndrome, $M(s + s_e) = Ms_e \neq 0$. Whether or not this happens depends on the properties of the classical code with $M$ as its parity-check matrix. To correct the syndrome, we decode using the Tanner graph based on $M$. Then we will use the corrected syndrome to decode the stabilizers. @@ -1220,14 +1215,8 @@ julia> check_weights(X_meta_L) By distance eight, scheme one was difficult to run without a cluster. We did not attempt distance nine with this scheme. This is problematic for many reasons, the most important of which is that many code families do not "settle in" to their asymptotic behaviors until distances much higher than this (although the exact distance depends on the decoder being used). For example, for the surface codes under minimum-weight perfect-matching (MWPM), anything below distance 20 is considered the small-code regime (compare this to distance seven for the same code family using trellis decoding). -![CSS_Single_Shot_test](./../assets/images/CSS_Single_Shot_test.png) - Logical errors were equally distributed among the cosets and only occurred on odd-distance codes. - - - - julia> x = -20:.05:20; y = [abs(atanh(tanh(x)) - x) for x in x]; y2 = [exp(2abs(x)) / 2^56 for x in x]; plot(x, [replace(y, 0.0 => 1e-21) y2], ylims = (1e-20, 1), yscale = :log10, linewidth = 0.5, label = ["abs(atanh(tanh(x)) - x)" "exp(2abs(x)) / 2^56"]) p = 1 - 1/(1 + exp(LLR)) if LLR = log(p / (1 - p)) From 97446a4a71a020b2c5ac0ae3b899308de9181870 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Sep 2024 22:29:01 +0500 Subject: [PATCH 08/10] minor fix --- docs/src/Classical/new_codes_from_old.md | 12 ++++++++++++ docs/src/Tutorials/Message Passing.md | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/docs/src/Classical/new_codes_from_old.md b/docs/src/Classical/new_codes_from_old.md index 5e9012f..484d3fe 100644 --- a/docs/src/Classical/new_codes_from_old.md +++ b/docs/src/Classical/new_codes_from_old.md @@ -23,8 +23,16 @@ construction_X3 The direct sum code has generator matrix `G1 ⊕ G2` and parity-check matrix `H1 ⊕ H2`. +```@docs +⊕ +``` + The generator matrix of the (direct) product code is the kronecker product of the generator matrices of the inputs. +```@docs +× +``` + The parity-check matrix of the tensor product code is the kronecker product of the parity-check matrices of the inputs. There is some debate on how to define this product. This is known to often be the full ambient space. @@ -32,6 +40,10 @@ There is some debate on how to define this product. This is known to often be th entrywise_product_code ``` +```@docs +/ +``` + `juxtaposition` is representation dependent and therefore works on the potentially over-complete generator matrices, not on the standard form. ```@docs juxtaposition diff --git a/docs/src/Tutorials/Message Passing.md b/docs/src/Tutorials/Message Passing.md index 650dc41..fde246c 100644 --- a/docs/src/Tutorials/Message Passing.md +++ b/docs/src/Tutorials/Message Passing.md @@ -1217,6 +1217,11 @@ By distance eight, scheme one was difficult to run without a cluster. We did not Logical errors were equally distributed among the cosets and only occurred on odd-distance codes. + + + + + julia> x = -20:.05:20; y = [abs(atanh(tanh(x)) - x) for x in x]; y2 = [exp(2abs(x)) / 2^56 for x in x]; plot(x, [replace(y, 0.0 => 1e-21) y2], ylims = (1e-20, 1), yscale = :log10, linewidth = 0.5, label = ["abs(atanh(tanh(x)) - x)" "exp(2abs(x)) / 2^56"]) p = 1 - 1/(1 + exp(LLR)) if LLR = log(p / (1 - p)) From 4a434ca83e60e5ac341e122500a3319793013e35 Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Sep 2024 22:52:06 +0500 Subject: [PATCH 09/10] fixup --- docs/src/Classical/linear_code.md | 4 ++++ docs/src/Classical/new_codes_from_old.md | 2 +- docs/src/LDPC/analysis.md | 2 ++ docs/src/LDPC/codes.md | 3 ++- docs/src/LDPC/decoders.md | 4 ++++ 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/src/Classical/linear_code.md b/docs/src/Classical/linear_code.md index cb038bc..a870ab3 100644 --- a/docs/src/Classical/linear_code.md +++ b/docs/src/Classical/linear_code.md @@ -31,6 +31,8 @@ cardinality rate ``` +See also: encode` + If the linear code was created by passing in a generator (parity-check) matrix, then this matrix is stored in addition to the standard form. Note that this matrix is potentially over complete (has more rows than its rank). The standard form is returned when the optional parameter `stand_form` is set to true. Some code families are not constructed using these matrices. In these cases, the matrices are initially `missing` and are computed and cached when these functions are called for the first time. Direct access to the underlying structs is not recommended. ```@docs generator_matrix @@ -82,6 +84,8 @@ set_distance_lower_bound! set_minimum_distance! ``` +See: `minimum_distance_lower_bound`, `set_distance_upper_bound!` + ## Methods ```@docs diff --git a/docs/src/Classical/new_codes_from_old.md b/docs/src/Classical/new_codes_from_old.md index 484d3fe..bf4661c 100644 --- a/docs/src/Classical/new_codes_from_old.md +++ b/docs/src/Classical/new_codes_from_old.md @@ -51,7 +51,7 @@ juxtaposition ## Methods -If `C` is a quasi-cyclic code, `permute_code` returns a `LinearCode` object. +If `C` is a quasi-cyclic code, `permute_code` returns a `LinearCode` object. See: `permute_code` The most common way to extend a code is to add an extra column to the generator matrix whose values make the sum of the rows zero. This is called an even extension and is the default for `extend(C)`. Alternatively, this new column may be inserted at any index `c` in the matrix, e.g. `extend(C, c)`. In the most general case, one may provide a vector `a` and define the values of the new column to be `-a` dot the row. The standard definition is clearly just the special case that `a` is the all-ones vector. ```@docs diff --git a/docs/src/LDPC/analysis.md b/docs/src/LDPC/analysis.md index 1806779..cc203a1 100644 --- a/docs/src/LDPC/analysis.md +++ b/docs/src/LDPC/analysis.md @@ -38,6 +38,8 @@ multiplicative_gap_lower_bound density_lower_bound ``` +See also: `plot_EXIT_chart`, `multiplicative_gap` + ## Comments (these are just temporary notes) diff --git a/docs/src/LDPC/codes.md b/docs/src/LDPC/codes.md index bcb455e..165f951 100644 --- a/docs/src/LDPC/codes.md +++ b/docs/src/LDPC/codes.md @@ -109,7 +109,8 @@ To count or explicitly enumerate the short cycles of the Tanner graph, use count_short_cycles ``` -Various information about the ACE values of cycles in the Tanner graph may be computed with the following functions. +See also: `shortest_cycles` +Various information about the ACE value of cycles in the Tanner graph may be computed with the following functions. See: `ACE_spectrum`, `shortest_cycle_ACE`, `ACE_distribution`, `average_ACE_distribution`, `median_ACE_distribution`, `mode_ACE_distribution` ## Greedy Construction Algorithms diff --git a/docs/src/LDPC/decoders.md b/docs/src/LDPC/decoders.md index d98b1d0..0cdc31a 100644 --- a/docs/src/LDPC/decoders.md +++ b/docs/src/LDPC/decoders.md @@ -21,6 +21,8 @@ sum_product_box_plus min_sum ``` +See also: `find_MP_schedule` + ## Linear Programming ```@docs @@ -28,3 +30,5 @@ LP_decoder_LDPC ``` ## Simulations + +See: `decoder_simulation` \ No newline at end of file From 24de38394f8360434573138bfb992c2a4dc86ebb Mon Sep 17 00:00:00 2001 From: Fe-r-oz Date: Fri, 20 Sep 2024 23:52:45 +0500 Subject: [PATCH 10/10] use warnonly instead of checkdocs in makedocs --- docs/make.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index dc6aac0..3c9dc88 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -11,7 +11,7 @@ Documenter.makedocs(; highlightsig = true, sitename = "Coding Theory Documentation", expandfirst = [], - checkdocs = :none, + warnonly = [:missing_docs], pages = ["Introduction" => "index.md", "Tutorials" => [ "Tutorials/Linear Codes.md",