Factor Graph as a Whole
Saving and Loading
Assuming some factor graph object has been constructed by hand or automation, it is often very useful to be able to store that factor graph to file for later loading, solving, analysis etc. Caesar.jl provides such functionality through easy saving and loading. To save a factor graph, simply do:
saveDFG("/somewhere/myfg", fg)
DistributedFactorGraphs.saveDFG
— FunctionsaveDFG(folder, dfg; saveMetadata)
Save a DFG to a folder. Will create/overwrite folder if it exists.
DevNotes:
- TODO remove
compress
kwarg.
Example
using DistributedFactorGraphs, IncrementalInference
# Create a DFG - can make one directly, e.g. GraphsDFG{NoSolverParams}() or use IIF:
dfg = initfg()
# ... Add stuff to graph using either IIF or DFG:
v1 = addVariable!(dfg, :a, ContinuousScalar, tags = [:POSE], solvable=0)
# Now save it:
saveDFG(dfg, "/tmp/saveDFG.tar.gz")
Similarly in the same or a new Julia context, you can load a factor graph object
# using Caesar
fg_ = loadDFG("/somwhere/myfg")
DistributedFactorGraphs.loadDFG
— FunctionDistributedFactorGraphs.loadDFG!
— FunctionloadDFG!(
dfgLoadInto,
dst;
overwriteDFGMetadata,
useDeprExtract
)
Load a DFG from a saved folder.
Example
using DistributedFactorGraphs, IncrementalInference
# Create a DFG - can make one directly, e.g. GraphsDFG{NoSolverParams}() or use IIF:
dfg = initfg()
# Load the graph
loadDFG!(dfg, "/tmp/savedgraph.tar.gz")
# Use the DFG as you do normally.
ls(dfg)
Julia natively provides a direct in memory deepcopy
function for making duplicate objects if you wish to keep a backup of the factor graph, e.g.
fg2 = deepcopy(fg)
Adding an Entry=>Data
Blob store
A later part of the documentation will show how to include a Entry=>Data
blob store.
Querying the Graph
List Variables:
A quick summary of the variables in the factor graph can be retrieved with:
# List variables
ls(fg)
# List factors attached to x0
ls(fg, :x0)
# TODO: Provide an overview of getVal, getVert, getBW, getBelief, etc.
It is possible to filter the listing with Regex
string:
ls(fg, r"x\d")
DistributedFactorGraphs.ls
— Functionls(dfg; ...)
ls(dfg, regexFilter; tags, solvable)
List the DFGVariables in the DFG. Optionally specify a label regular expression to retrieves a subset of the variables. Tags is a list of any tags that a node must have (at least one match).
Notes:
- Returns
Vector{Symbol}
ls(dfg; ...)
ls(dfg, node; solvable)
Retrieve a list of labels of the immediate neighbors around a given variable or factor.
unsorted = intersect(ls(fg, r"x"), ls(fg, Pose2)) # by regex
# sorting in most natural way (as defined by DFG)
sorted = sortDFG(unsorted)
DistributedFactorGraphs.sortDFG
— FunctionsortDFG(vars; by, kwargs...)
Convenience wrapper for Base.sort
. Sort variable (factor) lists in a meaningful way (by timestamp
, label
, etc), for example [:april;:x1_3;:x1_6;]
Defaults to sorting by timestamp for variables and factors and using natural_lt
for Symbols. See Base.sort for more detail.
Notes
- Not fool proof, but does better than native sort.
Example
sortDFG(ls(dfg))
sortDFG(ls(dfg), by=getLabel, lt=natural_lt)
Related
ls, lsf
List Factors:
unsorted = lsf(fg)
unsorted = ls(fg, Pose2Point2BearingRange)
or using the tags
(works for variables too):
lsf(fg, tags=[:APRILTAGS;])
DistributedFactorGraphs.lsf
— Functionlsf(dfg; ...)
lsf(dfg, regexFilter; tags, solvable)
List the DFGFactors in the DFG. Optionally specify a label regular expression to retrieves a subset of the factors.
Notes
- Return
Vector{Symbol}
DistributedFactorGraphs.lsfPriors
— FunctionlsfPriors(dfg)
Return vector of prior factor symbol labels in factor graph dfg
.
Notes:
- Returns
Vector{Symbol}
There are a variety of functions to query the factor graph, please refer to Function Reference for details and note that many functions still need to be added to this documentation.
Extracting a Subgraph
Sometimes it is useful to make a deepcopy of a segment of the factor graph for some purpose:
sfg = buildSubgraph(fg, [:x1;:x2;:l7], 1)
Extracting Belief Results (and PPE)
Once you have solved the graph, you can review the full marginal with:
X0 = getBelief(fg, :x0)
# Evaluate the marginal density function just for fun at [0.0, 0, 0].
X0(zeros(3,1))
This object is currently a Kernel Density which contains kernels at specific points on the associated manifold. These kernel locations can be retrieved with:
X0pts = getPoints(X0)
IncrementalInference.getBelief
— FunctiongetBelief(vnd)
Get a ManifoldKernelDensity estimate from variable node data.
Parametric Point Estimates (PPE)
Since Caesar.jl is build around the each variable state being estimated as a total marginal posterior belief, it is often useful to get the equivalent parametric point estimate from the belief. Many of these computations are already done by the inference library and avalable via the various getPPE
methods, e.g.:
getPPE(fg, :l3)
getPPESuggested(fg, :l5)
There are values for mean, max, or hybrid combinations.
DistributedFactorGraphs.getPPE
— FunctiongetPPE(vari)
getPPE(vari, solveKey)
Get the parametric point estimate (PPE) for a variable in the factor graph.
Notes
- Defaults on keywords
solveKey
andmethod
Related
getMeanPPE, getMaxPPE, getKDEMean, getKDEFit, getPPEs, getVariablePPEs
getPPE(v)
getPPE(v, ppekey)
Get the parametric point estimate (PPE) for a variable in the factor graph for a given solve key.
Notes
- Defaults on keywords
solveKey
andmethod
Related getPPEMean
, getPPEMax
, updatePPE!
, mean(BeliefType)
IncrementalInference.calcPPE
— FunctioncalcPPE(var; ...)
calcPPE(var, varType; ppeType, solveKey, ppeKey)
Get the ParametricPointEstimates–-based on full marginal belief estimates–-of a variable in the distributed factor graph. Calculate new Parametric Point Estimates for a given variable.
DevNotes
- TODO update for manifold subgroups.
- TODO standardize after AMP3D
Related
Getting Many Marginal Samples
It is also possible to sample the above belief objects for more samples:
pts = rand(X0, 200)
Building On-Manifold KDEs
These kernel density belief objects can be constructed from points as follows:
X0_ = manikde!(Pose2, pts)
Logging Output (Unique Folder)
Each new factor graph is designated a unique folder in /tmp/caesar
. This is usaully used for debugging or large scale test analysis. Sometimes it may be useful for the user to also use this temporary location. The location is stored in the SolverParams
:
getSolverParams(fg).logpath
The functions of interest are:
IncrementalInference.getLogPath
— FunctiongetLogPath(opt)
Get the folder location where debug and solver information is recorded for a particular factor graph.
IncrementalInference.joinLogPath
— FunctionjoinLogPath(opt, str)
Append str
onto factor graph log path as convenience function.
A useful tip for doing large scale processing might be to reduce amount of write operations to a solid-state drive that will be written to default location /tmp/caesar
by simplying adding a symbolic link to a USB drive or SDCard, perhaps similar to:
cd /tmp
mkdir -p /media/MYFLASHDRIVE/caesar
ln -s /media/MYFLASHDRIVE/caesar caesar
Other Useful Functions
IncrementalInference.getFactorDim
— FunctiongetFactorDim(w...) -> Any
Return the number of dimensions this factor vertex fc
influences.
DevNotes
- TODO document how this function handles partial dimensions
- Currently a factor manifold is just what the measurement provides (i.e. bearing only would be dimension 1)
DistributedFactorGraphs.getManifold
— FunctiongetManifold(_)
Interface function to return the <:ManifoldsBase.AbstractManifold
object of variableType<:InferenceVariable
.
getManifold(mkd)
getManifold(mkd, asPartial)
Return the manifold on which this ManifoldKernelDensity is defined.
DevNotes
- TODO currently ignores the .partial aspect (captured in parameter
L
)