DIVERSE PARTICLE MAX-PRODUCT (D-PMP)
====================================

This implementation of D-PMP is provided as-is, without warranty.  You
are free to modify and distribute this code provided that you do so
under the restrictions outlined in LICENSE (GPLv2).  Any publications
using this code should cite the following:

Pacheco, Jason and Sudderth, Erik. "Proteins, Particles, and
  Pseudo-Max-Marginals: A Submodular Approach." Proceedings of the
  32nd International Conference on Machine Learning (ICML). 2015 

For questions please contact:
Jason Pacheco, pachecoj@cs.brown.edu


OVERVIEW
========

For inference in continuous MRFs we provide implementations of D-PMP,
Top-N PMP (T-PMP), and Greedy PMP (G-PMP).  See the relevant sections
below for interfacing with each.

This library extends Mark Schmidt's UGM library for inference on
pairwise MRFs and adopts a similar design.  We provide Matlab and mex
implementations of all inference and a copy of UGM is included with
several modifications.

This library also implements Max-Sum inference as well as its tree
reweighted variant (e.g. in log-domain).  For numerical stability we
always maintain model potentials, messages, and max-marginals in
log-domain.  This is true for all of our code under src/ but existing
UGM code in lib/UGM typically maintains quantities in
probability-domain; keep this in mind when interfacing directly with
both libraries.


SETUP
=====

1) Unpack the archive and place the liv-dpmp/ directory in the
appropriate location.

2) Compiling Mex code is not required, but is recommended as we
observe 10-20x speed improvements.  To do this open Matlab and run the
following:

>> cd liv-dpmp/lib/UGM/
>> mexAll
>> cd ../../src
>> mexAll

3) The configuration assumes MATLAB is launched from the liv-dpmp/src
directory, which will run startup.m and load all relevant paths.  If
you are using this library for inference on an external model you will
need to modify the path accordingly.

EXAMPLE CODE
============

An example nonlinear time series model is located in
liv-dpmp/src/examples/smoothing_intro, see the README.md file in that
directory for instructions.


PARTICLE MAX-PRODUCT
====================

There are three variants of PMP algorithms provided, Diverse PMP
(D-PMP), Top-N PMP (T-PMP) and Greedy PMP (G-PMP).  We also provide
efficient and numerically stable implementations of loopy max-product
BP and reweighted max-product BP.

The interface is similar for each PMP method.  The user must provide
function handles which evaluate model log-potentials over a set of
particles, as well as function handles for proposal distributions.

The driver function for D-PMP and T-PMP is DPMP_Infer().  The methods
differ only in particle selection through the "selectType" parameter.
The driver function for G-PMP is DPMP_Infer_GPMP(); the nomenclature
is confusing but it has the same call signature:


DPMP_Infer( ...
  x, ...            % Particles: NDIM x NPARTICLES x NNODES
  edgeStruct, ...   % MRF structure from DPMP_makeEdgeStructCont
  funHandles, ...   % Function callbacks for proposals / eval / display
  opt, ...          % PMP Options from DPMP_setOptions
  sched, ...        % Message passing schedule (e.g. from DPMP_makeFwdBwdSched)
  rho ...           % RMP edge appearance probs.  Set to [] if using LBP.
  )

The following options need to be set for PMP:

function options = DPMP_setOptions( ...
  verbose,  ...     % Level of verbosity (0,1)
  display_iter, ... % # iterations to call display callback
  selectType, ...   % Particle Selection: 'tpmp', 'gpmp', 'dpmpsum', 'dpmpmax'
  msgPass, ...      % Message Passing: "lbp', 'trw'
  nParticles, ...   % Total particle budget by node (scalar or vector)
  maxIters, ...     % Number PMP iterations
  maxItersLBP, ...  % Maximum MP/RMP iterations (default 100)
  sampleProb, ...   % Probability for each proposal (probability vector)
  Temp, ...         % "Annealing" temperature for particle selection
  stepsize, ...     % MP/RMP stepsize
  convTolBP, ...    % MP/RMP message convergence tolerance (default 1e-4)
  useMex, ...       % Use Mex code?  (0,1)
  doTieRes ...      % Resolve ties with J-Tree? (0,1)
  );

The funHandles parameter contains function callbacks for the proposal
distributions and model evaluation.  The model evaluation accepts
particles and the MRF structure, and returns log-potentials for nodes
and edges:

funHandles.funEvalModel = ...
  @(x,edgeStruct) eval_my_model(x, edgeStruct);

The function eval_my_model returns:

 [ nodePot ...    %  NNODES x NPARTICLES array of log-potentails
   edgeStruct ]   % NPARTICLES x NPARTICLES x NEDGES array

