Skip to content

Commit 9e084ca

Browse files
committed
Merges
2 parents c5d448b + 6a4278a commit 9e084ca

File tree

29 files changed

+961
-479
lines changed

29 files changed

+961
-479
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ 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"

docs/src/func_ref.md

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

61-
### Visualization
61+
### Visualization and Plotting
6262
```@docs
6363
toDot
6464
toDotFile
65+
dfgplot
6566
```

src/CloudGraphsDFG/CloudGraphsDFG.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export getAddHistory, getDescription, getLabelDict
1717
export addVariable!, addFactor!
1818
export ls, lsf, getVariables, getFactors, getVariableIds, getFactorIds
1919
export getVariable, getFactor
20-
export updateVariable!, updateFactor!
20+
export updateVariable!, updateFactor!, updateVariableSolverData!
2121
export deleteVariable!, deleteFactor!
2222
export getAdjacencyMatrix
2323
export getNeighbors

src/CloudGraphsDFG/services/CloudGraphsDFG.jl

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ getDescription(dfg::CloudGraphsDFG) = dfg.description
6363
setDescription(dfg::CloudGraphsDFG, description::String) = dfg.description = description
6464
getAddHistory(dfg::CloudGraphsDFG) = dfg.addHistory
6565
getSolverParams(dfg::CloudGraphsDFG) = dfg.solverParams
66-
function setSolverParams(dfg::CloudGraphsDFG, solverParams::T) where T <: AbstractParams
67-
dfg.solverParams = solverParams
66+
function setSolverParams(dfg::CloudGraphsDFG, solverParams::T)::T where T <: AbstractParams
67+
return dfg.solverParams = solverParams
6868
end
6969

7070
"""
@@ -255,7 +255,7 @@ function getVariable(dfg::CloudGraphsDFG, variableId::Int64)::DFGVariable
255255
# props["label"] = Symbol(variable.label)
256256
timestamp = DateTime(props["timestamp"])
257257
tags = JSON2.read(props["tags"], Vector{Symbol})
258-
estimateDict = JSON2.read(props["estimateDict"], Dict{Symbol, VariableEstimate})
258+
estimateDict = JSON2.read(props["estimateDict"], Dict{Symbol, Dict{Symbol, VariableEstimate}})
259259
smallData = nothing
260260
smallData = JSON2.read(props["smallData"], Dict{String, String})
261261

@@ -389,6 +389,20 @@ function updateVariable!(dfg::CloudGraphsDFG, variable::DFGVariable)::DFGVariabl
389389
return variable
390390
end
391391

392+
"""
393+
$(SIGNATURES)
394+
Update solver and estimate data for a variable (variable can be from another graph).
395+
"""
396+
function updateVariableSolverData!(dfg::CloudGraphsDFG, sourceVariable::DFGVariable)::DFGVariable
397+
if !exists(dfg, sourceVariable)
398+
error("Source variable '$(sourceVariable.label)' doesn't exist in the graph.")
399+
end
400+
nodeId = _tryGetNeoNodeIdFromNodeLabel(dfg.neo4jInstance, dfg.userId, dfg.robotId, dfg.sessionId, sourceVariable.label)
401+
Neo4j.setnodeproperty(dfg.neo4jInstance.graph, nodeId, "estimateDict", JSON2.write(sourceVariable.estimateDict))
402+
Neo4j.setnodeproperty(dfg.neo4jInstance.graph, nodeId, "solverDataDict", JSON2.write(Dict(keys(sourceVariable.solverDataDict) .=> map(vnd -> pack(dfg, vnd), values(sourceVariable.solverDataDict)))))
403+
return sourceVariable
404+
end
405+
392406
"""
393407
$(SIGNATURES)
394408
Update a complete DFGFactor in the DFG.
@@ -704,25 +718,11 @@ Optionally provide a distance to specify the number of edges should be followed.
704718
Optionally provide an existing subgraph addToDFG, the extracted nodes will be copied into this graph. By default a new subgraph will be created.
705719
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.
706720
"""
707-
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
708722
distance < 1 && error("getSubgraphAroundNode() only works for distance > 0")
709723

710724
# Making a copy session if not specified
711-
if addToDFG == nothing
712-
addToDFG = _getDuplicatedEmptyDFG(dfg)
713-
end
714-
715-
# Thank you Neo4j for 0..* awesomeness!!
716-
neighborList = _getLabelsFromCyphonQuery(dfg.neo4jInstance, "(n:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId):$(node.label))-[FACTORGRAPH*0..$distance]-(node:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId))")
717-
718-
# Copy the section of graph we want
719-
_copyIntoGraph!(dfg, addToDFG, neighborList, includeOrphanFactors)
720-
return addToDFG
721-
end
722-
723-
function getSubgraphAroundNode(dfg::CloudGraphsDFG{<:AbstractParams}, node::DFGNode, distance::Int64, includeOrphanFactors::Bool, addToDFG::MetaGraphsDFG{AbstractParams})::AbstractDFG
724-
distance < 1 && error("getSubgraphAroundNode() only works for distance > 0")
725-
725+
#moved to parameter addToDFG::AbstractDFG=_getDuplicatedEmptyDFG(dfg)
726726

727727
# Thank you Neo4j for 0..* awesomeness!!
728728
neighborList = _getLabelsFromCyphonQuery(dfg.neo4jInstance, "(n:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId):$(node.label))-[FACTORGRAPH*0..$distance]-(node:$(dfg.userId):$(dfg.robotId):$(dfg.sessionId))")
@@ -739,11 +739,11 @@ Get a deep subgraph copy from the DFG given a list of variables and factors.
739739
Optionally provide an existing subgraph addToDFG, the extracted nodes will be copied into this graph. By default a new subgraph will be created.
740740
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.
741741
"""
742-
function getSubgraph(dfg::CloudGraphsDFG, variableFactorLabels::Vector{Symbol}, includeOrphanFactors::Bool=false, addToDFG::Union{Nothing, CloudGraphsDFG}=nothing)::CloudGraphsDFG
742+
function getSubgraph(dfg::CloudGraphsDFG,
743+
variableFactorLabels::Vector{Symbol},
744+
includeOrphanFactors::Bool=false,
745+
addToDFG::G=_getDuplicatedEmptyDFG(dfg) )::G where {G <: AbstractDFG}
743746
# Making a copy session if not specified
744-
if addToDFG == nothing
745-
addToDFG = _getDuplicatedEmptyDFG(dfg)
746-
end
747747

