code wiki / (root) / nx_symmetry_group_test.nx

nx_symmetry_group_test.nx source

↩ module page · 107 lines · 4314 B

1// nx_symmetry_group_test.nx -- smoke for multi-axis symmetry. 2 3import "nx_syscalls.nx" 4import "nx_tier.nx" 5import "nx_image.nx" 6import "nx_symmetry_group.nx" 7 8func main() -> nx_int { 9 // === Test 1: uniform image -- all axes trivially maximal === 10 let img_uni: *Image = nx_image_alloc(16, 16, 1) 11 var y1: nx_int = 0 12 while y1 < 16 { 13 var x1: nx_int = 0 14 while x1 < 16 { 15 nx_image_set(img_uni, x1, y1, 0, 128) 16 x1 = x1 + 1 17 } 18 y1 = y1 + 1 19 } 20 let r_uni: *SymmetryReport = (sys_mmap(12 * NX_SIZEOF_NX_INT)) as *SymmetryReport 21 nx_symmetry_compute(img_uni, r_uni) 22 // Uniform image has all axes trivially symmetric (NX_SYM_Q). 23 if r_uni.h_bilateral_q10 < 900 { return 1 } 24 if r_uni.v_bilateral_q10 < 900 { return 2 } 25 if r_uni.diagonal_q10 < 900 { return 3 } 26 if r_uni.rot_180_q10 < 900 { return 4 } 27 // At least 4 axes should be present at threshold for uniform image. 28 if r_uni.n_axes_present < 4 { return 5 } 29 30 // === Test 2: vertical-bands -> high V symmetry, low H symmetry === 31 // Bands change column-to-column but stay constant top-to-bottom. 32 let img_vbands: *Image = nx_image_alloc(16, 16, 1) 33 var y2: nx_int = 0 34 while y2 < 16 { 35 var x2: nx_int = 0 36 while x2 < 16 { 37 // Mirror-symmetric across vertical axis (x = 7.5). 38 var v: nx_int = x2 39 if v >= 8 { v = 15 - v } 40 nx_image_set(img_vbands, x2, y2, 0, v * 16) 41 x2 = x2 + 1 42 } 43 y2 = y2 + 1 44 } 45 let r_vb: *SymmetryReport = (sys_mmap(12 * NX_SIZEOF_NX_INT)) as *SymmetryReport 46 nx_symmetry_compute(img_vbands, r_vb) 47 // Mirror-symmetric in x = high H symmetry; bands don't have V mirror 48 // structure (column 0 has v=0, column 15 has v=0 -> H mirror; but 49 // column 0 row 0 vs row 15 are same v=0 -> V mirror IS high too). 50 // Use the relative ordering: H symmetry should be very high. 51 if r_vb.h_bilateral_q10 < 800 { return 10 } 52 53 // === Test 3: diagonal symmetric pattern === 54 // img(x, y) = img(y, x) by construction (use x*y). 55 let img_diag: *Image = nx_image_alloc(16, 16, 1) 56 var y3: nx_int = 0 57 while y3 < 16 { 58 var x3: nx_int = 0 59 while x3 < 16 { 60 nx_image_set(img_diag, x3, y3, 0, (x3 * y3)) 61 x3 = x3 + 1 62 } 63 y3 = y3 + 1 64 } 65 let r_diag: *SymmetryReport = (sys_mmap(12 * NX_SIZEOF_NX_INT)) as *SymmetryReport 66 nx_symmetry_compute(img_diag, r_diag) 67 // x*y is symmetric across the diagonal -> high diagonal_q10. 68 if r_diag.diagonal_q10 < 900 { return 20 } 69 70 // === Test 4: 180-rotation pattern -- img(x,y) = img(W-1-x, H-1-y) === 71 // Use a checkerboard which has 180 rotation under (x+y) parity. 72 let img_check: *Image = nx_image_alloc(16, 16, 1) 73 var y4: nx_int = 0 74 while y4 < 16 { 75 var x4: nx_int = 0 76 while x4 < 16 { 77 var v: nx_int = 0 78 if (x4 + y4) - ((x4 + y4) / 2) * 2 == 1 { v = 255 } 79 nx_image_set(img_check, x4, y4, 0, v) 80 x4 = x4 + 1 81 } 82 y4 = y4 + 1 83 } 84 let r_chk: *SymmetryReport = (sys_mmap(12 * NX_SIZEOF_NX_INT)) as *SymmetryReport 85 nx_symmetry_compute(img_check, r_chk) 86 // Even-sized checkerboard at corner (0,0)=0 vs corner (15,15) where 87 // (15+15)=30 even -> 0. So both corners are 0 -> 180-rot symmetric. 88 if r_chk.rot_180_q10 < 800 { return 30 } 89 // Also has translational symmetry at period 2. 90 if r_chk.translational_q10 < 800 { return 31 } 91 if r_chk.translation_period != 2 { return 32 } 92 93 // === Test 5: report field ranges === 94 if r_chk.composite_q10 < 0 { return 40 } 95 if r_chk.composite_q10 > 1024 { return 41 } 96 if r_chk.n_axes_present < 0 { return 42 } 97 if r_chk.n_axes_present > 7 { return 43 } 98 99 // === Test 6: dominant_kind sealed-enum is in valid range === 100 if nx_sym_kind_is_valid(r_chk.dominant_kind) != 1 { return 50 } 101 if nx_sym_kind_is_valid(NX_SYM_NONE) != 1 { return 51 } 102 if nx_sym_kind_is_valid(NX_SYM_TRANSLATIONAL) != 1 { return 52 } 103 if nx_sym_kind_is_valid(99) != 0 { return 53 } 104 if nx_sym_kind_is_valid(0 - 1) != 0 { return 54 } 105 106 return 0 107}