You may specify as many proposal distribution functions as you like,
but at minimum you should use at least a random walk proposal. It is
unlikely inference will be adequate with a random walk proposal alone.
Each proposal should set a name in the cell array:

funHandles.propType{1} = 'Random Walk';

and the callback function should accept at least the particles, number
of particles to add for each node, and MRF structure:

funHandles.proposal{1} = @(xs,nStatesAdd,eS) ...
    randwalk(xs, nStatesAdd, eS, sig_randwalk);

You can supply further static arguments, such as "sig_randwalk"
above.  Proposal functions should return just the new particle array.
The parameter "sampleProb" is a probability vector (>0, sum to 1) the
same length as the number of proposals, and determines the probability
of each proposal.  

You may optionally set funHandles.displayFun to a display callback
function, and set the "display_iter" option accordingly.  This is
useful for debugging.

The annealing temperature parameter "Temp" is used only for D-PMP
particle selection, to control the amount of diversity.  "Temp" is a
temporary rescaling of the relative mode heights in the model (e.g.
probability potentials are raised to the power "Temp").  This
compensates for the fact that model learning focuses on the MAP
solution, and models rarely capture relative probabilities well.  If
particle selection has too little diversity, then increase Temp>1,
otherwise decrease it.  


Max-Product (MP) and Reweighted Max-Product (RMP):
==================================================
The MP and RMP implementations provided use a similar call structure
to their counterparts in UGM, except that all quantities remain in
log-domain.  The main driver for RMP is:

DPMP_Infer_TRW(...
  nodePot, ...    % Node (log)-potential: NNODES x NSTATES
  edgePot, ...    % Edge (log)-potential: NSTATES x NSTATES x NEDGES
  edgeStruct, ... % MRF structure from UGM_makeEdgeStruct
  stepsize, ...   % RMP stepsize
  sched, ...      % Message update schedule (e.g. DPMP_makeFwdBwdSched)
  mu ...          % Edge appearance probabilities
  )

Note we use the "TRW" acronym to be consistent with UGM.  The Main
driver for MP is DPMP_Infer_LBP() and has a similar call structure.
Both methods require the following options and are similar to the PMP
counterparts listed:

lbpOpt.useMex = methodOpt.useMex;
lbpOpt.maxIter = maxItersLBP;
lbpOpt.convTolBP = convTolBP;
lbpOpt.stepsize = stepsize;
lbpOpt.nGrid = nParticles;
lbpOpt.verbose = methodOpt.verbose;
lbpOpt.doTieRes = doTieRes;


HELPER FUNCTIONS:
=================

Several helper/utility functions are provide to make life easier.
DPMP_setOptions() is one.  We also provide a method for constructing
the MRF structure, consistent with a similar function in UGM:

DPMP_makeEdgeStructCont(...
  adj, ...      % Adjacency matrix NNODES x NNODES (binary)
  nStates, ...  % Number states (scalar or NNODES vector)
  nDims, ...    % Number dimensions (scalar or NNODES vector)
  useMex, ...   % Use Mex code? (binary)
  maxIter, ...  % Maximum inference iterations (default 100)
  convTol ...   % MP/RMP Convergence tolerance (default 1e-4)
  )

For MP/RMP the user must specify a message update schedule as an (2*NEDGES)x1
vector.  Each element is a directed edge number, where numbers in (1,
NEDGES) are "forward" messages and (NEDGES+1, 2*NEDGES) are "backward"
messages.  We provide a default forward/backward schedule:

DPMP_makeFwdBwdSched(edgeStruct)

After inference you will want to construct the MAP label and get MAP
probability.  

[mapState, nTies] = DPMP_getMAPLabel(...
  doTieRes, ...   % Resolve ties with J-Tree? (binary: can be slow)
  nodeBel, ...    % Node (log)-beliefs
  nodePot, ...    % Node (log)-potentials
  edgePot, ...    % Edge (log)-potentials
  edgeStruct ...  % MRF structure
  )

You can get the probability of *any* label using:

[logP, logLike, logPrior] = DPMP_getLabelProb( ...
  state, ...      % NNODES x 1 label vector
  nodePot, ...    % Node log-potentials
  edgePot, ...    % Edge log-potentials
  edgeStruct ...  % MRF structure
  )

For PMP methods it's useful to get the (continuous) particles
corresponding to a label:

x = DPMP_getLabelParticles( ...
  state, ...  % NNODES x 1 label vector
  xAll ...    % All particles ( NDIM x NPARTICLES x NNODES )
  )

The returned value will be an NDIM x 1 x NNODES array.


CONTACT:
========
Jason Pacheco
pachecoj@cs.brown.edu