748748
_copyIntoGraph!(dfg, addToDFG, variableFactorLabels, includeOrphanFactors)
749749

@@ -787,6 +787,33 @@ function getAdjacencyMatrix(dfg::CloudGraphsDFG)::Matrix{Union{Nothing, Symbol}}
787787
return adjMat
788788
end
789789

790+
function getAdjacencyMatrixSparse(dfg::CloudGraphsDFG)::Tuple{SparseMatrixCSC, Vector{Symbol}, Vector{Symbol}}
791+
varLabels = getVariableIds(dfg)
792+
factLabels = sort(getFactorIds(dfg))
793+
vDict = Dict(varLabels .=> [1:length(varLabels)...].+1)
794+
fDict = Dict(factLabels .=> [1:length(factLabels)...].+1)
795+
796+
adjMat = spzeros(Int, length(factLabels)+1, length(varLabels)+1)
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+
790817
# """
791818
# $(SIGNATURES)
792819
# Produces a dot-format of the graph for visualization.

src/Common.jl

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11

2-
export sortVarNested
2+
export sortVarNested, sortDFG
33
export isPrior, lsfPriors
4-
export getData
54
export getVariableType, getSofttype
65
export getFactorType, getfnctype
76
export lsTypes, lsfTypes
87
export lsWho, lsfWho
98

9+
## Utility functions for getting type names and modules (from IncrementalInference)
10+
function _getmodule(t::T) where T
11+
T.name.module
12+
end
13+
function _getname(t::T) where T
14+
T.name.name
15+
end
16+
1017
"""
1118
$(SIGNATURES)
1219
Test if all elements of the string is a number: Ex, "123" is true, "1_2" is false.
@@ -85,10 +92,20 @@ end
8592
"""
8693
$SIGNATURES
8794
88-
Retrieve data structure stored in a node.
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
89107
"""
90-
getData(v::DFGFactor)::GenericFunctionNodeData = v.data
91-
getData(v::DFGVariable; solveKey::Symbol=:default)::VariableNodeData = v.solverDataDict[solveKey]
108+
sortDFG(vars::Vector{Symbol})::Vector{Symbol} = sortVarNested(vars)
92109

93110
"""
94111
$SIGNATURES
@@ -232,10 +249,38 @@ function lsTypes(dfg::G)::Dict{Symbol, Vector{String}} where G <: AbstractDFG
232249
end
233250

234251

