nx_select_joint_test.nx source
↩ module page · 208 lines · 8314 B
1// nx_select_joint_test.nx -- smoke for nx_select_joint SA-5 MVP.
2//
3// Demonstrates the LOAD-BEARING joint-DAG property: independent
4// argmin picks a locally-optimal pair that is layout-INCOMPATIBLE;
5// joint solver picks a globally-optimal pair that costs more locally
6// but composes through the edge.
7//
8// Two-node DAG:
9//
10// [node A: variant_class=100] --edge--> [node B: variant_class=200]
11//
12// Producer candidates (node A):
13// A_cheap_row : cost=100, out_layout=ROW_MAJOR
14// A_medium_col : cost=300, out_layout=COL_MAJOR
15// A_expensive_col: cost=900, out_layout=COL_MAJOR
16//
17// Consumer candidates (node B):
18// B_cheap_col : cost=100, in_layout=COL_MAJOR
19// B_expensive_row : cost=900, in_layout=ROW_MAJOR
20//
21// Per-node argmin (single-class):
22// node A picks A_cheap_row (cost=100)
23// node B picks B_cheap_col (cost=100)
24// But the edge A_cheap_row.out=ROW vs B_cheap_col.in=COL is INCOMPATIBLE.
25//
26// Joint argmin:
27// (A_cheap_row, B_expensive_row): row->row compatible; total=100+900=1000
28// (A_medium_col, B_cheap_col): col->col compatible; total=300+100=400 <- WIN
29// (A_expensive_col, B_cheap_col): col->col compatible; total=900+100=1000
30//
31// The joint solver must pick (A_medium_col, B_cheap_col) -- INDICES
32// (1, 0) -- demonstrating that the locally-suboptimal A_medium_col
33// is the globally-optimal choice given the edge constraint.
34//
35// SA-5 verification gate per NISHI_SELF_ASSEMBLY_ROADMAP.md ยง8:
36// "DAG composition smoke -- same algorithm, two layout choices,
37// joint solver picks bit-coherent layouts across nodes"
38
39import "nx_syscalls.nx"
40import "nx_probe.nx"
41import "nx_calibrate.nx"
42import "nx_select.nx"
43import "nx_select_joint.nx"
44
45func _make_probe_rv64() -> *NxProbeRecord {
46 let p: *NxProbeRecord = nx_probe_new()
47 p.actual_isa_family = NX_ISA_RV64
48 p.actual_endianness = NX_ENDIAN_LITTLE
49 p.actual_pointer_width_bits = 64
50 p.actual_page_size_bytes = 4096
51 p.actual_mmap_works = 1
52 p.actual_write_works = 1
53 p.actual_mono_clock_works = 1
54 return p
55}
56
57func main() -> i64 {
58 let probe: *NxProbeRecord = _make_probe_rv64()
59 let policy: *NxPolicy = nx_policy_throughput_default()
60
61 // ----- Node A candidates -----
62 let a_cheap_row: *NxManifest = nx_manifest_new(
63 100, 1001,
64 nx_isa_bit(NX_ISA_RV64),
65 0, 4096,
66 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
67 100, 0, 0, 0)
68 nx_manifest_set_layout(a_cheap_row, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_ROW_MAJOR)
69
70 let a_medium_col: *NxManifest = nx_manifest_new(
71 100, 1002,
72 nx_isa_bit(NX_ISA_RV64),
73 0, 4096,
74 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
75 300, 0, 0, 0)
76 nx_manifest_set_layout(a_medium_col, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_COL_MAJOR)
77
78 let a_expensive_col: *NxManifest = nx_manifest_new(
79 100, 1003,
80 nx_isa_bit(NX_ISA_RV64),
81 0, 4096,
82 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
83 900, 0, 0, 0)
84 nx_manifest_set_layout(a_expensive_col, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_COL_MAJOR)
85
86 // ----- Node B candidates -----
87 let b_cheap_col: *NxManifest = nx_manifest_new(
88 200, 2001,
89 nx_isa_bit(NX_ISA_RV64),
90 0, 4096,
91 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
92 100, 0, 0, 0)
93 nx_manifest_set_layout(b_cheap_col, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS)
94
95 let b_expensive_row: *NxManifest = nx_manifest_new(
96 200, 2002,
97 nx_isa_bit(NX_ISA_RV64),
98 0, 4096,
99 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
100 900, 0, 0, 0)
101 nx_manifest_set_layout(b_expensive_row, NX_LAYOUT_ROW_MAJOR, NX_LAYOUT_OPAQUE_PASS)
102
103 // ----- Build node arrays -----
104 let a_ptrs: *i64 = (sys_mmap(32)) as *i64
105 a_ptrs[0] = a_cheap_row as i64
106 a_ptrs[1] = a_medium_col as i64
107 a_ptrs[2] = a_expensive_col as i64
108
109 let b_ptrs: *i64 = (sys_mmap(32)) as *i64
110 b_ptrs[0] = b_cheap_col as i64
111 b_ptrs[1] = b_expensive_row as i64
112
113 let node_a: *NxJointNode = nx_joint_node_new(100, a_ptrs, 3)
114 let node_b: *NxJointNode = nx_joint_node_new(200, b_ptrs, 2)
115
116 // ----- 1. Single-class (independent) selection for sanity -----
117 // Per-node argmin: should pick A_cheap_row (index 0) and B_cheap_col (index 0).
118 // These local optima are INCOMPATIBLE across the edge.
119 let solo_a: i64 = nx_select(a_ptrs, 3, probe, NX_TIER_INF_LAPTOP, 1048576, 0, policy)
120 if solo_a != 0 { return 1 } // single-class picks A_cheap_row locally
121 let solo_b: i64 = nx_select(b_ptrs, 2, probe, NX_TIER_INF_LAPTOP, 1048576, 0, policy)
122 if solo_b != 0 { return 2 } // single-class picks B_cheap_col locally
123
124 // Confirm the local pair is layout-incompatible.
125 let local_a: *NxManifest = a_ptrs[solo_a] as *NxManifest
126 let local_b: *NxManifest = b_ptrs[solo_b] as *NxManifest
127 if nx_layout_compatible(local_a.out_layout, local_b.in_layout) != 0 { return 3 }
128
129 // ----- 2. Joint selection -----
130 let out_sel: *i64 = (sys_mmap(16)) as *i64
131 out_sel[0] = -99
132 out_sel[1] = -99
133 let rc: i64 = nx_select_joint_2node(node_a, node_b, probe,
134 NX_TIER_INF_LAPTOP, 1048576, 0,
135 policy, out_sel)
136 if rc != NX_SEL_JOINT_OK { return 4 }
137
138 // Expected: (A_medium_col=1, B_cheap_col=0)
139 if out_sel[0] != 1 { return 5 }
140 if out_sel[1] != 0 { return 6 }
141
142 // ----- 3. Compatibility verified end-to-end -----
143 let picked_a: *NxManifest = a_ptrs[out_sel[0]] as *NxManifest
144 let picked_b: *NxManifest = b_ptrs[out_sel[1]] as *NxManifest
145 if picked_a.out_layout != NX_LAYOUT_COL_MAJOR { return 7 }
146 if picked_b.in_layout != NX_LAYOUT_COL_MAJOR { return 8 }
147 if nx_layout_compatible(picked_a.out_layout, picked_b.in_layout) != 1 { return 9 }
148
149 // ----- 4. Variant ID survives selection -----
150 if picked_a.variant_id != 1002 { return 10 } // A_medium_col
151 if picked_b.variant_id != 2001 { return 11 } // B_cheap_col
152
153 // ----- 5. No-feasible-pair gate -----
154 // Construct a no-overlap case: node A produces ONLY row; node B
155 // consumes ONLY col. No compatible pair exists.
156 let a_only_row: *NxManifest = nx_manifest_new(
157 100, 5001,
158 nx_isa_bit(NX_ISA_RV64),
159 0, 4096,
160 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
161 100, 0, 0, 0)
162 nx_manifest_set_layout(a_only_row, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_ROW_MAJOR)
163
164 let b_only_col: *NxManifest = nx_manifest_new(
165 200, 5002,
166 nx_isa_bit(NX_ISA_RV64),
167 0, 4096,
168 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
169 100, 0, 0, 0)
170 nx_manifest_set_layout(b_only_col, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS)
171
172 let arow_ptrs: *i64 = (sys_mmap(8)) as *i64
173 arow_ptrs[0] = a_only_row as i64
174 let bcol_ptrs: *i64 = (sys_mmap(8)) as *i64
175 bcol_ptrs[0] = b_only_col as i64
176 let arow_node: *NxJointNode = nx_joint_node_new(100, arow_ptrs, 1)
177 let bcol_node: *NxJointNode = nx_joint_node_new(200, bcol_ptrs, 1)
178
179 let out_no: *i64 = (sys_mmap(16)) as *i64
180 let rc_no: i64 = nx_select_joint_2node(arow_node, bcol_node, probe,
181 NX_TIER_INF_LAPTOP, 1048576, 0,
182 policy, out_no)
183 if rc_no != NX_SEL_JOINT_NO_FEASIBLE_PAIR { return 12 }
184 if out_no[0] != -1 { return 13 }
185 if out_no[1] != -1 { return 14 }
186
187 // ----- 6. OPAQUE_PASS wildcard ----------
188 // A variant with OPAQUE_PASS on either side composes with anything.
189 let a_opaque: *NxManifest = nx_manifest_new(
190 100, 6001,
191 nx_isa_bit(NX_ISA_RV64),
192 0, 4096,
193 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
194 50, 0, 0, 0)
195 // a_opaque has default OPAQUE_PASS layouts -- composes universally.
196 let aop_ptrs: *i64 = (sys_mmap(8)) as *i64
197 aop_ptrs[0] = a_opaque as i64
198 let aop_node: *NxJointNode = nx_joint_node_new(100, aop_ptrs, 1)
199 let out_op: *i64 = (sys_mmap(16)) as *i64
200 let rc_op: i64 = nx_select_joint_2node(aop_node, bcol_node, probe,
201 NX_TIER_INF_LAPTOP, 1048576, 0,
202 policy, out_op)
203 if rc_op != NX_SEL_JOINT_OK { return 15 }
204 if out_op[0] != 0 { return 16 }
205 if out_op[1] != 0 { return 17 }
206
207 return 0
208}