Sign in

    moonldpc

    Bounded binary sparse parity-check coding and iterative soft-decision decoding

    ldpc
    error-correction
    belief-propagation
    alist
    soft-decision
    Download zip
    Author
    Version
    0.1.0
    License
    MIT
    Last updated
    10 hours ago
    Downloads
    15

    #MoonLDPC

    MoonLDPC 是 MoonBit 二进制稀疏校验矩阵、GF(2) 编码、软判决译码和擦除恢复库。模块版本为 red6667/moonldpc@0.1.0,MIT 许可。适合接收端/仿真工具、码设计互操作工具、遥测/协议服务复用同一核心;不提供 Wi-Fi、5G、DVB 标准 profile、随机信道仿真、密码学保证或生产吞吐量承诺。

    #安装与环境

    从 MoonCakes 安装精确版本:

    moon add red6667/moonldpc@0.1.0

    在消费者 moon.pkg 中添加 import { "red6667/moonldpc" }。本仓库本地使用 Moon 0.1.20261021、Moonc 0.10.17;CI 使用官方稳定工具链并记录实际版本。支持 wasm-gc、wasm、js 和 native;Windows 本地未安装 C 编译器,native 的 build/test/run 须看云端证据。

    发布是否已完成应以平台精确版本和 Release 记录为准;本地测试不等于真实云端 CI 或竞赛官方验收。

    #能力范围

    • ParityCheck:拥有式稀疏二进制 Tanner 图,综合、码字验证、置换、direct sum、dense 互操作、Hamming(7,4) 和重复码。
    • Encoder:受限 GF(2) RREF、秩/自由信息位置、编码/提取、综合方程特解、小码距枚举;CosetEncoder 支持 Hx=s 的仿射编码。另有对偶码和整体偶校验扩展。
    • 三种迭代软译码:Sum-Product、Flooding Min-Sum、Layered Min-Sum。合法码字收敛不证明原始发送内容已恢复。
    • BEC:队列 peeling、受限精确仿射恢复、stopping-set 诊断;精确恢复区分唯一、多解、无解。
    • 小码对照:nearest_word 穷举最近码字且拒绝并列;decode_exact 输出序列 ML 和比特 MAP 后验,有严格枚举预算。
    • 互操作:严格 padded alist 双向邻接校验、QC lift、四环/girth/连通分量;puncture 通过消元得到投影码,而非直接截断 H。
    • 接收适配:BPSK、AWGN/BSC/BEC LLR、逐样本方差、稳定概率转换、独立观测合并、重排、shortening/puncturing 和不可变统计合并。
    • JSON:analyze、encode、decode、peel、recover、bit-flip、distance、alist、exact-decode、nearest、correct-single、stopping、coset-encode。

    #最小 API 例子

    下面的操作可在本仓库 receiver 和 laboratory 查看完整的错误处理与可执行代码:

    let code = @moonldpc.hamming7()
    let encoder = @moonldpc.Encoder::new(code)
    let word = encoder.encode([1, 0, 1, 1])
    let llr = @moonldpc.awgn_llr(@moonldpc.bpsk(word), 0.5)
    let decoded = code.decode(llr, @moonldpc.DecoderConfig::new(SumProduct))
    let information = encoder.extract(decoded.word)

    这些 API 可能抛出 CodeError;调用函数需要声明 raise 或显式 catch。LLR 为 log(P0/P1),正值偏向 0,零硬判为 0。行/列索引从零开始;重复边、越界索引、非二值输入、NaN/Infinity 不是合法输入。

    #四个可运行工作流

    moon run examples/receiver moon run examples/designer moon run examples/telemetry moon run examples/laboratory

    1. 接收端/仿真开发者:矩阵和解调 LLR → 三种迭代译码 → 候选码字、综合历史、后验和误码统计。receiver 实跑自定义 42-bit QC 帧。
    2. 码设计工具作者:QC base matrix → lift、alist 导出/导入 → 邻接、环、秩、小码距和投影结果,供其他工具链接入。
    3. 遥测服务作者:重复/穿孔观测和 BEC 擦除 → RatePlan、peeling/精确恢复 → 结构化唯一/多解/错误结果。
    4. 接收校准与诊断工具:扩展 Hamming 码、重排观测和逐样本方差 → 对齐 LLR → 精确 ML/MAP 对照与比特概率。

    #JSON CLI

    moon run cmd/main -- '{"action":"analyze","code":{"variables":3,"rows":[[0,1],[1,2]]}}' moon run cmd/main -- '{"action":"exact-decode","code":{"variables":3,"rows":[[0,1],[1,2]]},"llr":[-2,0.1,-2]}'

    PowerShell 的原生命令引号转义可能不同;可运行 python scripts/smoke.py,它通过真实子进程传递 JSON,并检查成功和失败请求。协议拒绝未知字段、重复键和过深 JSON。CLI 将协议错误作为 ok:false 数据返回,进程退出零不是译码成功证明。

    #关键边界

    • 稀疏图最多 65,536 个变量/校验与 1,000,000 条边;稠密消元另限尺寸、单元数和工作量。详见 安全边界。
    • 精确小码译码长度不超过 256、维度不超过 16,且 n*(k+1)*2^k <= 20,000,000。不是大图生产译码器。
    • correct_single 只在单错误假设下返回唯一列匹配;多错误可能形成另一个合法码字。最近码字并列不猜,精确软译码并列按信息掩码顺序选首项并报告 ties。
    • recover_erasures 的 particular_word 不证明唯一;检查 unique、ambiguity_dimension。peel 不猜 stopping set。
    • RatePlan 只合并独立观测;相关观测重复使用会导致过度置信。有限 LLR shortening 必须在译码后用 accepts 检查;BEC 重复观测冲突会报错。
    • 不声称兼容某个无线标准、通过第三方认证、比某个实现更快或项目绝对唯一。

    #验证

    moon info && moon fmt moon fmt --check moon check --deny-warn moon test --deny-warn moon build --deny-warn python scripts/generate_oracles.py --check python scripts/test_audit_history.py python scripts/audit_local.py python scripts/audit_history.py python scripts/smoke.py --target wasm-gc

    当前 36 个 MoonBit 测试;独立 Python fixture 有 144 个迭代译码案例、40 个 GF(2) 案例、20 个精确边缘案例。新增测试穷举 Hamming 单错误、双对偶、仿射综合、置换和 stopping sets,并独立核对概率乘积枚举与 log-domain 后验。CI 对 wasm-gc、wasm、js、native 分别执行检查、测试、构建和真实工作流。工程 ledger 记录 20 个已逐项复核的真实切片,不将后续格式/修复提交自动计入门槛。

    #许可与参考

    原创实现,未复制近邻项目代码或测试夹具。MoonBit core 依赖与参考边界见 NOTICE,许可见 MIT LICENSE,AI 辅助开发披露见 AI-USE.md。本库没有网络发布或报名功能;私有申报材料不属于源码/包。

    CodeError

    pub suberror CodeError {
    InvalidDimensions(String)
    InvalidIndex(Int, Int)
    DuplicateEntry(Int, Int)
    InvalidBit(Int, Int)
    LengthMismatch(Int, Int)
    InvalidNumber(String)
    InvalidFormat(Int, String)
    ResourceLimit(String)
    Inconsistent(String)
    } derive(
    Debug
    )

    Algorithm

    pub(all) enum Algorithm {
    SumProduct
    MinSum
    LayeredMinSum
    } derive(Eq,
    Debug
    )

    Algorithm::equal

    fn Algorithm::equal(Algorithm, Algorithm) -> Bool

    Algorithm::not_equal

    fn Algorithm::not_equal(x : Algorithm, y : Algorithm) -> Bool

    BitFlipReport

    pub struct BitFlipReport {
    word : Array[Int]
    converged : Bool
    iterations : Int
    syndrome_weights : Array[Int]
    } derive(ToJson,
    Debug
    )

    BitFlipReport::to_json

    CosetEncoder

    pub struct CosetEncoder {
    // private fields
    } derive(
    Debug
    )

    Affine Hx=s encoding. This is not error correction or minimum-weight solving.

    CosetEncoder::dimension

    fn CosetEncoder::dimension(self : CosetEncoder) -> Int

    CosetEncoder::encode

    fn CosetEncoder::encode(self : CosetEncoder, information : Array[Int]) -> Array[Int] raise CodeError

    CosetEncoder::extract

    fn CosetEncoder::extract(self : CosetEncoder, word : Array[Int]) -> Array[Int] raise CodeError

    CosetEncoder::new

    fn CosetEncoder::new(code : ParityCheck, target : Array[Int]) -> CosetEncoder raise CodeError

    DecodeReport

    pub struct DecodeReport {
    word : Array[Int]
    posterior_llr : Array[Double]
    converged : Bool
    iterations : Int
    syndrome_weights : Array[Int]
    } derive(ToJson,
    Debug
    )

    DecodeReport::to_json

    DecoderConfig

    pub struct DecoderConfig {
    // private fields
    } derive(
    Debug
    )

    DecoderConfig::new

    fn DecoderConfig::new(algorithm : Algorithm, iterations? : Int, normalization? : Double, offset? : Double, llr_limit? : Double) -> DecoderConfig raise CodeError

    Min-sum uses signnormalizationmax(minimum-offset,0). SumProduct ignores normalization/offset, and rejects non-default values.

    DistanceReport

    pub struct DistanceReport {
    dimension : Int
    examined_nonzero_words : Int
    minimum_distance : Int?
    weight_distribution : Array[Int]
    } derive(ToJson,
    Debug
    )

    DistanceReport::to_json

    Encoder

    pub struct Encoder {
    // private fields
    } derive(
    Debug
    )

    Dense elimination is deliberately bounded separately from sparse decoding.

    Encoder::decode_exact

    fn Encoder::decode_exact(self : Encoder, llr : Array[Double], limit? : Double) -> ExactDecodeReport raise CodeError

    Exact sequence ML word and bitwise MAP marginals under a uniform codeword prior. Input LLRs and output marginals saturate at limit; ties select the first information mask deterministically. Bitwise posterior decisions need not form a codeword.

    Encoder::dimension

    fn Encoder::dimension(self : Encoder) -> Int

    Encoder::distance_report

    fn Encoder::distance_report(self : Encoder) -> DistanceReport raise CodeError

    Exhaustive exact analysis of small linear codes only (k<=20, n*2^k<=8M).

    Encoder::encode

    fn Encoder::encode(self : Encoder, information : Array[Int]) -> Array[Int] raise CodeError

    Free columns carry information; pivot columns are solved from RREF.

    Encoder::extract

    fn Encoder::extract(self : Encoder, word : Array[Int]) -> Array[Int] raise CodeError

    Extraction rejects a non-codeword rather than silently accepting corruption.

    Encoder::generator

    fn Encoder::generator(self : Encoder) -> Array[Array[Int]] raise CodeError

    Encoder::information_positions

    fn Encoder::information_positions(self : Encoder) -> Array[Int]

    Encoder::nearest_word

    fn Encoder::nearest_word(self : Encoder, received : Array[Int]) -> NearestReport raise CodeError

    Exhaustive nearest codeword for small codes, NOT a scalable LDPC decoder. A tied minimum returns no word rather than silently choosing a correction.

    Encoder::new

    fn Encoder::new(code : ParityCheck) -> Encoder raise CodeError

    Encoder::parity_positions

    fn Encoder::parity_positions(self : Encoder) -> Array[Int]

    Encoder::rank

    fn Encoder::rank(self : Encoder) -> Int

    Encoder::rate

    fn Encoder::rate(self : Encoder) -> Double

    Encoder::solve_syndrome

    fn Encoder::solve_syndrome(self : Encoder, syndrome : Array[Int]) -> Array[Int] raise CodeError

    Solve Hx=s over GF(2), choosing all free variables zero. This is an algebraic solution, NOT a minimum-weight error estimate.

    Encoder::to_repr

    ErasureReport

    pub struct ErasureReport {
    values : Array[Int?]
    recovered : Int
    unresolved : Array[Int]
    complete : Bool
    } derive(
    Debug
    )

    ErasureReport::to_json

    fn ErasureReport::to_json(self : ErasureReport) -> Json

    ErrorCounts

    pub struct ErrorCounts {
    // private fields
    } derive(ToJson,
    Debug
    )

    ErrorCounts::bit_error_rate

    fn ErrorCounts::bit_error_rate(self : ErrorCounts) -> Double?

    ErrorCounts::frame_error_rate

    fn ErrorCounts::frame_error_rate(self : ErrorCounts) -> Double?

    ErrorCounts::merge

    fn ErrorCounts::merge(self : ErrorCounts, other : ErrorCounts) -> ErrorCounts raise CodeError

    Merge independent simulation shards without sharing mutable counters.

    ErrorCounts::new

    ErrorCounts::nonconvergence_rate

    fn ErrorCounts::nonconvergence_rate(self : ErrorCounts) -> Double?

    ErrorCounts::observe

    fn ErrorCounts::observe(self : ErrorCounts, transmitted : Array[Int], decoded : Array[Int], converged : Bool) -> ErrorCounts raise CodeError

    Pure aggregation: each result is a new value, no aliasing or partial mutation on error.

    ErrorCounts::to_json

    fn ErrorCounts::to_json(ErrorCounts) -> Json

    ExactDecodeReport

    pub struct ExactDecodeReport {
    word : Array[Int]
    posterior_llr : Array[Double]
    ties : Int
    examined : Int
    } derive(ToJson,
    Debug
    )

    ExactDecodeReport::to_json

    GraphReport

    pub struct GraphReport {
    variables : Int
    checks : Int
    edges : Int
    isolated_variables : Int
    empty_checks : Int
    components : Int
    variable_degrees : Array[Int]
    check_degrees : Array[Int]
    four_cycles : Int64
    } derive(ToJson,
    Debug
    )

    GraphReport::to_json

    fn GraphReport::to_json(GraphReport) -> Json

    NearestReport

    pub struct NearestReport {
    word : Array[Int]?
    distance : Int
    ties : Int
    examined : Int
    } derive(ToJson,
    Debug
    )

    NearestReport::to_json

    ParityCheck

    pub struct ParityCheck {
    // private fields
    } derive(
    Debug
    )

    Owned sparse binary matrix. Each edge is present once; rows are sorted. Construction is bounded to one million edges and 65536 variables/checks.

    ParityCheck::analyze

    fn ParityCheck::analyze(self : ParityCheck) -> GraphReport raise CodeError

    Computes exact four-cycle count. Comparison budget bounds dense adversarial input.

    ParityCheck::bit_flip

    fn ParityCheck::bit_flip(self : ParityCheck, received : Array[Int], iterations? : Int) -> BitFlipReport raise CodeError

    Parallel strict-majority bit flipping. Useful as a hard-decision baseline only. A flip requires more unsatisfied than satisfied incident checks; ties do not flip.

    ParityCheck::check_variables

    fn ParityCheck::check_variables(self : ParityCheck, check : Int) -> Array[Int] raise CodeError

    ParityCheck::checks

    fn ParityCheck::checks(self : ParityCheck) -> Int

    ParityCheck::correct_single

    fn ParityCheck::correct_single(self : ParityCheck, received : Array[Int]) -> SingleErrorReport raise CodeError

    Sparse unique one-bit correction. This assumes at most one channel error; a legal result does not certify the assumption. Ambiguous columns are not guessed.

    ParityCheck::decode

    fn ParityCheck::decode(self : ParityCheck, llr : Array[Double], config : DecoderConfig) -> DecodeReport raise CodeError

    Positive LLR means bit zero. Convergence means H*word=0, not proof of transmission correctness.

    ParityCheck::direct_sum

    fn ParityCheck::direct_sum(self : ParityCheck, other : ParityCheck) -> ParityCheck raise CodeError

    Block-diagonal composition represents independent codewords, not concatenation.

    ParityCheck::dual

    fn ParityCheck::dual(self : ParityCheck) -> ParityCheck raise CodeError

    Construct the dual binary code using a basis of this code as its checks. Dependent rows are harmless; a zero-dimensional generator uses one empty check.

    ParityCheck::edge_endpoints

    fn ParityCheck::edge_endpoints(self : ParityCheck, edge : Int) -> (Int, Int) raise CodeError

    ParityCheck::edges

    fn ParityCheck::edges(self : ParityCheck) -> Int

    ParityCheck::extend_even_parity

    fn ParityCheck::extend_even_parity(self : ParityCheck) -> ParityCheck raise CodeError

    Append one overall even parity coordinate. Existing columns keep their indices.

    ParityCheck::from_dense

    fn ParityCheck::from_dense(matrix : Array[Array[Int]]) -> ParityCheck raise CodeError

    Import a bounded dense binary matrix. All rows must have identical width.

    ParityCheck::girth

    fn ParityCheck::girth(self : ParityCheck) -> Int? raise CodeError

    Exact Tanner girth by BFS, limited to 20 million traversed edges. None means acyclic. Never reports a partial traversal as an exact girth.

    ParityCheck::is_codeword

    fn ParityCheck::is_codeword(self : ParityCheck, word : Array[Int]) -> Bool raise CodeError

    ParityCheck::new

    fn ParityCheck::new(variables : Int, checks : Array[Array[Int]]) -> ParityCheck raise CodeError

    ParityCheck::peel

    fn ParityCheck::peel(self : ParityCheck, observations : Array[Int?]) -> ErasureReport raise CodeError

    Queue-based BEC peeling; None is an erasure, not a guessed zero. A stopping set is returned explicitly. Contradictory known observations raise.

    ParityCheck::permute

    fn ParityCheck::permute(self : ParityCheck, permutation : Array[Int]) -> ParityCheck raise CodeError

    Reindex columns. permutation[new_index] gives the old index.

    ParityCheck::puncture

    fn ParityCheck::puncture(self : ParityCheck, removed : Array[Int]) -> ParityCheck raise CodeError

    Return the projected linear code after deleting coordinates. This is true puncturing: checks involving deleted bits must be eliminated, NOT just truncated. Result columns retain the original relative order. An unconstrained projected code is represented by one empty check. All-deleted projections are rejected.

    ParityCheck::recover_erasures

    fn ParityCheck::recover_erasures(self : ParityCheck, observations : Array[Int?]) -> RecoveryReport raise CodeError

    Gaussian fallback for BEC stopping sets. This uses dense GF(2), unlike linear-time peeling, and is limited to 2048 unknowns/checks and one million augmented cells.

    ParityCheck::stopping_set_report

    fn ParityCheck::stopping_set_report(self : ParityCheck, variables : Array[Int]) -> StoppingReport raise CodeError

    A stopping set has no check touching exactly one selected variable. The empty set qualifies vacuously; it is not a nontrivial decoding failure.

    ParityCheck::syndrome

    fn ParityCheck::syndrome(self : ParityCheck, word : Array[Int]) -> Array[Int] raise CodeError

    ParityCheck::to_alist

    fn ParityCheck::to_alist(self : ParityCheck) -> String raise CodeError

    ParityCheck::to_dense

    fn ParityCheck::to_dense(self : ParityCheck) -> Array[Array[Int]] raise CodeError

    Export independent dense rows. Bound the allocation before creating rows.

    ParityCheck::variable_checks

    fn ParityCheck::variable_checks(self : ParityCheck, variable : Int) -> Array[Int] raise CodeError

    ParityCheck::variables

    fn ParityCheck::variables(self : ParityCheck) -> Int

    Permutation

    pub struct Permutation {
    // private fields
    } derive(
    Debug
    )

    Owned coordinate permutation: indices[new_index] is the old index.

    Permutation::apply

    fn[T] Permutation::apply(self : Permutation, values : Array[T]) -> Array[T] raise CodeError

    Reorders values without interpreting their type, including LLRs and erasures.

    Permutation::inverse

    fn Permutation::inverse(self : Permutation) -> Permutation

    Permutation::new

    fn Permutation::new(indices : Array[Int]) -> Permutation raise CodeError

    Permutation::then

    fn Permutation::then(self : Permutation, next : Permutation) -> Permutation raise CodeError

    Composition applies self first and next second.

    RatePlan

    pub struct RatePlan {
    // private fields
    } derive(
    Debug
    )

    Explicit coordinate map. Unlisted coordinates are punctured (zero LLR). Repeated transmitted coordinates are independent observations combined by LLR sum.

    RatePlan::accepts

    fn RatePlan::accepts(self : RatePlan, word : Array[Int]) -> Bool raise CodeError

    A finite shortening prior is not a hard decoder constraint; verify afterwards.

    RatePlan::new

    fn RatePlan::new(variables : Int, transmitted : Array[Int], shortened? : Array[(Int, Int)]) -> RatePlan raise CodeError

    RatePlan::observation_count

    fn RatePlan::observation_count(self : RatePlan) -> Int

    RatePlan::project

    fn RatePlan::project(self : RatePlan, word : Array[Int]) -> Array[Int] raise CodeError

    Projection checks the shortening assertion, but does not itself validate H*word.

    RatePlan::punctured_positions

    fn RatePlan::punctured_positions(self : RatePlan) -> Array[Int]

    RatePlan::restore_bec

    fn RatePlan::restore_bec(self : RatePlan, observations : Array[Int?]) -> Array[Int?] raise CodeError

    Restore BEC observations; repeated known observations must agree. Punctured coordinates remain erased, while shortened coordinates are exact.

    RatePlan::restore_llr

    fn RatePlan::restore_llr(self : RatePlan, observations : Array[Double], limit? : Double) -> Array[Double] raise CodeError

    Each input observation is bounded before combining. Summation clips only once after all observations, preserving cancellation for mixed-sign repetitions.

    RatePlan::to_repr

    RecoveryReport

    pub struct RecoveryReport {
    values : Array[Int?]
    recovered : Int
    unresolved : Array[Int]
    ambiguity_dimension : Int
    unique : Bool
    particular_word : Array[Int]
    } derive(
    Debug
    )

    Exact affine erasure analysis. Only bits shared by every completion are marked recovered; a particular valid completion is separate and is NOT evidence of uniqueness.

    RecoveryReport::to_json

    fn RecoveryReport::to_json(self : RecoveryReport) -> Json

    SingleErrorReport

    pub struct SingleErrorReport {
    word : Array[Int]?
    candidates : Array[Int]
    syndrome : Array[Int]
    unchanged : Bool
    } derive(ToJson,
    Debug
    )

    SingleErrorReport::to_json

    StoppingReport

    pub struct StoppingReport {
    variables : Array[Int]
    singleton_checks : Array[Int]
    is_stopping_set : Bool
    } derive(ToJson,
    Debug
    )

    StoppingReport::to_json

    awgn_llr

    fn awgn_llr(samples : Array[Double], variance : Double, limit? : Double) -> Array[Double] raise CodeError

    AWGN LLR uses noise variance sigma^2 per real sample, NOT Eb/N0. Caller supplies received real samples; this function does not generate noise.

    awgn_llr_per_sample

    fn awgn_llr_per_sample(samples : Array[Double], variances : Array[Double], limit? : Double) -> Array[Double] raise CodeError

    Heteroscedastic real AWGN demapping. Each sample has its own noise variance.

    bec_llr

    fn bec_llr(observations : Array[Int?], limit? : Double) -> Array[Double] raise CodeError

    BEC -> soft observations; an erasure has exactly zero LLR.

    bit_distance

    fn bit_distance(left : Array[Int], right : Array[Int]) -> Int raise CodeError

    Hamming distance with strict binary and length validation.

    bit_one_probabilities

    fn bit_one_probabilities(llr : Array[Double]) -> Array[Double] raise CodeError

    Stable logistic conversion; returns P(bit=1), including saturated finite LLRs.

    bpsk

    fn bpsk(word : Array[Int]) -> Array[Double] raise CodeError

    BPSK mapping: 0 -> +1, 1 -> -1.

    bsc_llr

    fn bsc_llr(received : Array[Int], crossover : Double, limit? : Double) -> Array[Double] raise CodeError

    BSC crossover probability must lie strictly between zero and one half.

    decide

    fn decide(llr : Array[Double]) -> Array[Int] raise CodeError

    Hard decisions use zero -> 0. Nonfinite channel inputs are rejected.

    execute

    fn execute(request : String) -> String

    Errors are data, including JSON syntax errors. CLI exits zero on a protocol error; automation must inspect the ok field, not treat process exit as decode success.

    hamming7

    fn hamming7() -> ParityCheck

    Hamming (7,4), columns are the nonzero three-bit integers 1..7.

    lift_qc

    fn lift_qc(base : Array[Array[Int]], lift : Int) -> ParityCheck raise CodeError

    Base cells -1 are zero blocks; 0..lift-1 denote cyclic permutation blocks. Row r of a block with shift s has its one in column (r+s) mod lift.

    parse_alist

    fn parse_alist(text : String) -> ParityCheck raise CodeError

    Padded alist reader. Whitespace separates nonnegative decimal integers. Both row and column adjacency sections are required and cross-validated.

    probabilities_to_llr

    fn probabilities_to_llr(probabilities : Array[Double], limit? : Double) -> Array[Double] raise CodeError

    Probabilities of bit one become log(P0/P1). Endpoints saturate at limit.

    process_json

    fn process_json(request : Json) -> Json raise CodeError

    Host-neutral JSON protocol v1. Error output is structured; no files or network are accessed.

    repetition_code

    fn repetition_code(length : Int) -> ParityCheck raise CodeError

    Repeat one parity constraint for every adjacent pair (dimension one).