From 6b222d01fee072bcd3a680e6a96ae7d22e13bcac Mon Sep 17 00:00:00 2001 From: Sagar Thakrar Date: Wed, 14 Oct 2026 16:04:28 +0530 Subject: [PATCH] Research: twisted helper contract absorbs three R439 helper-star restorations into A (no new kappa) Card bit-helper-contract. A replacement for the inherited H2/K and literal-H4 helper interface, strictly weaker than PR1194's semantic-D contract: D may leave helpers twisted by an invertible helper-only T if C U' diag(I_x, T) = I on z and the target response is N = K'T. An exact single-edge criterion (unique substitute set S) and an exhaustive census on the PR967, PR1062, PR1122 and PR1188 words find exactly three frame-legal positive absorptions. Applied to PR1062's word (11,500 -> 11,497 ADDs) and PR1188's word (10,492 -> 10,489), the boundary is exact on all 661 dirty columns with unchanged frame paths and paid profile; the inherited checker and PR1194's splice reject the words, and the literal-cleanup variant is a dirty-input counterexample. The instances keep the base words' literal C and use the inherited common-frame premise for three helpers, both stated explicitly. Seed 2, bit-helper-contract (refined). Prepared with substantial Anthropic Claude assistance. --- .../EXPECTED.json | 995 ++++++++++++++++++ .../PROOF.md | 215 ++++ .../README.md | 247 +++++ .../SOURCES.json | 60 ++ .../TASK.json | 78 ++ .../VERIFY.json | 38 + .../absorbed-pr1062.json.gz | Bin 0 -> 38423 bytes .../absorbed-pr1188.json.gz | Bin 0 -> 35755 bytes .../verify.py | 853 +++++++++++++++ 9 files changed, 2486 insertions(+) create mode 100644 research/r439-twisted-star-absorption-seed02/EXPECTED.json create mode 100644 research/r439-twisted-star-absorption-seed02/PROOF.md create mode 100644 research/r439-twisted-star-absorption-seed02/README.md create mode 100644 research/r439-twisted-star-absorption-seed02/SOURCES.json create mode 100644 research/r439-twisted-star-absorption-seed02/TASK.json create mode 100644 research/r439-twisted-star-absorption-seed02/VERIFY.json create mode 100644 research/r439-twisted-star-absorption-seed02/absorbed-pr1062.json.gz create mode 100644 research/r439-twisted-star-absorption-seed02/absorbed-pr1188.json.gz create mode 100644 research/r439-twisted-star-absorption-seed02/verify.py diff --git a/research/r439-twisted-star-absorption-seed02/EXPECTED.json b/research/r439-twisted-star-absorption-seed02/EXPECTED.json new file mode 100644 index 0000000000..e11da70965 --- /dev/null +++ b/research/r439-twisted-star-absorption-seed02/EXPECTED.json @@ -0,0 +1,995 @@ +{ + "census": { + "PR1062": { + "A_writer_pairs": 481, + "admitted": [ + [ + 506, + 374, + 288, + [ + 69 + ] + ], + [ + 507, + 355, + 290, + [ + 72 + ] + ], + [ + 514, + 367, + 304, + [ + 360 + ] + ] + ], + "centres": 162, + "d_tail_dirty_boundary_preserved": 148, + "d_tail_gains": [ + 0 + ], + "d_tail_same_centre_pairs": 148, + "dirty_boundary_preserved": 481, + "edges_with_A_writer": 236, + "first_centre_read": { + "A": 230, + "scatter": 6 + }, + "frame_by_gain": { + "-1": { + "frame_illegal": 192 + }, + "-10": { + "frame_illegal": 1 + }, + "-2": { + "frame_illegal": 45 + }, + "-3": { + "frame_illegal": 12 + }, + "-4": { + "frame_illegal": 6 + }, + "-5": { + "frame_illegal": 30 + }, + "-6": { + "frame_illegal": 25 + }, + "-7": { + "frame_illegal": 1 + }, + "-8": { + "frame_illegal": 1 + }, + "0": { + "frame_illegal": 116, + "frame_legal": 2, + "paths_changed": 2 + }, + "1": { + "frame_illegal": 45, + "frame_legal": 3 + } + }, + "gain_histogram": { + "-1": 192, + "-10": 1, + "-2": 45, + "-3": 12, + "-4": 6, + "-5": 30, + "-6": 25, + "-7": 1, + "-8": 1, + "0": 120, + "1": 48 + }, + "positive": 48, + "positive_outcomes": { + "admitted": 3, + "frame_illegal": 45 + }, + "star_edges": 236, + "substitute_size_histogram": { + "1": 109, + "10": 1, + "11": 2, + "2": 239, + "3": 56, + "4": 10, + "5": 4, + "6": 31, + "7": 27, + "8": 2 + } + }, + "PR1122": { + "A_writer_pairs": 489, + "admitted": [ + [ + 506, + 374, + 288, + [ + 69 + ] + ], + [ + 507, + 355, + 290, + [ + 72 + ] + ], + [ + 514, + 367, + 304, + [ + 360 + ] + ] + ], + "centres": 162, + "d_tail_dirty_boundary_preserved": 148, + "d_tail_gains": [ + 0 + ], + "d_tail_same_centre_pairs": 148, + "dirty_boundary_preserved": 489, + "edges_with_A_writer": 236, + "first_centre_read": { + "A": 230, + "scatter": 6 + }, + "frame_by_gain": { + "-1": { + "frame_illegal": 203 + }, + "-10": { + "frame_illegal": 2 + }, + "-2": { + "frame_illegal": 50 + }, + "-3": { + "frame_illegal": 27 + }, + "-4": { + "frame_illegal": 10 + }, + "-5": { + "frame_illegal": 14 + }, + "-6": { + "frame_illegal": 7 + }, + "-7": { + "frame_illegal": 2 + }, + "-8": { + "frame_illegal": 1 + }, + "-9": { + "frame_illegal": 2 + }, + "0": { + "frame_illegal": 119, + "frame_legal": 2, + "paths_changed": 2 + }, + "1": { + "frame_illegal": 45, + "frame_legal": 3 + } + }, + "gain_histogram": { + "-1": 203, + "-10": 2, + "-2": 50, + "-3": 27, + "-4": 10, + "-5": 14, + "-6": 7, + "-7": 2, + "-8": 1, + "-9": 2, + "0": 123, + "1": 48 + }, + "positive": 48, + "positive_outcomes": { + "admitted": 3, + "frame_illegal": 45 + }, + "star_edges": 236, + "substitute_size_histogram": { + "1": 109, + "10": 2, + "11": 3, + "2": 243, + "3": 60, + "4": 27, + "5": 10, + "6": 22, + "7": 11, + "8": 2 + } + }, + "PR1188": { + "A_writer_pairs": 470, + "admitted": [ + [ + 506, + 374, + 288, + [ + 69 + ] + ], + [ + 507, + 355, + 290, + [ + 72 + ] + ], + [ + 514, + 367, + 304, + [ + 360 + ] + ] + ], + "centres": 162, + "d_tail_dirty_boundary_preserved": 148, + "d_tail_gains": [ + 0 + ], + "d_tail_same_centre_pairs": 148, + "dirty_boundary_preserved": 470, + "edges_with_A_writer": 236, + "first_centre_read": { + "A": 230, + "scatter": 6 + }, + "frame_by_gain": { + "-1": { + "frame_illegal": 195 + }, + "-10": { + "frame_illegal": 2 + }, + "-2": { + "frame_illegal": 52 + }, + "-3": { + "frame_illegal": 20 + }, + "-4": { + "frame_illegal": 8 + }, + "-5": { + "frame_illegal": 13 + }, + "-6": { + "frame_illegal": 5 + }, + "-7": { + "frame_illegal": 2 + }, + "-8": { + "frame_illegal": 1 + }, + "-9": { + "frame_illegal": 2 + }, + "0": { + "frame_illegal": 119, + "frame_legal": 2, + "paths_changed": 2 + }, + "1": { + "frame_illegal": 44, + "frame_legal": 3 + } + }, + "gain_histogram": { + "-1": 195, + "-10": 2, + "-2": 52, + "-3": 20, + "-4": 8, + "-5": 13, + "-6": 5, + "-7": 2, + "-8": 1, + "-9": 2, + "0": 123, + "1": 47 + }, + "positive": 47, + "positive_outcomes": { + "admitted": 3, + "frame_illegal": 44 + }, + "star_edges": 236, + "substitute_size_histogram": { + "1": 109, + "10": 2, + "11": 3, + "2": 238, + "3": 61, + "4": 20, + "5": 10, + "6": 17, + "7": 8, + "8": 2 + } + }, + "PR967": { + "A_writer_pairs": 445, + "admitted": [ + [ + 506, + 374, + 288, + [ + 69 + ] + ], + [ + 507, + 355, + 290, + [ + 72 + ] + ], + [ + 514, + 367, + 304, + [ + 360 + ] + ] + ], + "centres": 157, + "d_tail_dirty_boundary_preserved": 128, + "d_tail_gains": [ + 0 + ], + "d_tail_same_centre_pairs": 128, + "dirty_boundary_preserved": 445, + "edges_with_A_writer": 221, + "first_centre_read": { + "A": 215, + "scatter": 6 + }, + "frame_by_gain": { + "-1": { + "frame_illegal": 169 + }, + "-10": { + "frame_illegal": 1 + }, + "-2": { + "frame_illegal": 45 + }, + "-3": { + "frame_illegal": 15 + }, + "-4": { + "frame_illegal": 5 + }, + "-5": { + "frame_illegal": 25 + }, + "-6": { + "frame_illegal": 21 + }, + "-7": { + "frame_illegal": 1 + }, + "-8": { + "frame_illegal": 1 + }, + "0": { + "frame_illegal": 110, + "frame_legal": 2, + "paths_changed": 2 + }, + "1": { + "frame_illegal": 45, + "frame_legal": 3 + } + }, + "gain_histogram": { + "-1": 169, + "-10": 1, + "-2": 45, + "-3": 15, + "-4": 5, + "-5": 25, + "-6": 21, + "-7": 1, + "-8": 1, + "0": 114, + "1": 48 + }, + "positive": 48, + "positive_outcomes": { + "admitted": 3, + "frame_illegal": 45 + }, + "star_edges": 221, + "substitute_size_histogram": { + "1": 104, + "10": 1, + "11": 2, + "2": 216, + "3": 55, + "4": 13, + "5": 4, + "6": 27, + "7": 22, + "8": 1 + } + } + }, + "inputs": { + "research/e8-bit-carrier-skeleton/code/bit/export_records.py": "8a5999601f917dbb492bb9ae9a344611f18cc7cedc53dc3c76496a369e530eb3", + "research/e8-bit-p111-tuned/code/xcheck_p.py": "af3decc877e27c00001cf56f50c6c09566e8e101297ab34c7860aed96a06d80e", + "research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz": "e3e301e62bc2b41dbf1ceac0acf3d35824ebeab1848c5a2142d4577b109da52f", + "research/r439-abc-star-composition/candidate.json.gz": "2b09a7a3851cdf2a7f19350d1555cf75788d001c9507a37e459cd931881ee066", + "research/r439-bsection-stars-seed01/candidate.json.gz": "b452d2c2b0b2a546d1105b1da9769aa78e5c54d6f00e97b30c77e3f54ce445ee", + "research/r439-gl5-shortest/candidate.json.gz": "4e7904d01ebdbfc60a26472b4e0d2e813c19c2fe1a4bb8ab390c12746a1da359", + "research/r439-helper-stars-seed19/candidate.json.gz": "d8b08885e8ce9868200b2645189d15ed18a27fc2742e54990b3257a0ca4df6b8" + }, + "instances": { + "PR1062": { + "chronology": { + "absorbing_gate_is_first_A_touch": true, + "cuts": 3270, + "cuts_with_difference": 459, + "differing_centres_stay_at_zero_frame": true, + "frames_identical_at_every_cut": true, + "max_registers_differing": 3 + }, + "columns": 661, + "controls": [ + [ + "omit restorations without the A edit", + "dirty endpoint wrong on 102 registers {'helper': 3, 'target': 99}; clean-helper endpoint passes" + ], + [ + "A edit with the literal cleanup of the edited A", + "dirty helpers [506, 507, 514] end as centre+leaf; clean helpers pass" + ], + [ + "A edit with literal cleanup, owner checker", + "owner checker rejects: helpers not restored: [506, 507, 514]" + ], + [ + "absorption after the first centre read (A[1218] for centre 514)", + "dirty boundary fails" + ], + [ + "wrong substitute register ([72] instead of [69] at A[288])", + "dirty boundary fails" + ], + [ + "frame-illegal substitution (centre 234, A[247], new [9])", + "illegal frame move: register 9 frame 115 -> 11" + ], + [ + "splice absorbed A/B/C with PR589 D", + "owner checker rejects: helpers not restored: [506, 507, 514]" + ], + [ + "corrupted source pin", + "source pin mismatch: research/r439-bsection-stars-seed01/candidate.json.gz" + ] + ], + "directions": 2, + "exporter": { + "absorbed": { + "ADD": 11497, + "B": 5858638, + "COPY": 9, + "COPY_ranks": [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7 + ], + "ERASE": 9, + "F": 25717, + "MOVE": 2911, + "payload_bits": 95, + "profile": { + "1": 1323, + "2": 1342, + "3": 79, + "4": 44, + "5": 102, + "6": 11, + "7": 19 + }, + "record_sha256": "c44b7709940a9256293cbd21a29e819382426ea15c02b90b0d39ca096bc53620", + "records": 14426 + }, + "base": { + "ADD": 11500, + "B": 5911840, + "COPY": 9, + "COPY_ranks": [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7 + ], + "ERASE": 9, + "F": 25717, + "MOVE": 2911, + "payload_bits": 95, + "profile": { + "1": 1323, + "2": 1342, + "3": 79, + "4": 44, + "5": 102, + "6": 11, + "7": 19 + }, + "record_sha256": "80bb888427eb8bf158dd4279aa56340d20cf573c296f15632b22afabedf0967d", + "records": 14429 + } + }, + "first_climbs": { + "absorbed": { + "helpers_climbing_from_zero": 439, + "non_own_value": [ + 506, + 507, + 514 + ], + "targets_climbing_in_D_or_A": 0 + }, + "base": { + "helpers_climbing_from_zero": 439, + "non_own_value": [], + "targets_climbing_in_D_or_A": 0 + } + }, + "literal": { + "absorbed": { + "ADDs": 11497, + "A_ADDs": 2130, + "B": 5858638, + "C_ADDs": 2495, + "D_ADDs": 5545, + "F": 25717, + "local_bits": 95, + "local_ok": true, + "nine_ok": true, + "nine_stage_bits": 182 + }, + "base": { + "ADDs": 11500, + "A_ADDs": 2130, + "B": 5911840, + "C_ADDs": 2495, + "D_ADDs": 5548, + "F": 25717, + "local_bits": 95, + "local_ok": true, + "nine_ok": true, + "nine_stage_bits": 182 + } + }, + "moves": [ + [ + 506, + 374, + 288, + [ + 69 + ] + ], + [ + 507, + 355, + 290, + [ + 72 + ] + ], + [ + 514, + 367, + 304, + [ + 360 + ] + ] + ], + "owner": { + "absorbed_false": [ + "H2_D_frame0_targets_from_helpers", + "H4_C_literal_reverse_at_full", + "K_equals_D", + "C_is_U_inverse" + ], + "absorbed_true": 5, + "base_false": [ + "H2_D_frame0_targets_from_helpers", + "K_equals_D" + ], + "original_D_splice_all_true": true + }, + "paths_registers": 661, + "payload": "absorbed-pr1062.json.gz", + "payload_sha256": "b6b2acfc7293ac1910fdf8b087ab62f002809eaec7760b7dcaae9aa754738062", + "perturbations_rejected": 1980, + "profile": { + "1": 1323, + "2": 1342, + "3": 79, + "4": 44, + "5": 102, + "6": 11, + "7": 19 + }, + "rank_mass": 5129, + "twisted": { + "absorbed": { + "C_Uprime_T_identity": true, + "C_Uprime_identity": false, + "C_full_frame_z_only": true, + "D_entry_frame_zero": true, + "D_frame_zero": true, + "D_no_target_feeds_helper": true, + "D_source_free": true, + "D_sources_identity": true, + "D_targets_y_plus_Nh": true, + "J_identity": true, + "N_equals_Kprime": false, + "N_equals_KprimeT": true, + "N_targets_touched": 111, + "T_helper_only": true, + "T_invertible": true, + "T_is_identity": false, + "T_offdiagonal": [ + [ + 506, + 374 + ], + [ + 507, + 355 + ], + [ + 514, + 367 + ] + ], + "U_block_form": true, + "V_identity": true, + "final_targets_y_plus_x": true + }, + "base": { + "C_Uprime_T_identity": true, + "C_Uprime_identity": true, + "C_full_frame_z_only": true, + "D_entry_frame_zero": true, + "D_frame_zero": true, + "D_no_target_feeds_helper": true, + "D_source_free": true, + "D_sources_identity": true, + "D_targets_y_plus_Nh": true, + "J_identity": true, + "N_equals_Kprime": true, + "N_equals_KprimeT": true, + "N_targets_touched": 111, + "T_helper_only": true, + "T_invertible": true, + "T_is_identity": true, + "T_offdiagonal": [], + "U_block_form": true, + "V_identity": true, + "final_targets_y_plus_x": true + } + } + }, + "PR1188": { + "chronology": { + "absorbing_gate_is_first_A_touch": true, + "cuts": 2821, + "cuts_with_difference": 459, + "differing_centres_stay_at_zero_frame": true, + "frames_identical_at_every_cut": true, + "max_registers_differing": 3 + }, + "columns": 661, + "controls": [ + [ + "omit restorations without the A edit", + "dirty endpoint wrong on 102 registers {'helper': 3, 'target': 99}; clean-helper endpoint passes" + ], + [ + "A edit with the literal cleanup of the edited A", + "dirty helpers [506, 507, 514] end as centre+leaf; clean helpers pass" + ], + [ + "A edit with literal cleanup, owner checker", + "owner checker rejects: helpers not restored: [506, 507, 514]" + ], + [ + "absorption after the first centre read (A[853] for centre 506)", + "dirty boundary fails" + ], + [ + "wrong substitute register ([72] instead of [69] at A[288])", + "dirty boundary fails" + ], + [ + "frame-illegal substitution (centre 234, A[247], new [9])", + "illegal frame move: register 9 frame 115 -> 11" + ], + [ + "splice absorbed A/B/C with PR589 D", + "owner checker rejects: helpers not restored: [506, 507, 514]" + ], + [ + "corrupted source pin", + "source pin mismatch: research/r439-gl5-shortest/candidate.json.gz" + ] + ], + "directions": 2, + "exporter": { + "absorbed": { + "ADD": 10489, + "B": 3748680, + "COPY": 9, + "COPY_ranks": [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7 + ], + "ERASE": 9, + "F": 13667, + "MOVE": 2911, + "payload_bits": 91, + "profile": { + "1": 1323, + "2": 1342, + "3": 79, + "4": 44, + "5": 102, + "6": 11, + "7": 19 + }, + "record_sha256": "2b4da8c826c816b58ea05f1b2906df46379e20da8d1e2bbd7e84430d99f0973f", + "records": 13418 + }, + "base": { + "ADD": 10492, + "B": 3758418, + "COPY": 9, + "COPY_ranks": [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7 + ], + "ERASE": 9, + "F": 13667, + "MOVE": 2911, + "payload_bits": 91, + "profile": { + "1": 1323, + "2": 1342, + "3": 79, + "4": 44, + "5": 102, + "6": 11, + "7": 19 + }, + "record_sha256": "2df55087c71725651b7fc531323a371810f6c8c6d49d84d2c397bdc2d1862133", + "records": 13421 + } + }, + "first_climbs": { + "absorbed": { + "helpers_climbing_from_zero": 439, + "non_own_value": [ + 506, + 507, + 514 + ], + "targets_climbing_in_D_or_A": 0 + }, + "base": { + "helpers_climbing_from_zero": 439, + "non_own_value": [], + "targets_climbing_in_D_or_A": 0 + } + }, + "literal": { + "absorbed": { + "ADDs": 10489, + "A_ADDs": 1626, + "B": 3748680, + "C_ADDs": 1991, + "D_ADDs": 5545, + "F": 13667, + "local_bits": 91, + "local_ok": true, + "nine_ok": true, + "nine_stage_bits": 175 + }, + "base": { + "ADDs": 10492, + "A_ADDs": 1626, + "B": 3758418, + "C_ADDs": 1991, + "D_ADDs": 5548, + "F": 13667, + "local_bits": 91, + "local_ok": true, + "nine_ok": true, + "nine_stage_bits": 175 + } + }, + "moves": [ + [ + 506, + 374, + 288, + [ + 69 + ] + ], + [ + 507, + 355, + 290, + [ + 72 + ] + ], + [ + 514, + 367, + 304, + [ + 360 + ] + ] + ], + "owner": { + "absorbed_false": [ + "H2_D_frame0_targets_from_helpers", + "H4_C_literal_reverse_at_full", + "K_equals_D", + "C_is_U_inverse" + ], + "absorbed_true": 5, + "base_false": [ + "H2_D_frame0_targets_from_helpers", + "K_equals_D" + ], + "original_D_splice_all_true": true + }, + "paths_registers": 661, + "payload": "absorbed-pr1188.json.gz", + "payload_sha256": "72a28b93811e7f175dd824079f776dfde41eda7482bb86db01e153d84cff3931", + "perturbations_rejected": 1980, + "profile": { + "1": 1323, + "2": 1342, + "3": 79, + "4": 44, + "5": 102, + "6": 11, + "7": 19 + }, + "rank_mass": 5129, + "twisted": { + "absorbed": { + "C_Uprime_T_identity": true, + "C_Uprime_identity": false, + "C_full_frame_z_only": true, + "D_entry_frame_zero": true, + "D_frame_zero": true, + "D_no_target_feeds_helper": true, + "D_source_free": true, + "D_sources_identity": true, + "D_targets_y_plus_Nh": true, + "J_identity": true, + "N_equals_Kprime": false, + "N_equals_KprimeT": true, + "N_targets_touched": 111, + "T_helper_only": true, + "T_invertible": true, + "T_is_identity": false, + "T_offdiagonal": [ + [ + 506, + 374 + ], + [ + 507, + 355 + ], + [ + 514, + 367 + ] + ], + "U_block_form": true, + "V_identity": true, + "final_targets_y_plus_x": true + }, + "base": { + "C_Uprime_T_identity": true, + "C_Uprime_identity": true, + "C_full_frame_z_only": true, + "D_entry_frame_zero": true, + "D_frame_zero": true, + "D_no_target_feeds_helper": true, + "D_source_free": true, + "D_sources_identity": true, + "D_targets_y_plus_Nh": true, + "J_identity": true, + "N_equals_Kprime": true, + "N_equals_KprimeT": true, + "N_targets_touched": 111, + "T_helper_only": true, + "T_invertible": true, + "T_is_identity": true, + "T_offdiagonal": [], + "U_block_form": true, + "V_identity": true, + "final_targets_y_plus_x": true + } + } + } + }, + "new_kappa_claim": false, + "status": "PASS_R439_TWISTED_STAR_ABSORPTION" +} diff --git a/research/r439-twisted-star-absorption-seed02/PROOF.md b/research/r439-twisted-star-absorption-seed02/PROOF.md new file mode 100644 index 0000000000..16c44dc821 --- /dev/null +++ b/research/r439-twisted-star-absorption-seed02/PROOF.md @@ -0,0 +1,215 @@ +# Twisted helper contract and single-edge absorption: proofs + +This note proves four statements: + +1. the scalar twisted-contract lemma; +2. uniqueness of the substitute register set; +3. the single-edge absorption criterion; +4. the chronological per-cut comparison for the two instances. + +It also names the inherited physical premise that the instances use for helpers. Item 4 and that +premise are confined to the two fixed words. The scalar lemma does not by itself give a +chronological bridge for an arbitrary word that satisfies the twisted contract. `verify.py` checks +every finite fact used here. + +## Notation + +A word has `n = 2v + R` registers: sources `x` (v of them), targets `y` (v) and helpers `h` (R). +Write `z = (x, h)`. Here `v = 111`, `R = 439` and `n = 661`. The word runs D, then A, then the +scatter, then B, then C. The scatter is realised literally: COPY one retained helper into a clean +temporary, ADD that temporary into the listed targets, then ERASE it. Each ADD `d ^= s` is an +elementary transvection over F2. + +Let M be any F2-module. This includes arbitrary F2-valued streams under pointwise addition. A +finite product of elementary transvections has coefficients in F2 and acts on `M^n` through those +coefficients. Two such programs therefore agree on every M exactly when their coefficient matrices +agree, and the n unit columns over F2 determine a coefficient matrix. "Boundary" below always means +the complete coefficient matrix on all 661 columns. Helper inputs are arbitrary ("dirty"), never +assumed to be zero. + +The raw word is `W0' = (A, scatter, B)`, without D and without C. Its block form is described below. +The inherited checker conditions (eumemic's PR555 adaptation, `xcheck_p.py`) are: + +- **H1**: no gate anywhere whose destination is a z register reads a target. +- **H3**: A writes only z registers. The scatter reads only retained helpers and writes only targets. + Each B gate either writes a z register from z registers, or writes a target. +- **H5**: the target-to-target block V of `W0'` is the identity. +- **J**: the raw source response J is the identity. As PR1194 noted, H1–H5 alone do not imply this + for an arbitrary word, so it is checked separately. + +## 1. The twisted contract + +The contract keeps H1, H3, H5 and `J = I`, and replaces H2, H4 and the K check by: + +- **H2-tw.** Every D gate is at the zero frame. Its operands are distinct targets and helpers only, + so D is source-free. D contains no COPY, ERASE or climb: targets and helpers enter D at the zero + frame and stay there. D's complete operator is + `(x, y, h) -> (x, y + N h, T h)` + for a binary v-by-R matrix N and an invertible binary R-by-R matrix T. T acts on helpers only. +- **H4-tw.** Every C gate has a z destination, reads only z registers and runs at the full frame. + All z registers end at the full frame. On z, C satisfies + `C · U' · (I_x ⊕ T) = I`. +- **K-tw.** `N = K' T`, where K' is the helper block of the raw target response of `W0'`. + +**Lemma.** Under H1, H2-tw, H3, H4-tw, H5, `J = I` and K-tw, the complete word maps +`(x, y, h) -> (x, y + x, h)` on every F2-module M. Assume the kept conditions and the structural +clauses of H2-tw (D's operator form) and of H4-tw (C z-only at the full frame). Then the equations +`C U' (I ⊕ T) = I` and `N = K'T` are also necessary for this boundary. + +*Proof.* By H1 and H3, no z register is ever written from a target in A or B, and the scatter +writes only targets. By induction over the gates, every z output of `W0'` is a combination of z +inputs. This gives the block form + + z' = U' z, y' = V y + J x + K' h. + +D sends `(x, y, h)` to `(x, y + N h, T h)`. Applying `W0'` to that state gives + + z' = U' (x, T h) = U' (I ⊕ T) z, + y' = V (y + N h) + J x + K' T h = y + x + (N + K' T) h, + +using `V = J = I`. C writes and reads only z registers, so it leaves y unchanged. It sends z' to +`C U' (I ⊕ T) z = z`. The final state is `(x, y + x + (N + K'T) h, h)`, and `N + K'T = 0` by K-tw. +Every coefficient lies in F2, so the identity holds on every M. + +For necessity, assume the kept conditions and the boundary `(x, y + x, h)`. On the z unit columns +in F2 the z rows give `C U' (I ⊕ T) = I`, and on the helper unit columns the target rows give +`N + K'T = 0`. ∎ + +**Strict weakening.** Setting `T = I` turns H2-tw into PR1194's H2-sem condition 3, +`(x, y, h) -> (x, y + N h, h)`. H4-tw becomes `C U' = I`, the `C = U^-1` conclusion that PR1194 +draws from the literal-reverse H4. K-tw becomes `N = K`. Every word meeting PR1194's contract +therefore meets the twisted contract with `T = I`. The two instances below meet the twisted contract +with `T ≠ I`. They fail H2-sem because D leaves three helpers unrestored. They also fail `C U' = I` +and the literal H4. The weakening is therefore strict. + +**The cleanup is weakened even at `T = I`.** The converse of the containment above fails already +at `T = I`. There, H4-tw is the semantic `C U' = I`, whereas PR1194 keeps the literal-reverse H4. +PR1311's stale-cleanup control (PR1122's word with PR589's C) satisfies every twisted condition +with `T = I` and the dirty boundary, yet the lineage rejects it. Endpoint success alone does not give +a chronological bridge for a non-literal full-frame cleanup. + +The instances avoid this: their C is byte-identical to the base word's literal C, and section 4 +bridges them cut by cut. Adopting H4-tw as a general interface would need such a bridge for +non-literal cleanups. + +## 2. The substitute set is unique + +Start the replay from the identity state. The state at a cut is the 661-by-661 matrix whose rows +are the current register values as vectors over the input columns. No temporary is live inside D +or A. Each ADD multiplies this matrix by an elementary transvection. The state is therefore +invertible over F2 at every D/A cut. + +For any vector δ there is then exactly one register set S whose current values XOR to δ. Its +indicator is `δ^T` times the inverse state matrix. `verify.py` maintains the inverse column by +column: `d ^= s` maps inverse column s to `col_s + col_d`. It then checks every computed S by +direct summation. + +## 3. Single-edge absorption criterion + +Let `e` be a trailing D restoration `a ^= b`. Let δ be b's value just before e; on all four lineage +words this is b's own input column. Let g be a later gate writing a, with source set Sg, such that +no gate strictly between e and g reads a. Let S be the unique set with value sum δ at the cut just +before g in the original word W. Suppose a is not in S. + +**Criterion.** Delete e and change only g's source set to some S' with a not in S'. The resulting +word W'' has W's complete boundary (forward literal COPY/ERASE replay, all 661 dirty columns) if +and only if + + S' = Sg ⊕ S. + +The ADD saving is `1 + |Sg| − |Sg ⊕ S|`. If `Sg ⊕ S` is empty, g is deleted as well. + +*Proof.* The two replays agree up to e. Between e and g, induction over the gates shows that W'' +differs from W only in register a, by exactly δ. No gate in that window reads a. A gate writing a +uses identical source values in both words, and every other gate sees identical operands. At g, +all registers other than a agree, so the S' sum is the same in both replays. After g, + + a_W = a + Σ Sg, a_W'' = a + δ + Σ S'. + +These are equal exactly when `Σ (S' ⊕ Sg) = δ` in W's state. By uniqueness this holds exactly when +`S' ⊕ Sg = S`. + +After g, W and W'' execute the same instruction sequence. If their states agree after g, their +complete boundaries agree, including the clean-temporary conditions. Conversely, the common suffix +is injective on states where those conditions hold. An ADD is invertible on rows. A COPY into a +zero temporary and the matching ERASE are mutually inverse on that domain. Equal final boundaries +therefore force equal states after g. The reverse replay is the inverse program, so the forward +statement transfers to it. ∎ + +Frame legality is a separate constraint. The new operands of g must be able to climb monotonically +to g's frame, and the ordered frame paths must stay unchanged. The census therefore classifies each +move twice: by its F2 boundary (always exact under the criterion) and by its frame legality. + +**Census class.** For each trailing restoration of a lineage word, the census considers every A +gate g that writes the centre a before a's first read. On all four words, each centre is first +read in A or by the scatter COPY, so no B or C gate can precede that read. The only other writers +of a before the read are the other restorations of the same centre in the D tail. Leaves are never +written in D, so for those pairs `S = {b}` and the saving is `1 + 1 − 2 = 0`. The census replays and +counts these pairs separately. Preparations of a are separated from e by target-block reads of a. +`verify.py` checks every part of this case analysis. + +**Joint moves.** Several moves with distinct centres and distinct gates compose provided every +`S_i` avoids the other centres whose differences are still pending at `g_i`. The two instances +satisfy this. The lockstep replay in Section 4 checks it directly. + +## 4. Chronological per-cut comparison for the instances + +Let W be the PR1062 or PR1188 word and W' its absorbed word. W' deletes three restorations and +edits A gates 288, 290 and 304. `verify.py` replays the D and A prefixes of W and W' in lockstep, +with frames, and checks the following at every cut (3,270 cuts for PR1062 and 2,821 for PR1188): + +- The registers that differ are exactly the centres whose restoration has been deleted and whose + absorbing gate has not yet run. Each differs by exactly its leaf's input column. At most three + registers differ, at 459 cuts. +- Every register is at the same frame in W and W' at every cut. This is stronger than equal ordered + frame paths, and the exporter's ordered per-register MOVE records also agree. +- Every differing centre stays at the zero frame until its absorbing gate. Each absorbing gate is + the first A gate that touches its centre. +- After A[304] the full states are equal. The remaining scatter, B and C instructions are + identical. + +**Physical reading.** For W, the chronological realization comes from PR1194. A proof-only word +with W's A/scatter/B/C and PR589's target-only D passes every inherited owner flag. Its zero-frame D +and W's D have the same complete operator, values and frames, so they give pointwise identical +states before the unchanged continuation. `verify.py` re-checks this splice and the D-operator +equality for both base words. PR1311 did the same for PR1122. + +W' and W agree in logical value and frame at every cut except the three pending centres. Each of +those centres sits at the zero frame holding `a + b` (its own input column plus the leaf's input +column). It then climbs to its absorbing gate's frame f, and at that frame immediately receives the +compensating ADD from registers already at f. + +The step from equal logical states to equal physical states after that gate uses one inherited +premise: + +> **Common-frame / climb additivity.** Identical ordered per-register frame paths plus identical +> logical values give identical physical states, across nonzero frames. Equivalently, the physical +> climb of a sum is the sum of the climbs, and additions at a common frame are additive. + +Targets already rely on this premise: after D they climb holding the dirty combination `y + N h`. +PR1194 deliberately restricted its own substitution to frame-zero prefixes and did not apply the +premise to helpers. This package newly uses it for helpers. The verifier's first-climb census +locates the use exactly. On both base words, every helper's first climb out of the zero frame +carries its own input column. On both absorbed words, exactly helpers 506, 507 and 514 first climb +carrying a non-own value, and none of them climbs again before its compensation. + +Nothing more is claimed physically. The verifier does not evaluate the premise numerically. Native +5/9/11-stage replay, hosted emission, all-size compiler, rounding/tape and analytic obligations +remain inherited and unexecuted here. + +## Accounting consequence + +Only three D ADDs disappear, so the D ADDs fall from 5,548 to 5,545. The three absorbing A gates +keep one source each, and C is byte-identical to the base word's C. That C is the literal reverse +of the original A/B z-gates, which is why the inherited literal H4 and `C_is_U_inverse` flags are +false. + +The following are all unchanged: + +- frames and climbs; +- COPY ranks; +- the paid profile `{1:1323, 2:1342, 3:79, 4:44, 5:102, 6:11, 7:19}`, rank mass 5,129; +- 2,911 MOVE records. + +The forward positive bound F is unchanged and the reverse bound B falls slightly. Both strict +precision guards keep their bit lengths. Exact values are in `EXPECTED.json` and `README.md`. diff --git a/research/r439-twisted-star-absorption-seed02/README.md b/research/r439-twisted-star-absorption-seed02/README.md new file mode 100644 index 0000000000..84bd783832 --- /dev/null +++ b/research/r439-twisted-star-absorption-seed02/README.md @@ -0,0 +1,247 @@ +# Twisted helper contract: helper-star restorations absorbed into A + +**Replacement-interface result with finite R439 instances. No new κ, and the bit side does not +bind.** The selected result, the selected bit supplier (PR589) and `upstream/` are unchanged. + +## The interface result + +PR1194's semantic-D contract lets D mix helpers temporarily. D must still return every helper: +`(x, y, h) -> (x, y + N h, h)`. This package weakens that requirement. D may leave the helpers +**twisted** by any invertible helper-only map T, provided the cleanup absorbs the twist: + +| | inherited / PR1194 | twisted contract | +|---|---|---| +| D operator | `(x, y + N h, h)` | `(x, y + N h, T h)`, T helper-only and invertible | +| D shape | zero frame, source-free, no COPY/ERASE/climb | same | +| cleanup C | literal reverse of A/B z-gates, so `C U = I` | z-only at the full frame, `C · U' · (I ⊕ T) = I` on z | +| target response | `N = K` | `N = K' T` | +| H1, H3, H5, `J = I` | kept | kept | + +Block algebra gives `y + x + (N + K'T) h = y + x` on every F2-module. Assume the kept conditions +and the structural clauses (D's operator form, and C being z-only at the full frame). Then the two +new equations are necessary and sufficient for the dirty boundary `(x, y, h) -> (x, y + x, h)`. + +**How it weakens PR1194, in two places.** + +- **The cleanup is weakened even at `T = I`.** Every PR1194 word meets the twisted contract with + `T = I`, but the converse fails at `T = I`. H4-tw replaces the literal-reverse cleanup by the + semantic condition `C U' (I ⊕ T) = I`. PR1311's stale-cleanup control satisfies the twisted + contract at `T = I`, yet the lineage rejects it: an endpoint alone does not give a chronological + bridge for a non-literal cleanup. +- **The helpers may stay twisted.** The instances below have `T ≠ I`. + +The two instances are not exposed to the first point. Their C is byte-identical to the base word's +literal C, and they are bridged cut by cut. + +[PROOF.md](PROOF.md) gives the lemma, the uniqueness of the substitute register set, the exact +single-edge criterion and the chronological per-cut argument. + +**Newly used premise.** The instances rely on the inherited common-frame / climb-additivity +premise, now applied to helpers: identical ordered per-register frame paths plus identical logical +values give identical physical states, across nonzero frames. Targets already rely on it, since +they climb holding `y + N h`. PR1194 deliberately restricted its substitution to frame-zero prefixes. +Here exactly three helpers (506, 507, 514) make their first climb out of the zero frame while +holding `centre + leaf`. Each does so at its absorbing gate, which immediately compensates. Nothing +beyond this premise is claimed about physical realization. + +## The helper-mixing word + +A helper-star restoration is the D gate `a ^= b` (centre a, leaf b). Delete it, and replace the +source set Sg of an A gate that writes a before a's first read by `Sg ⊕ S`. Here S is the unique +register set whose current values sum to b's input column. The state is invertible over F2 at every +cut, so S is unique. This preserves the whole boundary **if and only if** the new source set is +exactly `Sg ⊕ S`. + +The three frame-legal positive moves are the same on every lineage word: + +| deleted D restoration | absorbing A gate | old sources | new sources | +|---|---|---|---| +| `506 ^= 374` | A[288] at frame 71 | `[374]` | `[69]` | +| `507 ^= 355` | A[290] at frame 74 | `[355]` | `[72]` | +| `514 ^= 367` | A[304] at frame 65 | `[367]` | `[360]` | + +In each case A has already performed `leaf ^= substitute` at the same frame. The centre therefore +reads the substitute in place of the updated leaf. C is left byte-identical. The words are +[absorbed-pr1062.json.gz](absorbed-pr1062.json.gz) and [absorbed-pr1188.json.gz](absorbed-pr1188.json.gz). + +| complete local quantity | PR1062 word | absorbed | PR1188 word | absorbed | +|---|---:|---:|---:|---:| +| ADDs | 11,500 | **11,497** | 10,492 | **10,489** | +| D / A / C ADDs | 5,548 / 2,130 / 2,495 | 5,545 / 2,130 / 2,495 | 5,548 / 1,626 / 1,991 | 5,545 / 1,626 / 1,991 | +| exporter records (ADD / COPY / ERASE / MOVE) | 14,429 (11,500 / 9 / 9 / 2,911) | 14,426 (11,497 / 9 / 9 / 2,911) | 13,421 (10,492 / 9 / 9 / 2,911) | 13,418 (10,489 / 9 / 9 / 2,911) | +| forward / reverse positive bound F / B | 25,717 / 5,911,840 | 25,717 / 5,858,638 | 13,667 / 3,758,418 | 13,667 / 3,748,680 | +| local / nine-stage bits (strict caps 104 / 192) | 95 / 182 | 95 / 182 | 91 / 175 | 91 / 175 | + +For both absorbed words, `verify.py` checks the following: + +- **Boundary and frames.** The boundary is `(x, y, h) -> (x, y + x, h)` on all 661 dirty columns, + forward and reverse, through the literal COPY/ERASE stream. Every register has the same frame at + every D/A cut. The ordered per-register frame paths and exporter MOVE records are identical to + the base word's and to PR589's. +- **Paid profile.** It is `{1:1323, 2:1342, 3:79, 4:44, 5:102, 6:11, 7:19}`, rank mass 5,129, with + nine rank-7 COPYs. It is recomputed from frame paths and from the pinned exporter + (`research/e8-bit-carrier-skeleton/code/bit/export_records.py`). +- **Owner checker.** The unchanged `research/e8-bit-p111-tuned/code/xcheck_p.py` accepts the + complete geometry and endpoint. Exactly four flags are false: + `H2_D_frame0_targets_from_helpers`, `H4_C_literal_reverse_at_full`, `K_equals_D` and + `C_is_U_inverse`. All five others are true. The base words carry only the first and third. +- **Twisted identities.** `T ≠ I`, with off-diagonal entries exactly (506,374), (507,355) and + (514,367). T is invertible and helper-only. The checks also give `C U' (I_x ⊕ T) = I` and + `C U' ≠ I`, + `N = K'T` and `N ≠ K'`, and `V = J = I` with U in block form. D is frame-zero and source-free, + and C is z-only at the full frame. +- **Base-word bridge.** The PR1194-style splice of each base word with PR589's D passes every owner + flag, and each base D operator equals PR589's on all 661 columns. +- **Chronology.** A lockstep replay covers 3,270 cuts (PR1062) and 2,821 cuts (PR1188). At each cut + the differing registers are exactly the pending centres, each off by its leaf column. At most + three registers differ, at 459 cuts, and they stay at the zero frame. Each absorbing gate is the + first A gate touching its centre. +- **Uniqueness.** All 1,980 one-register perturbations of the three new source sets break the dirty + boundary. + +## Single-edge census + +The census covers every pair (trailing D restoration, A gate writing its centre before the centre's +first read) on four lineage words. Every pair's edited word is replayed on all 661 dirty columns in +both directions, and all of them preserve the boundary, as the criterion predicts. Frame legality +and the ordered frame paths are then checked separately. + +| word | star edges | pairs | gain histogram | positive | frame-illegal | admitted | +|---|---:|---:|---|---:|---:|---:| +| PR967 | 221 | 445 | −10:1 −8:1 −7:1 −6:21 −5:25 −4:5 −3:15 −2:45 −1:169 0:114 +1:48 | 48 | 45 | 3 | +| PR1062 | 236 | 481 | −10:1 −8:1 −7:1 −6:25 −5:30 −4:6 −3:12 −2:45 −1:192 0:120 +1:48 | 48 | 45 | 3 | +| PR1122 | 236 | 489 | −10:2 −9:2 −8:1 −7:2 −6:7 −5:14 −4:10 −3:27 −2:50 −1:203 0:123 +1:48 | 48 | 45 | 3 | +| PR1188 | 236 | 470 | −10:2 −9:2 −8:1 −7:2 −6:5 −5:13 −4:8 −3:20 −2:52 −1:195 0:123 +1:47 | 47 | 44 | 3 | + +On every word the three admitted moves are the triples above. Every negative-gain move is +frame-illegal. Among the gain-0 moves, two keep identical paths, two are legal but change paths, +and the rest are frame-illegal. + +Some centres are never read in A: on each word, 6 star edges have a centre that is first read by +the scatter COPY. The only other writers of a centre before its first read are its other D-tail +restorations: 128 pairs on PR967 and 148 on the others. All of them have gain exactly 0 and are replayed exactly. No B or +C gate precedes a first read. All counts are pinned in [EXPECTED.json](EXPECTED.json). + +## Controls (each instance; all must fail or be rejected) + +1. **Omit the restorations without the A edit.** The dirty endpoint is wrong on 102 registers + (99 targets and 3 helpers). The clean-helper endpoint passes, which makes this a dirty-input + counterexample. +2. **A edit with the literal cleanup of the edited A** (inherited literal H4 enforced). The result + fails exactly on dirty helpers 506, 507 and 514, which end as centre + leaf. It passes on clean + helpers, and the owner checker rejects it with `helpers not restored: [506, 507, 514]`. +3. **Absorption after the first centre read** (PR1062 A[1218] for centre 514; PR1188 A[853] for + centre 506). The dirty boundary fails. +4. **Wrong substitute register** (`[72]` instead of `[69]` at A[288]). The dirty boundary fails. +5. **One frame-illegal substitution** (centre 234, A[247], new source `[9]`). Its F2 boundary is + exact, but the frame replay rejects it: register 9 cannot move from frame 115 to frame 11. +6. **PR1194/PR1311-style splice** (absorbed A/B/C with PR589's target-only D). The owner checker + rejects it with `helpers not restored: [506, 507, 514]`. +7. **Corrupted source pin.** The SHA-256 check rejects it. + +## Reproduce + +From the repository root (standard library only, about 20 s per run on an Apple-silicon Mac): + +```sh +python3 -I -B research/r439-twisted-star-absorption-seed02/verify.py +python3 -I -O -B research/r439-twisted-star-absorption-seed02/verify.py +python3 scripts/research_package.py --package research/r439-twisted-star-absorption-seed02 --check-only +python3.12 scripts/research_package.py --package research/r439-twisted-star-absorption-seed02 +``` + +The expected final line is: + +```text +PASS_R439_TWISTED_STAR_ABSORPTION words=4 instances=2 ADDs 11500->11497 10492->10489 columns=661 controls=16 no_new_kappa (… s) +``` + +All seven inputs are pinned by SHA-256 in [SOURCES.json](SOURCES.json): four lineage words, +PR589's word, the owner checker and the exporter. The verifier refuses drifted bytes. It executes +the owner checker from the verified bytes in-process; that checker raises its own `Reject`, not +`assert`. It runs the exporter from the verified bytes in a child interpreter without `-O`. Checks +raise `ValueError`, so `-O` cannot weaken them. The report must equal EXPECTED.json exactly, and +the committed absorbed words must equal the rebuilt ones. `--write` regenerates both. The report is +identical under CPython 3.12.15 and 3.14.8. + +## Scope and limits + +- **Class.** The census covers only the single-edge, single-writer class: one deleted restoration + absorbed by one edited gate. Joint application of the three admitted moves is checked; this is + not a global minimum or an unrestricted circuit optimum. +- **New result.** The new content is the interface lemma, its finite instances and the census. The + three-ADD saving is a small finite consequence. It does not change the paid profile, the selected + moment or κ. +- **Not run.** Native 5/9/11-stage C++ replay was not run on the absorbed words. Open PR #1509's + checked `cpp_int` stand-in may make that possible on hosts without Boost. Hosted + emission/invoice and outer assembly were not rerun either. All-size compiler, + common-label/mutable-source, rounding/tape and analytic obligations remain inherited. +- **Physical realization.** It is argued only for the two instances. The argument uses the + per-cut comparison with the PR1194-bridged base words and the climb-additivity premise stated + above. The scalar lemma alone is not a chronological bridge for arbitrary twisted words. +- **Terminal-restoration exclusions.** Open PRs #1580 and #1592 rule out moving restorations to + the end of C and arbitrary terminal compensation. Absorption happens before the centre's first + read and changes A, so it lies outside their terminal domain and is consistent with them. + #1592's stated next question was to move the cut earlier and change the continuation; this + package answers it for the centre-writer class. + +## Concurrent work on the same card and words + +None of these uses the twisted mechanism: none leaves helpers twisted (`T ≠ I`), and none edits A +to absorb a D restoration. + +- **Same base word, other mechanisms.** These open PRs work on PR1062's 11,500-ADD word: + - #1543 (ToikY): two nonpositive helper moves, 11,500 → 11,489; + - #1709 (Cinna Davis, @1337isnot1337): a five-helper cycle, 11,500 → 11,488; + - #1704 (Ross Richardson): a two-copy scatter under a replacement immutable-temporary interface, + 11,500 → 11,380. + + Their scalar savings are larger than this package's three ADDs. Whether the three absorptions + compose with them has not been tested. +- **Restored-helper (H2-sem) work.** #1782 (Aaron Wang) and #1805 (VictorLiwentao) admit and price + PR848's helper-sharing wraps under PR1194's contract, with `N = K` and `T = I`. That is a + different object. +- **Terminal deferral.** Discussion #1743 (Cinna Davis) claimed compensated terminal deferral; it + expired with no PR. That domain is the terminal one PR1592 already excludes. + +## Open next questions + +The structured versions are in [TASK.json](TASK.json). + +1. **Multi-gate splits and the neutral moves.** Can a restoration be absorbed by splitting S across + two or more centre writers, or by chaining one of the gain-0 moves (two path-preserving per + word) with a positive one? The single-edge census excludes these by construction. *First step:* + extend the census to two-writer splits of S, on the same frame-legality filter. +2. **Native replay of the absorbed words.** *First step:* run PR1188's native 5/9/11-stage + checkers on `absorbed-pr1188.json.gz`, with Boost or PR #1509's stand-in. *Blocker:* a host with + Boost or an accepted stand-in. +3. **Feedback results with a twisted helper exit.** PR1706 (with PR1306/PR1557) finds no + target-feedback saving for fully restored dirty shears, which is the `T = I` case. Does any + feedback or shear gain appear once the helper exit may be permuted or twisted (`T ≠ I`) and + absorbed by C? *First step:* rerun the 3-by-3 shear census allowing any helper exit T in + `GL(R, 2)`, and charge the C absorption. +4. **Adoption of the twisted contract.** Would maintainers accept H2-tw/H4-tw/K-tw, together with + the helper climb premise, as the interface for hosted admission? + - *Why it needs more than the premise:* adopting H4-tw as a general interface also needs a + chronological bridge for non-literal full-frame cleanups. PR1311 declined to infer one from + endpoint success, and the helper climb premise does not cover it. + - *How the instances avoid it:* they keep the base word's literal C. + - *Blocker:* a maintainer decision, then a hosted emission of an absorbed word. + +## Credit + +- **Interface and checker lineage.** woklerx's PR1194 semantic-D contract and frame-zero + substitution argument; Arham Tahir's PR1311 bridge on the composed word; Zhihao Chen's PR425 + scalar-interface lemma; eumemic's PR555 checker adaptation (`xcheck_p.py`); Dylan Crow's exporter. +- **Lineage words.** Sricharan Vagvala (@theon199): PR967 helper stars. Sagar Thakrar: PR1062 + B-block and helper-star D composition. Gareth Davidson (@bitplane): PR1122 A/B/star composition + and PR1188 GL5 windows. Aaron Wang's PR1015 and Ross Richardson's PR923 B circuits are inside + those words. DreamingOfClouds' PR589 tuning sits on eumemic's PR555 punctured word. +- **Terminal-restoration exclusions.** Arham Tahir's open PRs #1580 and #1592. +- **Restoration-coalescing lineage.** #1155 (Aaron Wang, open), #1199 (Sagar Thakrar), #1203 + (mightyOil) and #1205 (Adam Gall). +- **Concurrent same-card work.** Cited above: #1543, #1704, #1709, #1782, #1805 and the #1743 + claim. #1592's next question motivated the early-cut absorption. + +Prepared by Sagar Thakrar with substantial Anthropic Claude assistance (Claude Code, including +subagents for the probes). No independent human review. New work is Apache-2.0. diff --git a/research/r439-twisted-star-absorption-seed02/SOURCES.json b/research/r439-twisted-star-absorption-seed02/SOURCES.json new file mode 100644 index 0000000000..aa18fb221c --- /dev/null +++ b/research/r439-twisted-star-absorption-seed02/SOURCES.json @@ -0,0 +1,60 @@ +{ + "schema_version": 1, + "base_commit": "0b1cccf86e2f5132ed286a26ef0a681a495740ea", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "ae6a99f28aa468649eb66a361e764d769363bf11", + "sha256": "10b9e340fd8e354a37a0c4813c90e5de1dd42044b5f6aca4a3fc5a42b685fa32" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "06c96f5579bb67ed1b86d334e78fbed7da6945f1", + "sha256": "6686ad58f1fbdbc87134a78901b60fd53a20d3984355e91defbbebc9e9fa8075" + }, + { + "path": "research/e8-bit-carrier-skeleton/code/bit/export_records.py", + "usage": "input", + "git_blob": "3632d370486a02f5456f7643ced03f8c925b2350", + "sha256": "8a5999601f917dbb492bb9ae9a344611f18cc7cedc53dc3c76496a369e530eb3" + }, + { + "path": "research/e8-bit-p111-tuned/code/xcheck_p.py", + "usage": "input", + "git_blob": "184f5dcf94a486cc7db91ca4db5865916bf26009", + "sha256": "af3decc877e27c00001cf56f50c6c09566e8e101297ab34c7860aed96a06d80e" + }, + { + "path": "research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz", + "usage": "input", + "git_blob": "85a4499bf9e4911a705d50567a2c2ef6cf23739a", + "sha256": "e3e301e62bc2b41dbf1ceac0acf3d35824ebeab1848c5a2142d4577b109da52f" + }, + { + "path": "research/r439-abc-star-composition/candidate.json.gz", + "usage": "input", + "git_blob": "0ab597fefd68bfefecc85d631b172d174bdaeb70", + "sha256": "2b09a7a3851cdf2a7f19350d1555cf75788d001c9507a37e459cd931881ee066" + }, + { + "path": "research/r439-bsection-stars-seed01/candidate.json.gz", + "usage": "input", + "git_blob": "9a17b4920334878d6c949191f6931bd97126fe3c", + "sha256": "b452d2c2b0b2a546d1105b1da9769aa78e5c54d6f00e97b30c77e3f54ce445ee" + }, + { + "path": "research/r439-gl5-shortest/candidate.json.gz", + "usage": "input", + "git_blob": "0d4dd2fb241a00cab1b57b17991db82bc06edd91", + "sha256": "4e7904d01ebdbfc60a26472b4e0d2e813c19c2fe1a4bb8ab390c12746a1da359" + }, + { + "path": "research/r439-helper-stars-seed19/candidate.json.gz", + "usage": "input", + "git_blob": "8b0210d8b8e9524182e5f54f9bf93c28f4719735", + "sha256": "d8b08885e8ce9868200b2645189d15ed18a27fc2742e54990b3257a0ca4df6b8" + } + ] +} diff --git a/research/r439-twisted-star-absorption-seed02/TASK.json b/research/r439-twisted-star-absorption-seed02/TASK.json new file mode 100644 index 0000000000..9fc2bbd7c8 --- /dev/null +++ b/research/r439-twisted-star-absorption-seed02/TASK.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "task_id": "bit-helper-contract", + "priority_revision": 3, + "base_commit": "0b1cccf86e2f5132ed286a26ef0a681a495740ea", + "original_card": { + "id": "bit-helper-contract", + "question": "Can one precisely specified helper-mixing word satisfy a replacement for the inherited H2/K interface?", + "starting_points": [ + "research/r439-bsection-stars-seed01/README.md", + "research/r439-copy-path-sharing-barrier/README.md" + ], + "methods": [ + "Derive a replacement interface lemma and price its implementation.", + "Seek an exact dirty-input or chronological-cut counterexample to the proposed replacement." + ], + "acceptance_gate": "A full boundary contract and paid profile; unchanged scalar counts alone are insufficient.", + "first_step": { + "command": [ + "python3", + "-B", + "research/r439-bsection-stars-seed01/verify.py" + ], + "expected": "PASS_R439_BSECTION_STARS", + "inspect": "Compare the two false H2/K flags with the unchanged paid profile in its README.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Write one replacement H2/K implication for a single helper-star operation, then try to falsify it on dirty inputs.", + "bottleneck_link": "A legitimate replacement could admit a cheaper bit circuit; scalar savings alone do not alter the selected moment.", + "allowed_variations": [ + "Choose one helper-star or quartet instance; narrow to one boundary implication." + ], + "scope_change_triggers": [ + "Changing only source count or scalar addition count without an interface argument." + ], + "overlap_terms": [ + "H2_D_frame0_targets_from_helpers", + "K_equals_D", + "helper-star" + ] + }, + "scope_status": "refined", + "actual_scope": "Replace the inherited H2/K (and literal H4) interface by a twisted contract: frame-zero, source-free D may leave the helpers in any invertible helper-only state T, provided C U' (I_x ⊕ T) = I on z and N = K'T. Prove it, exhibit one precisely specified helper-mixing word (three helper-star restorations of the PR1062 and PR1188 words absorbed into A gates before the centres' first reads) with full dirty boundary, unchanged frame paths and paid profile, and run an exhaustive single-edge single-writer census on the PR967, PR1062, PR1122 and PR1188 words.", + "scope_change_reason": "PR1194 and PR1311 already cover the T = I semantic-D replacement for words whose D restores every helper. This package narrows, as the card allows, to one helper-star absorption class and weakens the contract further to unrestored (twisted) helpers, which the absorbed words need. It does not attempt hosted adoption, native replay or a global optimum.", + "bottleneck_link": "Side result on the bit supplier. A legitimate replacement interface admits a cheaper helper-mixing word (3 complete ADDs fewer) with an unchanged paid profile and rank mass, so the selected moment and kappa are unchanged; the bit side does not bind.", + "budget_minutes": 60, + "stop_rule": "Stop after the twisted lemma, the two fixed instances, the single-edge single-writer census on four lineage words and the seven controls; no multi-gate search, native replay or hosted emission.", + "outcome": "completed", + "evidence": "EXPECTED.json, PROOF.md, absorbed-pr1062.json.gz and absorbed-pr1188.json.gz; python3 -I -B research/r439-twisted-star-absorption-seed02/verify.py prints PASS_R439_TWISTED_STAR_ABSORPTION.", + "author": "Sagar Thakrar", + "ai_assistance": "Prepared by Sagar Thakrar with substantial Anthropic Claude assistance (Claude Code, including subagents for the exploratory probes and package assembly). No independent human review.", + "open_questions": [ + { + "question": "Can a helper-star restoration be absorbed by splitting its substitute set across two or more centre writers, or by chaining one of the gain-0 neutral moves (120 on the PR1062 word, two of them path-preserving) with a positive move?", + "why_it_matters": "The census is exhaustive only for one deleted restoration and one edited gate; multi-gate absorption could admit further frame-legal savings under the same twisted contract.", + "first_step": "Extend the census to two-writer splits of S before the first centre read, with the same frame-path filter.", + "blocked_by": "Search budget only; the candidate space grows quadratically in the centre writers per edge." + }, + { + "question": "Do the absorbed words pass the native 5/9/11-stage C++ checkers that PR1122 and PR1188 ran on their base words?", + "why_it_matters": "This package checks local scalar, frame and precision facts only; native multistage replay is the next layer of evidence.", + "first_step": "Run the PR1188 native checkers on absorbed-pr1188.json.gz with Boost, or with open PR #1509's checked cpp_int stand-in.", + "blocked_by": "A host with Boost headers or an accepted stand-in; not run here." + }, + { + "question": "Do target-feedback or shear savings appear once the helper exit may be twisted (T != I) and absorbed by C?", + "why_it_matters": "PR1706 (with PR1306 and PR1557) finds no feedback saving for fully restored dirty shears, the T = I case; the twisted contract enlarges that model.", + "first_step": "Rerun the 3-by-3 shear census allowing any helper exit T in GL(R,2) and charge the C absorption.", + "blocked_by": "A cost convention for the C absorption that is consistent with the scalar shear model." + }, + { + "question": "Will maintainers accept the twisted contract, together with the helper common-frame/climb-additivity premise, as an interface for hosted admission?", + "why_it_matters": "Without acceptance the absorbed words remain scoped finite constructions, not supplier candidates.", + "first_step": "Review PROOF.md section 4 against the inherited chronological lemma and PR1194's frame-zero restriction.", + "blocked_by": "Maintainer decision, then a hosted emission and invoice of an absorbed word." + } + ] +} diff --git a/research/r439-twisted-star-absorption-seed02/VERIFY.json b/research/r439-twisted-star-absorption-seed02/VERIFY.json new file mode 100644 index 0000000000..56ae525231 --- /dev/null +++ b/research/r439-twisted-star-absorption-seed02/VERIFY.json @@ -0,0 +1,38 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/e8-bit-carrier-skeleton/code/bit/export_records.py", + "research/e8-bit-p111-tuned/code/xcheck_p.py", + "research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz", + "research/r439-abc-star-composition/candidate.json.gz", + "research/r439-bsection-stars-seed01/candidate.json.gz", + "research/r439-gl5-shortest/candidate.json.gz", + "research/r439-helper-stars-seed19/candidate.json.gz" + ], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 300, + "checks": "SHA-256 input pins; single-edge census on four lineage words with every move replayed on all 661 dirty columns; two absorbed instances (literal boundary both directions, per-cut frames, MOVE records, paid profile, exporter bill, 104/192-bit guards, owner flags, twisted identities, chronology, 1,980 perturbations each); seven controls per instance; EXPECTED.json and payload equality." + }, + { + "argv": [ + "{python}", + "-I", + "-O", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 300, + "checks": "The same verification under -O: every check raises ValueError and the pinned exporter child runs without -O." + } + ] +} diff --git a/research/r439-twisted-star-absorption-seed02/absorbed-pr1062.json.gz b/research/r439-twisted-star-absorption-seed02/absorbed-pr1062.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..7656a7996e8fefdd0a40d9a4439deea8f121f015 GIT binary patch literal 38423 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 literal 0 HcmV?d00001 diff --git a/research/r439-twisted-star-absorption-seed02/absorbed-pr1188.json.gz b/research/r439-twisted-star-absorption-seed02/absorbed-pr1188.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..ff8d2cfd045303a2a5426cb8b7d2cfdd9a7b9994 GIT binary patch literal 35755 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 (x,y+x,h) both directions, ordered per-register frame paths and + exporter MOVE records identical to the base word, paid profile and rank mass, exporter bill, + strict 104/192-bit precision guards, the unchanged owner checker's flag pattern, the twisted + identities (T != I, C U' diag(I_x, T) = I, N = K' T, V = J = I), the chronological per-cut state difference + and the first-climb census that isolates the newly used helper climb premise; +* seven controls that must fail or be rejected. +Standard library only. Every check raises ValueError (never assert), so -O cannot weaken it. The +pinned exporter uses assert, so it runs from its verified bytes in a child interpreter without -O. +""" +import argparse +import gzip +import hashlib +import json +import os +import struct +import subprocess +import sys +import tempfile +import time +import types +from collections import Counter +from fractions import Fraction +from pathlib import Path + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] + +WORDS = { + 'PR967': 'research/r439-helper-stars-seed19/candidate.json.gz', + 'PR1062': 'research/r439-bsection-stars-seed01/candidate.json.gz', + 'PR1122': 'research/r439-abc-star-composition/candidate.json.gz', + 'PR1188': 'research/r439-gl5-shortest/candidate.json.gz', +} +PR589 = 'research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz' +CHECKER = 'research/e8-bit-p111-tuned/code/xcheck_p.py' +EXPORTER = 'research/e8-bit-carrier-skeleton/code/bit/export_records.py' +INPUTS = sorted([*WORDS.values(), PR589, CHECKER, EXPORTER]) + +INSTANCES = {'PR1062': ('absorbed-pr1062.json.gz', 11500, 11497), + 'PR1188': ('absorbed-pr1188.json.gz', 10492, 10489)} +# (centre a, leaf b, absorbing A index, new source set of that A gate) +TRIPLES = [[506, 374, 288, [69]], [507, 355, 290, [72]], [514, 367, 304, [360]]] +PROFILE = {1: 1323, 2: 1342, 3: 79, 4: 44, 5: 102, 6: 11, 7: 19} +OWNER_FALSE = ['H2_D_frame0_targets_from_helpers', 'H4_C_literal_reverse_at_full', 'K_equals_D', 'C_is_U_inverse'] +LOCAL_CAP, NINE_CAP = 104, 192 + + +def need(cond, msg): + if not cond: + raise ValueError(msg) + + +def canonical(w): + return json.dumps(w, sort_keys=True, separators=(',', ':')).encode() + + +def sha(b): + return hashlib.sha256(b).hexdigest() + + +# ------------------------------------------------------------------ pinned inputs + +def check_pin(path, data, pinned): + need(sha(data) == pinned, 'source pin mismatch: ' + path) + + +def load_inputs(): + src = json.loads((HERE / 'SOURCES.json').read_text(encoding='utf-8')) + pins = {r['path']: r['sha256'] for r in src['files'] if r['usage'] == 'input'} + need(sorted(pins) == INPUTS, 'SOURCES.json input set differs from the verifier inputs') + man = json.loads((HERE / 'VERIFY.json').read_text(encoding='utf-8')) + need(sorted(man['inputs']) == INPUTS, 'VERIFY.json input set differs from the verifier inputs') + data = {} + for p in INPUTS: + b = (ROOT / p).read_bytes() + check_pin(p, b, pins[p]) + data[p] = b + return data, pins + + +def owner_module(code): + mod = types.ModuleType('r439_owner_xcheck_p') + mod.__file__ = CHECKER + exec(compile(code, CHECKER, 'exec'), mod.__dict__) + return mod + + +# ------------------------------------------------------------------ geometry + +def rank_q(rows): + m = [[Fraction(x) for x in r] for r in rows] + rk = 0 + for col in range(len(m[0]) if m else 0): + p = next((i for i in range(rk, len(m)) if m[i][col] != 0), None) + if p is None: + continue + m[rk], m[p] = m[p], m[rk] + for i in range(len(m)): + if i != rk and m[i][col] != 0: + f = m[i][col] / m[rk][col] + m[i] = [a - f * b for a, b in zip(m[i], m[rk])] + rk += 1 + return rk + + +class Geo: + def __init__(self, w): + self.v, self.R = w['v'], w['R'] + self.n = 2 * self.v + self.R + self.fs = [frozenset(f) for f in w['frames']] + self.fdim = [rank_q([w['lines'][i] for i in f]) if f else 0 for f in w['frames']] + zero = [k for k, d in enumerate(self.fdim) if d == 0] + full = [k for k, d in enumerate(self.fdim) if d == 8] + need(len(zero) == 1 and len(full) == 1, 'one zero and one full frame') + self.ZERO, self.FULL = zero[0], full[0] + self.X = (1 << self.v) - 1 + self.Y = self.X << self.v + self.H = ((1 << self.R) - 1) << (2 * self.v) + + def is_y(self, r): + return self.v <= r < 2 * self.v + + +def same_geometry(a, b): + return all(a[k] == b[k] for k in ('v', 'R', 'h', 'lines', 'frames', 'start', 'final', 'ret', 'scatter')) + + +def frame_paths(w, geo): + fs = geo.fs + ps = [[f] for f in w['start']] + for sec in 'DABC': + for f, d, ss in w[sec]: + for r in (d, *ss): + if ps[r][-1] != f: + need(fs[ps[r][-1]] < fs[f], 'illegal frame move: register %d frame %d -> %d' % (r, ps[r][-1], f)) + ps[r].append(f) + for r, f in enumerate(w['final']): + if ps[r][-1] != f: + need(fs[ps[r][-1]] < fs[f], 'illegal final move: register %d' % r) + ps[r].append(f) + return ps + + +def copy_ranks(w, geo): + cur = list(w['start']) + for sec in 'DA': + for f, d, ss in w[sec]: + for r in (d, *ss): + cur[r] = f + return [geo.fdim[cur[q]] for q in w['ret']] + + +def paid_profile(w, geo): + prof = Counter(geo.fdim[b] - geo.fdim[a] for p in frame_paths(w, geo) for a, b in zip(p, p[1:])) + prof.update(copy_ranks(w, geo)) + return {k: prof[k] for k in sorted(prof)} + + +# ------------------------------------------------------------------ literal F2 stream + +def stream(w): + v, tmp = w['v'], 2 * w['v'] + w['R'] + out = [(0, d, s) for sec in 'DA' for _, d, ss in w[sec] for s in ss] + for j, centre in enumerate(w['ret']): + out.append((1, tmp, centre)) + out += [(0, v + i, tmp) for i, row in enumerate(w['scatter']) if j in row] + out.append((2, tmp, centre)) + out += [(0, d, s) for sec in 'BC' for _, d, ss in w[sec] for s in ss] + return out + + +def literal(w, reverse=False, clean_helpers=False): + """Set-valued (bitmask) replay of the literal ADD/COPY/ERASE stream on all formal columns.""" + v, n = w['v'], 2 * w['v'] + w['R'] + rows = [0 if clean_helpers and r >= 2 * v else 1 << r for r in range(n)] + [0] + ins = stream(w) + for kind, d, s in (reversed(ins) if reverse else ins): + if reverse and kind: + kind = 3 - kind + if kind == 0: + rows[d] ^= rows[s] + elif kind == 1: + need(not rows[d], 'COPY into a live temporary') + rows[d] = rows[s] + else: + need(rows[d] == rows[s], 'ERASE of a changed copy') + rows[d] = 0 + need(not rows[-1], 'temporary not erased') + return rows[:-1] + + +def wanted(w, clean_helpers=False): + v, n = w['v'], 2 * w['v'] + w['R'] + out = [] + for r in range(n): + if v <= r < 2 * v: + out.append((1 << r) | (1 << (r - v))) + else: + out.append(0 if clean_helpers and r >= 2 * v else 1 << r) + return out + + +def boundary_ok(w): + want = wanted(w) + try: + return all(literal(w, rev) == want for rev in (False, True)) + except ValueError: + return False + + +def bounds(w): + peaks = [] + ins = stream(w) + for reverse in (False, True): + val = [1] * (2 * w['v'] + w['R'] + 1) + peak = 1 + for kind, d, s in (reversed(ins) if reverse else ins): + if reverse and kind: + kind = 3 - kind + val[d] = val[d] + val[s] if kind == 0 else (val[s] if kind == 1 else 0) + peak = max(peak, val[d]) + peaks.append(peak) + F, B = peaks + local, nine = 64 * F**3 * B**2, (1 << 18) * F**5 * B**4 + return dict(ADDs=sum(k == 0 for k, _, _ in ins), D_ADDs=sum(len(g[2]) for g in w['D']), + A_ADDs=sum(len(g[2]) for g in w['A']), C_ADDs=sum(len(g[2]) for g in w['C']), + F=F, B=B, local_bits=local.bit_length(), nine_stage_bits=nine.bit_length(), + local_ok=local < 1 << LOCAL_CAP, nine_ok=nine < 1 << NINE_CAP) + + +def guards(b): + need(b['local_ok'] and b['nine_ok'], 'precision guard') + + +def run_values(w, secs, start=None): + v, n = w['v'], 2 * w['v'] + w['R'] + val = list(start) if start is not None else [1 << r for r in range(n)] + for sec in secs: + if sec == 'scatter': + cp = [val[q] for q in w['ret']] + for t, row in enumerate(w['scatter']): + for j in row: + val[v + t] ^= cp[j] + else: + for f, d, ss in w[sec]: + acc = 0 + for s in ss: + acc ^= val[s] + val[d] ^= acc + return val + + +def bits(x): + out = [] + while x: + low = x & -x + out.append(low.bit_length() - 1) + x ^= low + return out + + +def f2_rank(rows): + rows = [r for r in rows if r] + rk = 0 + while rows: + p = rows.pop() + if not p: + continue + rk += 1 + low = p & -p + rows = [r ^ p if r & low else r for r in rows] + rows = [r for r in rows if r] + return rk + + +# ------------------------------------------------------------------ helper-star structure and census + +def stars(w, geo): + v, H0, D = geo.v, 2 * geo.v, w['D'] + nh2 = sum(1 for g in D if g[1] >= H0) + need(nh2 % 2 == 0, 'helper gate count') + nh = nh2 // 2 + prep, rest, mid = D[:nh], D[len(D) - nh:], D[nh:len(D) - nh] + need(all(g[0] == geo.ZERO and g[1] >= H0 and len(g[2]) == 1 and g[2][0] >= H0 for g in prep), 'star preparation shape') + need(rest == prep[::-1], 'restorations are the reversed preparations') + need(all(g[0] == geo.ZERO and geo.is_y(g[1]) and all(s >= v for s in g[2]) for g in mid), 'target block shape') + centres = Counter(g[1] for g in prep) + leaves = [g[2][0] for g in prep] + need(len(set(leaves)) == nh and not set(leaves) & set(centres), 'leaves distinct and never centres') + need(all(any(c in g[2] for g in mid) for c in centres), 'every centre is read by the target block') + return nh, centres + + +def census(w, geo): + v, n, D, A = geo.v, geo.n, w['D'], w['A'] + nh, centres = stars(w, geo) + tail0 = len(D) - nh + val = [1 << i for i in range(n)] + icol = [1 << i for i in range(n)] # columns of the inverse state matrix + + def apply(d, ss): + for s in ss: + val[d] ^= val[s] + icol[s] ^= icol[d] + + def unique_set(delta): + S = [j for j in range(n) if (icol[j] & delta).bit_count() & 1] + acc = 0 + for j in S: + acc ^= val[j] + need(acc == delta, 'inverse state representation') + return S + + for g in D[:tail0]: + apply(g[1], g[2]) + edges, dtail = [], [] + by_centre = {} + for i in range(tail0, len(D)): + f, a, ss = D[i] + by_centre.setdefault(a, []).append((i, ss[0])) + for i in range(tail0, len(D)): + f, a, ss = D[i] + b = ss[0] + need(val[b] == 1 << b, 'leaf holds its own input at its restoration') + need(not any(a in D[j][2] for j in range(i + 1, len(D))), 'centre read later in the D tail') + for e, b2 in by_centre[a]: + if e != i: # D-tail alternative writer: absorb restoration e into this restoration i + S = unique_set(1 << b2) + new = sorted(set(ss) ^ set(S)) + dtail.append((e, i, new, 1 + 1 - len(new))) + edges.append((i, a, b, 1 << b)) + apply(a, ss) + read, moves = {}, [] + for k, (f, d, ss) in enumerate(A): + for i, a, b, delta in edges: + if i in read: + continue + if a in ss: + read[i] = 'A' + continue + if d == a: + S = unique_set(delta) + new = sorted(set(ss) ^ set(S)) + moves.append(dict(restoration=i, edge=[a, b], k=k, S=S, new=new, gain=1 + len(ss) - len(new), + a_in_S=a in S)) + apply(d, ss) + for i, a, b, _ in edges: + if i not in read: + need(a in w['ret'], 'centre never read before B') + read[i] = 'scatter' + return dict(nh=nh, centres=centres, edges=edges, read=read, moves=moves, dtail=dtail) + + +def edit(w, moves): + """Delete each move's restoration and give its A gate the move's new source set.""" + dels = {m['restoration'] for m in moves} + need(len(dels) == len(moves) and len({m['k'] for m in moves}) == len(moves), 'one move per edge and gate') + out = dict(w) + out['D'] = [g for i, g in enumerate(w['D']) if i not in dels] + A = [list(g) for g in w['A']] + for m in moves: + f, d, ss = A[m['k']] + need(d == m['edge'][0], 'move gate writes the centre') + A[m['k']] = [f, d, list(m['new'])] if m['new'] else None + out['A'] = [g for g in A if g is not None] + return out + + +def classify(w2, geo, base_paths): + try: + ps = frame_paths(w2, geo) + except ValueError: + return 'frame_illegal' + if ps != base_paths: + return 'paths_changed' + return 'frame_legal' + + +def census_report(name, w, geo, base_paths): + c = census(w, geo) + moves = c['moves'] + need(not any(m['a_in_S'] for m in moves), 'a centre in its own substitute set') + boundary_pass = 0 + legal_by_gain = {} + outcomes = Counter() + admitted = [] + first_illegal = None + for m in moves: + w2 = edit(w, [m]) + need(boundary_ok(w2), '%s move %s at A[%d] breaks the boundary' % (name, m['edge'], m['k'])) + boundary_pass += 1 + cls = classify(w2, geo, base_paths) + m['frame'] = cls + row = legal_by_gain.setdefault(m['gain'], Counter()) + row[cls] += 1 + if m['gain'] > 0: + if cls == 'frame_legal': + b = bounds(w2) + cls = 'admitted' if b['local_ok'] and b['nine_ok'] else 'guard_fail' + if cls == 'admitted': + admitted.append(m) + elif cls == 'frame_illegal' and first_illegal is None: + first_illegal = m + outcomes[cls] += 1 + # D-tail same-centre alternatives (the only other writers of a before its first read) never gain. + for e, i, new, gain in c['dtail']: + D = [list(g) for g in w['D']] + D[i] = [D[i][0], D[i][1], new] + need(gain == 0 and boundary_ok(dict(w, D=[g for j, g in enumerate(D) if j != e])), 'D-tail alternative') + return c, dict( + star_edges=len(c['edges']), centres=len(c['centres']), + first_centre_read=dict(sorted(Counter(c['read'].values()).items())), + A_writer_pairs=len(moves), edges_with_A_writer=len({m['restoration'] for m in moves}), + gain_histogram={str(g): n for g, n in sorted(Counter(m['gain'] for m in moves).items())}, + substitute_size_histogram={str(s): n for s, n in sorted(Counter(len(m['S']) for m in moves).items())}, + frame_by_gain={str(g): dict(sorted(r.items())) for g, r in sorted(legal_by_gain.items())}, + dirty_boundary_preserved=boundary_pass, + positive=sum(m['gain'] > 0 for m in moves), positive_outcomes=dict(sorted(outcomes.items())), + admitted=[[m['edge'][0], m['edge'][1], m['k'], m['new']] for m in sorted(admitted, key=lambda m: m['edge'])], + d_tail_same_centre_pairs=len(c['dtail']), d_tail_gains=sorted({x[3] for x in c['dtail']}), + d_tail_dirty_boundary_preserved=len(c['dtail'])), admitted, first_illegal + + +# ------------------------------------------------------------------ twisted contract identities + +def twisted(w, geo): + v, n, R, H0 = geo.v, geo.n, geo.R, 2 * geo.v + X, Y, H = geo.X, geo.Y, geo.H + z = [r for r in range(n) if not geo.is_y(r)] + out = {} + out['D_frame_zero'] = all(g[0] == geo.ZERO for g in w['D']) + out['D_source_free'] = all(g[1] >= v and all(s >= v for s in g[2]) for g in w['D']) + out['D_no_target_feeds_helper'] = not any(g[1] >= H0 and any(geo.is_y(s) for s in g[2]) for g in w['D']) + out['D_entry_frame_zero'] = all(w['start'][r] == geo.ZERO for r in range(v, n)) + Dm = run_values(w, ['D']) + out['D_sources_identity'] = all(Dm[s] == 1 << s for s in range(v)) + out['T_helper_only'] = all(Dm[h] & ~H == 0 for h in range(H0, n)) + out['T_invertible'] = f2_rank([Dm[h] for h in range(H0, n)]) == R + out['T_is_identity'] = all(Dm[h] == 1 << h for h in range(H0, n)) + out['T_offdiagonal'] = sorted([h, j] for h in range(H0, n) for j in bits(Dm[h] ^ (1 << h))) + out['D_targets_y_plus_Nh'] = all(Dm[v + t] & ~H == 1 << (v + t) for t in range(v)) + N = [Dm[v + t] & H for t in range(v)] + raw = run_values(w, ['A', 'scatter', 'B']) + out['U_block_form'] = all(raw[r] & Y == 0 for r in z) + out['V_identity'] = all(raw[v + t] & Y == 1 << (v + t) for t in range(v)) + out['J_identity'] = all(raw[v + t] & X == 1 << t for t in range(v)) + Kp = [raw[v + t] & H for t in range(v)] + KpT = [] + for t in range(v): + acc = 0 + for j in bits(Kp[t]): + acc ^= Dm[j] & H + KpT.append(acc) + out['N_equals_KprimeT'] = N == KpT + out['N_equals_Kprime'] = N == Kp + out['C_full_frame_z_only'] = all(g[0] == geo.FULL and not geo.is_y(g[1]) and not any(geo.is_y(s) for s in g[2]) + for g in w['C']) + after_C = run_values(w, ['C'], raw) + out['C_Uprime_identity'] = all(after_C[r] == 1 << r for r in z) + full = run_values(w, ['D', 'A', 'scatter', 'B', 'C']) + out['C_Uprime_T_identity'] = all(full[r] == 1 << r for r in z) + out['final_targets_y_plus_x'] = all(full[v + t] == (1 << (v + t)) | (1 << t) for t in range(v)) + out['N_targets_touched'] = sum(1 for t in range(v) if N[t]) + return out + + +TWISTED_REQUIRED = ['D_frame_zero', 'D_source_free', 'D_no_target_feeds_helper', 'D_entry_frame_zero', + 'D_sources_identity', 'T_helper_only', 'T_invertible', 'D_targets_y_plus_Nh', 'U_block_form', + 'V_identity', 'J_identity', 'N_equals_KprimeT', 'C_full_frame_z_only', 'C_Uprime_T_identity', + 'final_targets_y_plus_x'] + + +# ------------------------------------------------------------------ chronology + +def per_cut(w0, w1, geo, moves): + """Lockstep D/A replay of the base word w0 and absorbed word w1, with frames.""" + dels = {m['restoration']: m for m in moves} + edits = {m['k']: m for m in moves} + seq0 = [('D', i, g) for i, g in enumerate(w0['D'])] + [('A', k, g) for k, g in enumerate(w0['A'])] + n = geo.n + vals = [[1 << r for r in range(n)], [1 << r for r in range(n)]] + curs = [list(w0['start']), list(w0['start'])] + pending = {} + cuts = diff_cuts = 0 + frames_equal = True + maxpend = 0 + + def gate(side, f, d, ss): + for r in (d, *ss): + if curs[side][r] != f: + need(geo.fs[curs[side][r]] < geo.fs[f], 'per-cut frame climb') + curs[side][r] = f + acc = 0 + for s in ss: + acc ^= vals[side][s] + vals[side][d] ^= acc + + for sec, i, g in seq0: + gate(0, *g) + if sec == 'D' and i in dels: + m = dels[i] + pending[m['edge'][0]] = 1 << m['edge'][1] + elif sec == 'A' and i in edits: + m = edits[i] + gate(1, g[0], g[1], m['new']) + need(m['edge'][0] in pending, 'absorption before its restoration') + del pending[m['edge'][0]] + else: + gate(1, *g) + cuts += 1 + diff = {r: vals[0][r] ^ vals[1][r] for r in range(n) if vals[0][r] != vals[1][r]} + need(diff == pending, 'state difference at a cut is not exactly the pending leaf columns') + diff_cuts += bool(diff) + maxpend = max(maxpend, len(diff)) + frames_equal &= curs[0] == curs[1] + need(all(curs[1][c] == geo.ZERO for c in pending), 'a differing centre left the zero frame') + need(not pending and vals[0] == vals[1], 'states equal after the last absorption') + need(frames_equal, 'register frames identical at every cut') + first_touch = all(min(k for k, g in enumerate(w1['A']) if m['edge'][0] in (g[1], *g[2])) == m['k'] for m in moves) + need(first_touch, 'each absorbing gate is the first A gate touching its centre') + return dict(cuts=cuts, cuts_with_difference=diff_cuts, max_registers_differing=maxpend, + frames_identical_at_every_cut=frames_equal, differing_centres_stay_at_zero_frame=True, + absorbing_gate_is_first_A_touch=first_touch) + + +def first_climbs(w, geo): + """Helpers whose first climb out of the zero frame (in D/A) carries a value other than their own column.""" + n, H0 = geo.n, 2 * geo.v + val = [1 << r for r in range(n)] + cur = list(w['start']) + seen = {} + for sec in 'DA': + for f, d, ss in w[sec]: + for r in (d, *ss): + if cur[r] != f and r not in seen and cur[r] == geo.ZERO: + seen[r] = val[r] + cur[r] = f + acc = 0 + for s in ss: + acc ^= val[s] + val[d] ^= acc + hel = [r for r in seen if r >= H0] + return dict(helpers_climbing_from_zero=len(hel), non_own_value=sorted(r for r in hel if seen[r] != 1 << r), + targets_climbing_in_D_or_A=sum(1 for r in seen if geo.is_y(r))) + + +# ------------------------------------------------------------------ owner checker and exporter + +def owner_flags(own, w): + try: + _, _, _, hyp, con, _ = own.check(w) + except own.Reject as e: + raise ValueError('owner checker rejects: %s' % e) + flags = {**hyp, **con} + return flags + + +def exporter(code, w, work, name): + d = work / name + d.mkdir() + (d / 'export_records.py').write_bytes(code) + (d / 'word.json.gz').write_bytes(gzip.compress(canonical(w), mtime=0)) + env = {k: x for k, x in os.environ.items() if k != 'PYTHONOPTIMIZE'} + subprocess.run([sys.executable, '-I', '-B', str(d / 'export_records.py'), str(d / 'word.json.gz'), str(d / 'rec')], + check=True, capture_output=True, text=True, env=env) + raw = (d / 'rec/249-records.bin').read_bytes() + need(len(raw) % 24 == 0, 'record alignment') + rec = list(struct.iter_unpack('<6i', raw)) + peaks = [] + for reverse in (False, True): + norm, peak, open_ = [1] * (2 * w['v'] + w['R'] + 1), 1, False + for op, a, b, c, _, _ in (reversed(rec) if reverse else rec): + if op == 0: + continue + if reverse and op in (2, 3): + op = 5 - op + if op == 1: + norm[a] += abs(c) * norm[b] + peak = max(peak, norm[a]) + elif op == 2: + need(not open_, 'nested copy') + norm[b], open_ = norm[a], True + elif op == 3: + need(open_, 'erase without copy') + norm[b], open_ = 0, False + else: + raise ValueError('record opcode') + need(not open_, 'unclosed copy') + peaks.append(peak) + moves = {} + for r in rec: + if r[0] == 0: + moves.setdefault(r[1], []).append((r[2], r[3], r[4])) + prof = Counter(r[4] for r in rec if r[0] == 0) + prof.update(r[5] for r in rec if r[0] == 2) + return dict(records=len(rec), ADD=sum(r[0] == 1 for r in rec), COPY=sum(r[0] == 2 for r in rec), + ERASE=sum(r[0] == 3 for r in rec), MOVE=sum(r[0] == 0 for r in rec), + COPY_ranks=[r[5] for r in rec if r[0] == 2], F=peaks[0], B=peaks[1], + payload_bits=(64 * peaks[0]**3 * peaks[1]**2).bit_length(), + profile={k: prof[k] for k in sorted(prof)}, record_sha256=sha(raw)), moves + + +# ------------------------------------------------------------------ controls + +def rejected(label, fn, out): + try: + detail = fn() + except ValueError as e: + out.append([label, str(e)[:120]]) + return + raise ValueError('control accepted: %s (%s)' % (label, detail)) + + +def controls(name, base, absorbed, moves, geo, own, p589, first_illegal, data, pins): + out = [] + v = geo.v + # 1. omit the restorations without the A edit: dirty endpoint fails, clean-helper endpoint passes. + omit = dict(base, D=absorbed['D']) + rows = literal(omit) + bad = [r for r, (x, y) in enumerate(zip(rows, wanted(omit))) if x != y] + need(literal(omit, clean_helpers=True) == wanted(omit, True), 'omit-only control: clean helpers must pass') + kinds = Counter('source' if r < v else 'target' if r < 2 * v else 'helper' for r in bad) + + def omit_check(): + need(rows == wanted(omit), 'dirty endpoint wrong on %d registers %s; clean-helper endpoint passes' + % (len(bad), dict(sorted(kinds.items())))) + rejected('omit restorations without the A edit', omit_check, out) + # 2. the A edit with the literal cleanup of the edited A (inherited literal H4 enforced). + zg = [[geo.FULL, g[1], list(g[2])] for sec in 'AB' for g in absorbed[sec] if not geo.is_y(g[1])] + lit = dict(absorbed, C=zg[::-1]) + rows2 = literal(lit) + bad2 = [r for r, (x, y) in enumerate(zip(rows2, wanted(lit))) if x != y] + need(bad2 == [m['edge'][0] for m in moves] and all(rows2[m['edge'][0]] == (1 << m['edge'][0]) | (1 << m['edge'][1]) + for m in moves), 'literal-H4 control fails exactly on the centres') + need(literal(lit, clean_helpers=True) == wanted(lit, True), 'literal-H4 control passes on clean helpers') + + def lit_check(): + need(rows2 == wanted(lit), 'dirty helpers %s end as centre+leaf; clean helpers pass' % bad2) + rejected('A edit with the literal cleanup of the edited A', lit_check, out) + rejected('A edit with literal cleanup, owner checker', lambda: owner_flags(own, lit), out) + # 3. absorption after the first centre read. + late = None + for m in moves: + a = m['edge'][0] + first = next(k for k, g in enumerate(base['A']) if a in g[2]) + k = next((k for k, g in enumerate(base['A']) if k > first and g[1] == a), None) + if k is not None: + late = (m, k) + break + need(late is not None, 'a late writer exists') + m, k = late + # Same recipe at a writer after the first read: S represents the leaf column at that cut of the + # base word, but the pending difference has already leaked through the read. + ref = run_values(dict(base, A=base['A'][:k]), ['D', 'A']) + S = solve_set(ref, 1 << m['edge'][1], geo.n) + need(m['edge'][0] not in S, 'late control substitute avoids the centre') + late_word = edit(base, [dict(m, k=k, new=sorted(set(base['A'][k][2]) ^ set(S)))]) + rejected('absorption after the first centre read (A[%d] for centre %d)' % (k, m['edge'][0]), + lambda: need(boundary_ok(late_word), 'dirty boundary fails'), out) + # 4. wrong substitute register. + wrong = [dict(x) for x in moves] + wrong[0]['new'] = sorted(moves[1]['new']) + wrong_word = edit(base, wrong) + rejected('wrong substitute register (%s instead of %s at A[%d])' % (wrong[0]['new'], moves[0]['new'], moves[0]['k']), + lambda: need(boundary_ok(wrong_word), 'dirty boundary fails'), out) + # 5. one frame-illegal substitution (its F2 boundary is exact; frames reject it). + need(first_illegal is not None, 'a frame-illegal positive move exists') + ill = edit(base, [first_illegal]) + need(boundary_ok(ill), 'frame-illegal control has an exact F2 boundary') + rejected('frame-illegal substitution (centre %d, A[%d], new %s)' % (first_illegal['edge'][0], first_illegal['k'], + first_illegal['new']), + lambda: frame_paths(ill, geo), out) + # 6. PR1194/PR1311-style splice: absorbed A/B/C with PR589's target-only D. + rejected('splice absorbed A/B/C with PR589 D', lambda: owner_flags(own, dict(absorbed, D=p589['D'])), out) + # 7. corrupted source pin. + b = bytearray(data[WORDS[name]]) + b[len(b) // 2] ^= 1 + rejected('corrupted source pin', lambda: check_pin(WORDS[name], bytes(b), pins[WORDS[name]]), out) + return out + + +def solve_set(val, target, n): + """Unique register set whose current values sum to target (Gaussian elimination over F2).""" + piv = {} + for r in range(n): + x, tag = val[r], 1 << r + while x: + low = x & -x + if low not in piv: + piv[low] = (x, tag) + break + px, pt = piv[low] + x ^= px + tag ^= pt + need(x, 'state not invertible') + x, tag = target, 0 + while x: + low = x & -x + px, pt = piv[low] + x ^= px + tag ^= pt + return bits(tag) + + +# ------------------------------------------------------------------ instances + +def perturbations(base, moves, geo): + """Every one-register change of each admitted new source set breaks the dirty boundary.""" + tried = 0 + for idx, m in enumerate(moves): + for r in range(geo.n): + if r == m['edge'][0]: + continue + alt = [dict(x) for x in moves] + alt[idx]['new'] = sorted(set(m['new']) ^ {r}) + need(not boundary_ok(edit(base, alt)), 'perturbed source set accepted: move %d register %d' % (idx, r)) + tried += 1 + return tried + + +def instance(name, base, admitted, geo, own, p589, code, work, first_illegal, data, pins): + fname, adds0, adds1 = INSTANCES[name] + moves = sorted(admitted, key=lambda m: m['k']) + need([[m['edge'][0], m['edge'][1], m['k'], m['new']] for m in moves] == TRIPLES, name + ' admitted triples') + centres = {m['edge'][0] for m in moves} + need(not any(set(m['S']) & (centres - {m['edge'][0]}) for m in moves), 'joint substitutes avoid other centres') + w = edit(base, moves) + for k in base: + if k not in ('A', 'D'): + need(w[k] == base[k], '%s field %s changed' % (name, k)) + need(len(w['D']) == len(base['D']) - 3 and len(w['A']) == len(base['A']), name + ' edit shape') + for rev in (False, True): + need(literal(w, rev) == wanted(w), '%s boundary (%s)' % (name, 'reverse' if rev else 'forward')) + ps0, ps1 = frame_paths(base, geo), frame_paths(w, geo) + need(ps1 == ps0, name + ' ordered frame paths') + need(same_geometry(p589, base) and frame_paths(p589, geo) == ps0, name + ' frame paths equal PR589') + prof0, prof1 = paid_profile(base, geo), paid_profile(w, geo) + need(prof0 == prof1 == PROFILE and sum(k * x for k, x in prof1.items()) == 5129, name + ' paid profile') + b0, b1 = bounds(base), bounds(w) + need(b0['ADDs'] == adds0 and b1['ADDs'] == adds1, name + ' ADD count') + guards(b0) + guards(b1) + e0, mv0 = exporter(code, base, work, name + '-base') + e1, mv1 = exporter(code, w, work, name + '-absorbed') + for e, b in ((e0, b0), (e1, b1)): + need(e['ADD'] == b['ADDs'] and e['COPY'] == e['ERASE'] == 9 and e['F'] == b['F'] and e['B'] == b['B'], + name + ' exporter bill') + need(e['profile'] == PROFILE, name + ' exporter profile') + need(mv0 == mv1, name + ' ordered per-register MOVE records') + f0, f1 = owner_flags(own, base), owner_flags(own, w) + need([k for k, x in f0.items() if not x] == ['H2_D_frame0_targets_from_helpers', 'K_equals_D'], name + ' base owner') + need([k for k, x in f1.items() if not x] == OWNER_FALSE, name + ' absorbed owner flags') + bridge = owner_flags(own, dict(base, D=p589['D'])) + need(all(bridge.values()), name + ' PR1194-style original-D splice on the base word') + need(run_values(base, ['D']) == run_values(p589, ['D']), name + ' base D operator equals PR589 D') + t0, t1 = twisted(base, geo), twisted(w, geo) + for t in (t0, t1): + need(all(t[k] for k in TWISTED_REQUIRED), name + ' twisted contract') + need(t0['T_is_identity'] and t0['C_Uprime_identity'] and t0['N_equals_Kprime'], name + ' base is the T = I case') + need(not t1['T_is_identity'] and not t1['C_Uprime_identity'] and not t1['N_equals_Kprime'] + and t1['T_offdiagonal'] == sorted([m['edge'][0], m['edge'][1]] for m in moves), name + ' T != I exactly on the stars') + chron = per_cut(base, w, geo, moves) + fc0, fc1 = first_climbs(base, geo), first_climbs(w, geo) + need(fc0['non_own_value'] == [] and fc1['non_own_value'] == sorted(centres), name + ' first-climb census') + tried = perturbations(base, moves, geo) + ctl = controls(name, base, w, moves, geo, own, p589, first_illegal, data, pins) + return w, dict( + payload=fname, payload_sha256=sha(canonical(w)), moves=TRIPLES, + literal=dict(base=b0, absorbed=b1), exporter=dict(base=e0, absorbed=e1), + profile=prof1, rank_mass=sum(k * x for k, x in prof1.items()), + paths_registers=len(ps1), columns=geo.n, directions=2, + owner=dict(base_false=[k for k, x in f0.items() if not x], absorbed_false=[k for k, x in f1.items() if not x], + absorbed_true=sum(1 for x in f1.values() if x), original_D_splice_all_true=True), + twisted=dict(base=t0, absorbed=t1), chronology=chron, first_climbs=dict(base=fc0, absorbed=fc1), + perturbations_rejected=tried, controls=ctl) + + +# ------------------------------------------------------------------ driver + +def run(write=False): + data, pins = load_inputs() + words = {k: json.loads(gzip.decompress(data[p])) for k, p in WORDS.items()} + p589 = json.loads(gzip.decompress(data[PR589])) + own = owner_module(data[CHECKER]) + geo = Geo(p589) + for k, w in words.items(): + need(same_geometry(w, p589), k + ' geometry differs from PR589') + rep = dict(status='PASS_R439_TWISTED_STAR_ABSORPTION', inputs={p: pins[p] for p in INPUTS}, census={}, instances={}) + built = {} + with tempfile.TemporaryDirectory(prefix='r439-twisted-') as tmp: + work = Path(tmp) + for name, w in words.items(): + ps = frame_paths(w, geo) + _, summary, admitted, first_illegal = census_report(name, w, geo, ps) + need(summary['admitted'] == TRIPLES, name + ': exactly the three frame-legal positive moves') + need(set(summary['first_centre_read']) <= {'A', 'scatter'}, name + ': every centre is first read in A or the scatter') + rep['census'][name] = summary + if name in INSTANCES: + built[name], rep['instances'][name] = instance(name, w, admitted, geo, own, p589, data[EXPORTER], work, + first_illegal, data, pins) + rep['new_kappa_claim'] = False + rep = json.loads(json.dumps(rep)) + if write: + for name, w in built.items(): + (HERE / INSTANCES[name][0]).write_bytes(gzip.compress(canonical(w), mtime=0)) + (HERE / 'EXPECTED.json').write_text(json.dumps(rep, indent=1, sort_keys=True) + '\n', encoding='utf-8') + for name, w in built.items(): + committed = json.loads(gzip.decompress((HERE / INSTANCES[name][0]).read_bytes())) + need(canonical(committed) == canonical(w), 'committed payload differs from the rebuilt word: ' + name) + need(json.loads((HERE / 'EXPECTED.json').read_text(encoding='utf-8')) == rep, 'EXPECTED.json mismatch') + return rep + + +def main(): + ap = argparse.ArgumentParser(description=__doc__.split('\n')[0]) + ap.add_argument('--write', action='store_true', help='regenerate EXPECTED.json and the absorbed payloads') + a = ap.parse_args() + t0 = time.perf_counter() + rep = run(write=a.write) + for name, c in rep['census'].items(): + print('census %-6s star_edges=%d A_writer_pairs=%d gains=%s positive=%d outcomes=%s admitted=%d' % ( + name, c['star_edges'], c['A_writer_pairs'], json.dumps(c['gain_histogram'], separators=(',', ':')), + c['positive'], json.dumps(c['positive_outcomes'], separators=(',', ':')), len(c['admitted']))) + for name, x in rep['instances'].items(): + b0, b1 = x['literal']['base'], x['literal']['absorbed'] + print('instance %-6s ADDs %d -> %d F/B %d/%d -> %d/%d bits %d/%d -> %d/%d profile %s mass %d owner_false=%s ' + 'controls=%d perturbations=%d' % ( + name, b0['ADDs'], b1['ADDs'], b0['F'], b0['B'], b1['F'], b1['B'], b0['local_bits'], + b0['nine_stage_bits'], b1['local_bits'], b1['nine_stage_bits'], + json.dumps(x['profile'], separators=(',', ':')), x['rank_mass'], ','.join(x['owner']['absorbed_false']), + len(x['controls']), x['perturbations_rejected'])) + for label, why in x['controls']: + print(' control rejected: %s -- %s' % (label, why)) + print('PASS_R439_TWISTED_STAR_ABSORPTION words=%d instances=%d ADDs 11500->11497 10492->10489 columns=661 ' + 'controls=%d no_new_kappa (%.1f s)' % (len(rep['census']), len(rep['instances']), + sum(len(x['controls']) for x in rep['instances'].values()), + time.perf_counter() - t0)) + + +if __name__ == '__main__': + main()