pub fn gauss_hermite(n: usize) -> (Vec<f64>, Vec<f64>) {
assert!(n >= 1, "gauss_hermite requires n >= 1");
let mut d = vec![0.0_f64; n];
let mut e = vec![0.0_f64; n];
for i in 1..n {
e[i - 1] = (i as f64).sqrt();
}
let mut z = vec![0.0_f64; n];
z[0] = 1.0;
for l in 0..n {
let mut iter = 0usize;
loop {
let mut m = l;
while m < n - 1 {
let dd = d[m].abs() + d[m + 1].abs();
if e[m].abs() + dd == dd {
break;
}
m += 1;
}
if m == l {
break; }
iter += 1;
assert!(iter <= 50, "gauss_hermite: QL failed to converge");
let mut g = (d[l + 1] - d[l]) / (2.0 * e[l]);
let mut r = g.hypot(1.0);
g = d[m] - d[l] + e[l] / (g + r.copysign(g));
let mut s = 1.0_f64;
let mut c = 1.0_f64;
let mut p = 0.0_f64;
let mut cancelled = false;
for i in (l..m).rev() {
let f = s * e[i];
let b = c * e[i];
r = f.hypot(g);
e[i + 1] = r;
if r == 0.0 {
d[i + 1] -= p;
e[m] = 0.0;
cancelled = true;
break;
}
s = f / r;
c = g / r;
g = d[i + 1] - p;
r = (d[i] - g) * s + 2.0 * c * b;
p = s * r;
d[i + 1] = g + p;
g = c * r - b;
let zf = z[i + 1];
z[i + 1] = s * z[i] + c * zf;
z[i] = c * z[i] - s * zf;
}
if cancelled {
continue;
}
d[l] -= p;
e[l] = g;
e[m] = 0.0;
}
}
let mut idx: Vec<usize> = (0..n).collect();
idx.sort_by(|&a, &b| d[a].partial_cmp(&d[b]).unwrap());
let nodes = idx.iter().map(|&i| d[i]).collect();
let weights = idx.iter().map(|&i| z[i] * z[i]).collect();
(nodes, weights)
}