Skip to content

Commit 8af412a

Browse files
authored
Merge pull request #230 from JuliaRobotics/feat/4Q19/fcttime
add timestamps to DFGFactor/Summary and closest functions
2 parents e5826db + c399c1f commit 8af412a

File tree

10 files changed

+336
-93
lines changed

10 files changed

+336
-93
lines changed

src/Common.jl

Lines changed: 135 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ export getFactorType, getfnctype
88
export lsTypes, lsfTypes
99
export lsWho, lsfWho
1010
export *
11+
export findClosestTimestamp, findVariableNearTimestamp
12+
export addTags!
13+
export hasTags, hasTagsNeighbors
1114

1215
*(a::Symbol, b::AbstractString)::Symbol = Symbol(string(a,b))
1316

@@ -182,21 +185,6 @@ function lsfPriors(dfg::G)::Vector{Symbol} where G <: AbstractDFG
182185
return priors
183186
end
184187

185-
"""
186-
$(SIGNATURES)
187-
188-
Variable nodes softtype information holding a variety of meta data associated with the type of variable stored in that node of the factor graph.
189-
190-
Related
191-
192-
getVariableType
193-
"""
194-
function getSofttype(vnd::VariableNodeData)
195-
return vnd.softtype
196-
end
197-
function getSofttype(v::DFGVariable; solveKey::Symbol=:default)
198-
return getSofttype(solverData(v, solveKey))
199-
end
200188

