function build_samples(f, a, b, opts = {}) {
let { N = 9, max_depth = 6 } = opts;
let dx = (b - a) / N;
let root_intervals = Array.from({ length: N }).map(
(_, i) => new Interval(a + i * dx, a + (i + 1) * dx, 0)
);
root_intervals.forEach((I) => {
I.fa = f(I.a);
I.fb = f(I.b);
});
root_intervals.reverse();
let stack = root_intervals;
let cnt = 0;
let pts = [];
let nodeRight, nodeLeft;
while (stack.length > 0 && cnt++ < 100000) {
let node = stack.pop();
if (test(f, node, opts)) {
let midpoint = node.midpoint;
let new_depth = node.depth + 1;
if (new_depth <= max_depth) {
let a_left = node.a;
let b_left = midpoint;
nodeLeft = new Interval(a_left, b_left, new_depth);
nodeLeft.fa = f(a_left);
nodeLeft.fb = f(b_left);
node.left = nodeLeft;
let a_right = midpoint;
let b_right = node.b;
nodeRight = new Interval(a_right, b_right, new_depth);
nodeRight.fa = f(a_left);
nodeRight.fb = f(b_left);
node.right = nodeRight;
stack.push(nodeRight);
stack.push(nodeLeft);
} else {
pts.push(node.a);
}
} else {
pts.push(node.a);
}
}
pts.push(b);
pts = pts.map((x) => [x, f(x)]);
if (opts.show_roots) {
let function_roots = [];
pts.forEach(function (o, i) {
if (i < pts.length - 1 && Math.sign(o.y) != Math.sign(pts[i + 1].y)) {
function_roots.push((o.x + pts[i + 1].x) / 2);
}
});
pts.function_roots = function_roots;
}
return pts;
}