Skip to content

Commit a829983

Browse files
committed
Merge branch '4Q19/poc/v0_6' of https://github.com/JuliaRobotics/DistributedFactorGraphs.jl into twig/tags_set
2 parents eac347d + 7b12c3e commit a829983

File tree

11 files changed

+213
-275
lines changed

11 files changed

+213
-275
lines changed

docs/src/BuildingGraphs.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ DFG and IIF rely on a CRUD (Create, Read, Update, and Delete) interface to allow
6262
Variables are added using IncrementalInference's `addVariable!` function. To create the variable, you provide the following parameters:
6363
- The graph the variable is being added to
6464
- The variable's label (e.g. :x1 or :a)
65-
- The variable type (which is a subtype of InferenceVariable)
65+
- The variable inference type (aka soft type), which is a subtype of InferenceVariable
66+
67+
**Note**: Once variables are initialized to a specific soft type, all variable node data (solver data) must use that type.
6668

6769
In addition, the following optional parameters are provided:
6870
- Additional labels for the variable (in DFG these are referred to as tags)

docs/src/GraphData.md

Lines changed: 103 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,185 +1,167 @@
1-
# Creating Graphs
1+
# Using Graph Elements
22

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).
46

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)
1011

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.
1213

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.
1815
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.
2017
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.
2519
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.
3621
37-
### Creating a LightDFG Graph
22+
The following examples make use this data:
3823

3924
```julia
25+
using IncrementalInference
4026
# Create a DFG with default solver parameters using the LightGraphs.jl driver.
4127
dfg = LightDFG{SolverParams}(params=SolverParams())
42-
```
43-
44-
### Creating a CloudGraphsDFG Graph
4528

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)
5432
```
5533

56-
## Creating Variables and Factors
34+
## Variable and Factor Elements
5735

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
5937

60-
### Creating Variables with IIF
38+
#### Labels
6139

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.
6641

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+
```
7245

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
7748
```
7849

79-
### Creating Factors with IIF
50+
#### Timestamps
8051

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.
8553

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+
```
8758

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
8960

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.
9162

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!
9767
```
9868

99-
The produced factor graph is:
69+
### Solvable
10070

101-
![imgs/initialgraph.jpg](imgs/initialgraph.jpg)
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.
10272

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+
```
10577

106-
## Listing Variables and Factors
78+
### Variables
10779

108-
Reading, updating, and deleting all use DFG functions (as opposed to adding,
109-
where using the IncrementalInference functions are recommended).
80+
#### Soft Type
11081

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.
11483

11584
```@docs
116-
getVariableIds
117-
ls
85+
getSofttype
11886
```
11987

120-
```@docs
121-
getFactorIds
122-
lsf
123-
```
88+
#### Packed Parametric Estimates
12489

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).
12791

12892
```@docs
129-
getVariables
130-
getFactors
13193
```
13294

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
13796

138-
## Getting (Reading) Variables and Factors
97+
Solver data is used by IncrementalInference/RoME/Caesar solver to produce the above PPEs.
13998

140-
Individual variables and factors can be retrieved from their labels using the following functions:
99+
Example of updating solver data:
141100

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)
144111
```
145112

113+
Related Functions:
114+
146115
```@docs
147-
getFactor
116+
listVariableSolverData
117+
getVariableSolverData
118+
addVariableSolverData!
119+
updateVariableSolverData!
120+
deleteVariableSolverData!
148121
```
149122

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
154124

155-
## Updating Variables and Factors
125+
#### Big Data
156126

157-
Full variables and factors can be updated using the following functions:
127+
### Factors
158128

159-
```@docs
160-
updateVariable!
161-
```
129+
## Graph-Related Data
162130

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`.
166135

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
169145

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:
174147

175-
## Deleting Variables and Factors
148+
```@docs
149+
getUserData
150+
getRobotData
151+
getSessionData
152+
```
176153

177-
Variables and factors can be deleted using the following functions:
154+
It can be set using the following functions:
178155

179156
```@docs
180-
deleteVariable!
157+
setUserData!
158+
setRobotData!
159+
setSessionData!
181160
```
182161

