nx_select_joint_chain_test.nx source
↩ module page · 202 lines · 9400 B
1// nx_select_joint_chain_test.nx -- smoke for nx_select_joint_chain
2// SA-5 N-node linear chain selector.
3//
4// Exercises:
5// 1. Degenerate N=1 chain falls back to single-class selection
6// 2. N=0 -> BAD_INPUT
7// 3. N=3 linear chain A -> B -> C demonstrates the LOAD-BEARING
8// property: middle node forced into non-locally-optimal variant
9// so the chain composes
10// 4. N=4 linear chain A -> B -> C -> D where the optimal pick at
11// each interior node depends on BOTH neighbors
12// 5. No-feasible-chain detection (incompatible layouts in any pair)
13//
14// SA-5 remainder verification gate per NISHI_SELF_ASSEMBLY_ROADMAP.md
15// ยง8: "DAG composition smoke -- same algorithm, two layout choices,
16// joint solver picks bit-coherent layouts across nodes".
17
18import "nx_syscalls.nx"
19import "nx_probe.nx"
20import "nx_calibrate.nx"
21import "nx_select.nx"
22import "nx_select_joint.nx"
23
24func _make_probe_rv64() -> *NxProbeRecord {
25 let p: *NxProbeRecord = nx_probe_new()
26 p.actual_isa_family = NX_ISA_RV64
27 p.actual_endianness = NX_ENDIAN_LITTLE
28 p.actual_pointer_width_bits = 64
29 p.actual_page_size_bytes = 4096
30 p.actual_mmap_works = 1
31 p.actual_write_works = 1
32 p.actual_mono_clock_works = 1
33 return p
34}
35
36// Helper: build a manifest with given variant_id, cost, in_layout,
37// out_layout. All other fields default-compatible with RV64.
38func _mk(variant_id: i64, cost: i64, in_layout: i64, out_layout: i64) -> *NxManifest {
39 let m: *NxManifest = nx_manifest_new(
40 100, variant_id,
41 nx_isa_bit(NX_ISA_RV64),
42 0, 4096,
43 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
44 cost, 0, 0, 0)
45 nx_manifest_set_layout(m, in_layout, out_layout)
46 return m
47}
48
49func main() -> i64 {
50 let probe: *NxProbeRecord = _make_probe_rv64()
51 let policy: *NxPolicy = nx_policy_throughput_default()
52
53 // ----- 1. BAD_INPUT for n_nodes <= 0 -----
54 let empty_ptrs: *i64 = (sys_mmap(8)) as *i64
55 let empty_out: *i64 = (sys_mmap(8)) as *i64
56 let rc_empty: i64 = nx_select_joint_chain(empty_ptrs, 0, probe,
57 NX_TIER_INF_LAPTOP, 1048576, 0,
58 policy, empty_out)
59 if rc_empty != NX_SEL_JOINT_BAD_INPUT { return 1 }
60
61 // ----- 2. Degenerate N=1 chain falls back to single-class -----
62 let n1_m_cheap: *NxManifest = _mk(1001, 100, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_OPAQUE_PASS)
63 let n1_m_exp: *NxManifest = _mk(1002, 500, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_OPAQUE_PASS)
64 let n1_ptrs: *i64 = (sys_mmap(16)) as *i64
65 n1_ptrs[0] = n1_m_cheap as i64
66 n1_ptrs[1] = n1_m_exp as i64
67 let n1_node: *NxJointNode = nx_joint_node_new(100, n1_ptrs, 2)
68 let n1_nodes_arr: *i64 = (sys_mmap(8)) as *i64
69 n1_nodes_arr[0] = n1_node as i64
70 let n1_out: *i64 = (sys_mmap(8)) as *i64
71 let rc_n1: i64 = nx_select_joint_chain(n1_nodes_arr, 1, probe,
72 NX_TIER_INF_LAPTOP, 1048576, 0,
73 policy, n1_out)
74 if rc_n1 != NX_SEL_JOINT_OK { return 2 }
75 if n1_out[0] != 0 { return 3 } // n1_m_cheap wins
76
77 // ----- 3. N=3 chain with NON-LOCAL middle pick -----
78 // A produces ROW or COL. B consumes either ROW or COL, produces
79 // the SAME shape (in == out). C consumes COL only.
80 //
81 // Per-node argmin: A_cheap (cheapest), B_cheap_row (cheapest),
82 // C_only_col_cheap (only option). Chain: A.out=ROW ->
83 // B_cheap_row.in=ROW OK -> B_cheap_row.out=ROW -> C.in=COL FAIL.
84 //
85 // Joint argmin: must route through a COL middle. Either
86 // (A_row, B_row_to_col_transform, C_col) -- but we don't have
87 // a transform variant yet, so the chain must pick:
88 // (A_medium_col, B_col_pass, C_col_cheap) where each component
89 // is layout-consistent.
90 let a_cheap_row: *NxManifest = _mk(2001, 100, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_ROW_MAJOR)
91 let a_med_col: *NxManifest = _mk(2002, 300, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_COL_MAJOR)
92 let b_cheap_row: *NxManifest = _mk(2101, 100, NX_LAYOUT_ROW_MAJOR, NX_LAYOUT_ROW_MAJOR)
93 let b_med_col: *NxManifest = _mk(2102, 200, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_COL_MAJOR)
94 let c_col_cheap: *NxManifest = _mk(2201, 100, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS)
95
96 let a_ptrs: *i64 = (sys_mmap(16)) as *i64
97 a_ptrs[0] = a_cheap_row as i64
98 a_ptrs[1] = a_med_col as i64
99 let b_ptrs: *i64 = (sys_mmap(16)) as *i64
100 b_ptrs[0] = b_cheap_row as i64
101 b_ptrs[1] = b_med_col as i64
102 let c_ptrs: *i64 = (sys_mmap(8)) as *i64
103 c_ptrs[0] = c_col_cheap as i64
104
105 let a_node: *NxJointNode = nx_joint_node_new(100, a_ptrs, 2)
106 let b_node: *NxJointNode = nx_joint_node_new(200, b_ptrs, 2)
107 let c_node: *NxJointNode = nx_joint_node_new(300, c_ptrs, 1)
108
109 let chain3_nodes: *i64 = (sys_mmap(24)) as *i64
110 chain3_nodes[0] = a_node as i64
111 chain3_nodes[1] = b_node as i64
112 chain3_nodes[2] = c_node as i64
113
114 let chain3_out: *i64 = (sys_mmap(24)) as *i64
115 let rc3: i64 = nx_select_joint_chain(chain3_nodes, 3, probe,
116 NX_TIER_INF_LAPTOP, 1048576, 0,
117 policy, chain3_out)
118 if rc3 != NX_SEL_JOINT_OK { return 4 }
119
120 // Expected joint solution: (a_med_col=1, b_med_col=1, c_col_cheap=0).
121 // Total = 300 + 200 + 100 = 600 vs. (a_cheap_row, b_cheap_row, ???) =
122 // no compatible C -> infeasible. Other compatible chain:
123 // (a_med_col, b_med_col, c_col_cheap) = 600 ONLY feasible.
124 if chain3_out[0] != 1 { return 5 }
125 if chain3_out[1] != 1 { return 6 }
126 if chain3_out[2] != 0 { return 7 }
127
128 // Verify layout compatibility across the picked chain.
129 let pa: *NxManifest = a_ptrs[chain3_out[0]] as *NxManifest
130 let pb: *NxManifest = b_ptrs[chain3_out[1]] as *NxManifest
131 let pc: *NxManifest = c_ptrs[chain3_out[2]] as *NxManifest
132 if nx_layout_compatible(pa.out_layout, pb.in_layout) != 1 { return 8 }
133 if nx_layout_compatible(pb.out_layout, pc.in_layout) != 1 { return 9 }
134
135 // Verify variant IDs survived.
136 if pa.variant_id != 2002 { return 10 }
137 if pb.variant_id != 2102 { return 11 }
138 if pc.variant_id != 2201 { return 12 }
139
140 // ----- 4. N=4 chain where every interior node is forced -----
141 // A -> B -> C -> D. All four must agree on COL.
142 let d_col_cheap: *NxManifest = _mk(2301, 100, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS)
143 let d_ptrs: *i64 = (sys_mmap(8)) as *i64
144 d_ptrs[0] = d_col_cheap as i64
145 let d_node: *NxJointNode = nx_joint_node_new(400, d_ptrs, 1)
146
147 let chain4_nodes: *i64 = (sys_mmap(32)) as *i64
148 chain4_nodes[0] = a_node as i64
149 chain4_nodes[1] = b_node as i64
150 chain4_nodes[2] = b_node as i64 // reuse b_node candidates
151 chain4_nodes[3] = d_node as i64
152
153 let chain4_out: *i64 = (sys_mmap(32)) as *i64
154 let rc4: i64 = nx_select_joint_chain(chain4_nodes, 4, probe,
155 NX_TIER_INF_LAPTOP, 1048576, 0,
156 policy, chain4_out)
157 if rc4 != NX_SEL_JOINT_OK { return 13 }
158 // All four nodes must pick the COL-consistent variant.
159 if chain4_out[0] != 1 { return 14 } // a_med_col
160 if chain4_out[1] != 1 { return 15 } // b_med_col
161 if chain4_out[2] != 1 { return 16 } // b_med_col again
162 if chain4_out[3] != 0 { return 17 } // d_col_cheap
163
164 // ----- 5. No-feasible-chain detection -----
165 // Force a chain where the first node produces ROW only and the
166 // second consumes COL only -- no compatible bridge.
167 let only_row_out: *NxManifest = _mk(3001, 100, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_ROW_MAJOR)
168 let only_col_in: *NxManifest = _mk(3002, 100, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS)
169 let row_only_ptrs: *i64 = (sys_mmap(8)) as *i64
170 row_only_ptrs[0] = only_row_out as i64
171 let col_only_ptrs: *i64 = (sys_mmap(8)) as *i64
172 col_only_ptrs[0] = only_col_in as i64
173 let row_node: *NxJointNode = nx_joint_node_new(100, row_only_ptrs, 1)
174 let col_node: *NxJointNode = nx_joint_node_new(200, col_only_ptrs, 1)
175
176 let infeasible_nodes: *i64 = (sys_mmap(16)) as *i64
177 infeasible_nodes[0] = row_node as i64
178 infeasible_nodes[1] = col_node as i64
179 let infeasible_out: *i64 = (sys_mmap(16)) as *i64
180 let rc_inf: i64 = nx_select_joint_chain(infeasible_nodes, 2, probe,
181 NX_TIER_INF_LAPTOP, 1048576, 0,
182 policy, infeasible_out)
183 if rc_inf != NX_SEL_JOINT_NO_FEASIBLE_PAIR { return 18 }
184 if infeasible_out[0] != -1 { return 19 }
185 if infeasible_out[1] != -1 { return 20 }
186
187 // ----- 6. Bad input gates -----
188 let null_out: *i64 = (0 as i64) as *i64
189 let rc_null: i64 = nx_select_joint_chain(chain3_nodes, 3, probe,
190 NX_TIER_INF_LAPTOP, 1048576, 0,
191 policy, null_out)
192 if rc_null != NX_SEL_JOINT_BAD_INPUT { return 21 }
193
194 // Oversized N rejected.
195 let too_big_out: *i64 = (sys_mmap(8)) as *i64
196 let rc_too_big: i64 = nx_select_joint_chain(chain3_nodes, 999, probe,
197 NX_TIER_INF_LAPTOP, 1048576, 0,
198 policy, too_big_out)
199 if rc_too_big != NX_SEL_JOINT_BAD_INPUT { return 22 }
200
201 return 0
202}