|
1 |
| -# Creating Graphs |
| 1 | +# Using Graph Elements |
2 | 2 |
|
3 |
| -In this section constructing DFG graphs will be discussed. To start, bring DistributedFactorGraphs into your workspace: |
| 3 | +Variables and factors in DistributedFactorGraphs are used for a variety of |
| 4 | +different applications. We have tried to compartmentalize the data as much as |
| 5 | +possible so that users do not need to dig around to find what they need (it's a work in progress). |
4 | 6 |
|
5 |
| -```julia |
6 |
| -using DistributedFactorGraphs |
7 |
| -``` |
8 |
| - |
9 |
| -We recommend using IncrementalInference (IIF) to populate DFG graphs. DFG provides the structure, but IIF overloads the provided `addVariable!` and `addFactor!` functions and creates solver-specific data that allows the graph to be solved. So although you can use DFG's `addVariable!` and `addFactor!`, it is better to start with IIF's functions so that the graph is solvable. |
| 7 | +There are three fundamental types of data in DFG: |
| 8 | +- Variable and factor data (stored in the nodes themselves) |
| 9 | +- Offloaded big data elements (keyed in a variable or factor, but stored in another location) |
| 10 | +- Graph data (data that is related to the graph itself) |
10 | 11 |
|
11 |
| -So for the following examples, IncrementalInference will be used to create the variables and factors. It should be added and imported to run the examples: |
| 12 | +The following is a guideline to using these parameters. |
12 | 13 |
|
13 |
| -```julia |
14 |
| -using Pkg |
15 |
| -Pkg.add("IncrementalInference") |
16 |
| -using IncrementalInference |
17 |
| -``` |
| 14 | +> Note: Some functions are direct accessors to the internal parameters, others are derived functions (e.g. getLabel(v) = v.label). In other cases the accessors are simplified ways to interact with the structures. We recommend using the accessors as the internal structure may change over time. |
18 | 15 |
|
19 |
| -## Initializing a Graph |
| 16 | +> Note: Adds in general throw an error if the element already exists. Update will update the element if it exists, otherwise it will add it. |
20 | 17 |
|
21 |
| -DFG graphs can be built using various drivers (different representations of the underlying graph). At the moment DFG supports 3 drivers: |
22 |
| -- GraphsDFG: An in-memory graph that uses Graphs.jl for representing the graph. |
23 |
| -- LightDFG: An in-memory graph that uses LightGraphs.jl for representing the graph. |
24 |
| -- CloudGraphs: A database-driven graph that uses Neo4j.jl for interacting with the graph. |
| 18 | +> Note: In general these functions will return an error if the respective element is not found. This is to avoid returning, say, nothing, which will be horribly confusing if you tried `getVariableSolverData(dfg, :a, :b)` and it returned nothing - which was missing, :a or :b, or was there a communication issue? We recommend coding defensively and trapping errors in critical portions of your user code. |
25 | 19 |
|
26 |
| -In general the first two are used for building and solving graphs, and CloudGraphs is used for persisting in-memory graphs into a database. In the long term we recommend using the LightDFG driver for in-memory operation because Graphs.jl is not actively supported and over time that driver may be deprecated. |
27 |
| - |
28 |
| -To continue the example, run one of the following to create a DFG driver: |
29 |
| - |
30 |
| -### Creating a GraphsDFG Graph |
31 |
| - |
32 |
| -```julia |
33 |
| -# Create a DFG with default solver parameters using the Graphs.jl driver. |
34 |
| -dfg = GraphsDFG{SolverParams}(params=SolverParams()) |
35 |
| -``` |
| 20 | +> Note: All data is passed by reference, so if you update the returned structure it will update in the graph. The database driver is an exception, and once the variable or factor is updated you need to call update* to persist the changes to the graph. |
36 | 21 |
|
37 |
| -### Creating a LightDFG Graph |
| 22 | +The following examples make use this data: |
38 | 23 |
|
39 | 24 | ```julia
|
| 25 | +using IncrementalInference |
40 | 26 | # Create a DFG with default solver parameters using the LightGraphs.jl driver.
|
41 | 27 | dfg = LightDFG{SolverParams}(params=SolverParams())
|
42 |
| -``` |
43 |
| - |
44 |
| -### Creating a CloudGraphsDFG Graph |
45 | 28 |
|
46 |
| -```julia |
47 |
| -# Create a DFG with no solver parameters (just to demonstrate the difference) using the CloudGraphs driver, and connect it to a local Neo4j instance. |
48 |
| -dfg = CloudGraphsDFG{NoSolverParams}("localhost", 7474, "neo4j", "test", |
49 |
| - "testUser", "testRobot", "testSession", |
50 |
| - nothing, |
51 |
| - nothing, |
52 |
| - IncrementalInference.decodePackedType, |
53 |
| - IncrementalInference.rebuildFactorMetadata!) |
| 29 | +x0 = addVariable!(dfg, :x0, ContinuousScalar, labels = [:POSE], solvable=1) |
| 30 | +x1 = addVariable!(dfg, :x1, ContinuousScalar, labels = [:POSE], solvable=1) |
| 31 | +f1 = addFactor!(dfg, [:x0; :x1], LinearConditional(Normal(50.0,2.0)), solvable=1) |
54 | 32 | ```
|
55 | 33 |
|
56 |
| -## Creating Variables and Factors |
| 34 | +## Variable and Factor Elements |
57 | 35 |
|
58 |
| -DFG and IIF rely on a CRUD (Create, Read, Update, and Delete) interface to allow users to create and edit graphs. |
| 36 | +### Common Elements |
59 | 37 |
|
60 |
| -### Creating Variables with IIF |
| 38 | +#### Labels |
61 | 39 |
|
62 |
| -Variables are added using IncrementalInference's `addVariable!` function. To create the variable, you provide the following parameters: |
63 |
| -- The graph the variable is being added to |
64 |
| -- The variable's label (e.g. :x1 or :a) |
65 |
| -- The variable type (which is a subtype of InferenceVariable) |
| 40 | +Labels are the principle identifier of a variable or factor. |
66 | 41 |
|
67 |
| -In addition, the following optional parameters are provided: |
68 |
| -- Additional labels for the variable (in DFG these are referred to as tags) |
69 |
| -- A `solvable` flag to indicate whether the variable is ready to be added to a solution |
70 |
| - |
71 |
| -Three variables are added: |
| 42 | +```@docs |
| 43 | +getLabel |
| 44 | +``` |
72 | 45 |
|
73 |
| -```julia |
74 |
| -v1 = addVariable!(dfg, :x0, ContinuousScalar, labels = [:POSE], solvable=1) |
75 |
| -v2 = addVariable!(dfg, :x1, ContinuousScalar, labels = [:POSE], solvable=1) |
76 |
| -v3 = addVariable!(dfg, :l0, ContinuousScalar, labels = [:LANDMARK], solvable=1) |
| 46 | +```@docs |
| 47 | +getLabel |
77 | 48 | ```
|
78 | 49 |
|
79 |
| -### Creating Factors with IIF |
| 50 | +#### Timestamps |
80 | 51 |
|
81 |
| -Similarly to variables, it is recommended that users start with the IIF implementation of the `addFactor!` functions to create factors. To create the factors, you provide the following parameters: |
82 |
| -- The graph the variable is being added to |
83 |
| -- The labels for the variables that the factor is linking |
84 |
| -- The factor function (which is a subtype of ) |
| 52 | +Each variable or factor can have a timestamp associated with it. |
85 | 53 |
|
86 |
| -Additionally, the solvable flag is also set to indicate that the factor can be used in solving graphs. |
| 54 | +```@docs |
| 55 | +getTimestamp |
| 56 | +setTimestamp! |
| 57 | +``` |
87 | 58 |
|
88 |
| -**NOTE:** Every graph requires a prior for it to be solvable, so it is a good practice to make sure one is added (generally by adding to the first variable in the graph). |
| 59 | +#### Tags |
89 | 60 |
|
90 |
| -Four factors are added: a prior, a linear conditional relationship with a normal distribution between x0 and x1, and a pair of linear conditional relationships between each pose and the landmark. |
| 61 | +Tags are a set of symbols that contain identifiers for the variable or factor. |
91 | 62 |
|
92 |
| -```julia |
93 |
| -prior = addFactor!(dfg, [:x0], Prior(Normal(0,1))) |
94 |
| -f1 = addFactor!(dfg, [:x0; :x1], LinearConditional(Normal(50.0,2.0)), solvable=1) |
95 |
| -f1 = addFactor!(dfg, [:l0; :x0], LinearConditional(Normal(40.0,5.0)), solvable=1) |
96 |
| -f1 = addFactor!(dfg, [:l0; :x1], LinearConditional(Normal(-10.0,5.0)), solvable=1) |
| 63 | +```@docs |
| 64 | +addTag |
| 65 | +mergeTags! |
| 66 | +deleteTags! |
97 | 67 | ```
|
98 | 68 |
|
99 |
| -The produced factor graph is: |
| 69 | +### Solvable |
100 | 70 |
|
101 |
| - |
| 71 | +The solvable flag indicates whether the solver should make use of the variable or factor while solving the graph. This can be used to construct graphs in chunks while solving asynchronously, or for selectively solving portions of the graph. |
102 | 72 |
|
103 |
| -(For more information on producing plots of the graph, please refer to the |
104 |
| -[Drawing Graphs](DrawingGraphs.md) section). |
| 73 | +```@docs |
| 74 | +getSolvable |
| 75 | +setSolvable! |
| 76 | +``` |
105 | 77 |
|
106 |
| -## Listing Variables and Factors |
| 78 | +### Variables |
107 | 79 |
|
108 |
| -Reading, updating, and deleting all use DFG functions (as opposed to adding, |
109 |
| -where using the IncrementalInference functions are recommended). |
| 80 | +#### Soft Type |
110 | 81 |
|
111 |
| -Each variable and factor is uniquely identified by its label. The list of |
112 |
| -variable and factor labels can be retrieved with the `ls`/`getVariableIds` and |
113 |
| -`lsf`/`getFactorIds` functions: |
| 82 | +The soft type is the underlying inference variable type, such as a Pose2. |
114 | 83 |
|
115 | 84 | ```@docs
|
116 |
| -getVariableIds |
117 |
| -ls |
| 85 | +getSofttype |
118 | 86 | ```
|
119 | 87 |
|
120 |
| -```@docs |
121 |
| -getFactorIds |
122 |
| -lsf |
123 |
| -``` |
| 88 | +#### Packed Parametric Estimates |
124 | 89 |
|
125 |
| -To list all variables or factors (instead of just their labels), use the |
126 |
| -`getVariables` and `getFactors` functions: |
| 90 | +Solved graphs contain estimates for the variables, which are keyed by the solution (the default is saved as :default). |
127 | 91 |
|
128 | 92 | ```@docs
|
129 |
| -getVariables |
130 |
| -getFactors |
131 | 93 | ```
|
132 | 94 |
|
133 |
| -**NOTE**: `getNeighbors` is also worth mentioning at this point as it is a simple way to |
134 |
| -find the bigraph relationships. More information on this and other ways to |
135 |
| -retrieve filtered lists of variables/factors (an area that's currently WIP in |
136 |
| -DFG) can be found in [Traversing and Querying](TraversingAndQuerying.md). |
| 95 | +#### Solver Data |
137 | 96 |
|
138 |
| -## Getting (Reading) Variables and Factors |
| 97 | +Solver data is used by IncrementalInference/RoME/Caesar solver to produce the above PPEs. |
139 | 98 |
|
140 |
| -Individual variables and factors can be retrieved from their labels using the following functions: |
| 99 | +Example of updating solver data: |
141 | 100 |
|
142 |
| -```@docs |
143 |
| -getVariable |
| 101 | +```julia |
| 102 | +# Add new VND of type ContinuousScalar to :x0 |
| 103 | +# Could also do VariableNodeData(ContinuousScalar()) |
| 104 | +vnd = VariableNodeData{ContinuousScalar}() |
| 105 | +addVariableSolverData!(dfg, :x0, vnd, :parametric) |
| 106 | +@show listVariableSolverData(dfg, :x0) |
| 107 | +# Get the data back - note that this is a reference to above. |
| 108 | +vndBack = getVariableSolverData(dfg, :x0, :parametric) |
| 109 | +# Delete it |
| 110 | +deleteVariableSolverData!(dfg, :x0, :parametric) |
144 | 111 | ```
|
145 | 112 |
|
| 113 | +Related Functions: |
| 114 | + |
146 | 115 | ```@docs
|
147 |
| -getFactor |
| 116 | +listVariableSolverData |
| 117 | +getVariableSolverData |
| 118 | +addVariableSolverData! |
| 119 | +updateVariableSolverData! |
| 120 | +deleteVariableSolverData! |
148 | 121 | ```
|
149 | 122 |
|
150 |
| -It is worth noting that `getVariable` allows a user to retrieve only a single |
151 |
| -solver entry, so that subsets of the solver data can be retrieved individually |
152 |
| -(say, in the case that there are many solutions). These can then be updated |
153 |
| -independently using the functions as discussed in the update section below. |
| 123 | +#### Small Data |
154 | 124 |
|
155 |
| -## Updating Variables and Factors |
| 125 | +#### Big Data |
156 | 126 |
|
157 |
| -Full variables and factors can be updated using the following functions: |
| 127 | +### Factors |
158 | 128 |
|
159 |
| -```@docs |
160 |
| -updateVariable! |
161 |
| -``` |
| 129 | +## Graph-Related Data |
162 | 130 |
|
163 |
| -```@docs |
164 |
| -updateFactor! |
165 |
| -``` |
| 131 | +DFG can store data in the graph itself (as opposed to inside graph elements). |
| 132 | +When you retrieve graphs from a database, this information is carried along. If |
| 133 | +you are working with an in-memory graph, the structure is flattened into the |
| 134 | +graph itself as `userData`, `robotData`, and `sessionData`. |
166 | 135 |
|
167 |
| -**NOTE**: Skeleton and summary variables are read-only. To perform updates you |
168 |
| -should use the full factors and variables. |
| 136 | +Graphs reside inside a hierarchy made up in the following way: |
| 137 | +- User1 |
| 138 | + - Robot1 |
| 139 | + - Session1 (the graph itself) |
| 140 | +- User2 |
| 141 | + - Robot2 |
| 142 | + - Robot3 |
| 143 | + - Session2 |
| 144 | + - Session3 |
169 | 145 |
|
170 |
| -**NOTE**: `updateVariable`/`updateFactor` performs a complete update of the |
171 |
| -respective node. It's not a very efficient way to edit fine-grain detail. There |
172 |
| -are other methods to perform smaller in-place changes. This is discussed in |
173 |
| -more detail in [Data Structure](DataStructure.md). |
| 146 | +This data can be retrieved with the follow functions: |
174 | 147 |
|
175 |
| -## Deleting Variables and Factors |
| 148 | +```@docs |
| 149 | +getUserData |
| 150 | +getRobotData |
| 151 | +getSessionData |
| 152 | +``` |
176 | 153 |
|
177 |
| -Variables and factors can be deleted using the following functions: |
| 154 | +It can be set using the following functions: |
178 | 155 |
|
179 | 156 | ```@docs
|
180 |
| -deleteVariable! |
| 157 | +setUserData! |
| 158 | +setRobotData! |
| 159 | +setSessionData! |
181 | 160 | ```
|
182 | 161 |
|
183 |
| -```@docs |
184 |
| -deleteFactor! |
| 162 | +Example of using graph-level data: |
| 163 | + |
| 164 | +```julia |
| 165 | +setUserData!(dfg, Dict(:a => "Hello")) |
| 166 | +getUserData(dfg) |
185 | 167 | ```
|
0 commit comments