183-
```@docs
184-
deleteFactor!
162+
Example of using graph-level data:
163+
164+
```julia
165+
setUserData!(dfg, Dict(:a => "Hello"))
166+
getUserData(dfg)
185167
```

src/CloudGraphsDFG/services/CGStructure.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,23 +296,23 @@ function getUserData(dfg::CloudGraphsDFG)::Dict{Symbol, String}
296296
propVal = _getNodeProperty(dfg.neo4jInstance, [dfg.userId, "USER"], "data")
297297
return JSON2.read(String(base64decode(propVal)), Dict{Symbol, String})
298298
end
299-
function setUserData(dfg::CloudGraphsDFG, data::Dict{Symbol, String})::Bool
299+
function setUserData!(dfg::CloudGraphsDFG, data::Dict{Symbol, String})::Bool
300300
count = _setNodeProperty(dfg.neo4jInstance, [dfg.userId, "USER"], "data", base64encode(JSON2.write(data)))
301301
return count == 1
302302
end
303303
function getRobotData(dfg::CloudGraphsDFG)::Dict{Symbol, String}
304304
propVal = _getNodeProperty(dfg.neo4jInstance, [dfg.userId, dfg.robotId, "ROBOT"], "data")
305305
return JSON2.read(String(base64decode(propVal)), Dict{Symbol, String})
306306
end
307-
function setRobotData(dfg::CloudGraphsDFG, data::Dict{Symbol, String})::Bool
307+
function setRobotData!(dfg::CloudGraphsDFG, data::Dict{Symbol, String})::Bool
308308
count = _setNodeProperty(dfg.neo4jInstance, [dfg.userId, dfg.robotId, "ROBOT"], "data", base64encode(JSON2.write(data)))
309309
return count == 1
310310
end
311311
function getSessionData(dfg::CloudGraphsDFG)::Dict{Symbol, String}
312312
propVal = _getNodeProperty(dfg.neo4jInstance, [dfg.userId, dfg.robotId, dfg.sessionId, "SESSION"], "data")
313313
return JSON2.read(String(base64decode(propVal)), Dict{Symbol, String})
314314
end
315-
function setSessionData(dfg::CloudGraphsDFG, data::Dict{Symbol, String})::Bool
315+
function setSessionData!(dfg::CloudGraphsDFG, data::Dict{Symbol, String})::Bool
316316
count = _setNodeProperty(dfg.neo4jInstance, [dfg.userId, dfg.robotId, dfg.sessionId, "SESSION"], "data", base64encode(JSON2.write(data)))
317317
return count == 1
318318
end

src/DistributedFactorGraphs.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,18 @@ export getLabel, getTimestamp, setTimestamp!, getTags, setTags!
6060
export getMaxPPE, getMeanPPE, getSuggestedPPE, getVariablePPE, getPPE, getVariablePPEs, getPPEs #, getEstimates
6161
export getSofttype
6262
# Level 2
63-
export getSolverData, solverData, getData, getSolverDataDict, setSolverData!, getInternalId, smallData, setSmallData!, bigData
63+
export getData, getSolverData, getSolverDataDict, setSolverData!, getInternalId
64+
export listVariableSolverData, getVariableSolverData, addVariableSolverData!, updateVariableSolverData!, deleteVariableSolverData!
65+
66+
export getSmallData, setSmallData!, bigData
6467
export addBigDataEntry!, getBigDataEntry, updateBigDataEntry!, deleteBigDataEntry!, getBigDataEntries, getBigDataKeys
6568

6669
# Find a home
6770
export getVariableOrder
6871

6972
# Services/AbstractDFG Exports
7073
export isInitialized, getFactorFunction, isVariable, isFactor
71-
export isSolvable, isSolveInProgress, getSolvable, setSolvable!, getSolveInProgress
74+
export isSolveInProgress, getSolvable, setSolvable!, getSolveInProgress
7275
export mergeUpdateVariableSolverData!, mergeUpdateGraphSolverData!
7376

7477
# Solver (IIF) Exports
@@ -87,7 +90,7 @@ export MeanMaxPPE
8790
#--------
8891
export setSerializationModule!, getSerializationModule
8992
export getLabelDict, getDescription, setDescription, getAddHistory, getSolverParams, setSolverParams
90-
export getUserData, setUserData, getRobotData, setRobotData, getSessionData, setSessionData
93+
export getUserData, setUserData!, getRobotData, setRobotData!, getSessionData, setSessionData!
9194

9295
# Not sure these are going to work everywhere, TODO implement in cloud?
9396
export updateUserData!, updateRobotData!, updateSessionData!, deleteUserData!, deleteRobotData!, deleteSessionData!

0 commit comments

Comments
 (0)