Skip to content

Commit

Permalink
Merge pull request #265 from null-a/hmc
Browse files Browse the repository at this point in the history
HMC
  • Loading branch information
stuhlmueller committed Jan 11, 2016
2 parents cb21d4b + 3206ef2 commit 49bf7d0
Show file tree
Hide file tree
Showing 59 changed files with 1,170 additions and 255 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ npm-debug.log
compiled/
docs/_build
docs/_static
docs/_templates
docs/_templates
src/erp.js
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var jslintSettings = {
src: [
'Gruntfile.js',
'src/header.wppl',
'src/**/*.js'
'src/**/!(erp).js'
]
},
test: {
Expand Down
1 change: 1 addition & 0 deletions docs/development/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Installation from GitHub

git clone https://github.com/probmods/webppl.git
cd webppl
./scripts/transformERP
npm install
npm install -g nodeunit grunt-cli

Expand Down
35 changes: 34 additions & 1 deletion docs/development/workflow.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
Workflow
========

Before committing changes, run grunt (which runs tests and linting)::
Committing changes
------------------

Before committing changes, run grunt (which runs `tests`_ and
`linting`_)::

grunt

If grunt doesn’t succeed, the `continuous integration tests`_ will fail
as well.

Modifying erp.ad.js
-------------------

During development, it is necessary to transform ``src/erp.ad.js``
after it has been modified by running::

./scripts/transformERP

This transforms ERP score functions in order to support automatic
differentiation using `ad.js <https://github.com/iffsid/ad.js>`_.

For performance reasons, not all code is transformed. All code
relating to computing scores should therefore be implemented as some
combination of the following:

* Named functions where the name ends with ``Score`` or ``AD``. e.g.
``function gaussianScore() {}``, ``function sumAD() {}``.
* Anonymous functions defined as the ``score`` property of an object
literal. e.g. ``{ score: function() {} }``

Tests
-----

To only run the tests, do::

npm test
Expand All @@ -23,6 +50,9 @@ nodeunit can also run individual tests or test groups. For example::

See the `nodeunit documentation`_ for details.

Linting
-------

To only run the linter::

grunt gjslint
Expand All @@ -36,6 +66,9 @@ many of them automatically using::

grunt fixjsstyle

Compiling for browser
---------------------

To compile webppl for use in browser, run::

npm install -g browserify uglifyjs
Expand Down
54 changes: 45 additions & 9 deletions docs/inference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,7 @@ MCMC

.. describe:: kernel

The transition kernel to use for inference. The following
kernels are available:

========= ============================================
Option Description
========= ============================================
``'MH'`` Single site Metropolis-Hastings [wingate11]_
========= ============================================
The transition kernel to use for inference. See `Kernels`_.

Default: ``'MH'``

Expand Down Expand Up @@ -138,6 +131,46 @@ MCMC

MCMC(model, { samples: 1000, lag: 100, burn: 5 });

Kernels
^^^^^^^

The following kernels are available:

.. describe:: MH

Implements single site Metropolis-Hastings. [wingate11]_

Example usage::

MCMC(model, { kernel: 'MH' });

.. describe:: HMC

Implements Hamiltonian Monte Carlo. [neal11]_

As the HMC algorithm is only applicable to continuous variables,
``HMC`` is a cycle kernel which includes a MH step for discrete
variables.

The following options are supported:

.. describe:: steps

The number of steps to take per-iteration.

Default: ``5``

.. describe:: stepSize

The size of each step.

Default: ``0.1``

Example usage::

MCMC(model, { kernel: 'HMC' });
MCMC(model, { kernel: { HMC: { steps: 10, stepSize: 1 }}});

Incremental MH
--------------

Expand Down Expand Up @@ -224,7 +257,7 @@ SMC

.. describe:: rejuvKernel

The :js:func:`MCMC` kernel to use for rejuvenation.
The MCMC kernel to use for rejuvenation. See `Kernels`_.

Default: ``'MH'``

Expand All @@ -240,6 +273,9 @@ SMC
compilation." International Conference on Artificial
Intelligence and Statistics. 2011.
.. [neal11] Radford M. Neal, "MCMC using Hamiltonian dynamics."
Handbook of Markov Chain Monte Carlo 2 (2011).
.. [ritchie15] Daniel Ritchie, Andreas Stuhlmüller, and Noah D.
Goodman. "C3: Lightweight Incrementalized MCMC for
Probabilistic Programs using Continuations and Callsite
Expand Down
2 changes: 1 addition & 1 deletion examples/ldaCollapsed.wppl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var makeDirichletDiscrete = function(pseudocounts) {
};
var ddObserve = function(val) {
var pc = globalStore[ddname]; // get current sufficient stats
factor(discreteERP.score([util.normalizeArray(pc)], val));
factor(discreteERP.score([normalize(pc)], val));
// score based on predictive distribution (normalize counts)
globalStore[ddname] = addCount(pc, val); // update sufficient stats
};
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"test": "tests"
},
"dependencies": {
"ad.js": "^1.4.1",
"amdefine": "^1.0.0",
"ast-types": "^0.8.13",
"escodegen": "^1.7.0",
Expand Down Expand Up @@ -44,7 +45,8 @@
"through2": "^2.0.0"
},
"scripts": {
"test": "nodeunit tests/test-*.js"
"test": "nodeunit tests/test-*.js",
"postinstall": "./scripts/transformERP"
},
"bugs": {
"url": "https://github.com/probmods/webppl/issues"
Expand Down
13 changes: 13 additions & 0 deletions scripts/transformERP
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env node

'use strict';

var fs = require('fs');
var path = require('path');
var adscorers = require('../src/transforms/adscorers').adscorers;

var inFile = path.join(__dirname, '../src/erp.ad.js');
var outFile = path.join(__dirname, '../src/erp.js');

var code = fs.readFileSync(inFile, 'utf8');
fs.writeFileSync(outFile, adscorers(code));
8 changes: 8 additions & 0 deletions src/ad.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var _ = require('underscore');
var ad = require('ad.js')({ mode: 'r', noHigher: true });

ad.isTape = function(obj) {
return _.has(obj, 'primal');
};

module.exports = ad;
14 changes: 14 additions & 0 deletions src/aggregation.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
'use strict';

var _ = require('underscore');
var erp = require('./erp');
var util = require('./util');
var ad = require('./ad');

var Histogram = function() {
this.hist = {};
};

Histogram.prototype.add = function(value) {
var value = untapify(value);
var k = util.serialize(value);
if (this.hist[k] === undefined) {
this.hist[k] = { prob: 0, val: value };
Expand All @@ -26,6 +29,7 @@ var MAP = function(retainSamples) {
};

MAP.prototype.add = function(value, score) {
var value = untapify(value);
if (this.retainSamples) {
this.samples.push(value);
}
Expand All @@ -45,6 +49,16 @@ MAP.prototype.toERP = function() {
return erp;
};

// Recursively untapify objects. ad.js already does this for arrays,
// here we extend that to other objects.
function untapify(x) {
if (_.isObject(x) && !_.isArray(x) && !ad.isTape(x)) {
return _.mapObject(x, untapify);
} else {
return ad.untapify(x);
}
}

module.exports = {
Histogram: Histogram,
MAP: MAP
Expand Down

0 comments on commit 49bf7d0

Please sign in to comment.