code wiki / (root) / nx_calc_series.nx

nx_calc_series.nx source

↩ module page · 83 lines · 3179 B

1// nx_calc_series.nx -- Taylor / Maclaurin series expansion engine. 2// 3// Per the comparison commit's named LOSE_BIG vs Mathematica: 4// "ship symbolic Integrate + Series + Solve". Integrate shipped 5// last commit; this commit ships Series. 6// 7// Taylor series of f(x) about center 0 up to degree N: 8// f(x) ~ f(0) + f'(0)*x + f''(0)*x^2/2! + ... + f^(n)(0) * x^n / n! 9// 10// We build the symbolic series as a Term using nx_calc_deriv n times 11// to get each f^(k). At evaluation time the user can plug numeric 12// values; this engine returns the SYMBOLIC polynomial form. 13// 14// "About center 0" = Maclaurin. General Taylor about center c is the 15// same algorithm with substitution (x - c) for x; named follow-up. 16 17// nx_safety_envelope: 18// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 19// sil_target: SIL1 20// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 21// verdict: NOT_YET_EVALUATED 22 23import "nx_calc.nx" 24 25// nx_factorial(n) -- precompute small factorials for series coefficients. 26func nx_factorial(n: nx_int) -> nx_int { 27 var r: nx_int = 1 28 var i: nx_int = 1 29 while i <= n { 30 r = r * i 31 i = i + 1 32 } 33 return r 34} 35 36// Substitute x -> 0 in t. We don't have a general substitution 37// engine yet, so use a structural pass that replaces every VAR with 38// CONST(0). Returns a new Term. 39func nx_calc_subst_zero(t: *Term, var_id: nx_int) -> *Term { 40 if t.kind == NX_TERM_VAR { 41 if t.sym == var_id { return nx_calc_const_int(0) } 42 return t 43 } 44 if t.kind == NX_TERM_CONST { return t } 45 if t.sym == NX_CALC_SYM_CONST { return t } 46 if t.n_args == 1 { 47 let inner: *Term = nx_term_arg(t, 0) 48 let new_inner: *Term = nx_calc_subst_zero(inner, var_id) 49 return nx_calc_un(t.sym, new_inner) 50 } 51 if t.n_args == 2 { 52 let a: *Term = nx_term_arg(t, 0) 53 let b: *Term = nx_term_arg(t, 1) 54 let new_a: *Term = nx_calc_subst_zero(a, var_id) 55 let new_b: *Term = nx_calc_subst_zero(b, var_id) 56 return nx_calc_bin(t.sym, new_a, new_b) 57 } 58 return t 59} 60 61// Maclaurin series: build f(0) + f'(0)*x + f''(0)*x^2/2! + ... up to 62// degree N. Returns a Term that is the polynomial sum. Each k-th 63// coefficient = f^(k)(0) / k! built symbolically. 64func nx_calc_maclaurin(f: *Term, var_id: nx_int, max_degree: nx_int) -> *Term { 65 let x: *Term = nx_term_var(var_id) 66 var sum: *Term = nx_calc_subst_zero(f, var_id) // c0 = f(0) 67 var current: *Term = f 68 var k: nx_int = 1 69 while k <= max_degree { 70 // current = derivative_of_previous 71 current = nx_calc_deriv(current, var_id) 72 let coef_at_zero: *Term = nx_calc_subst_zero(current, var_id) 73 let kfact: nx_int = nx_factorial(k) 74 let coef_term: *Term = nx_calc_bin(NX_CALC_SYM_DIV, 75 coef_at_zero, 76 nx_calc_const_int(kfact)) 77 let xk: *Term = nx_calc_pow(x, nx_calc_const_int(k)) 78 let term_k: *Term = nx_calc_mul(coef_term, xk) 79 sum = nx_calc_add(sum, term_k) 80 k = k + 1 81 } 82 return sum 83}