Skip to main content

Infer.NET user guide : The Infer.NET Modelling API

Repeat blocks

Repeat blocks provide an efficient way to repeat part of a model many times. A repeat block takes an argument count and contains the statements which are to be repeated:

using (Variable.Repeat(count))  
{  
  // contained modelling statements  
}

For an integer count, a repeat block is equivalent to a ForEach block, in the sense that it repeats the contained statements count times. However, a repeat block is much more efficient. It achieves this efficiency by not providing any index variable—every repetition must be identical. Also, local variables of a repeat block cannot be used outside of the block (otherwise they would have to be treated as arrays of length count, which we want to avoid). As with ForEach blocks, the using syntax is optional.

Using repeat blocks to speed up inference

When parts of a model are repeated identically, repeat blocks can lead to substantial speed-ups. For example, suppose we wish to learn the probability of heads of a coin from 10,000,000 tosses. Let’s say we are given a bool array flips containing these coin tosses. The standard approach in Infer.NET would be:

var probHeads = Variable.Beta(1, 1); // The bias of the coin  
var N = new Range(flips.Length); // Range over the flips  
var flipArray = Variable.Array<bool>(N); // Array of flips  
// Model for the flips  
flipArray[N] = Variable.Bernoulli(probHeads).ForEach(N);  
flipArray.ObservedValue = flips;

Intuitively this seems very inefficient - we have to allocate and process large arrays. The code will take longer and longer as we make more and more coin tosses.

In this particular model, all tosses which give heads are equivalent, as are all tosses that give tails. So we can just record the counts of heads and tails instead of all individual coin tosses. Repeat blocks provide a consistent way to do this for any type of model.

Here is how we can write the same model using repeat blocks, assuming we now have counts of heads and tails in the variables countTrue and countFalse:

using(Variable.Repeat(countTrue)) {  
  Variable.ConstrainTrue(Variable.Bernoulli(probHeads));  
}  
using(Variable.Repeat(countFalse)) {  
  Variable.ConstrainFalse(Variable.Bernoulli(probHeads));  
}

Inference of probHeads using this code takes the same amount of time no matter how many coin tosses were made. For example, for 10,000,000 tosses inference takes ~3 seconds using the original code but less than 1 millisecond when repeat blocks are used.

Other uses of repeat blocks

This section describes an experimental use of repeat blocks

The count argument of a repeat block can be any real number, including fractions and negative numbers. This has no correspondence to traditional programming, but it does make sense in terms of factor graphs. Essentially the repeat block is raising the contained factors to a power. If the power is a positive integer N, it is as if the factors were simply repeated N times. Negative powers can be used to define partition functions as part of an undirected model. This use of repeat blocks will be explored further in future versions of this guide.