201189
"""
202190
$SIGNATURES
@@ -320,3 +308,135 @@ function lsfWho(dfg::AbstractDFG, type::Symbol)::Vector{Symbol}
320308
end
321309
return labels
322310
end
311+
312+
313+
"""
314+
$SIGNATURES
315+
316+
Find and return the closest timestamp from two sets of Tuples. Also return the minimum delta-time (`::Millisecond`) and how many elements match from the two sets are separated by the minimum delta-time.
317+
"""
318+
function findClosestTimestamp(setA::Vector{Tuple{DateTime,T}},
319+
setB::Vector{Tuple{DateTime,S}}) where {S,T}
320+
#
321+
# build matrix of delta times, ranges on rows x vars on columns
322+
DT = Array{Millisecond, 2}(undef, length(setA), length(setB))
323+
for i in 1:length(setA), j in 1:length(setB)
324+
DT[i,j] = setB[j][1] - setA[i][1]
325+
end
326+
327+
DT .= abs.(DT)
328+
329+
# absolute time differences
330+
# DTi = (x->x.value).(DT) .|> abs
331+
332+
# find the smallest element
333+
mdt = minimum(DT)
334+
corrs = findall(x->x==mdt, DT)
335+
336+
# return the closest timestamp, deltaT, number of correspondences
337+
return corrs[1].I, mdt, length(corrs)
338+
end
339+
340+
"""
341+
$SIGNATURES
342+
343+
Find and return nearest variable labels per delta time. Function will filter on `regexFilter`, `tags`, and `solvable`.
344+
345+
DevNotes:
346+
- TODO `number` should allow returning more than one for k-nearest matches.
347+
- Future versions likely will require some optimization around the internal `getVariable` call.
348+
- Perhaps a dedicated/efficient `getVariableTimestamp` for all DFG flavors.
349+
350+
Related
351+
352+
ls, getVariableIds, findClosestTimestamp
353+
"""
354+
function findVariableNearTimestamp(dfg::AbstractDFG,
355+
timest::DateTime,
356+
regexFilter::Union{Nothing, Regex}=nothing;
357+
tags::Vector{Symbol}=Symbol[],
358+
solvable::Int=0,
359+
warnDuplicate::Bool=true,
360+
number::Int=1 )::Vector{Tuple{Vector{Symbol}, Millisecond}}
361+
#
362+
# get the variable labels based on filters
363+
# syms = getVariableIds(dfg, regexFilter, tags=tags, solvable=solvable)
364+
syms = getVariableIds(dfg, regexFilter, tags=tags, solvable=solvable)
365+
# compile timestamps with label
366+
# vars = map( x->getVariable(dfg, x), syms )
367+
timeset = map(x->(getTimestamp(getVariable(dfg,x)), x), syms)
368+
mask = BitArray{1}(undef, length(syms))
369+
fill!(mask, true)
370+
371+
RET = Vector{Tuple{Vector{Symbol},Millisecond}}()
372+
SYMS = Symbol[]
373+
CORRS = 1
374+
NUMBER = number
375+
while 0 < CORRS + NUMBER
376+
# get closest
377+
link, mdt, corrs = findClosestTimestamp([(timest,0)], timeset[mask])
378+
push!(SYMS, syms[link[2]])
379+
mask[link[2]] = false
380+
CORRS = corrs-1
381+
# last match, done with this delta time
382+
if corrs == 1
383+
NUMBER -= 1
384+
push!(RET, (deepcopy(SYMS),mdt))
385+
SYMS = Symbol[]
386+
end
387+
end
388+
# warn if duplicates found
389+
# warnDuplicate && 1 < corrs ? @warn("getVariableNearTimestamp found more than one variable at $timestamp") : nothing
390+
391+
return RET
392+
end
393+
394+
"""
395+
$SIGNATURES
396+
397+
Return the tags for a variable or factor.
398+
"""
399+
function getTags(dfg::InMemoryDFGTypes, sym::Symbol)
400+
getFnc = isVariable(dfg,sym) ? getVariable : getFactor
401+
getTags(getFnc(dfg, sym))
402+
end
403+
404+
"""
405+
$SIGNATURES
406+
407+
Add tags to a variable or factor
408+
"""
409+
function addTags!(dfg::InMemoryDFGTypes, sym::Symbol, tags::Vector{Symbol})
410+
union!(getTags(getFactor(fg, sym)), tags)
411+
end
412+
413+
"""
414+
$SIGNATURES
415+
416+
Determine if the variable or factor neighbors have the `tags:;Vector{Symbol}`, and `matchAll::Bool`.
417+
"""
418+
function hasTags(dfg::InMemoryDFGTypes,
419+
sym::Symbol,
420+
tags::Vector{Symbol};
421+
matchAll::Bool=true )::Bool
422+
#
423+
alltags = getTags(dfg, sym)
424+
length(filter(x->x in alltags, tags)) >= (matchAll ? length(tags) : 1)
425+
end
426+
427+
428+
"""
429+
$SIGNATURES
430+
431+
Determine if the variable or factor neighbors have the `tags:;Vector{Symbol}`, and `matchAll::Bool`.
432+
"""
433+
function hasTagsNeighbors(dfg::InMemoryDFGTypes,
434+
sym::Symbol,
435+
tags::Vector{Symbol};
436+
matchAll::Bool=true )::Bool
437+
#
438+
# assume only variables or factors are neighbors
439+
getNeiFnc = isVariable(dfg, sym) ? getFactor : getVariable
440+
alltags = union( (ls(dfg, sym) .|> x->getTags(getNeiFnc(dfg,x)))... )
441+
length(filter(x->x in alltags, tags)) >= (matchAll ? length(tags) : 1)
442+
end

src/CommonAccessors.jl

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Common get and set methods
2+
3+
# NOTE this could be reduced with macros and function generation to even less code.
4+
5+
export getLabel, label
6+
export getTags, setTags!, tags
7+
export getTimestamp, setTimestamp!, timestamp
8+
export getInternalId, internalId
9+
10+
11+
const DataLevel0 = Union{VariableDataLevel0, FactorDataLevel0}
12+
const DataLevel1 = Union{VariableDataLevel1, FactorDataLevel1}
13+
const DataLevel2 = Union{VariableDataLevel2, FactorDataLevel2}
14+
15+
16+
"""
17+
$SIGNATURES
18+
19+
Return the label for a variable or factor.
20+
"""
21+
getLabel(v::DataLevel0) = v.label
22+
23+
"""
24+
$SIGNATURES
25+
26+
Return the label for a variable or factor.
27+
28+
DEPRECATED label -> getLabel
29+
"""
30+
function label(v::DataLevel0)
31+
@warn "Deprecated label, use getLabel instead."
32+
getLabel(v)
33+
end
34+
35+
36+
"""
37+
$SIGNATURES
38+
39+
Return the tags for a variable.
40+
"""
41+
getTags(v::DataLevel0) = v.tags
42+
43+
44+
"""
45+
$SIGNATURES
46+
47+
Return the tags for a variable.
48+
49+
DEPRECATED, tags -> getTags
50+
"""
51+
function tags(v::DataLevel0)
52+
@warn "tags deprecated, use getTags instead"
53+
getTags(v)
54+
end
55+
56+
"""
57+
$SIGNATURES
58+
59+
Set the tags for a factor.
60+
"""
61+
function setTags!(f::DataLevel0, tags::Vector{Symbol})
62+
resize!(f.tags, length(tags))
63+
f.tags .= tags
64+
end
65+
66+
67+
"""
68+
$SIGNATURES
69+
70+
Get the timestamp from a DFGFactor object.
71+
"""
72+
getTimestamp(v::DataLevel1) = v.timestamp
73+
74+
"""
75+
$SIGNATURES
76+
77+
Get the timestamp from a DFGFactor object.
78+
79+
DEPRECATED -> use getTimestamp instead.
80+
"""
81+
function timestamp(v::DataLevel1)
82+
@warn "timestamp deprecated, use getTimestamp instead"
83+
getTimestamp(v)
84+
end
85+
86+
"""
87+
$SIGNATURES
88+
89+
Set the timestamp of a DFGFactor object.
90+
"""
91+
setTimestamp!(v::DataLevel1, ts::DateTime) = v.timestamp = ts
92+
93+
94+
"""
95+
$SIGNATURES
96+
97+
Return the internal ID for a variable.
98+
"""
99+
getInternalId(v::DataLevel1) = v._internalId
100+
101+
"""
102+
$SIGNATURES
103+
104+
Return the internal ID for a variable.
105+
106+
DEPRECATED, internalId -> getInternalId
107+
"""
108+
function internalId(v::DataLevel1)
109+
@warn "Deprecated interalId, use getInternalId instead."
110+
getInternalId(v)
111+
end

src/DistributedFactorGraphs.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ export DFGNode, DFGVariable, DFGFactor, AbstractDFGVariable, AbstractDFGFactor
2222
export InferenceType, PackedInferenceType, FunctorInferenceType, InferenceVariable, ConvolutionObject
2323
export FunctorSingleton, FunctorPairwise, FunctorPairwiseMinimize
2424
export getMaxPPE, getMeanPPE, getSuggestedPPE
25-
export label, timestamp, setTimestamp!, tags, setTags!, estimates, estimate, data, softtype, solverData, getData, solverDataDict, setSolverData, setSolverData!, internalId, smallData, setSmallData!, bigData
25+
export timestamp # DEPRECATED
26+
export label, getTimestamp, setTimestamp!, tags, setTags!, estimates, estimate, data, softtype, solverData, getData, solverDataDict, setSolverData, setSolverData!, internalId, smallData, setSmallData!, bigData
2627
export DFGVariableSummary, DFGFactorSummary, AbstractDFGSummary
2728
export addBigDataEntry!, getBigDataEntry, updateBigDataEntry!, deleteBigDataEntry!, getBigDataEntries, getBigDataKeys
2829

@@ -78,6 +79,7 @@ export
7879
include("services/AbstractDFG.jl")
7980
include("services/DFGVariable.jl")
8081
include("services/DFGFactor.jl")
82+
include("CommonAccessors.jl")
8183
include("services/CompareUtils.jl")
8284

8385
# Include the Graphs.jl API.

src/entities/DFGFactor.jl

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,30 @@ mutable struct GenericFunctionNodeData{T, S}
3131
end
3232

3333
"""
34-
$(SIGNATURES)
34+
$(TYPEDEF)
35+
3536
Fundamental structure for a DFG factor.
3637
"""
3738
mutable struct DFGFactor{T, S} <: AbstractDFGFactor
3839
label::Symbol
3940
tags::Vector{Symbol}
4041
data::GenericFunctionNodeData{T, S}
4142
solvable::Int
43+
timestamp::DateTime
4244
_internalId::Int64
4345
_variableOrderSymbols::Vector{Symbol}
44-
DFGFactor{T, S}(label::Symbol) where {T, S} = new{T, S}(label, Symbol[], GenericFunctionNodeData{T, S}(), 0, 0, Symbol[])
45-
DFGFactor{T, S}(label::Symbol, _internalId::Int64) where {T, S} = new{T, S}(label, Symbol[], GenericFunctionNodeData{T, S}(), 0, _internalId, Symbol[])
46+
# TODO back to front ts and _internalId for legacy reasons
47+
DFGFactor{T, S}(label::Symbol, _internalId::Int64=0, timestamp::DateTime=now()) where {T, S} = new{T, S}(label, Symbol[], GenericFunctionNodeData{T, S}(), 0, timestamp, 0, Symbol[])
48+
# DFGFactor{T, S}(label::Symbol, _internalId::Int64) where {T, S} = new{T, S}(label, Symbol[], GenericFunctionNodeData{T, S}(), 0, now(), _internalId, Symbol[])
4649
end
4750

51+
"""
52+
$(SIGNATURES)
53+
54+
Convenience constructor for DFG factor.
55+
"""
56+
DFGFactor(label::Symbol; tags::Vector{Symbol}=Symbol[], data::GenericFunctionNodeData{T, S}=GenericFunctionNodeData{T, S}(), solvable::Int=0, timestamp::DateTime=now(), _internalId::Int64=0, _variableOrderSymbols::Vector{Symbol}=Symbol[]) where {T, S} = DFGFactor{T,S}(label,tags,data,solvable,timestamp,_internalId,_variableOrderSymbols)
57+
4858
# Simply for convenience - don't export
4959
const PackedFunctionNodeData{T} = GenericFunctionNodeData{T, <: AbstractString}
5060
PackedFunctionNodeData(x1, x2, x3, x4, x5::S, x6::T, x7::String="", x8::Vector{Int}=Int[], x9::Int=0) where {T <: PackedInferenceType, S <: AbstractString} = GenericFunctionNodeData(x1, x2, x3, x4, x5, x6, x7, x8, x9)
@@ -76,38 +86,14 @@ end
7686
#NOTE I feel like a want to force a variableOrderSymbols
7787
SkeletonDFGFactor(label::Symbol, variableOrderSymbols::Vector{Symbol} = Symbol[]) = SkeletonDFGFactor(label, Symbol[], variableOrderSymbols)
7888

89+
90+
7991
# Accessors
8092

8193
const FactorDataLevel0 = Union{DFGFactor, DFGFactorSummary, SkeletonDFGFactor}
8294
const FactorDataLevel1 = Union{DFGFactor, DFGFactorSummary}
95+
const FactorDataLevel2 = Union{DFGFactor}
8396

84-
"""
85-
$SIGNATURES
86-
87-
Return the label for a factor.
88-
"""
89-
label(f::FactorDataLevel0) = f.label
90-
91-
"""
92-
$SIGNATURES
93-
94-
Return the tags for a variable.
95-
"""
96-
tags(f::FactorDataLevel0) = f.tags
97-
98-
"""
99-
$SIGNATURES
100-
101-
Set the tags for a factor.
102-
"""
103-
setTag!s(f::FactorDataLevel0, tags::Vector{Symbol}) = f.tags = tags
104-
105-
"""
106-
$SIGNATURES
107-
108-
Return the internal ID for a variable.
109-
"""
110-
internalId(f::FactorDataLevel1) = f._internalId
11197

11298
"""
11399
$SIGNATURES

0 commit comments

Comments
 (0)