Working with Variables#

Inspect an Existing Graph#

Most use cases will involve retrieving information from a factor graph session already available on the server. Setup the API server connection, and if not guest use an auth token:

# Define user, robot, session
userLabel = "guest@navability.io"
robotLabel = "TestRobot"
sessionLabel = "TestHex"

# create an authorized client connection
# leave out the auth_token if using `guest@navability.io`
fgclient = DFGClient(userLabel, robotLabel, sessionLabel)

# For authorized users, copy the auth token from the NavAbility App "Connect" page
# auth_token = "r3ft ... eo7_" # e.g. if not guest
# fgclient = DFGClient(userLabel, robotLabel, sessionLabel, auth_token=auth_token)

DFGClient is used to make requests to the system and internally holds a context which is used to describe a specific session graph according to the userLabel, robotLabel, and sessionLabel.

Parameters:
  • userLabel (str) – guest@navability.io

  • robotLabel (str) – TestRobot

  • sessionLabel (str) – TestHex

  • [auth_token=] (str) – for authorized access, get a temporary token from app.navability.io Connect page.

Variables#

Variables represent state variables of interest such as vehicle or landmark positions, sensor calibration parameters, and more. Variables are likely hidden values that are not directly observed, but we want to estimate them from observed data. Let’s start by listing all the variables in the session:

varLbls = listVariables(fgclient)
# varLbls = await listVariablesAsync(fgclient)

Returns ["l1","x0","x1","x2","x3","x4","x5","x6"]. The await ... Async version of the function starts a task which can conducted according to parallelism of this host language. Some NavAbilitySDKs in other languages may have better or worse support for parallelism, depending on host language features and capabilities – e.g. the NavAbilitySDK.jl has a more advanced parallism design than NavAbilitySDK.py owing advances made in compiler technology.

Tip

There is a handy alias familiar to Linux, ls = listVariables, e.g. ls(fgclient) returns all the variables in the graph.

Getting a Variable#

The main purpose of using a factor graph is not only as data index but also to deeply connect with the mapping and localization problem. Variables in the factor graph represent the states to be estimated from the relevant measurement data. The numerical values for each variable are computed by any number of solver operations. The numerical results are primarily stored in a variables solverData field, such that either parametric or non-parametric inference results can be used:

v0 = getVariable(fgclient, "x0")
# v0 = await getVariableAsync(fgclient, "x0")

E.g. Variable (Node) Tags#

The getVariable call returns a Variable object containing many fields. For example, one can readily check which tags have been added to this variable with:

print('The tags on this variable are', v0.tags)

which would print the list of tags similar to:

The tags on this variable are ["VARIABLE", "POSE", "DOCS_EXAMPLE"]

A factor graph variable node as well as data carrying object that can serialized and distributed across computing nodes.

Parameters:
  • label (str) – The variable label, such as “x1” or “pose_7”

  • variableType (str) – For example “Pose2” or “Pose3”

  • tags (List[str]) – A string list of tags for annotating and later searching through nodes, e.g. [“POSE”, “VARIABLE”, “AUTO”]

  • timestamp (datetime) – When the variable instance occurred.

  • nstime (str) – duplicate ns scale time information which does not store full unix time, but rather only the nanosecond portion for higher resolution.

  • solvable (str) – indicate whether the variable is ready to be incldued in a solve.

  • ppes (Dict[str, Ppe]) – Parametric point estimate solutions which summarize the possibly non-Gaussian solution contained in .solverData.

  • blobEntries (Dict[str, BlobEntry]) – A list of BlobEntry`s which holds contextual information for (data) `Blob`s stored in a separate `BlobStore.

  • solverData (Dict[str, VariableNodeData]) – In depth solver information used for numerical solutions of the factor graph, including non-Gaussian and multiple solveKeys.

  • metadata (dict) – To store opportunistic “small data” that migth be useful to keep. Use BlobEntries and Blobs as main mechanism for storing heavy lift data.

  • _version (str) – Serialization support of Variable objects benefit from knowing the library version used for this object.

  • id (Optional[UUID]) – Autogenerated uuid4 for use in a distributed system, do not self assign.

Parametric Point Estimates (PPEs)#

To better bridge the gap between non-Gaussian and Gaussian solutions, variables also store a convenience numerical solution (or summary) called the parametric point estimate (PPE) for each of the solveKeys. While various forms of PPEs can exists—such as mean, max, modes, etc.—a common suggested field exists for basic usage. For example, the suggested parametric equivalent solution from the nonparametric solver (default) can be obtained by:

xyr = v0.ppes['default'].suggested
# [-0.00, 0.00, 0.00]

See also

The tutorial on leveraging (contradictory) prior data is a good example of the on when oversimplified parametric estimates (from a non-Gaussian posterior) break down.

Warning

At time of writing, the PPE numerical values are stored in coordinates. These values change to change to on-manifold point representations. Note that the internal solver computations (i.e. solverData) values are already stored as on-manifold points. For more information, see the on-manifold points, tangent vectors, and coordinates description presented here.

Numerical values, & solveKeys#

Since various numerical solutions may exists for the same factor graph, we introduce the idea of a solveKey. Different numerical values for different solveKeys can exists for any number of reasons. For example, we may find a different situation in each of three solveKeys, ('default', 'parametric', 'graphinit'), where we can explore some of the properties:

v0.solverData['default'].variableType
# 'RoME.Pose3'
v0.solverData['parametric'].initialized
# False
v0.solverData['grahpinit'].vecval
# [0,0,0...]

Each of these solverDatas are unique identified via the solveKey. The graphinit solver values are a duplicate of the numerical values for the variable before inference computation was performed. In this example the default key corresponds to the nonparametric solution, and parametric represents a Gaussian only parametric solution. Repeat solves, or solving via different methods, or solves with different parameter selections can all be supported via solveKeys.

The numerical values can be obtained from the solverData via:

v0.solverData['graphinit'].vecval
# [-0.001, 0.002, 0.001, ...]

SDK Supported Variables#

The list of variable types currently supported by the SDK are:

  • Position1 / ContinuousScalar

  • Position2 / Point2

  • Pose2

  • Position3 / Point3

  • Pose3

Tip

Many more variable types are already supported by the solver, see additional docs here. Reach out to NavAbility for help or support in bringing more variable types to the SDK sooner, or for help in building more variable types that may not yet exist in either libraries.