Examples
      
      
        We start with a simple model for Markov chains:
      
      
      package blang.validation.internals.fixtures
model MarkovChain {
  param Simplex initialDistribution
  param TransitionMatrix transitionProbabilities
  random List<IntVar> chain
  laws {
    // Initial distribution:
    chain.get(0) | initialDistribution ~ Categorical(initialDistribution)
    // Transitions:
    for (int step : 1 ..< chain.size) {
      chain.get(step) |
        IntVar previous = chain.get(step - 1),
        transitionProbabilities
        ~ Categorical(
          if (previous >= 0 && previous < transitionProbabilities.nRows)
            transitionProbabilities.row(previous)
          else
            transitionProbabilities.row(0)
        )
    }
  }
}
      
      
      
        Notice that we used the pre-computation construct, namely
      
      
        IntVar previous = chain.get(step - 1)
      
      
        Accessing an array is not so much expensive, so you may wonder why we bothered pre-computing this. 
        It turns out there is actually an important speed gain to be made, of the order of the length of the chain. Why?
      
      
        To understand, we need to outline how the blang inference engines work under the hood. 
        Most of these engines exploit cases where conditional distributions only depend on subsets of the variables. 
        To do so, blang inspects the model constituents (for example the Categorical constituents) to 
        infer what is the scope of the constituent. A scope is simply the subset of the variables 
        available at a given location of the code (e.g. the code in one function cannot access the local variables 
        declared in another function, they are out of scope). So coming back to the Markov chain example, 
        this means that by passing in the precomputed chain.get(step - 1) rather than all the latent 
        variables, we make it possible for blang engines to infer that each time step in the HMM only have 
        interdependence with the previous and next state rather than all states. 
        In graphical model parlance, this means sparsity patterns in the graphical model are inferred.
      
      
        Let us look now how we can use a Markov chain as a building block for an HMM:
      
      
      package blang.validation.internals.fixtures
model DynamicNormalMixture  {
  param  int               nLatentStates
  random List<RealVar>     observations
  random List<IntVar>      states ?: latentIntList(observations.size)
  random DenseSimplex           initialDistribution ?: latentSimplex(nLatentStates)
  random DenseTransitionMatrix  transitionProbabilities ?: latentTransitionMatrix(nLatentStates)
  random List<RealVar>     means ?: latentRealList(nLatentStates), variances ?: latentRealList(nLatentStates)
  param  Matrix            concentrations ?: ones(nLatentStates).readOnlyView
  laws {
    // Priors on initial and transition probabilities
    initialDistribution | concentrations ~ Dirichlet(concentrations)
    for (int latentStateIdx : 0 ..< means.size) {
      transitionProbabilities.row(latentStateIdx) | concentrations ~ Dirichlet(concentrations)
    }
    // Priors on means and variances
    for (int latentStateIdx : 0 ..< means.size) {
      means.get(latentStateIdx) ~ Normal(0.0, 1.0)
      variances.get(latentStateIdx) ~ Gamma(1.0, 1.0)
    }
    states | initialDistribution, transitionProbabilities
      ~ MarkovChain(initialDistribution, transitionProbabilities)
    // Gaussian emissions
    for (int obsIdx : 0 ..< observations.size) {
      observations.get(obsIdx) |
        means,
        variances,
        IntVar curIndic = states.get(obsIdx)
      ~ Normal(means.get(curIndic), variances.get(curIndic))
    }
  }
}
      
      
      
      
        Undirected graphical models (AKA Markov random fields) are supported: here is 
        for example how a square Ising model is implemented:
      
      
      package blang.validation.internals.fixtures
import briefj.collections.UnorderedPair
import static blang.validation.internals.fixtures.Functions.squareIsingEdges
model Ising {
  param Double moment ?: 0.0
  param Double beta ?: log(1 + sqrt(2.0)) / 2.0 // critical point
  param Integer N ?: 5
  random List<IntVar> vertices ?: latentIntList(N*N)
  laws {
    // Pairwise potentials
    for (UnorderedPair<Integer, Integer> pair : squareIsingEdges(N)) {
      | IntVar first  = vertices.get(pair.getFirst),
        IntVar second = vertices.get(pair.getSecond),
        beta
      ~ LogPotential(
          if ((first < 0 || first > 1 || second < 0 || second > 1))
            return NEGATIVE_INFINITY
          else
            return beta*(2*first-1)*(2*second-1))
    }
    // Node potentials
    for (IntVar vertex : vertices) {
      vertex | moment ~ Bernoulli(logistic(-2.0*moment))
    }
  }
}
      
      
      
      
        First, we create a custom data type:
      
      
      package blang.types
import blang.core.RealVar
import blang.core.IntVar
import blang.types.StaticUtils
class SpikedRealVar implements RealVar {
  public val IntVar selected = StaticUtils::latentInt
  public val RealVar continuousPart = StaticUtils::latentReal
  override doubleValue() {
    if (selected.intValue < 0 || selected.intValue > 1)
      StaticUtils::invalidParameter()
    if (selected.intValue == 0) return 0.0
    else return continuousPart.doubleValue
  }
  override toString() { "" + doubleValue }
}
      
      
      
        We can now define a distribution for this type:
      
      
      package blang.validation.internals.fixtures
model SpikeAndSlab {
  random List<SpikedRealVar> variables
  param RealVar zeroProbability
  param RealDistribution nonZeroLogDensity
  laws {
    for (int index : 0 ..< variables.size) {
      logf(zeroProbability, nonZeroLogDensity, RealVar variable = variables.get(index)) {
        if (zeroProbability < 0.0 || zeroProbability > 1.0) return NEGATIVE_INFINITY
        if (variable == 0.0) {
          log(zeroProbability)
        } else {
          log(1.0 - zeroProbability) + nonZeroLogDensity.logDensity(variable)
        }
      }
      logf(SpikedRealVar variable = variables.get(index)) {
        if (variable.selected.isBool) return 0.0
        else return NEGATIVE_INFINITY
      }
      variables.get(index) is Constrained
    }
  }
  generate(rand) {
    for (SpikedRealVar variable : variables) {
      (variable.selected as WritableIntVar).set(Generators::bernoulli(rand, zeroProbability).asInt)
      (variable.continuousPart as WritableRealVar).set(nonZeroLogDensity.sample(rand))
    }
  }
}
      
      
      
        Afterwards, it is easy to incorporate Spike and Slab priors in more complicated models, for example a 
        naive GLM here: 
      
      
      package blang.validation.internals.fixtures
model SpikedGLM {
  param Matrix designMatrix // n by p
  random List<IntVar> output // size n
  random List<SpikedRealVar> coefficients ?: {
    val p = designMatrix.nCols
    return new ArrayList(p) => [
      for (int i : 0 ..< p)
        add(new SpikedRealVar)
    ]
  }
  random RealVar zeroProbability ?: latentReal
  laws {
    zeroProbability ~ Beta(1,1)
    coefficients | zeroProbability ~
      SpikeAndSlab(zeroProbability, Normal::distribution(0, 1))
    for (int index : 0 ..< output.size) {
      output.get(index) | coefficients,
                          Matrix predictors = designMatrix.row(index)
                        ~ Bernoulli(logistic({
                          var sum = 0.0
                          for (i : 0 ..< coefficients.size)
                            sum += coefficients.get(i).doubleValue * predictors.get(i)
                          sum
                        }))
    }
  }
}