252+
function ls(dfg::G, ::Type{T}; solveKey::Symbol=:default) where {G <: AbstractDFG, T <: InferenceVariable}
253+
xx = getVariables(dfg)
254+
mask = getVariableType.(xx, solveKey=solveKey) .|> typeof .== T
255+
vxx = view(xx, mask)
256+
map(x->x.label, vxx)
257+
end
258+
259+
260+
function ls(dfg::G, ::Type{T}) where {G <: AbstractDFG, T <: FunctorInferenceType}
261+
xx = getFactors(dfg)
262+
names = getfield.(typeof.(getFactorType.(xx)), :name) .|> Symbol
263+
vxx = view(xx, names .== Symbol(T))
264+
map(x->x.label, vxx)
265+
end
266+
267+
function lsf(dfg::G, ::Type{T}) where {G <: AbstractDFG, T <: FunctorInferenceType}
268+
ls(dfg, T)
269+
end
270+
271+
235272
"""
236273
$(SIGNATURES)
237274
Gives back all factor labels that fit the bill:
238275
lsWho(dfg, :Pose3)
276+
277+
Dev Notes
278+
- Cloud versions will benefit from less data transfer
279+
- `ls(dfg::C, ::T) where {C <: CloudDFG, T <: ..}`
280+
281+
Related
282+
283+
ls, lsf, lsfPriors
239284
"""
240285
function lsWho(dfg::AbstractDFG, type::Symbol; solveKey::Symbol=:default)::Vector{Symbol}
241286
vars = getVariables(dfg)
@@ -252,6 +297,14 @@ end
252297
$(SIGNATURES)
253298
Gives back all factor labels that fit the bill:
254299
lsfWho(dfg, :Point2Point2)
300+
301+
Dev Notes
302+
- Cloud versions will benefit from less data transfer
303+
- `ls(dfg::C, ::T) where {C <: CloudDFG, T <: ..}`
304+
305+
Related
306+
307+
ls, lsf, lsfPriors
255308
"""
256309
function lsfWho(dfg::AbstractDFG, type::Symbol)::Vector{Symbol}
257310
facs = getFactors(dfg)

src/DFGPlots/DFGPlots.jl

Lines changed: 59 additions & 1 deletion
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 DistributedFactoGraphs 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,6 +67,25 @@ function dfgplot(dfg::LightDFG, p::DFGPlotProps = DFGPlotProps())
4667

4768
end
4869

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.
74+
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+
"""
4989
function dfgplot(dfg::MetaGraphsDFG, p::DFGPlotProps = DFGPlotProps())
5090

5191
nodesize = [has_prop(dfg.g,i,:factor) ? p.nodesize.fac : p.nodesize.var for i=vertices(dfg.g)]
@@ -60,14 +100,32 @@ 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"
66125
ldfg = MetaGraphsDFG{AbstractParams}()
67126
DistributedFactorGraphs._copyIntoGraph!(dfg, ldfg, union(getVariableIds(dfg), getFactorIds(dfg)), true)
68127

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

73131
function gplot(dfg::MetaGraphsDFG; keyargs...)

src/DistributedFactorGraphs.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ export InferenceType, PackedInferenceType, FunctorInferenceType, InferenceVariab
2525
export FunctorSingleton, FunctorPairwise, FunctorPairwiseMinimize
2626

2727
export DFGVariable
28-
export label, timestamp, tags, estimates, estimate, solverData, solverDataDict, id, smallData, bigData
28+
export label, timestamp, tags, estimates, estimate, solverData, getData, solverDataDict, internalId, smallData, bigData
2929
export setSolverData
3030
export label, data, id
3131

32+
# Services/AbstractDFG Exports
33+
export hasFactor, hasVariable, isInitialized, getFactorFunction, isVariable, isFactor
34+
export updateGraphSolverData!
35+
3236
# Solver (IIF) Exports
3337
export VariableNodeData, PackedVariableNodeData, VariableEstimate
3438
export GenericFunctionNodeData#, FunctionNodeData
@@ -38,6 +42,9 @@ export pack, unpack
3842
#Interfaces
3943
export getAdjacencyMatrixSparse
4044

45+
# File import and export
46+
export saveDFG, loadDFG
47+
4148
# Common includes
4249
include("services/AbstractDFG.jl")
4350
include("services/DFGVariable.jl")
@@ -57,8 +64,6 @@ include("SymbolDFG/SymbolDFG.jl")
5764
include("LightDFG/LightDFG.jl")
5865
@reexport using .LightDFGs
5966

60-
export saveDFG, loadDFG
61-
6267
function __init__()
6368
@require Neo4j="d2adbeaf-5838-5367-8a2f-e46d570981db" begin
6469
# Include the Cloudgraphs API
@@ -72,9 +77,7 @@ function __init__()
7277

7378
end
7479

75-
76-
# not sure where to put
80+
# To be moved as necessary.
7781
include("Common.jl")
78-
include("NeedsAHome.jl")
7982

8083
end

0 commit comments

Comments
 (0)