leapfrog = function(steps, epsilon, log_density, gradient_log_density, p_init, q_init) {
const negative_log_density = (x) => math.multiply(-1, log_density(x));
const negative_gradient_log_density = (x) => math.multiply(-1, gradient_log_density(x));
const K0 = math.sum(q_init.map((d) => Math.pow(d, 2))) / 2;
const P0 = negative_log_density(p_init);
const K = [K0];
const P = [P0];
const p = [p_init];
const q = [q_init];
for(let step = 1; step < steps; step++) {
const next_step = leapfrog_step(p[step - 1], q[step - 1], epsilon, negative_gradient_log_density);
p[step] = next_step.position;
q[step] = next_step.momentum;
K[step] = math.sum(q[step].map((d) => Math.pow(d, 2))) / 2;
P[step] = negative_log_density(p[step]);
}
return ({
K, P,
p,
q,
divergent: P[P.length - 1] > 10000
});
}