@decidables/discountable-elements
Version:
discountable-elements: Web Components for visualizing Hyperbolic Temporal Discounting
72 lines (57 loc) • 1.97 kB
JavaScript
/* eslint no-restricted-globals: ["off", "self"] */
// Needed for d3 in WebWorker!
import 'regenerator-runtime/runtime';
import * as BayesDistributions from 'bayes.js/distributions';
import * as BayesMcmc from 'bayes.js/mcmc';
import * as d3 from 'd3';
import HTDMath from '@decidables/discountable-math';
self.onmessage = (event) => {
const params = {
k: {type: 'real', lower: HTDMath.k.MIN, upper: HTDMath.k.MAX},
luce: {type: 'real', lower: 0, upper: 100},
};
const logPost = (state, data) => {
let lp = 0;
// Priors
const kMean = 2;
const kShape = 3;
lp += BayesDistributions.gamma(
state.k,
kShape,
kShape / kMean,
);
// lp += BayesDistributions.unif(state.k, 0, 100);
const luceMean = 2;
const luceShape = 3;
lp += BayesDistributions.gamma(
state.luce,
luceShape,
luceShape / luceMean,
);
// lp += BayesDistributions.unif(state.luce, 0, 100);
// Likelihood
data.forEach((choice) => {
// Values
const vs = HTDMath.adk2v(choice.as, choice.ds, state.k);
const vl = HTDMath.adk2v(choice.al, choice.dl, state.k);
// Choice of sooner or later is sampled from a Bernoulli distribution
// Luce choice rule is used to compute probability of waiting! (0 = sooner, 1 = later)
const binval = 1 / (1 + Math.exp(state.luce * (vs - vl)));
// Actual response
const response = (choice.response === 'first') ? 0 : 1;
lp += BayesDistributions.bern(response, binval);
});
return lp;
};
// Initializing the sampler
const sampler = new BayesMcmc.AmwgSampler(params, logPost, event.data);
// Burning some samples to the MCMC gods and sampling 5000 draws
sampler.burn(1000);
const samples = sampler.sample(5000);
// Extract summary stats
const results = {
k: d3.median(samples.k),
luce: d3.median(samples.luce),
};
self.postMessage({results: results, samples: samples});
};