code wiki / (root) / nx_build_plan_test.nx

nx_build_plan_test.nx source

↩ module page · 118 lines · 5731 B

1// nx_build_plan_test.nx -- verify multi-process schedule solver. 2// 3// Closed-form invariants: 4// (a) plan_new sane: n=0, capacity correct, printer_free zeroed 5// (b) add_part returns sequential ids; bad inputs return negative 6// (c) set_dep updates child's bitmap; self-dep rejected 7// (d) Independent-parts case (no deps, distinct processes): 8// all start at T=0 in parallel, total = max(each) 9// (e) Sequential dep chain (A->B->C): B starts at A.end, C at B.end 10// (f) Same-process serialization: 2 FDM parts share 1 printer, 11// second starts at first.end 12// (g) Cross-process Christus demo: FDM PLA body (240m) + DIW cement 13// (60m+1440m cure) + FDM metal (30m+2880m sinter) all start at 14// T=0 because distinct processes do not contend; total = 15// max(240, 1500, 2910) = 2910 min ≈ 48.5 hours 16// (h) Cycle detection: A<->B returns NX_BUILD_ERR_CYCLE 17// 18// expect_exit: 0 19// license_tier: ORIGINAL 20 21import "nx_syscalls.nx" 22import "nx_print_process.nx" 23import "nx_build_plan.nx" 24 25func main() -> i64 { 26 // --- (a) plan_new sane defaults --- 27 let plan: *NxBuildPlan = nx_build_plan_new(8) 28 if (plan as i64) == 0 { return 5 } 29 if plan.n_parts != 0 { return 10 } 30 if plan.capacity != 8 { return 11 } 31 if plan.printer_free[NX_PROCESS_FDM_POLYMER] != 0 { return 12 } 32 if plan.printer_free[NX_PROCESS_DIW_CEMENT] != 0 { return 13 } 33 34 // --- (b) add_part returns sequential ids --- 35 let id0: i64 = nx_build_plan_add_part(plan, NX_PROCESS_FDM_POLYMER, 60, 0) 36 if id0 != 0 { return 20 } 37 let id1: i64 = nx_build_plan_add_part(plan, NX_PROCESS_DIW_CEMENT, 30, 1440) 38 if id1 != 1 { return 21 } 39 if plan.n_parts != 2 { return 22 } 40 41 // Bad input: invalid process class. 42 let bad: i64 = nx_build_plan_add_part(plan, 999, 60, 0) 43 if bad >= 0 { return 23 } 44 45 // --- (c) set_dep updates child's bitmap; self-dep rejected --- 46 if nx_build_part_set_dep(plan, 1, 0) != 0 { return 30 } 47 let p1: *NxBuildPart = (((plan.parts as i64) + 1 * NX_BUILD_PART_BYTES)) as *NxBuildPart 48 if p1.dep_bitmap != 1 { return 31 } // bit 0 = depends on part 0 49 if nx_build_part_set_dep(plan, 0, 0) >= 0 { return 32 } // self-dep error 50 // Reset dep for next test: 51 p1.dep_bitmap = 0 52 53 // --- (d) Independent parts, distinct processes --- 54 let total_d: i64 = nx_build_plan_solve(plan) 55 let p0: *NxBuildPart = plan.parts 56 if p0.start_time_min != 0 { return 40 } 57 if p1.start_time_min != 0 { return 41 } 58 if p0.end_time_min != 60 { return 42 } // 60 + 0 cure 59 if p1.end_time_min != 1470 { return 43 } // 30 + 1440 cure 60 if total_d != 1470 { return 44 } 61 62 // --- (e) Sequential dep chain A -> B -> C --- 63 let plan2: *NxBuildPlan = nx_build_plan_new(8) 64 let a: i64 = nx_build_plan_add_part(plan2, NX_PROCESS_FDM_POLYMER, 100, 0) 65 let b: i64 = nx_build_plan_add_part(plan2, NX_PROCESS_FDM_POLYMER, 50, 0) 66 let c: i64 = nx_build_plan_add_part(plan2, NX_PROCESS_FDM_POLYMER, 20, 0) 67 nx_build_part_set_dep(plan2, b, a) 68 nx_build_part_set_dep(plan2, c, b) 69 let t_e: i64 = nx_build_plan_solve(plan2) 70 let pa: *NxBuildPart = plan2.parts 71 let pb: *NxBuildPart = (((plan2.parts as i64) + 1 * NX_BUILD_PART_BYTES)) as *NxBuildPart 72 let pc: *NxBuildPart = (((plan2.parts as i64) + 2 * NX_BUILD_PART_BYTES)) as *NxBuildPart 73 if pa.start_time_min != 0 { return 50 } 74 if pb.start_time_min != 100 { return 51 } 75 if pc.start_time_min != 150 { return 52 } 76 if t_e != 170 { return 53 } 77 78 // --- (f) Same-process serialization: 2 FDM parts share 1 printer --- 79 let plan3: *NxBuildPlan = nx_build_plan_new(8) 80 nx_build_plan_add_part(plan3, NX_PROCESS_FDM_POLYMER, 80, 0) 81 nx_build_plan_add_part(plan3, NX_PROCESS_FDM_POLYMER, 40, 0) 82 nx_build_plan_solve(plan3) 83 let q0: *NxBuildPart = plan3.parts 84 let q1: *NxBuildPart = (((plan3.parts as i64) + 1 * NX_BUILD_PART_BYTES)) as *NxBuildPart 85 if q0.start_time_min != 0 { return 60 } 86 if q1.start_time_min != 80 { return 61 } // serialized on same printer 87 88 // --- (g) Christus 3-process demo --- 89 let chris: *NxBuildPlan = nx_build_plan_new(8) 90 let body: i64 = nx_build_plan_add_part(chris, NX_PROCESS_FDM_POLYMER, 240, 0) 91 let base: i64 = nx_build_plan_add_part(chris, NX_PROCESS_DIW_CEMENT, 60, 1440) 92 let crown: i64 = nx_build_plan_add_part(chris, NX_PROCESS_FDM_METAL, 30, 2880) 93 let total_chris: i64 = nx_build_plan_solve(chris) 94 let pb_chris: *NxBuildPart = chris.parts 95 let pbase_chris: *NxBuildPart = (((chris.parts as i64) + 1 * NX_BUILD_PART_BYTES)) as *NxBuildPart 96 let pcrown: *NxBuildPart = (((chris.parts as i64) + 2 * NX_BUILD_PART_BYTES)) as *NxBuildPart 97 if pb_chris.start_time_min != 0 { return 70 } 98 if pbase_chris.start_time_min != 0 { return 71 } 99 if pcrown.start_time_min != 0 { return 72 } 100 if pb_chris.end_time_min != 240 { return 73 } 101 if pbase_chris.end_time_min != 1500 { return 74 } // 60 + 1440 102 if pcrown.end_time_min != 2910 { return 75 } // 30 + 2880 103 if total_chris != 2910 { return 76 } 104 // 48.5 hours -- robot pickup at T+2910 min (48h 30min) 105 106 // --- (h) Cycle detection --- 107 let plan_cyc: *NxBuildPlan = nx_build_plan_new(4) 108 nx_build_plan_add_part(plan_cyc, NX_PROCESS_FDM_POLYMER, 10, 0) 109 nx_build_plan_add_part(plan_cyc, NX_PROCESS_FDM_POLYMER, 10, 0) 110 nx_build_part_set_dep(plan_cyc, 0, 1) 111 nx_build_part_set_dep(plan_cyc, 1, 0) 112 let cyc_result: i64 = nx_build_plan_solve(plan_cyc) 113 if cyc_result >= 0 { return 80 } // negative = error 114 let expected_cyc: i64 = 0 - NX_BUILD_ERR_CYCLE 115 if cyc_result != expected_cyc { return 81 } 116 117 return 0 118}