Skip to content

Commit 838d83b

Browse files
authored
Merge pull request #159 from JuliaRobotics/master
Release 0.4.1
2 parents 735e8ec + 3191d82 commit 838d83b

33 files changed

+1102
-516
lines changed

Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
77
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
88
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
99
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
10+
GraphPlot = "a2cc645c-3eea-5389-862e-a155d0052231"
1011
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1112
JSON2 = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3"
1213
LightGraphs = "093fc24a-ae57-5d10-9952-331d41423f4d"
1314
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1415
MetaGraphs = "626554b9-1ddb-594c-aa3c-2596fe9399a5"
15-
Neo4j = "d2adbeaf-5838-5367-8a2f-e46d570981db"
1616
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1717
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
1818
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
@@ -28,6 +28,8 @@ julia = "0.7, 1"
2828

2929
[extras]
3030
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
31+
GraphPlot = "a2cc645c-3eea-5389-862e-a155d0052231"
32+
Neo4j = "d2adbeaf-5838-5367-8a2f-e46d570981db"
3133

3234
[targets]
33-
test = ["Test"]
35+
test = ["Test", "GraphPlot", "Neo4j"]

docs/src/func_ref.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,15 @@ getSubgraphAroundNode
5858
getSubgraph
5959
```
6060

61-
### Visualization
61+
### Summaries
62+
```@docs
63+
getSummary
64+
getSummaryGraph
65+
```
66+
67+
### Visualization and Plotting
6268
```@docs
6369
toDot
6470
toDotFile
71+
dfgplot
6572
```
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Serialization of Variables and Factors
2+
3+
If you are transferring variables and factors over a wire you need to serialize
4+
and deserialize variables and factors.
5+
6+
## Packing and Unpacking
7+
8+
Packing is done with the exposed functions `packVariable()::Dict{String, Any}` and
9+
`packFactor()::Dict{String, Any}`. You can then serialize this into a string or JSON
10+
as you would normally.
11+
12+
> Note: When you deserialize a factor and want to use it for solving, you must call IncrementalInference.rebuildFactorMetadata!(dfgLoadInto, factor) to reinflate it completely. Please review [FileDFG service](src/FileDFG/services/FileDFG.jl) for an example.
13+
14+
For example:
15+
```julia
16+
using DistributedFactorGraphs
17+
using IncrementalInference, RoME
18+
19+
# Make a variable and a factor:
20+
# Make a simple graph
21+
dfg = GraphsDFG{SolverParams}(params=SolverParams())
22+
# Add the first pose :x0
23+
x0 = addVariable!(dfg, :x0, Pose2)
24+
# Add at a fixed location PriorPose2 to pin :x0 to a starting location (10,10, pi/4)
25+
prior = addFactor!(dfg, [:x0], PriorPose2( MvNormal([10; 10; 1.0/8.0], Matrix(Diagonal([0.1;0.1;0.05].^2))) ) )
26+
27+
# Now serialize them:
28+
pVariable = packVariable(dfg, x0)
29+
pFactor = packFactor(dfg, prior)
30+
31+
# And we can deserialize them
32+
upVariable = unpackVariable(dfg, pVariable)
33+
# FYI: The graph is used in unpackFactor to find the variables that the factor links to.
34+
upFactor = unpackFactor(dfg, pFactor, IncrementalInference)
35+
# Note, you need to call IncrementalInference.rebuildFactorMetadata!(dfgLoadInto, factor)
36+
# to make it useable. Please add an issue if this poses a problem or causes issues.
37+
```
38+
39+
As a more complex example, we can use JSON2 to stringify the data and write it to a folder of files as FileDFG does:
40+
41+
```julia
42+
using DistributedFactorGraphs
43+
using IncrementalInference, RoME
44+
45+
# Make a variable and a factor:
46+
# Make a simple graph
47+
dfg = GraphsDFG{SolverParams}(params=SolverParams())
48+
# Add the first pose :x0
49+
x0 = addVariable!(dfg, :x0, Pose2)
50+
# Add at a fixed location PriorPose2 to pin :x0 to a starting location (10,10, pi/4)
51+
prior = addFactor!(dfg, [:x0], PriorPose2( MvNormal([10; 10; 1.0/8.0], Matrix(Diagonal([0.1;0.1;0.05].^2))) ) )
52+
53+
# Slightly fancier example: We can use JSON2, we can serialize to a string
54+
varFolder = "/tmp"
55+
for v in getVariables(dfg)
56+
vPacked = packVariable(dfg, v)
57+
io = open("$varFolder/$(v.label).json", "w")
58+
JSON2.write(io, vPacked)
59+
close(io)
60+
end
61+
# Factors
62+
for f in getFactors(dfg)
63+
fPacked = packFactor(dfg, f)
64+
io = open("$folder/factors/$(f.label).json", "w")
65+
JSON2.write(io, fPacked)
66+
close(io)
67+
end
68+
```

src/CloudGraphsDFG/services/CloudGraphsDFG.jl

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -718,25 +718,11 @@ Optionally provide a distance to specify the number of edges should be followed.
718718
Optionally provide an existing subgraph addToDFG, the extracted nodes will be copied into this graph. By default a new subgraph will be created.
719719
Note: By default orphaned factors (where the subgraph does not contain all the related variables) are not returned. Set includeOrphanFactors to return the orphans irrespective of whether the subgraph contains all the variables.
720720
"""
721-
function getSubgraphAroundNode(dfg::CloudGraphsDFG, node::DFGNode, distance::Int64=1, includeOrphanFactors::Bool=false, addToDFG::Union{Nothing, CloudGraphsDFG}=nothing)::CloudGraphsDFG
721+
function getSubgraphAroundNode(dfg::CloudGraphsDFG, node::DFGNode, distance::Int64=1, includeOrphanFactors::Bool=false, addToDFG::AbstractDFG=_getDuplicatedEmptyDFG(dfg))::AbstractDFG
722722
distance < 1 && error("getSubgraphAroundNode() only works for distance > 0")
723723

724724
# Making a copy session if not specified
725-
if addToDFG == nothing
726-
addToDFG = _getDuplicatedEmptyDFG(dfg)
727-
end
728-
729-
# Thank you Neo4j for 0..* awesomeness!!
730-
neighborList = _getLabelsFromCyphonQuery(dfg.neo4jInstance, "(n:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId):$(node.label))-[FACTORGRAPH*0..$distance]-(node:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId))")
731-
732-
# Copy the section of graph we want
733-
_copyIntoGraph!(dfg, addToDFG, neighborList, includeOrphanFactors)
734-
return addToDFG
735-
end
736-
737-
function getSubgraphAroundNode(dfg::CloudGraphsDFG{<:AbstractParams}, node::DFGNode, distance::Int64, includeOrphanFactors::Bool, addToDFG::MetaGraphsDFG{AbstractParams})::AbstractDFG
738-
distance < 1 && error("getSubgraphAroundNode() only works for distance > 0")
739-
725+
#moved to parameter addToDFG::AbstractDFG=_getDuplicatedEmptyDFG(dfg)
740726

741727
# Thank you Neo4j for 0..* awesomeness!!
742728
neighborList = _getLabelsFromCyphonQuery(dfg.neo4jInstance, "(n:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId):$(node.label))-[FACTORGRAPH*0..$distance]-(node:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId))")
@@ -801,6 +787,33 @@ function getAdjacencyMatrix(dfg::CloudGraphsDFG)::Matrix{Union{Nothing, Symbol}}
801787
return adjMat
802788
end
803789

790+
function getAdjacencyMatrixSparse(dfg::CloudGraphsDFG)::Tuple{SparseMatrixCSC, Vector{Symbol}, Vector{Symbol}}
791+
varLabels = getVariableIds(dfg)
792+
factLabels = getFactorIds(dfg)
793+
vDict = Dict(varLabels .=> [1:length(varLabels)...])
794+
fDict = Dict(factLabels .=> [1:length(factLabels)...])
795+
796+
adjMat = spzeros(Int, length(factLabels), length(varLabels))
797+
798+
# Now ask for all relationships for this session graph
799+
loadtx = transaction(dfg.neo4jInstance.connection)
800+
query = "START n=node(*) MATCH (n:VARIABLE:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId))-[r:FACTORGRAPH]-(m:FACTOR:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId)) RETURN n.label as variable, m.label as factor;"
801+
nodes = loadtx(query; submit=true)
802+
# Have to finish the transaction
803+
commit(loadtx)
804+
if length(nodes.errors) > 0
805+
error(string(nodes.errors))
806+
end
807+
# Add in the relationships
808+
varRel = Symbol.(map(node -> node["row"][1], nodes.results[1]["data"]))
809+
factRel = Symbol.(map(node -> node["row"][2], nodes.results[1]["data"]))
810+
for i = 1:length(varRel)
811+
adjMat[fDict[factRel[i]], vDict[varRel[i]]] = 1
812+
end
813+
814+
return adjMat, varLabels, factLabels
815+
end
816+
804817
# """
805818
# $(SIGNATURES)
806819
# Produces a dot-format of the graph for visualization.

src/Common.jl

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export sortVarNested
1+
2+
export sortVarNested, sortDFG
23
export isPrior, lsfPriors
34
export getVariableType, getSofttype
45
export getFactorType, getfnctype
@@ -88,6 +89,24 @@ function sortVarNested(vars::Vector{Symbol})::Vector{Symbol}
8889
return retvars
8990
end
9091

92+
"""
93+
$SIGNATURES
94+
95+
Sort variable (factor) lists in a meaningful way, for example `[:april;:x1_3;:x1_6;]`
96+
97+
Notes
98+
- Not fool proof, but does better than native sort.
99+
100+
Example
101+
102+
`sortDFG(ls(dfg))`
103+
104+
Related
105+
106+
ls, lsf
107+
"""
108+
sortDFG(vars::Vector{Symbol})::Vector{Symbol} = sortVarNested(vars)
109+
91110
"""
92111
$SIGNATURES
93112

src/DFGPlots/DFGPlots.jl

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ using Colors
44
using LightGraphs
55
using MetaGraphs
66
using GraphPlot
7+
using DocStringExtensions
78
import GraphPlot: gplot
89

910
using ...DistributedFactorGraphs
@@ -28,6 +29,26 @@ DFGPlotProps() = DFGPlotProps( (var=colorant"seagreen", fac=colorant"cyan3"),
2829
true)
2930

3031

32+
33+
"""
34+
$(SIGNATURES)
35+
Plots the structure of the factor graph. GraphPlot must be imported before DistributedFactorGraphs for these functions to be available.
36+
Returns the plot context.
37+
38+
E.g.
39+
```
40+
using GraphPlot
41+
using DistributedFactorGraphs, DistributedFactorGraphs.DFGPlots
42+
# ... Make graph...
43+
# Using GraphViz plotting
44+
dfgplot(fg)
45+
# Save to PDFG
46+
using Compose
47+
draw(PDF("/tmp/graph.pdf", 16cm, 16cm), dfgplot(fg))
48+
```
49+
50+
More information at [GraphPlot.jl](https://github.com/JuliaGraphs/GraphPlot.jl)
51+
"""
3152
function dfgplot(dfg::LightDFG, p::DFGPlotProps = DFGPlotProps())
3253

3354
nodetypes = [haskey(dfg.g.variables, s) for s in dfg.g.labels]
@@ -46,8 +67,27 @@ function dfgplot(dfg::LightDFG, p::DFGPlotProps = DFGPlotProps())
4667

4768
end
4869

49-
function dfgplot(dfg::MetaGraphsDFG, p::DFGPlotProps = DFGPlotProps())
70+
"""
71+
$(SIGNATURES)
72+
Plots the structure of the factor graph. GraphPlot must be imported before DistributedFactoGraphs for these functions to be available.
73+
Returns the plot context.
5074
75+
E.g.
76+
```
77+
using GraphPlot
78+
using DistributedFactorGraphs, DistributedFactorGraphs.DFGPlots
79+
# ... Make graph...
80+
# Using GraphViz plotting
81+
dfgplot(fg)
82+
# Save to PDFG
83+
using Compose
84+
draw(PDF("/tmp/graph.pdf", 16cm, 16cm), dfgplot(fg))
85+
```
86+
87+
More information at [GraphPlot.jl](https://github.com/JuliaGraphs/GraphPlot.jl)
88+
"""
89+
function dfgplot(dfg::DistributedFactorGraphs.MetaGraphsDFG, p::DFGPlotProps = DFGPlotProps())
90+
@info "Deprecated, please use GraphsDFG or LightDFG."
5191
nodesize = [has_prop(dfg.g,i,:factor) ? p.nodesize.fac : p.nodesize.var for i=vertices(dfg.g)]
5292
if p.drawlabels
5393
nodelabel = [has_prop(dfg.g,i,:factor) ? "" : string(get_prop(dfg.g,i,:label)) for i=vertices(dfg.g)]
@@ -60,17 +100,36 @@ function dfgplot(dfg::MetaGraphsDFG, p::DFGPlotProps = DFGPlotProps())
60100

61101
end
62102

103+
"""
104+
$(SIGNATURES)
105+
Plots the structure of the factor graph. GraphPlot must be imported before DistributedFactoGraphs for these functions to be available.
106+
Returns the plot context.
107+
108+
E.g.
109+
```
110+
using GraphPlot
111+
using DistributedFactorGraphs, DistributedFactorGraphs.DFGPlots
112+
# ... Make graph...
113+
# Using GraphViz plotting
114+
dfgplot(fg)
115+
# Save to PDFG
116+
using Compose
117+
draw(PDF("/tmp/graph.pdf", 16cm, 16cm), dfgplot(fg))
118+
```
119+
120+
More information at [GraphPlot.jl](https://github.com/JuliaGraphs/GraphPlot.jl)
121+
"""
63122
function dfgplot(dfg::AbstractDFG, p::DFGPlotProps = DFGPlotProps())
64123
# TODO implement convert functions
65124
@warn "TODO Implement convert"
66-
ldfg = MetaGraphsDFG{AbstractParams}()
125+
ldfg = LightDFG{AbstractParams}()
67126
DistributedFactorGraphs._copyIntoGraph!(dfg, ldfg, union(getVariableIds(dfg), getFactorIds(dfg)), true)
68127

69128
dfgplot(ldfg, p)
70-
71129
end
72130

73-
function gplot(dfg::MetaGraphsDFG; keyargs...)
131+
function gplot(dfg::DistributedFactorGraphs.MetaGraphsDFG; keyargs...)
132+
@info "Deprecated, please use GraphsDFG or LightDFG."
74133
gplot(dfg.g; keyargs...)
75134
end
76135

src/DistributedFactorGraphs.jl

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,18 @@ using LinearAlgebra
1111
using SparseArrays
1212

1313
# Entities
14-
include("entities/AbstractTypes.jl")
14+
include("entities/AbstractDFG.jl")
1515
include("entities/DFGFactor.jl")
1616
include("entities/DFGVariable.jl")
17+
include("entities/AbstractDFGSummary.jl")
1718

1819
export AbstractDFG
1920
export AbstractParams, NoSolverParams
20-
export DFGNode
21-
22-
export DFGFactor
21+
export DFGNode, DFGVariable, DFGFactor
2322
export InferenceType, PackedInferenceType, FunctorInferenceType, InferenceVariable, ConvolutionObject
24-
2523
export FunctorSingleton, FunctorPairwise, FunctorPairwiseMinimize
26-
27-
export DFGVariable
28-
export label, timestamp, tags, estimates, estimate, solverData, getData, solverDataDict, internalId, smallData, bigData
29-
export setSolverData
30-
export label, data, id
24+
export label, timestamp, tags, estimates, estimate, data, solverData, getData, solverDataDict, setSolverData, internalId, smallData, bigData
25+
export DFGVariableSummary, DFGFactorSummary, AbstractDFGSummary
3126

3227
# Services/AbstractDFG Exports
3328
export hasFactor, hasVariable, isInitialized, getFactorFunction, isVariable, isFactor
@@ -38,13 +33,23 @@ export VariableNodeData, PackedVariableNodeData, VariableEstimate
3833
export GenericFunctionNodeData#, FunctionNodeData
3934
export getSerializationModule, setSerializationModule!
4035
export pack, unpack
36+
# Resolve with above
37+
export packVariable, unpackVariable, packFactor, unpackFactor
38+
4139

4240
#Interfaces
4341
export getAdjacencyMatrixSparse
4442

43+
# File import and export
44+
export saveDFG, loadDFG
45+
46+
# Summary functions
47+
export getSummary, getSummaryGraph
48+
4549
# Common includes
4650
include("services/AbstractDFG.jl")
4751
include("services/DFGVariable.jl")
52+
include("services/DFGFactor.jl")
4853

4954
# Include the Graphs.jl API.
5055
include("GraphsDFG/GraphsDFG.jl")
@@ -56,13 +61,11 @@ include("FileDFG/FileDFG.jl")
5661
include("MetaGraphsDFG/MetaGraphsDFG.jl")
5762

5863
include("SymbolDFG/SymbolDFG.jl")
59-
@reexport using .SymbolDFGs
64+
using .SymbolDFGs
6065

6166
include("LightDFG/LightDFG.jl")
6267
@reexport using .LightDFGs
6368

64-
export saveDFG, loadDFG
65-
6669
function __init__()
6770
@require Neo4j="d2adbeaf-5838-5367-8a2f-e46d570981db" begin
6871
# Include the Cloudgraphs API

0 commit comments

Comments
 (0)