Understanding the Infer operator

21 views
Skip to first unread message

Isaac Davis

unread,
Apr 20, 2020, 6:14:09 PM4/20/20
to webppl-dev
Hi folks. 

I appreciate all the help I've received, and am very thankful to those who have offered advice. I am a PhD student doing my dissertation on Social Cognition/Theory of Mind, and I am currently working on coding up a panel of simulations in WebPPL. I'm somewhat new to the language and I'm still a little uncertain about the Infer operator and how it works.

Below, I've posted two very simple example programs that (as far as I can tell) should perform the same computations in the same order, but only one of them works. I think the issue has something to do with how Infer is implemented, but I'm not certain.

//------------------------------------------
//simple agent model (version 0): 
//------------------------------------------


//This is an extremely simple model of a rational agent, with preferences [p1, p2, p3] over three "goal" objects [0, 1, 2]. The program "goal_sampler(prefs)" returns a sample from a categorical //distribution over [0,1,2] with weights given by prefs. 

var goal_sampler=function(prefs){
  return categorical({ps: prefs, vs: [0,1,2]})
}

//The program "action_sampler(goal, err)" outputs either a) the correct action for obtaining "goal" with probability 1-err, or a randomly chosen incorrect action with probability err

var action_sampler=function(goal, err){
  var moves=['L', 'M', 'R'];
  if(flip(1-err)){
    return moves[goal]
  }
  else{
    return uniformDraw(remove(moves[goal], moves))
  }
}

//The program "agent_distribution_v0" creates a distribution object over actions for an agent with preferences "prefs" and error rate "err"
var agent_distribution_v0=function(prefs,err){return
Infer(function(){
  var goal=goal_sampler(prefs);
  return action_sampler(goal,err)
})}

goal_sample(prefs) and action_sampler(goal, err) both work correctly, but when I call "sample(agent_distribution_v0)", I get the error message sample() expected a distribution but received "undefined".

Now here is v1:

//------------------------------------------
//simple agent model (version 1): 
//------------------------------------------

//The only difference between v0 and v1 is that the component functions for goals returns a distribution object, rather than a sample from that distribution (and similarly for actions)

var goal_prior=function(prefs){
  return Categorical({ps: prefs, vs: [0,1,2]})
}

var action_distribution=function(goal, err){
  return Infer(function(){
    var moves=['L', 'M', 'R'];
    if(flip(1-err)){
      return moves[goal]
    }
    else{
      return uniformDraw(remove(moves[goal], moves))
    }
  })}

//The "agent_distribution_v1" function then draws a sample from the distribution object returned by goal_prior(prefs), and similarly for action_distribution. Whereas v0 just calls //goal_sampler(prefs), which returns a sampled value

var agent_distribution_v1=function(prefs,err){
  return Infer(function(){
    var goal=sample(goal_prior(prefs));
    return sample(action_distribution(goal, err))
  })
}


When I try "agent_distribution_v1(prefs, err)", I now get an appropriate histogram (or an appropriate sample from sample(agent_distribution_v1(prefs, err))". So this version seems to work. But as far as I can tell, both versions seem to execute the same computations in the same order. e.g. I would assume that "categorical(params)" is the same as "sample(Categorical(params))", so I'm wondering if the discrepancy is due to some property of the Infer operator that I don't understand. 


If anyone could shed some light on this, it would be much appreciated.

Cheers
-Isaac




null-a

unread,
Apr 21, 2020, 3:15:10 AM4/21/20
to webppl-dev
As written, it looks like you're passing a function rather than a distribution to `sample` in your version zero. i.e. `sample(agent_distribution_v0)`, rather than something like `sample(agent_distribution_v0(prefs, err))`.

Isaac Davis

unread,
Apr 21, 2020, 10:33:22 AM4/21/20
to webppl-dev
Good catch, thanks for pointing that out. However, I think that was just an error in how I transcribed the code. When I replace "sample(agent_distribution_v0)" with "sample(agent_distribution_v0(prefs, err))", I get the same error message telling me that "Sample expected a distribution but received undefined"

null-a

unread,
Apr 21, 2020, 11:29:11 AM4/21/20
to webppl-dev
This is an odd one. It looks like you can fix your version zero by removing the newline between `return` and `Infer`. That is, replace:

var agent_distribution_v0=function(prefs,err){return
Infer(function(){


... with say:

var agent_distribution_v0=function(prefs,err){
return Infer(function(){


This is surprising to me, I guess it's a bug.

Cheers,
Paul

Isaac Davis

unread,
Apr 21, 2020, 11:36:52 AM4/21/20
to webppl-dev
That is very odd, but it does seem to be working. Thanks again!
-Isaac

null-a

unread,
Apr 21, 2020, 11:50:01 AM4/21/20
to webppl-dev
> it does seem to be working

Great.

> I guess it's a bug.

I take that back. Javascript behaves the same way, the `return` on a line by itself is an early return from the function, with a return value of `undefined` . For example, the following returns `undefined` under Node.js:

var f = function() {
 
return
 
42;
};

WebPPL aims to follow JS, so I don't think this is a bug.

Cheers,
Paul.

Isaac Davis

unread,
Apr 21, 2020, 2:05:04 PM4/21/20
to webppl-dev
That is good to know, and may explain some other weird results I'd been getting.

Thanks again!
-Isaac
Reply all
Reply to author
Forward
0 new messages