code wiki / _hdl_build / nx_eqsat_membership_proof.nx

nx_eqsat_membership_proof.nx

buildroot/runtime/_hdl_build/nx_eqsat_membership_proof.nx

31313 B623 linesdepth 8pulls 12 transitivereach 4 importersview sourcekind librarytopic eqsat
docsdependenciesstructsconstsfunctions

about

nx_eqsat_membership_proof.nx -- MEMBERSHIP-AS-PROOF CERTIFICATE for the eqsat e-graph (the sovereign analogue of ROVER's "verified rewriting": no external SMT oracle; the rewrite rules' soundness + e-class membership IS the proof). THE CLAIM BEING CERTIFIED: Two expressions a, b are equivalent-for-all-inputs (mod 2^W) iff (1) MEMBERSHIP: nx_eqsat_find(g, a) == nx_eqsat_find(g, b) (they landed in the same canonical e-class after saturation), AND (2) PROVENANCE: every union on the rewrite path that merged them used a rule from the PROVEN-SOUND set. When BOTH hold, a == b for all inputs -- membership is a rewrite-path equivalence PROOF, not a heuristic. LIVE CERTIFICATION (mp_certify_live): the engine (nx_eqsat.nx) now logs the citing rule-id of EVERY real merge at its single union chokepoint (nx_eqsat_union_cited) when provenance is enabled (nx_eqsat_enable_prov). The live certifier runs the REAL nx_eqsat_saturate and checks the GLOBAL property "every logged rule-id is in the proven-sound set" + find(a)==find(b) + the log did not overflow (fail-closed). Because every merge flows through the one function that mutates canon, a merge cannot happen without a rule-id being logged -- so an unlogged/un-cited merge (RULE_NONE) poisons the certificate. The gated recorder (mp_prov_admit_union) is RETAINED for the load-bearing negatives' belt-and-suspenders legs + the k<MP_W boundary side-condition. THE SOUND SET (justified, not asserted): a rule is admitted to the sound set ONLY after its W-bit (mod 2^W) algebraic identity is machine-checked EXHAUSTIVELY at a representative width W=8 -- the same width-independent exhaustive-small-width discipline as nx_alu_divider_proof_test.nx. Every evaluator output is MASKED to W bits before comparison (mask = (1<<W)-1) so we prove the true mod-2^W theorem, NOT a coincidental full-i64 identity (the truncation gap). The oracle is also reduced mod 2^W and is independent of both the MUL and SHL nodes (computed by repeated doubling), so the two netlist legs + oracle are three independent witnesses fed through nx_triangulate. LOAD-BEARING (defense in depth): the certificate must FAIL when (NEG-A) a NON-sound rule is used (it is not in the allow-list AND its W=8 battery DISAGREES, so it can never enter the sound set), or (NEG-B) the two endpoints are NOT in the same e-class (membership fails). Both negatives are exercised + asserted in the test (FAIL LOUD known answer).

dependencies 3 imports · 4 importers

nx_eqsat.nx nx_alu_divider.nx nx_triangulate.nx nx_eqsat_membership_proof.nx nx_eqsat_constfold_test.nx nx_eqsat_dsl_parity_test.nx nx_eqsat_membership_proof_test.nx nx_rule_soundness_test.nx

imports: nx_eqsat.nxnx_alu_divider.nxnx_triangulate.nx

imported by: nx_eqsat_constfold_test.nxnx_eqsat_dsl_parity_test.nxnx_eqsat_membership_proof_test.nxnx_rule_soundness_test.nx

structs

514struct NxMpProvenance
556struct NxMpCertificate

consts

52const MP_MAGIC_999999: i64 = 999999
56const MP_W: i64 = 8 // representative width: sweep x in [0, 2^W)
68const MP_RULE_NONE: i64 = 0 // sentinel: no/unknown rule -> NOT sound
69const MP_RULE_ADD_ZERO: i64 = 1
70const MP_RULE_SUB_SELF: i64 = 2
71const MP_RULE_ADD_SELF: i64 = 3
72const MP_RULE_AND_SELF: i64 = 4
73const MP_RULE_OR_ZERO: i64 = 5
74const MP_RULE_MUL_ONE: i64 = 6
75const MP_RULE_MUL_POW2: i64 = 7
82const MP_RULE_CONGRUENCE: i64 = 8
90const MP_RULE_XOR_SELF: i64 = 9
104const MP_RULE_CONSTFOLD: i64 = 10
112const MP_RULE_SHIFT_MERGE: i64 = 11
113const MP_RULE_N: i64 = 12
118const MP_RULE_BOGUS_MUL3: i64 = 100

functions

58func mp_mask() -> i64 { return (1 << MP_W) - 1 } // (1<<W)-1 = mod-2^W reducer
59func mp_count() -> i64 { return 1 << MP_W } // 2^W vectors per unary rule
124func mp_rule_ids_lockstep() -> i64
called by 3: mainmainmain
146func _mp_reset(g: *NxGsim, vals: *i64, cells: *NxGsimCell) -> i64
152func _mp_eval_op_const(g: *NxGsim, vals: *i64, cells: *NxGsimCell,
164func _mp_eval_op_self(g: *NxGsim, vals: *i64, cells: *NxGsimCell,
178func _mp_oracle_identity(x: i64) -> i64 { return x & mp_mask() } // == x
called by 1: mp_battery_unary calls 1: mp_mask
179func _mp_oracle_zero() -> i64 { return 0 } // sub_self
called by 1: mp_battery_unary
181func _mp_oracle_double_k(x: i64, k: i64) -> i64
197func _mp_witnessA(rule: i64, x: i64, k: i64) -> i64
222func _mp_shiftmerge_witnessA(x: i64, i: i64, j: i64) -> i64
called by 1: mp_battery_shift_merge calls 1: mp_mask
234func _mp_shl_wbit(x: i64, k: i64) -> i64
247func mp_battery_shift_merge(g: *NxGsim, vals: *i64, cells: *NxGsimCell, t: *NxTriTally) -> i64
303func mp_shiftmerge_boundary_unsound(x: i64, i: i64, j: i64) -> i64
325func mp_battery_unary(g: *NxGsim, vals: *i64, cells: *NxGsimCell,
393func mp_battery_mul_pow2_inrange(g: *NxGsim, vals: *i64, cells: *NxGsimCell,
432func mp_battery_xor_self(g: *NxGsim, vals: *i64, cells: *NxGsimCell, t: *NxTriTally) -> i64
called by 1: main calls 1: mp_battery_unary
443func mp_is_sound_rule(rule: i64) -> i64
488func mp_shift_merge_ij_ok(i: i64, j: i64) -> i64
500func mp_mul_pow2_k_ok(k: i64) -> i64
521func mp_prov_init(p: *NxMpProvenance) -> i64
called by 1: main
533func mp_prov_admit_union(p: *NxMpProvenance, g: *NxEGraph,
564func mp_certify(g: *NxEGraph, a: i64, b: i64,
called by 1: main calls 1: nx_eqsat_find
597func mp_log_all_sound(g: *NxEGraph) -> i64
606func mp_certify_live(g: *NxEGraph, a: i64, b: i64, out: *NxMpCertificate) -> i64