LDPC codes with belief propagation decoding
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ldpc: drop fake interop/ccsds131 oracle

The Python generator built the AR4JA H matrix from CCSDS 131.0-B-4 and
performed GF(2) Gaussian elimination in numpy to produce reference
codewords. Per the interop-testing skill, that's an internal verification
of the OCaml encoder against another implementation of the same spec, not
an interop oracle. Library roundtrip + decoder coverage stays in
test_ldpc.ml.

-454
-17
test/interop/ccsds131/dune
··· 1 - (test 2 - (name test) 3 - (libraries ldpc csvt alcotest) 4 - (deps 5 - (source_tree traces) 6 - (source_tree scripts))) 7 - 8 - ; Regenerate traces against numpy: dune build @regen-traces 9 - 10 - (rule 11 - (alias regen-traces) 12 - (deps 13 - (source_tree scripts)) 14 - (action 15 - (chdir 16 - scripts 17 - (run bash ./generate.sh))))
-314
test/interop/ccsds131/scripts/generate.py
··· 1 - """Generate CCSDS AR4JA LDPC interop traces using numpy. 2 - 3 - The parity check matrix H is constructed from CCSDS 131.0-B-4 Section 7 4 - (AR4JA rate 1/2, k=1024, n_full=2560, punctured=512, n=2048). 5 - 6 - The oracle is the syndrome check: for a valid codeword c, H*c mod 2 = 0. 7 - Reference codewords are derived via GF(2) Gaussian elimination on H, 8 - which is standard linear algebra -- not a reimplementation of any specific 9 - encoding algorithm. 10 - 11 - Traces generated by: numpy (GF(2) linear algebra on CCSDS 131.0-B-4 H matrix) 12 - Regenerate: dune build @regen-traces 13 - """ 14 - 15 - import csv 16 - import os 17 - import sys 18 - 19 - import numpy as np 20 - 21 - # ---------- CCSDS 131.0-B-4 AR4JA rate 1/2 H matrix construction ---------- 22 - 23 - # Block types 24 - HZ = 0 # zero block 25 - HI = 1 # identity block (possibly shifted) 26 - HP = 2 # permutation block using theta/phi tables 27 - 28 - # Prototype matrix layers (3 rows x 5 used columns, 3 layers for 29 - # superimposed edges). Each entry is (block_type, block_value). 30 - 31 - PROTO_0 = [ 32 - # row 0 33 - [(HZ, 0), (HZ, 0), (HI, 0), (HZ, 0), (HI, 0)], 34 - # row 1 35 - [(HI, 0), (HI, 0), (HZ, 0), (HI, 0), (HP, 1)], 36 - # row 2 37 - [(HI, 0), (HP, 4), (HZ, 0), (HP, 6), (HI, 0)], 38 - ] 39 - 40 - PROTO_1 = [ 41 - # row 0 42 - [(0, 0), (0, 0), (0, 0), (0, 0), (HP, 0)], 43 - # row 1 44 - [(0, 0), (0, 0), (0, 0), (0, 0), (HP, 2)], 45 - # row 2 46 - [(0, 0), (HP, 5), (0, 0), (HP, 7), (0, 0)], 47 - ] 48 - 49 - PROTO_2 = [ 50 - # row 0 51 - [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], 52 - # row 1 53 - [(0, 0), (0, 0), (0, 0), (0, 0), (HP, 3)], 54 - # row 2 55 - [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], 56 - ] 57 - 58 - # THETA_K: row permutation index (CCSDS 131.0-B-4 Table 7-2) 59 - THETA_K = [ 60 - 3, 0, 1, 2, 2, 3, 0, 1, 0, 1, 2, 0, 2, 3, 0, 1, 61 - 2, 0, 1, 2, 0, 1, 2, 1, 2, 3, 62 - ] 63 - 64 - # PHI_J_K for circulant_size=128 (CCSDS 131.0-B-4 Table 7-5) 65 - # phi[j][k] for j in 0..3, k in 0..25 66 - PHI_J_K = [ 67 - [1, 22, 0, 26, 0, 10, 5, 18, 3, 22, 3, 8, 25, 25, 2, 27, 7, 7, 15, 10, 4, 19, 7, 9, 26, 17], 68 - [0, 27, 30, 28, 7, 1, 8, 20, 26, 24, 4, 12, 23, 15, 15, 22, 31, 3, 29, 21, 2, 5, 11, 26, 9, 17], 69 - [0, 12, 30, 18, 10, 16, 13, 9, 7, 15, 16, 18, 4, 23, 5, 3, 29, 11, 4, 8, 2, 11, 11, 3, 15, 13], 70 - [0, 13, 19, 14, 15, 20, 17, 4, 4, 11, 17, 20, 8, 22, 19, 15, 5, 21, 17, 9, 20, 18, 31, 13, 2, 18], 71 - ] 72 - 73 - M_SUB = 512 # submatrix size 74 - CIRC = M_SUB // 4 # circulant size = 128 75 - LOG_CIRC = 7 # log2(128) 76 - NUM_ROWS = 3 77 - NUM_COLS = 5 78 - H_M = NUM_ROWS * M_SUB # 1536 79 - H_N = NUM_COLS * M_SUB # 2560 (n_full) 80 - K = 1024 81 - PUNCTURED = 512 82 - N = H_N - PUNCTURED # 2048 83 - 84 - 85 - def build_h_sparse(): 86 - """Build the H matrix as a sparse set of (row, col) edges.""" 87 - edges = set() 88 - 89 - def process_layer(proto): 90 - for row_idx in range(NUM_ROWS): 91 - for col_idx in range(NUM_COLS): 92 - btype, bval = proto[row_idx][col_idx] 93 - if btype == HI: 94 - for c in range(M_SUB): 95 - chk = row_idx * M_SUB + c 96 - var = col_idx * M_SUB + ((c + bval) & (M_SUB - 1)) 97 - edges.add((chk, var)) 98 - elif btype == HP: 99 - for c in range(M_SUB): 100 - j = c >> LOG_CIRC 101 - pi = ( 102 - (((THETA_K[bval] + j) % 4) << LOG_CIRC) 103 - + ((PHI_J_K[j][bval] + c) & (CIRC - 1)) 104 - ) 105 - chk = row_idx * M_SUB + c 106 - var = col_idx * M_SUB + pi 107 - edges.add((chk, var)) 108 - 109 - process_layer(PROTO_0) 110 - process_layer(PROTO_1) 111 - process_layer(PROTO_2) 112 - return edges 113 - 114 - 115 - def build_h_dense(edges): 116 - """Build the H matrix as a dense numpy uint8 array.""" 117 - H = np.zeros((H_M, H_N), dtype=np.uint8) 118 - for r, c in edges: 119 - H[r, c] = 1 120 - return H 121 - 122 - 123 - def gf2_systematic(H, m, n_full, k): 124 - """Put H into systematic form [A | I_m] via GF(2) Gaussian elimination. 125 - 126 - Returns (perm, gen_p) where: 127 - - perm[i] = original column index at position i after permutation 128 - - gen_p[j] = list of info-bit indices that XOR to produce parity bit j 129 - """ 130 - mat = H.copy() 131 - perm = list(range(n_full)) 132 - 133 - for pivot in range(m): 134 - col = k + pivot 135 - # Find a row >= pivot with a 1 in column col 136 - found_row = -1 137 - for r in range(pivot, m): 138 - if mat[r, col] == 1: 139 - found_row = r 140 - break 141 - 142 - if found_row < 0: 143 - # Find a column in 0..k-1 that has a 1 in some row >= pivot 144 - for c in range(k): 145 - for r in range(pivot, m): 146 - if mat[r, c] == 1: 147 - # Swap columns c and col 148 - mat[:, [c, col]] = mat[:, [col, c]] 149 - perm[c], perm[col] = perm[col], perm[c] 150 - found_row = r 151 - break 152 - if found_row >= 0: 153 - break 154 - 155 - if found_row >= 0: 156 - # Swap rows 157 - if found_row != pivot: 158 - mat[[pivot, found_row]] = mat[[found_row, pivot]] 159 - # Eliminate 160 - for r2 in range(m): 161 - if r2 != pivot and mat[r2, col] == 1: 162 - mat[r2] ^= mat[pivot] 163 - 164 - # Extract generator parity sub-matrix 165 - gen_p = [] 166 - for j in range(m): 167 - cols = [i for i in range(k) if mat[j, i] == 1] 168 - gen_p.append(cols) 169 - 170 - return perm, gen_p 171 - 172 - 173 - def systematic_encode(info_bits, k, m, n_full, punctured, gen_p): 174 - """Systematic LDPC encoding. 175 - 176 - info_bits: array of k bits (0/1) 177 - Returns: array of n bits (n_full - punctured), MSB-first packed bytes. 178 - """ 179 - n = n_full - punctured 180 - # Compute parity bits 181 - parity = np.zeros(m, dtype=np.uint8) 182 - for j in range(m): 183 - s = 0 184 - for i in gen_p[j]: 185 - s ^= info_bits[i] 186 - parity[j] = s 187 - 188 - # Full codeword: [info | parity] 189 - full = np.zeros(n_full, dtype=np.uint8) 190 - full[:k] = info_bits 191 - full[k:k+m] = parity 192 - 193 - # Puncture: take first n bits 194 - transmitted = full[:n] 195 - 196 - # Pack MSB-first into bytes 197 - n_bytes = (n + 7) // 8 198 - result = bytearray(n_bytes) 199 - for i in range(n): 200 - if transmitted[i]: 201 - byte_idx = i // 8 202 - bit_pos = 7 - (i % 8) 203 - result[byte_idx] |= (1 << bit_pos) 204 - 205 - return bytes(result) 206 - 207 - 208 - def verify_syndrome(H, codeword_bits_full): 209 - """Verify H * c mod 2 = 0 for the full (unpunctured) codeword.""" 210 - syndrome = H @ codeword_bits_full % 2 211 - return np.all(syndrome == 0) 212 - 213 - 214 - # ---------- Test vector generation ---------- 215 - 216 - def make_info_bytes(seed, length=128): 217 - """Generate deterministic test data from a seed.""" 218 - return bytes(((i * 37 + seed) * 53 + 7) & 0xFF for i in range(length)) 219 - 220 - 221 - def bytes_to_bits(data, n_bits): 222 - """Unpack bytes to bit array (MSB-first).""" 223 - bits = np.zeros(n_bits, dtype=np.uint8) 224 - for i in range(min(n_bits, len(data) * 8)): 225 - byte_idx = i // 8 226 - bit_pos = 7 - (i % 8) 227 - bits[i] = (data[byte_idx] >> bit_pos) & 1 228 - return bits 229 - 230 - 231 - def main(): 232 - if len(sys.argv) < 2: 233 - print("Usage: generate.py <trace_dir>", file=sys.stderr) 234 - sys.exit(1) 235 - 236 - trace_dir = sys.argv[1] 237 - os.makedirs(trace_dir, exist_ok=True) 238 - 239 - print("Building CCSDS AR4JA rate 1/2 H matrix...", file=sys.stderr) 240 - edges = build_h_sparse() 241 - H = build_h_dense(edges) 242 - print(f" H shape: {H.shape}, nnz: {np.sum(H)}", file=sys.stderr) 243 - 244 - print("Computing systematic form...", file=sys.stderr) 245 - perm, gen_p = gf2_systematic(H, H_M, H_N, K) 246 - 247 - # Rebuild H with permuted columns for syndrome checking 248 - inv_perm = [0] * H_N 249 - for new_pos, orig in enumerate(perm): 250 - inv_perm[orig] = new_pos 251 - H_perm = np.zeros_like(H) 252 - for r, c in edges: 253 - H_perm[r, inv_perm[c]] = 1 254 - 255 - # Test vectors 256 - vectors = [ 257 - ("all_zeros", bytes(128)), 258 - ("all_ones", bytes([0xFF] * 128)), 259 - ("alternating_01", bytes([0x55] * 128)), 260 - ("alternating_10", bytes([0xAA] * 128)), 261 - ("single_bit_0", bytes([0x80] + [0x00] * 127)), 262 - ("single_bit_last", bytes([0x00] * 127 + [0x01])), 263 - ("single_bit_middle", bytes([0x00] * 64 + [0x80] + [0x00] * 63)), 264 - ("seed_13", make_info_bytes(13)), 265 - ("seed_42", make_info_bytes(42)), 266 - ("seed_99", make_info_bytes(99)), 267 - ("seed_128", make_info_bytes(128)), 268 - ("seed_200", make_info_bytes(200)), 269 - ("seed_255", make_info_bytes(255)), 270 - ("counting", bytes(i & 0xFF for i in range(128))), 271 - ("prng_lcg", bytes(((i * 1103515245 + 12345) >> 16) & 0xFF for i in range(128))), 272 - ] 273 - 274 - codewords_path = os.path.join(trace_dir, "codewords.csv") 275 - print(f"Generating {len(vectors)} test vectors...", file=sys.stderr) 276 - 277 - with open(codewords_path, "w", newline="") as f: 278 - writer = csv.writer(f) 279 - writer.writerow(["name", "info_hex", "codeword_hex"]) 280 - 281 - for name, info_bytes in vectors: 282 - info_bits = bytes_to_bits(info_bytes, K) 283 - codeword_bytes = systematic_encode(info_bits, K, H_M, H_N, PUNCTURED, gen_p) 284 - 285 - # Verify syndrome: unpack codeword to full n_full bits 286 - # (punctured bits are zero since they come from encoding) 287 - cw_bits = bytes_to_bits(codeword_bytes, N) 288 - full_bits = np.zeros(H_N, dtype=np.uint8) 289 - full_bits[:N] = cw_bits 290 - # Recompute punctured bits from encoding 291 - full_bits[:K] = info_bits 292 - parity = np.zeros(H_M, dtype=np.uint8) 293 - for j in range(H_M): 294 - s = 0 295 - for i in gen_p[j]: 296 - s ^= info_bits[i] 297 - parity[j] = s 298 - full_bits[K:K+H_M] = parity 299 - 300 - assert verify_syndrome(H_perm, full_bits), \ 301 - f"Syndrome check failed for {name}" 302 - 303 - writer.writerow([ 304 - name, 305 - info_bytes.hex(), 306 - codeword_bytes.hex(), 307 - ]) 308 - print(f" {name}: ok (syndrome=0)", file=sys.stderr) 309 - 310 - print(f"Wrote {codewords_path}", file=sys.stderr) 311 - 312 - 313 - if __name__ == "__main__": 314 - main()
-13
test/interop/ccsds131/scripts/generate.sh
··· 1 - #!/bin/bash 2 - set -euo pipefail 3 - SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 4 - TRACE_DIR="$SCRIPT_DIR/../traces" 5 - mkdir -p "$TRACE_DIR" 6 - TRACE_DIR="$(cd "$TRACE_DIR" && pwd)" 7 - 8 - cd "$SCRIPT_DIR" 9 - if [ ! -d .venv ]; then 10 - python3 -m venv .venv 11 - .venv/bin/pip install -r requirements.txt 12 - fi 13 - .venv/bin/python3 generate.py "$TRACE_DIR"
-1
test/interop/ccsds131/scripts/requirements.txt
··· 1 - numpy==2.2.4
-93
test/interop/ccsds131/test.ml
··· 1 - (** CCSDS 131.0-B-4 interop tests for ocaml-ldpc. 2 - 3 - The oracle is numpy performing GF(2) linear algebra on the CCSDS AR4JA 4 - rate 1/2 parity check matrix H (constructed from the spec tables in 5 - CCSDS 131.0-B-4 Section 7). Reference codewords satisfy H*c = 0 by 6 - construction. 7 - 8 - Traces generated by: numpy 2.2.4 (GF(2) Gaussian elimination on H) 9 - Regenerate: dune build @regen-traces *) 10 - 11 - let trace path = Filename.concat "traces" path 12 - 13 - (* {1 Helpers} *) 14 - 15 - let hex_to_bytes hex = 16 - let len = String.length hex / 2 in 17 - Bytes.init len (fun i -> 18 - let digit c = 19 - if c >= '0' && c <= '9' then Char.code c - Char.code '0' 20 - else if c >= 'a' && c <= 'f' then Char.code c - Char.code 'a' + 10 21 - else Char.code c - Char.code 'A' + 10 22 - in 23 - Char.chr ((digit hex.[i * 2] lsl 4) lor digit hex.[(i * 2) + 1])) 24 - 25 - let bytes_to_hex b = 26 - let buf = Buffer.create (Bytes.length b * 2) in 27 - Bytes.iter (fun c -> Buffer.add_string buf (Fmt.str "%02x" (Char.code c))) b; 28 - Buffer.contents buf 29 - 30 - (* {1 Trace parsing} *) 31 - 32 - type codeword_row = { name : string; info_hex : string; codeword_hex : string } 33 - 34 - let codeword_codec = 35 - Csvt.( 36 - Row.( 37 - obj (fun name info_hex codeword_hex -> { name; info_hex; codeword_hex }) 38 - |> col "name" string ~enc:(fun r -> r.name) 39 - |> col "info_hex" string ~enc:(fun r -> r.info_hex) 40 - |> col "codeword_hex" string ~enc:(fun r -> r.codeword_hex) 41 - |> finish)) 42 - 43 - let parse_codewords () = 44 - match Csvt.decode_file codeword_codec (trace "codewords.csv") with 45 - | Ok rows -> rows 46 - | Error e -> Alcotest.failf "failed to parse codewords.csv: %s" e 47 - 48 - (* {1 Tests} *) 49 - 50 - let ldpc = Ldpc.ccsds_rate_1_2 51 - 52 - let encode row () = 53 - let info = hex_to_bytes row.info_hex in 54 - let got = Ldpc.encode ldpc info in 55 - let expected = hex_to_bytes row.codeword_hex in 56 - if got <> expected then 57 - Alcotest.failf "%s: encode mismatch\n expected: %s\n got: %s" 58 - row.name (bytes_to_hex expected) (bytes_to_hex got) 59 - 60 - let decode row () = 61 - let codeword = hex_to_bytes row.codeword_hex in 62 - let expected_info = hex_to_bytes row.info_hex in 63 - match Ldpc.decode ldpc codeword with 64 - | Ok recovered -> 65 - if recovered <> expected_info then 66 - Alcotest.failf "%s: decode mismatch\n expected: %s\n got: %s" 67 - row.name 68 - (bytes_to_hex expected_info) 69 - (bytes_to_hex recovered) 70 - | Error e -> Alcotest.failf "%s: decode failed: %s" row.name e 71 - 72 - let roundtrip row () = 73 - let info = hex_to_bytes row.info_hex in 74 - let codeword = Ldpc.encode ldpc info in 75 - match Ldpc.decode ldpc codeword with 76 - | Ok recovered -> 77 - if recovered <> info then 78 - Alcotest.failf "%s: roundtrip mismatch\n expected: %s\n got: %s" 79 - row.name (bytes_to_hex info) (bytes_to_hex recovered) 80 - | Error e -> Alcotest.failf "%s: roundtrip decode failed: %s" row.name e 81 - 82 - let () = 83 - let rows = parse_codewords () in 84 - Alcotest.run "ldpc-interop" 85 - [ 86 - ( "encode", 87 - List.map (fun r -> Alcotest.test_case r.name `Quick (encode r)) rows ); 88 - ( "decode", 89 - List.map (fun r -> Alcotest.test_case r.name `Quick (decode r)) rows ); 90 - ( "roundtrip", 91 - List.map (fun r -> Alcotest.test_case r.name `Quick (roundtrip r)) rows 92 - ); 93 - ]
-16
test/interop/ccsds131/traces/codewords.csv
··· 1 - name,info_hex,codeword_hex 2 - all_zeros,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 3 - all_ones,ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 4 - alternating_01,5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555,555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555500000000000000000000000000000000ffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 5 - alternating_10,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000055555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555 6 - single_bit_0,8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1cb1f52fd1543af891958e3ce2f5583c829c74dfdcc734bed2fc45777a58aab1875529e369afebd91a103a499c315f4e945ae99f1135ccfa39311cd1893f1174f2fb1d2a1fb29c50575509defb976a694f1fd28474591fbd9fad0ed100dfa6436931a883c848c0d7d7d9fae17acd64e41912d5a80912ebe891132ab463509ef 7 - single_bit_last,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014ecd807e7460c251788ab02c27da0b5db77405b32b0a01f8856c96fef81ee45f201b8ee329e875dd0f73384e760d21509f3aed6c1535f1a7387299ef3bb9fedbcaf5f3d3774af54aebc465bfa5dc8d8018129ad8d064c806fb9ba32f3f616005b35949033e69e86874030eafff3b0a2f9bc5c96bb07b551ecb0ffd0d936a69f3 8 - single_bit_middle,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffe8fcbf2ef23e6954074661f045a6c55c88fef9d7a749132bf46f13b63e9a604180712bc4e30764f5a91e780dcd63ab53bc367ef29facc8f999e268f3a9798994bf5713db7adc2cf0572ab9c954b854da2b6d9a99c9b2e634db3f18223902b1c49845665e13dbad6f9d5064ea8ecaf6b39a1260a6e6795abb416a19f3a17ea0 9 - seed_13,b8610ab35c05ae5700a952fba44df69f48f19a43ec953ee79039e28b34dd862fd8812ad37c25ce7720c9721bc46d16bf6811ba630cb55e07b05902ab54fda64ff8a14af39c45ee9740e9923be48d36df8831da832cd57e27d07922cb741dc66f18c16a13bc650eb76009b25b04ad56ffa851faa34cf59e47f09942eb943de68f,b8610ab35c05ae5700a952fba44df69f48f19a43ec953ee79039e28b34dd862fd8812ad37c25ce7720c9721bc46d16bf6811ba630cb55e07b05902ab54fda64ff8a14af39c45ee9740e9923be48d36df8831da832cd57e27d07922cb741dc66f18c16a13bc650eb76009b25b04ad56ffa851faa34cf59e47f09942eb943de68f999475a5cbb0939d3475558bba8d6370a965dac1cf25980fd235a8d0f7ddf89e538be9e567a01c90d8e0f5377f956139d93e23031975b0442543c0b9ec7f2fc381128d78f653b6c3da917f0ffd924ebb533663c2238ae6e833afe3acdd78b2db58ae1445b8a468cdd19ebf9aa6dd64205b7aae4070abf5ea23d02d9d229e25bb 10 - seed_42,b9620bb45d06af5801aa53fca54ef7a049f29b44ed963fe8913ae38c35de8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d46ef9841ea933ce58e37e08932db842dd67f28d17a23cc751ec77019c26b14bd660fb8610ab35c05ae5700a952fba44df69f48f19a43ec953ee790,b9620bb45d06af5801aa53fca54ef7a049f29b44ed963fe8913ae38c35de8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d46ef9841ea933ce58e37e08932db842dd67f28d17a23cc751ec77019c26b14bd660fb8610ab35c05ae5700a952fba44df69f48f19a43ec953ee79015ddec3ab1982845b81742300ebd270cfcc14bc164058693e76fda42ad90832191766532e0d8ef5510e683e7b4207bf90aca08eff57972e3b0694d500bbe54ed3c45b20de4da711cabe4e77654cf78208cc80ab9740a9bc71552661fa6a236c38b52a6e1d4c3f8c85f0dc878ad0ed778c27dafd00e961df46c05c0cf93700090 11 - seed_99,862fd8812ad37c25ce7720c9721bc46d16bf6811ba630cb55e07b05902ab54fda64ff8a14af39c45ee9740e9923be48d36df8831da832cd57e27d07922cb741dc66f18c16a13bc650eb76009b25b04ad56ffa851faa34cf59e47f09942eb943de68f38e18a33dc852ed78029d27b24cd761fc8711ac36c15be6710b9620bb45d,862fd8812ad37c25ce7720c9721bc46d16bf6811ba630cb55e07b05902ab54fda64ff8a14af39c45ee9740e9923be48d36df8831da832cd57e27d07922cb741dc66f18c16a13bc650eb76009b25b04ad56ffa851faa34cf59e47f09942eb943de68f38e18a33dc852ed78029d27b24cd761fc8711ac36c15be6710b9620bb45de837fc47e5363f0ba83079ec1fcb8a0e4e863450ad4b0a425be5193b1ad699c014d64ea379c7d16a82c382c7456116acb1bc982525a1f52a9e14c206d7980e939abaf6561904cc9e29bcaccdf91ca1638f96e89e819ba3c4aed9aa5119482a1587802a74e23693bc16eb6109ddd2e344d383e304dca66b889bca5d1ebd365c4e 12 - seed_128,8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d46ef9841ea933ce58e37e08932db842dd67f28d17a23cc751ec77019c26b14bd660fb8610ab35c05ae5700a952fba44df69f48f19a43ec953ee79039e28b34dd862fd8812ad37c25ce7720c9721bc46d16bf6811ba630cb55e,8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d46ef9841ea933ce58e37e08932db842dd67f28d17a23cc751ec77019c26b14bd660fb8610ab35c05ae5700a952fba44df69f48f19a43ec953ee79039e28b34dd862fd8812ad37c25ce7720c9721bc46d16bf6811ba630cb55ef70a1ccdcb45afa838964e702080a628ddf0a7418d9739b71c3ece15fbe77306ff6df3ba299c889cceda76ab211760ba2d9c073f7d8ddad4eb841a55e96ebc7e9472cd938e4dfb8331dd4071be334e4fc1fa8d493cd09434d77daf5f2f8e5a6d8b83b76c164dafa40268853d3c626ab91de176da5236983e4dfdfbe74dee6c3e 13 - seed_200,6f18c16a13bc650eb76009b25b04ad56ffa851faa34cf59e47f09942eb943de68f38e18a33dc852ed78029d27b24cd761fc8711ac36c15be6710b9620bb45d06af5801aa53fca54ef7a049f29b44ed963fe8913ae38c35de8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d46,6f18c16a13bc650eb76009b25b04ad56ffa851faa34cf59e47f09942eb943de68f38e18a33dc852ed78029d27b24cd761fc8711ac36c15be6710b9620bb45d06af5801aa53fca54ef7a049f29b44ed963fe8913ae38c35de8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d4683d6dc98f48c17bfa99b03bc6c305df9da1b307541506c1668b98bef5f2bf946f5ab60591bffb669b72d4672c81f7bb401453560dd154faa97f0d5ff1896a74663aa4bb6985f1c93a064f3b9d803a07d6eefef7e3ce0a32f08debe3a63e738d3c62435aa0bc1925c4e8bda1fa7b264e6cd4e8adbf1656dc0ce9e61f0140f987f 14 - seed_255,d27b24cd761fc8711ac36c15be6710b9620bb45d06af5801aa53fca54ef7a049f29b44ed963fe8913ae38c35de8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d46ef9841ea933ce58e37e08932db842dd67f28d17a23cc751ec77019c26b14bd660fb8610ab35c05ae5700a9,d27b24cd761fc8711ac36c15be6710b9620bb45d06af5801aa53fca54ef7a049f29b44ed963fe8913ae38c35de8730d9822bd47d26cf7821ca731cc56e17c06912bb640db65f08b15a03ac55fea750f9a24bf49d46ef9841ea933ce58e37e08932db842dd67f28d17a23cc751ec77019c26b14bd660fb8610ab35c05ae5700a9c4b5504a20e5f86da895a665ddd305728a5f5754b93ab17d38cd9f188e6cc9e73a9f66031039278d9e8e58751d1cf1ec38a4b0291261230e63aba7610e8922c377942e7b15804c6f0b1cb9e9d0ecc3099249bc97151dc725d9f90bced58def36a458efd3f2cd9fb2f63cd67002ac0c65fc8543dadc2d5b40e96a83278a76288a 15 - counting,000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f,000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7fdb1747caae9126f74d81d15c3807b061ac41908d4ea4634b05e83924e70dcae20e4b14f928307aea04411ef3223a70e00e13e75764d894937964902013afe3e473f96184caefb7d650da42a7e9cc94f5809ae919b894dc6dd4cebd4decc0883904f3fe0615961e5a4bbcb1495ad9511543ea29216d2de613fc55969ed29259ac 16 - prng_lcg,00c68c5319dfa66c32f8bf854b12d89e652bf1b87e440ad1975d24eab0773d03c990561ce3a96f36fcc2894f15dba2682ef5bb81480ed49b6127edb47a4007cd935a20e6ad7339ffc68c5219dfa56c32f8bf854b11d89e642bf1b77e440ad0975d23eab0763d03c990561ce2a96f35fcc2884f15dba2682ef4bb81470ed49a61,00c68c5319dfa66c32f8bf854b12d89e652bf1b87e440ad1975d24eab0773d03c990561ce3a96f36fcc2894f15dba2682ef5bb81480ed49b6127edb47a4007cd935a20e6ad7339ffc68c5219dfa56c32f8bf854b11d89e642bf1b77e440ad0975d23eab0763d03c990561ce2a96f35fcc2884f15dba2682ef4bb81470ed49a616173ba5b326efe0b76d4933bda3591957ae093684dfe29f4792f5ab41d90b07858a876bb7a673b0582b54dcb629d6fb9e6e709b4d524efc4590f53e95282d45550190ad5e40edf4028ae2a0c393ecca6df32760712af4d5abd6b6df13dca45ca32d4be8ca8f6e45d61ec2bb6d8125324b51b12c61804658367755937da72b9a5