code wiki / _hdl_build / nx_pattern_classify.nx
nx_pattern_classify.nx source
↩ module page · 140 lines · 8736 B
1// nx_pattern_classify.nx -- the BUILDER's pattern CLASSIFIER (the rung nx_pattern_library itself flags:
2// "a real classifier would infer shape from the spec's in/out types"). Until now the pipeline trusted a
3// hand-assigned shape_id -- which means a human (or Claude) still classified every spec. This module
4// closes that: a spec is described by a small FEATURE VECTOR (what its inputs/outputs ARE), and a
5// data-driven DECISION TABLE maps features -> pattern id. Adding a shape = adding a row, not code
6// (rule 11). First-match-in-order resolves overlaps (PID before GOVERNOR: both stateful, plant wins;
7// STATE_FLOW before THRESHOLD_TABLE: both table-driven, verdict-out vs value-out splits them).
8// 0 = NOVEL -> NEEDS_TUTOR, honest and measured, exactly as bp_claude_touch counts it.
9// RACI: BUILDER owns this (AUTHOR's front door: spec -> which emitter authors it).
10// LAWS: struct-free, integer-only, flat ifs. license_tier: ORIGINAL
11import "nx_pattern_library.nx"
12import "nx_syscalls.nx"
13
14// ---- the feature vector: f[i] = 1 if the spec has the trait (indices are the contract) ----
15const PLC_IN_BYTES: i64 = 0 // consumes a byte buffer (parse)
16const PLC_IN_ARRAY: i64 = 1 // consumes an i64 array (fold)
17const PLC_IN_PAIR: i64 = 2 // compares two scalars (a vs b)
18const PLC_IN_STATE: i64 = 3 // mutates carried state (integ, per-host last-hit)
19const PLC_IN_TABLE: i64 = 4 // core logic IS a data table (curve, transitions)
20const PLC_IN_COORDS: i64 = 5 // nm coordinates / dimensions
21const PLC_HAS_TIME: i64 = 6 // timestamps / rates / pacing
22const PLC_HAS_PLANT: i64 = 7 // closed feedback loop against a plant
23const PLC_OUT_VERDICT:i64 = 8 // output is a small enum (UNDER/OK/OVER, winner, next-state)
24const PLC_OUT_VALUE: i64 = 9 // output is a computed quantity
25const PLC_IS_META: i64 = 10 // emits modules/boilerplate rather than computing
26const PLC_IN_COEFFS: i64 = 11 // spec is a coefficient/constant table (oracle-generated f64 kernels)
27const PLC_IN_FRAMED: i64 = 12 // framed binary layout (TLV / length-prefixed field sequences)
28const PLC_IN_MARKED: i64 = 13 // prefix+marker stream (JPEG-style: standalone table, terminator)
29const PLC_HAS_INVERSE:i64 = 14 // lossless round-trip law: an exact inverse must reconstruct the
30 // input bit-for-bit (predictor/residual coders, codecs)
31const PLC_IN_INGEST: i64 = 15 // the COMPOSE-shape: a spec that wires a fixed pipeline of named
32 // organ fns (walk-all-chunks -> field-split -> canon/CID ->
33 // idempotent store). Routes PL_PNG_INGEST (emit15). DECLARED-
34 // SCAFFOLD trait, R3-authorized (X-AUT-NCF-001).
35// shape-20 LOG_SCAN traits (additive; NO existing index changes). A spec that READS a log/universe
36// and DERIVES a permil scoreboard. Deliberately distinct from in_bytes so it never touches the
37// t[15..17] zero-gap row (proven DIFFS=0).
38const PLC_READS_LOG: i64 = 16 // consumes a log/universe + target stream to count coverage
39const PLC_DERIVES_PERMIL:i64 = 17 // derives permil=count*1000/total + a verdict-band ladder
40// shape-21 RANK_FUSE trait (additive; no existing index changes): a spec consuming K source-rankings to FUSE
41// (internal+external) via reciprocal-rank fusion. Routes PL_RANK_FUSE (emitter nx_pattern_emit_rankfuse).
42const PLC_IN_RANKINGS: i64 = 18 // consumes K rankings to fuse (RRF)
43const PLC_IN_CORPUS: i64 = 19 // consumes a doc corpus + query -> ranked TF retrieval (RANK_RETRIEVE)
44const PLC_IN_OPDAG: i64 = 20 // consumes a 3-address op-DAG -> lowered dataflow core (RTL_SYNTH)
45const PLC_IN_SUBFABRICS: i64 = 21 // consumes K sub-fabrics to fold via fab_append (NETLIST_COMPOSE)
46const PLC_IN_FABRIC: i64 = 22 // emits a gate-level LUT4 fabric (cells+nets) -> runs on fab_eval (FABRIC_NETLIST)
47const PLC_N_FEATURES: i64 = 23
48
49// ---- the decision table: ordered (pattern_id, must_a, must_b) triples; must_b = -1 means one trait
50// suffices. FIRST full match wins; table order IS the disambiguation policy. ----
51func plc_table_rows() -> i64 { return 25 }
52func plc_table() -> *i64 {
53 let t: *i64 = sys_mmap(640) as *i64
54 // PNG_INGEST (compose-shape) FIRST: in_ingest is a distinct trait so it routes here
55 // before the is_meta SCAFFOLD/IO_CONTRACT rows could absorb it (order = policy).
56 t[0]=PL_PNG_INGEST; t[1]=PLC_IN_INGEST; t[2]=0-1
57 t[3]=PL_PID_LOOP; t[4]=PLC_HAS_PLANT; t[5]=PLC_IN_STATE
58 t[6]=PL_GOVERNOR; t[7]=PLC_HAS_TIME; t[8]=0-1
59 t[9]=PL_GEOMETRY; t[10]=PLC_IN_COORDS; t[11]=0-1
60 t[12]=PL_MATH_KERNEL; t[13]=PLC_IN_COEFFS; t[14]=0-1
61 t[18]=PL_IO_CONTRACT; t[19]=PLC_IS_META; t[20]=PLC_IN_FRAMED
62 t[21]=PL_STRUCT_WALK; t[22]=PLC_IN_FRAMED; t[23]=PLC_IN_TABLE
63 t[24]=PL_WIRE_MARKER; t[25]=PLC_IN_MARKED; t[26]=0-1
64 t[27]=PL_WIRE_TLV; t[28]=PLC_IN_FRAMED; t[29]=0-1
65 // TEMPLATE_TABLE before STATE_FLOW/THRESHOLD_TABLE: a renderer spec is
66 // table-driven AND consumes payload bytes; verdict/value-out specs lack
67 // IN_BYTES so the older rows keep their routes (order = policy).
68 t[30]=PL_TEMPLATE_TABLE; t[31]=PLC_IN_TABLE; t[32]=PLC_IN_BYTES
69 // STATE_MACHINE before STATE_FLOW (index order IS the policy): both are
70 // table-driven w/ enum out, but a machine spec CARRIES state between
71 // events (IN_STATE); flow specs do not.
72 t[33]=PL_STATE_MACHINE; t[34]=PLC_IN_TABLE; t[35]=PLC_IN_STATE
73 t[36]=PL_STATE_FLOW; t[37]=PLC_IN_TABLE; t[38]=PLC_OUT_VERDICT
74 t[39]=PL_THRESHOLD_TABLE;t[40]=PLC_IN_TABLE; t[41]=PLC_OUT_VALUE
75 t[42]=PL_PARSER_KAT; t[43]=PLC_IN_BYTES; t[44]=PLC_OUT_VALUE
76 t[45]=PL_PREDICTOR_CODER;t[46]=PLC_IN_ARRAY; t[47]=PLC_HAS_INVERSE
77 t[48]=PL_ACCUMULATOR; t[49]=PLC_IN_ARRAY; t[50]=0-1
78 t[51]=PL_COMPARATOR; t[52]=PLC_IN_PAIR; t[53]=PLC_OUT_VERDICT
79 t[54]=PL_SCAFFOLD; t[55]=PLC_IS_META; t[56]=0-1
80 // shape-20 LOG_SCAN (NEW scanned row r=19): reads_log + derives_permil. Placed AFTER all other
81 // rows so nothing it could shadow exists; the t[15..17] zero gap is left untouched (proven safe).
82 t[57]=PL_LOG_SCAN; t[58]=PLC_READS_LOG; t[59]=PLC_DERIVES_PERMIL
83 // VERDICT_GATE kept in the catalog but DORMANT (unscanned, exactly as before): relocated to
84 // t[60..62] which sits past plc_table_rows(); out_verdict-only specs stay NOVEL as today.
85 t[60]=PL_RANK_FUSE; t[61]=PLC_IN_RANKINGS;t[62]=0-1
86 // shape-22 RANK_RETRIEVE (active row 21): a spec consuming a corpus+query routes here (IN_CORPUS, a new trait).
87 t[63]=PL_RANK_RETRIEVE; t[64]=PLC_IN_CORPUS; t[65]=0-1
88 // shape-23 RTL_SYNTH (active row 22): a spec consuming a 3-address op-DAG routes here (IN_OPDAG, a new trait).
89 t[66]=PL_RTL_SYNTH; t[67]=PLC_IN_OPDAG; t[68]=0-1
90 // shape-24 NETLIST_COMPOSE (active row 23): a spec consuming K sub-fabrics routes here (IN_SUBFABRICS, a new trait).
91 t[69]=PL_NETLIST_COMPOSE;t[70]=PLC_IN_SUBFABRICS;t[71]=0-1
92 // shape-25 FABRIC_NETLIST (active row 24): a spec emitting a gate-level fabric routes here (IN_FABRIC, a new trait).
93 t[72]=PL_FABRIC_NETLIST; t[73]=PLC_IN_FABRIC; t[74]=0-1
94 t[75]=PL_VERDICT_GATE; t[76]=PLC_OUT_VERDICT;t[77]=0-1
95 return t
96}
97
98// classify a spec's feature vector -> pattern id (0 = NOVEL -> NEEDS_TUTOR, measured not hidden)
99func plc_classify(f: *i64) -> i64 {
100 let t: *i64 = plc_table()
101 let nr: i64 = plc_table_rows()
102 var r: i64 = 0
103 while r < nr {
104 let pa: i64 = t[r*3+1]
105 let pb: i64 = t[r*3+2]
106 var hit: i64 = 0
107 if f[pa] == 1 { hit = 1 }
108 if hit == 1 { if pb >= 0 { if f[pb] != 1 { hit = 0 } } }
109 if hit == 1 { return t[r*3] }
110 r = r + 1
111 }
112 return 0
113}
114
115// the pipeline's new front door: classify, then confirm the library covers it (always true for a
116// table row, by construction -- but the check keeps the contract explicit if rows outpace emitters)
117func plc_match_spec(f: *i64) -> i64 {
118 let p: i64 = plc_classify(f)
119 if p == 0 { return 0 }
120 if pl_covered(p) == 1 { return p }
121 return 0
122}
123
124// fresh all-zero feature vector (callers set traits then classify)
125func plc_new_features() -> *i64 {
126 return sys_mmap(160) as *i64
127}
128
129// the highest pattern id the decision table can route (the sync gate's coverage probe:
130// emitters past this id exist but have no classifier route = census drift)
131func plc_max_covered() -> i64 {
132 let t: *i64 = plc_table()
133 var best: i64 = 0
134 var r: i64 = 0
135 while r < plc_table_rows() {
136 if t[r*3] > best { best = t[r*3] }
137 r = r + 1
138 }
139 return best
140}