Skip to content

Commit 6ae1537

Browse files
committed
deprecate buildSubgraphFromLabels!, getSubgraph, getSubgraphAroundNode, _copyIntoGraph!
1 parent 93314c7 commit 6ae1537

File tree

9 files changed

+293
-418
lines changed

9 files changed

+293
-418
lines changed

src/DFGPlots/DFGPlots.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ More information at [GraphPlot.jl](https://github.com/JuliaGraphs/GraphPlot.jl)
8888
function dfgplot(dfg::AbstractDFG, p::DFGPlotProps = DFGPlotProps())
8989
# TODO implement convert functions
9090
ldfg = LightDFG{NoSolverParams}()
91-
DistributedFactorGraphs._copyIntoGraph!(dfg, ldfg, union(listVariables(dfg), listFactors(dfg)), true, copyGraphMetadata=false)
91+
copyGraph!(ldfg, dfg, union(listVariables(dfg), listFactors(dfg)), copyGraphMetadata=false)
9292
dfgplot(ldfg, p)
9393
end
9494

src/Deprecated.jl

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,176 @@ function Base.convert(::Type{SkeletonDFGFactor}, f::FactorDataLevel1)
115115
Base.depwarn("convert to type SkeletonDFGFactor is deprecated use the constructor", :convert)
116116
return SkeletonDFGFactor(f)
117117
end
118+
119+
##==============================================================================
120+
## WIP on consolidated subgraph functions, aim to remove in 0.8
121+
##==============================================================================
122+
123+
"""
124+
$(SIGNATURES)
125+
Common function for copying nodes from one graph into another graph.
126+
This is overridden in specialized implementations for performance.
127+
NOTE: copyGraphMetadata not supported yet.
128+
"""
129+
function _copyIntoGraph!(sourceDFG::G, destDFG::H, variableFactorLabels::Vector{Symbol}, includeOrphanFactors::Bool=false; copyGraphMetadata::Bool=false)::Nothing where {G <: AbstractDFG, H <: AbstractDFG}
130+
# Split into variables and factors
131+
Base.depwarn("_copyIntoGraph! is deprecated use copyGraph/deepcopyGraph[!]", :_copyIntoGraph!)
132+
133+
includeOrphanFactors && (@error "Adding orphaned factors is not supported")
134+
135+
sourceVariables = map(vId->getVariable(sourceDFG, vId), intersect(listVariables(sourceDFG), variableFactorLabels))
136+
sourceFactors = map(fId->getFactor(sourceDFG, fId), intersect(listFactors(sourceDFG), variableFactorLabels))
137+
if length(sourceVariables) + length(sourceFactors) != length(variableFactorLabels)
138+
rem = symdiff(map(v->v.label, sourceVariables), variableFactorLabels)
139+
rem = symdiff(map(f->f.label, sourceFactors), variableFactorLabels)
140+
error("Cannot copy because cannot find the following nodes in the source graph: $rem")
141+
end
142+
143+
# Now we have to add all variables first,
144+
for variable in sourceVariables
145+
if !exists(destDFG, variable)
146+
addVariable!(destDFG, deepcopy(variable))
147+
end
148+
end
149+
# And then all factors to the destDFG.
150+
for factor in sourceFactors
151+
# Get the original factor variables (we need them to create it)
152+
sourceFactorVariableIds = getNeighbors(sourceDFG, factor)
153+
# Find the labels and associated variables in our new subgraph
154+
factVariableIds = Symbol[]
155+
for variable in sourceFactorVariableIds
156+
if exists(destDFG, variable)
157+
push!(factVariableIds, variable)
158+
end
159+
end
160+
# Only if we have all of them should we add it (otherwise strange things may happen on evaluation)
161+
if includeOrphanFactors || length(factVariableIds) == length(sourceFactorVariableIds)
162+
if !exists(destDFG, factor)
163+
addFactor!(destDFG, deepcopy(factor))
164+
end
165+
end
166+
end
167+
168+
if copyGraphMetadata
169+
setUserData(destDFG, getUserData(sourceDFG))
170+
setRobotData(destDFG, getRobotData(sourceDFG))
171+
setSessionData(destDFG, getSessionData(sourceDFG))
172+
end
173+
return nothing
174+
end
175+
176+
"""
177+
$(SIGNATURES)
178+
Retrieve a deep subgraph copy around a given variable or factor.
179+
Optionally provide a distance to specify the number of edges should be followed.
180+
Optionally provide an existing subgraph addToDFG, the extracted nodes will be copied into this graph. By default a new subgraph will be created.
181+
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.
182+
Note: Always returns the node at the center, but filters around it if solvable is set.
183+
"""
184+
function getSubgraphAroundNode(dfg::AbstractDFG, node::DFGNode, distance::Int=1, includeOrphanFactors::Bool=false, addToDFG::AbstractDFG=_getDuplicatedEmptyDFG(dfg); solvable::Int=0)::AbstractDFG
185+
186+
Base.depwarn("getSubgraphAroundNode is deprecated use buildSubgraph", :getSubgraphAroundNode)
187+
188+
if !exists(dfg, node.label)
189+
error("Variable/factor with label '$(node.label)' does not exist in the factor graph")
190+
end
191+
192+
neighbors = getNeighborhood(dfg, node.label, distance)
193+
194+
# for some reason: always returns the node at the center with || (nlbl == node.label)
195+
solvable != 0 && filter!(nlbl -> (getSolvable(dfg, nlbl) >= solvable) || (nlbl == node.label), neighbors)
196+
197+
# Copy the section of graph we want
198+
_copyIntoGraph!(dfg, addToDFG, neighbors, includeOrphanFactors)
199+
return addToDFG
200+
end
201+
202+
"""
203+
$(SIGNATURES)
204+
Get a deep subgraph copy from the DFG given a list of variables and factors.
205+
Optionally provide an existing subgraph addToDFG, the extracted nodes will be copied into this graph. By default a new subgraph will be created.
206+
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.
207+
"""
208+
function getSubgraph(dfg::G,
209+
variableFactorLabels::Vector{Symbol},
210+
includeOrphanFactors::Bool=false,
211+
addToDFG::H=_getDuplicatedEmptyDFG(dfg))::H where {G <: AbstractDFG, H <: AbstractDFG}
212+
213+
Base.depwarn("getSubgraph is deprecated use buildSubgraph", :getSubgraph)
214+
215+
for label in variableFactorLabels
216+
if !exists(dfg, label)
217+
error("Variable/factor with label '$(label)' does not exist in the factor graph")
218+
end
219+
end
220+
221+
_copyIntoGraph!(dfg, addToDFG, variableFactorLabels, includeOrphanFactors)
222+
return addToDFG
223+
end
224+
225+
226+
# TODO needsahome: home should be in IIF, calling just deepcopyGraph, or copyGraph
227+
# Into, Labels, Subgraph are all implied from the parameters.
228+
# can alies names but like Sam suggested only on copy is needed.
229+
230+
231+
"""
232+
$SIGNATURES
233+
Construct a new factor graph object as a subgraph of `dfg <: AbstractDFG` based on the
234+
variable labels `syms::Vector{Symbols}`.
235+
236+
SamC: Can we not just use _copyIntoGraph! for this? Looks like a small refactor to make it work.
237+
Will paste in as-is for now and we can figure it out as we go.
238+
DF: Absolutely agree that subgraph functions should use `DFG._copyIntoGraph!` as a single dependency in the code base. There have been a repeated new rewrites of IIF.buildSubGraphFromLabels (basic wrapper is fine) but nominal should be to NOT duplicate DFG functionality in IIF -- rather use/improve the existing features in DFG. FYI, I have repeatedly refactored this function over and over to use DFG properly but somehow this (add/delete/Variable/Factor) version keeps coming back without using `_copyIntoGraph`!!??? See latest effort commented out below `buildSubgraphFromLabels!_SPECIAL`...
239+
240+
Notes
241+
- Slighly messy internals, but gets the job done -- some room for performance improvement.
242+
- Defaults to GraphDFG, but likely to change to LightDFG in future.
243+
- since DFG v0.6 LightDFG is the default.
244+
245+
DevNotes
246+
- TODO: still needs to be consolidated with `DFG._copyIntoGraph`
247+
248+
Related
249+
250+
listVariables, _copyIntoGraph!
251+
"""
252+
function buildSubgraphFromLabels!(dfg::G,
253+
syms::Vector{Symbol};
254+
subfg::AbstractDFG=(G <: InMemoryDFGTypes ? G : GraphsDFG)(params=getSolverParams(dfg)),
255+
solvable::Int=0,
256+
allowedFactors::Union{Nothing, Vector{Symbol}}=nothing )::AbstractDFG where G <: AbstractDFG
257+
#
258+
Base.depwarn("buildSubgraphFromLabels! is deprecated use copyGraph, buildSubgraph or buildCliqueSubgraph!(IIF)", :buildSubgraphFromLabels!)
259+
# add a little too many variables (since we need the factors)
260+
for sym in syms
261+
if solvable <= getSolvable(dfg, sym)
262+
getSubgraphAroundNode(dfg, getVariable(dfg, sym), 2, false, subfg, solvable=solvable)
263+
end
264+
end
265+
266+
# remove excessive variables that were copied by neighbors distance 2
267+
currVars = listVariables(subfg)
268+
toDelVars = setdiff(currVars, syms)
269+
for dv in toDelVars
270+
# delete any neighboring factors first
271+
for fc in lsf(subfg, dv)
272+
deleteFactor!(subfg, fc)
273+
end
274+
275+
# and the variable itself
276+
deleteVariable!(subfg, dv)
277+
end
278+
279+
# delete any factors not in the allowed list
280+
if allowedFactors != nothing
281+
delFcts = setdiff(lsf(subfg), allowedFactors)
282+
for dfct in delFcts
283+
deleteFactor!(subfg, dfct)
284+
end
285+
end
286+
287+
# orphaned variables are allowed, but not orphaned factors
288+
289+
return subfg
290+
end

src/DistributedFactorGraphs.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export packVariableNodeData, unpackVariableNodeData
162162
export getSolvedCount, isSolved, setSolvedCount!, isInitialized
163163

164164
export getNeighborhood, getNeighbors, _getDuplicatedEmptyDFG
165-
export buildSubgraph
165+
export copyGraph!, deepcopyGraph, deepcopyGraph!, buildSubgraph
166166
# TODO Deprecate in favor of buildSubgraph
167167
export getSubgraph, getSubgraphAroundNode
168168
# Big Data
@@ -252,8 +252,6 @@ include("entities/AbstractDFGSummary.jl")
252252

253253
include("services/AbstractDFG.jl")
254254

255-
include("services/copyFunctions.jl")
256-
257255
# In Memory Types
258256
include("GraphsDFG/GraphsDFG.jl")
259257
include("LightDFG/LightDFG.jl")

src/GraphsDFG/services/GraphsDFG.jl

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ function getFactors(dfg::GraphsDFG, regexFilter::Union{Nothing, Regex}=nothing;
208208
if regexFilter != nothing
209209
factors = filter(f -> occursin(regexFilter, String(f.label)), factors)
210210
end
211-
211+
212212
if length(tags) > 0
213213
mask = map(v -> length(intersect(v.tags, tags)) > 0, factors )
214214
return factors[mask]
@@ -255,42 +255,6 @@ function getNeighbors(dfg::GraphsDFG, label::Symbol; solvable::Int=0)::Vector{Sy
255255
return map(n -> n.dfgNode.label, neighbors)
256256
end
257257

258-
#NOTE Replaced by abstract function in services/AbstractDFG.jl
259-
# """
260-
# $(SIGNATURES)
261-
# Retrieve a deep subgraph copy around a given variable or factor.
262-
# Optionally provide a distance to specify the number of edges should be followed.
263-
# Optionally provide an existing subgraph addToDFG, the extracted nodes will be copied into this graph. By default a new subgraph will be created.
264-
# 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.
265-
# """
266-
# function getSubgraphAroundNode(dfg::GraphsDFG{P}, node::T, distance::Int64=1, includeOrphanFactors::Bool=false, addToDFG::GraphsDFG=GraphsDFG{P}(); solvable::Int=0)::GraphsDFG where {P <: AbstractParams, T <: DFGNode}
267-
# if !haskey(dfg.labelDict, node.label)
268-
# error("Variable/factor with label '$(node.label)' does not exist in the factor graph")
269-
# end
270-
#
271-
# # Build a list of all unique neighbors inside 'distance'
272-
# neighborList = Dict{Symbol, Any}()
273-
# push!(neighborList, node.label => dfg.g.vertices[dfg.labelDict[node.label]])
274-
# curList = Dict{Symbol, Any}(node.label => dfg.g.vertices[dfg.labelDict[node.label]])
275-
# for dist in 1:distance
276-
# newNeighbors = Dict{Symbol, Any}()
277-
# for (key, node) in curList
278-
# neighbors = in_neighbors(node, dfg.g) #Don't use out_neighbors! It enforces directiveness even if we don't want it
279-
# for neighbor in neighbors
280-
# if !haskey(neighborList, neighbor.dfgNode.label) && (isSolvable(neighbor.dfgNode) >= solvable)
281-
# push!(neighborList, neighbor.dfgNode.label => neighbor)
282-
# push!(newNeighbors, neighbor.dfgNode.label => neighbor)
283-
# end
284-
# end
285-
# end
286-
# curList = newNeighbors
287-
# end
288-
#
289-
# # Copy the section of graph we want
290-
# _copyIntoGraph!(dfg, addToDFG, collect(keys(neighborList)), includeOrphanFactors)
291-
# return addToDFG
292-
# end
293-
294258
"""
295259
$(SIGNATURES)
296260
Produces a dot-format of the graph for visualization.

src/LightDFG/LightDFG.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module LightDFGs
33
using LightGraphs
44
using DocStringExtensions
55

6-
import ...DistributedFactorGraphs: AbstractDFG, DFGNode, AbstractDFGVariable, AbstractDFGFactor, DFGSummary, AbstractParams, NoSolverParams, DFGVariable, DFGFactor
6+
using ...DistributedFactorGraphs
7+
8+
# import ...DistributedFactorGraphs: AbstractDFG, DFGNode, AbstractDFGVariable, AbstractDFGFactor, DFGSummary, AbstractParams, NoSolverParams, DFGVariable, DFGFactor
79

810
# import DFG functions to extend
911
import ...DistributedFactorGraphs: setSolverParams!,
@@ -38,8 +40,8 @@ import ...DistributedFactorGraphs: setSolverParams!,
3840
isFullyConnected,
3941
hasOrphans,
4042
getNeighbors,
41-
getSubgraphAroundNode,
42-
getSubgraph,
43+
buildSubgraph,
44+
copyGraph!,
4345
getBiadjacencyMatrix,
4446
_getDuplicatedEmptyDFG,
4547
toDot,

src/LightDFG/services/LightDFG.jl

Lines changed: 17 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -265,76 +265,31 @@ function getNeighbors(dfg::LightDFG, label::Symbol; solvable::Int=0)::Vector{Sym
265265

266266
end
267267

268-
function _copyIntoGraph!(sourceDFG::LightDFG{<:AbstractParams, V, F}, destDFG::LightDFG{<:AbstractParams, V, F}, ns::Vector{Int}, includeOrphanFactors::Bool=false)::Nothing where {V <: AbstractDFGVariable, F <: AbstractDFGFactor}
269268

270-
includeOrphanFactors && (@error "Adding orphaned factors is not supported")
269+
# TODO copy LightDFG to LightDFG overwrite
270+
# function copyGraph!(destDFG::LightDFG,
271+
# sourceDFG::LightDFG,
272+
# variableFactorLabels::Vector{Symbol};
273+
# copyGraphMetadata::Bool=false,
274+
# overwriteDest::Bool=false,
275+
# deepcopyNodes::Bool=false,
276+
# verbose::Bool = true)
271277

272-
#kan ek die in bulk copy, soos graph en dan nuwe map maak
273-
# Add all variables first,
274-
labels = [sourceDFG.g.labels[i] for i in ns]
278+
function buildSubgraph(::Type{G}, dfg::LightDFG, variableFactorLabels::Vector{Symbol}, distance::Int=0; solvable::Int=0, kwargs...) where G <: AbstractDFG
275279

276-
for v in values(sourceDFG.g.variables)
277-
if v.label in labels
278-
exists(destDFG, v) ? (@warn "_copyIntoGraph $(v.label) exists, ignoring pending error behaviour decision") : addVariable!(destDFG, deepcopy(v))
279-
end
280-
end
280+
# find neighbors at distance to add
281+
nbhood = Int[]
281282

282-
# And then all factors to the destDFG.
283-
for f in values(sourceDFG.g.factors)
284-
if f.label in labels
285-
# Get the original factor variables (we need them to create it)
286-
neigh_ints = FactorGraphs.outneighbors(sourceDFG.g, sourceDFG.g.labels[f.label])
287-
288-
neigh_labels = [sourceDFG.g.labels[i] for i in neigh_ints]
289-
# Find the labels and associated variables in our new subgraph
290-
factVariables = V[]
291-
for v_lab in neigh_labels
292-
if haskey(destDFG.g.variables, v_lab)
293-
push!(factVariables, getVariable(destDFG, v_lab))
294-
#otherwise ignore
295-
end
296-
end
297-
298-
# Only if we have all of them should we add it (otherwise strange things may happen on evaluation)
299-
if includeOrphanFactors || length(factVariables) == length(neigh_labels)
300-
exists(destDFG, f.label) ? (@warn "_copyIntoGraph $(f.label) exists, ignoring pending error behaviour decision") : addFactor!(destDFG, deepcopy(f))
301-
end
302-
end
303-
end
304-
return nothing
305-
end
306-
307-
308-
function getSubgraphAroundNode(dfg::LightDFG{P,V,F}, node::DFGNode, distance::Int64=1, includeOrphanFactors::Bool=false, addToDFG::LightDFG=LightDFG{P,V,F}(); solvable::Int=0)::LightDFG where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor}
309-
if !exists(dfg,node.label)
310-
error("Variable/factor with label '$(node.label)' does not exist in the factor graph")
283+
for l in variableFactorLabels
284+
union!(nbhood, neighborhood(dfg.g, dfg.g.labels[l], distance))
311285
end
312286

313-
# Get a list of all unique neighbors inside 'distance'
314-
ns = neighborhood(dfg.g, dfg.g.labels[node.label], distance)
315-
# Always return the center node, skip that if we're filtering.
316-
solvable != 0 && (filter!(id -> _isSolvable(dfg, dfg.g.labels[id], solvable) || dfg.g.labels[id] == node.label, ns))
317-
287+
solvable != 0 && (filter!(id -> _isSolvable(dfg, dfg.g.labels[id], solvable), nbhood))
318288

289+
allvarfacs = [dfg.g.labels[id] for id in nbhood]
319290
# Copy the section of graph we want
320-
_copyIntoGraph!(dfg, addToDFG, ns, includeOrphanFactors)
321-
return addToDFG
322-
323-
end
324-
# dfg::LightDFG{P,V,F}
325-
# where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor}
326-
327-
function getSubgraph(dfg::LightDFG{P,V,F}, variableFactorLabels::Vector{Symbol}, includeOrphanFactors::Bool=false, addToDFG::LightDFG=LightDFG{P,V,F}())::LightDFG where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor}
328-
for label in variableFactorLabels
329-
if !exists(dfg, label)
330-
error("Variable/factor with label '$(label)' does not exist in the factor graph")
331-
end
332-
end
333-
334-
variableFactorInts = [dfg.g.labels[s] for s in variableFactorLabels]
335-
336-
_copyIntoGraph!(dfg, addToDFG, variableFactorInts, includeOrphanFactors)
337-
return addToDFG
291+
destDFG = deepcopyGraph(G, dfg, allvarfacs; kwargs...)
292+
return destDFG
338293
end
339294

340295

0 commit comments

Comments
 (0)