Discrete Robot Localization
This example builds a grid-cell robot localization problem. The robot moves through three corridor cells, and the state variables are the possible cells at consecutive time steps. Motion and beacon observations form a chain, so the factor graph is tree-structured and forward-backward discrete belief propagation is exact.
Variable Nodes
Each position variable has the same three possible cell states:
using FactorGraph
cells = [:A, :B, :C]
variables = [
DiscreteVariable(:x1, length(cells); label = "x1", states = cells),
DiscreteVariable(:x2, length(cells); label = "x2", states = cells),
DiscreteVariable(:x3, length(cells); label = "x3", states = cells),
DiscreteVariable(:x4, length(cells); label = "x4", states = cells)
]Prior Factor Node
The robot is believed to start near cell A:
prior = DiscreteFactor(:x1, [0.85, 0.10, 0.05]; label = "prior_x1", initialize = true)Motion Factor Nodes
The motion model favors moving one cell to the right, while still allowing the robot to stay in place or slip:
motion = [
0.20 0.75 0.05
0.05 0.20 0.75
0.02 0.18 0.80
]
motion12 = DiscreteFactor(:x1, :x2, motion; label = "motion12")
motion23 = DiscreteFactor(:x2, :x3, motion; label = "motion23")
motion34 = DiscreteFactor(:x3, :x4, motion; label = "motion34")Rows follow the previous cell and columns follow the next cell.
Beacon Factor Nodes
Beacon observations are unary likelihood factors. A beacon near cell C is detected at time step 3, and another observation again favors cell C at time step 4:
beacon3 = DiscreteFactor(:x3, [0.05, 0.15, 0.80]; label = "beacon3")
beacon4 = DiscreteFactor(:x4, [0.03, 0.17, 0.80]; label = "beacon4")Factor Graph Construction
Collect the factors and build a tree graph with a selected root:
factors = [prior, motion12, motion23, motion34, beacon3, beacon4]
graph = factorGraph(variables, factors; root = :x1)The graph can be rendered as an SVG factor graph figure:
saveGraphFigure("../drl.svg", graph; layout = (columnSpacing = 120, rowSpacing = 90))Running Belief Propagation
Run sum-product belief propagation on the tree:
inference = sumproduct(graph)
forwardBackward!(graph, inference)Results
Inspect the posterior cell probabilities:
printMarginal(graph, inference)Variable marginals (sum-product form):
Marginal for variable node "x1":
probability = [0.8261052256238364, 0.11494644808955293, 0.05894832628661077]
Marginal for variable node "x2":
probability = [0.04768022810366688, 0.7617809936202635, 0.19053877827606952]
Marginal for variable node "x3":
probability = [0.0016831764592516471, 0.07577558232694633, 0.922541241213802]
Marginal for variable node "x4":
probability = [0.0010617437359046814, 0.04734964369219023, 0.9515886125719051]Adding a New Time Step
In an online localization problem, the robot later moves again and a new position state is needed. Add the new variable, connect it with the latest motion model, add a new beacon observation, and continue from the current inference state:
addVariable!(graph, inference, :x5, length(cells); label = "x5", states = cells)
addFactor!(graph, inference, :x4, :x5, motion; label = "motion45")
addFactor!(graph, inference, :x5, [0.02, 0.18, 0.80]; label = "beacon5")
forwardStep!(graph, inference; variable = :x5, factor = "beacon5")
forwardStep!(graph, inference; variable = :x5, factor = "motion45")
backward!(graph, inference)
marginals!(graph, inference)The previous messages and marginals are kept as a warm start. Use the inference-aware addVariable! and addFactor! forms for this warm start; graph-only topology changes require a fresh inference object.
The updated graph is still a tree. A full forwardBackward! sweep can be used instead when all messages in the updated tree should be recomputed.
printMarginal(graph, inference; variable = :x5)Marginal for variable node "x5" (sum-product form):
probability = [0.0006445639312052108, 0.0487329844192641, 0.9506224516495306]