Skip to content

Commit 6ae3c88

Browse files
authored
Merge pull request #893 from JuliaRobotics/22Q3/enh/dsrzvargql
deseriaize variable on dicts or vectors
2 parents 0d783b5 + fc9dca4 commit 6ae3c88

File tree

8 files changed

+141
-94
lines changed

8 files changed

+141
-94
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ ManifoldsBase = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb"
1717
Neo4j = "d2adbeaf-5838-5367-8a2f-e46d570981db"
1818
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
1919
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
20+
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
2021
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
2122
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
2223
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"

src/DistributedFactorGraphs.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ import ManifoldsBase
3636
import ManifoldsBase: AbstractManifold, manifold_dimension
3737
export AbstractManifold, manifold_dimension
3838

39+
import RecursiveArrayTools: ArrayPartition
40+
export ArrayPartition
41+
3942
import Base: getindex
4043

4144

src/Neo4jDFG/Neo4jDFG.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ import ...DistributedFactorGraphs: setSolverParams!,
8787
addDataEntry!,
8888
updateDataEntry!,
8989
deleteDataEntry!,
90-
_getDFGVersion
90+
_getDFGVersion,
91+
_unpackPPE,
92+
_unpackVariableNodeData
9193

9294
using Neo4j
9395
using Base64

src/Neo4jDFG/services/Neo4jDFG.jl

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -530,32 +530,13 @@ end
530530

531531
### PPE CRUD
532532

533-
"""
534-
$(SIGNATURES)
535-
Unpack a Dict{String, Any} into a PPE.
536-
"""
537-
function _unpackPPE(dfg::G, packedPPE::Dict{String, Any})::AbstractPointParametricEst where G <: AbstractDFG
538-
# Cleanup Zoned timestamp, which is always UTC
539-
if packedPPE["lastUpdatedTimestamp"][end] == 'Z'
540-
packedPPE["lastUpdatedTimestamp"] = packedPPE["lastUpdatedTimestamp"][1:end-1]
541-
end
542-
543-
!haskey(packedPPE, "_type") && error("Cannot find type key '_type' in packed PPE data")
544-
type = pop!(packedPPE, "_type")
545-
(type === nothing || type == "") && error("Cannot deserialize PPE, type key is empty")
546-
ppe = Unmarshal.unmarshal(
547-
DistributedFactorGraphs.getTypeFromSerializationModule(dfg, Symbol(type)),
548-
packedPPE)
549-
return ppe
550-
end
551-
552533
function listPPEs(dfg::Neo4jDFG, variablekey::Symbol; currentTransaction::Union{Nothing, Neo4j.Transaction}=nothing)::Vector{Symbol}
553534
return _listVarSubnodesForType(dfg, variablekey, MeanMaxPPE, "solveKey"; currentTransaction=currentTransaction)
554535
end
555536

556537
function getPPE(dfg::Neo4jDFG, variablekey::Symbol, ppekey::Symbol=:default; currentTransaction::Union{Nothing, Neo4j.Transaction}=nothing)::AbstractPointParametricEst
557538
properties = _getVarSubnodeProperties(dfg, variablekey, MeanMaxPPE, ppekey; currentTransaction=currentTransaction)
558-
return _unpackPPE(dfg, properties)
539+
return _unpackPPE(properties)
559540
end
560541

561542
function _generateAdditionalProperties(variableType::ST, ppe::P)::Dict{String, String} where {P <: AbstractPointParametricEst, ST <: InferenceVariable}
@@ -594,7 +575,7 @@ function addPPE!(dfg::Neo4jDFG,
594575
variableType = getVariableType(dfg, variablekey)
595576
# Add additional properties for the PPE
596577
addProps = _generateAdditionalProperties(variableType, ppe)
597-
return _unpackPPE(dfg, _matchmergeVariableSubnode!(
578+
return _unpackPPE(_matchmergeVariableSubnode!(
598579
dfg,
599580
variablekey,
600581
_getLabelsForInst(dfg, ppe, parentKey=variablekey),
@@ -617,7 +598,7 @@ function updatePPE!(
617598
variableType = getVariableType(dfg, variablekey, currentTransaction=currentTransaction)
618599
# Add additional properties for the PPE
619600
addProps = _generateAdditionalProperties(variableType, ppe)
620-
return _unpackPPE(dfg, _matchmergeVariableSubnode!(
601+
return _unpackPPE(_matchmergeVariableSubnode!(
621602
dfg,
622603
variablekey,
623604
_getLabelsForInst(dfg, ppe, parentKey=variablekey),
@@ -649,7 +630,7 @@ function deletePPE!(dfg::Neo4jDFG, variablekey::Symbol, ppekey::Symbol=:default;
649630
_getLabelsForType(dfg, MeanMaxPPE, parentKey=variablekey),
650631
ppekey,
651632
currentTransaction=currentTransaction)
652-
return _unpackPPE(dfg, props)
633+
return _unpackPPE(props)
653634
end
654635

655636
## DataEntry CRUD
@@ -747,15 +728,6 @@ end
747728

748729
## VariableSolverData CRUD
749730

750-
"""
751-
$(SIGNATURES)
752-
Unpack a Dict{String, Any} into a PPE.
753-
"""
754-
function _unpackVariableNodeData(dfg::G, packedDict::Dict{String, Any})::VariableNodeData where G <: AbstractDFG
755-
packedVND = Unmarshal.unmarshal(PackedVariableNodeData, packedDict)
756-
return unpackVariableNodeData(dfg, packedVND)
757-
end
758-
759731
function listVariableSolverData(dfg::Neo4jDFG, variablekey::Symbol; currentTransaction::Union{Nothing, Neo4j.Transaction}=nothing)::Vector{Symbol}
760732
return _listVarSubnodesForType(dfg, variablekey, VariableNodeData, "solveKey"; currentTransaction=currentTransaction)
761733
end

src/entities/DFGVariable.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,13 @@ abstract type AbstractPointParametricEst end
235235
236236
Data container to store Parameteric Point Estimate (PPE) for mean and max.
237237
"""
238-
struct MeanMaxPPE <: AbstractPointParametricEst
238+
Base.@kwdef struct MeanMaxPPE <: AbstractPointParametricEst
239239
# repeat key value internally (from a design request by Sam)
240240
solveKey::Symbol
241241
suggested::Vector{Float64}
242242
max::Vector{Float64}
243243
mean::Vector{Float64}
244-
lastUpdatedTimestamp::DateTime
244+
lastUpdatedTimestamp::DateTime = now(Dates.UTC)
245245
end
246246

247247
##------------------------------------------------------------------------------

src/services/DFGVariable.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ See documentation in [Manifolds.jl on making your own](https://juliamanifolds.gi
8686
8787
Example:
8888
```
89-
DFG.@defVariable Pose2 SpecialEuclidean(2) ProductRepr([0;0.0],[1 0; 0 1.0])
89+
DFG.@defVariable Pose2 SpecialEuclidean(2) ArrayPartition([0;0.0],[1 0; 0 1.0])
9090
```
9191
"""
9292
macro defVariable(structname, manifold, point_identity)

src/services/Serialization.jl

Lines changed: 120 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,11 @@ end
7979

8080
typeModuleName(varT::Type{<:InferenceVariable}) = typeModuleName(varT())
8181

82-
function getTypeFromSerializationModule(variableTypeString::String)
82+
function getTypeFromSerializationModule(_typeString::AbstractString)
83+
@debug "DFG converting type string to Julia type" _typeString
8384
try
8485
# split the type at last `.`
85-
split_st = split(variableTypeString, r"\.(?!.*\.)")
86+
split_st = split(_typeString, r"\.(?!.*\.)")
8687
#if module is specified look for the module in main, otherwise use Main
8788
if length(split_st) == 2
8889
m = getfield(Main, Symbol(split_st[1]))
@@ -102,7 +103,7 @@ function getTypeFromSerializationModule(variableTypeString::String)
102103
return ret
103104

104105
catch ex
105-
@error "Unable to deserialize soft type $(variableTypeString)"
106+
@error "Unable to deserialize type $(_typeString)"
106107
io = IOBuffer()
107108
showerror(io, ex, catch_backtrace())
108109
err = String(take!(io))
@@ -111,6 +112,25 @@ function getTypeFromSerializationModule(variableTypeString::String)
111112
nothing
112113
end
113114

115+
"""
116+
$(SIGNATURES)
117+
Get a type from the serialization module inside DFG.
118+
"""
119+
function getTypeFromSerializationModule(dfg::G, moduleType::Symbol) where G <: AbstractDFG
120+
@warn "Deprecating getTypeFromSerializationModule(dfg,symbol), use getTypeFromSerializationModule(string) instead." maxlog=10
121+
st = nothing
122+
try
123+
st = getfield(Main, Symbol(moduleType))
124+
catch ex
125+
@error "Unable to deserialize packed variableType $(moduleType)"
126+
io = IOBuffer()
127+
showerror(io, ex, catch_backtrace())
128+
err = String(take!(io))
129+
@error(err)
130+
end
131+
return st
132+
end
133+
114134
##==============================================================================
115135
## Variable Packing and unpacking
116136
##==============================================================================
@@ -131,12 +151,69 @@ function packVariable(dfg::AbstractDFG, v::DFGVariable)
131151
return props::Dict{String, Any}
132152
end
133153

154+
"""
155+
$(SIGNATURES)
156+
157+
Common unpack a Dict{String, Any} into a PPE.
158+
"""
159+
function _unpackPPE(
160+
packedPPE::Dict{String, Any};
161+
_type = pop!(packedPPE, "_type") # required for generic use
162+
)
163+
#
164+
# Cleanup Zoned timestamp, which is always UTC
165+
if packedPPE["lastUpdatedTimestamp"][end] == 'Z'
166+
packedPPE["lastUpdatedTimestamp"] = packedPPE["lastUpdatedTimestamp"][1:end-1]
167+
end
168+
169+
# !haskey(packedPPE, "_type") && error("Cannot find type key '_type' in packed PPE data")
170+
if (_type === nothing || _type == "")
171+
@warn "Cannot deserialize PPE, unknown type key, trying DistributedFactorGraphs.MeanMaxPPE" _type
172+
_type = "DistributedFactorGraphs.MeanMaxPPE"
173+
end
174+
ppeType = getTypeFromSerializationModule(_type)
175+
176+
ppe = Unmarshal.unmarshal(
177+
ppeType,
178+
packedPPE
179+
)
180+
# _pk = Symbol(packedPPE["solveKey"])
181+
# ppe = MeanMaxPPE(;
182+
# solveKey=_pk,
183+
# suggested=float.(pd["suggested"]),
184+
# max=float.(pd["max"]),
185+
# mean=float.(pd["mean"]),
186+
# lastUpdatedTimestamp=DateTime(string(pd["lastUpdatedTimestamp"]))
187+
# )
188+
189+
return ppe
190+
end
191+
192+
"""
193+
$(SIGNATURES)
194+
195+
Unpack a Dict{String, Any} into a PPE.
196+
197+
Notes:
198+
- returns `::VariableNodeData`
199+
"""
200+
function _unpackVariableNodeData(
201+
dfg::AbstractDFG,
202+
packedDict::Dict{String, Any}
203+
)
204+
#
205+
packedVND = Unmarshal.unmarshal(PackedVariableNodeData, packedDict)
206+
return unpackVariableNodeData(dfg, packedVND)
207+
end
208+
134209
# returns a DFGVariable
135-
function unpackVariable(dfg::G,
210+
function unpackVariable(dfg::AbstractDFG,
136211
packedProps::Dict{String, Any};
137212
unpackPPEs::Bool=true,
138213
unpackSolverData::Bool=true,
139-
unpackBigData::Bool=true) where G <: AbstractDFG
214+
unpackBigData::Bool = haskey(packedProps,"dataEntryType") && haskey(packedProps, "dataEntry")
215+
)
216+
#
140217
@debug "Unpacking variable:\r\n$packedProps"
141218
# Version checking.
142219
_versionCheck(packedProps)
@@ -146,32 +223,51 @@ function unpackVariable(dfg::G,
146223
# Parse it
147224
timestamp = ZonedDateTime(packedProps["timestamp"])
148225
nstime = Nanosecond(get(packedProps, "nstime", 0))
149-
# Supporting string serialization using packVariable and CGDFG serialization (Vector{String})
150-
if packedProps["tags"] isa String
151-
tags = JSON2.read(packedProps["tags"], Vector{Symbol})
226+
227+
# FIXME, drop nested packing, see DFG #867
228+
# string serialization using packVariable and CGDFG serialization (Vector{String})
229+
tags = if packedProps["tags"] isa String
230+
JSON2.read(packedProps["tags"], Vector{Symbol})
152231
else
153-
tags = Symbol.(packedProps["tags"])
232+
Symbol.(packedProps["tags"])
154233
end
155-
ppeDict = unpackPPEs ? JSON2.read(packedProps["ppeDict"], Dict{Symbol, MeanMaxPPE}) : Dict{Symbol, MeanMaxPPE}()
156-
smallData = JSON2.read(packedProps["smallData"], Dict{Symbol, SmallDataTypes})
157234

158-
variableTypeString = if haskey(packedProps, "softtype")
159-
# TODO Deprecate, remove in v0.12
160-
@warn "Packed field `softtype` is deprecated and replaced with `variableType`"
161-
packedProps["softtype"]
235+
# FIXME, drop nested packing, see DFG #867
236+
ppeDict = if unpackPPEs && haskey(packedProps,"ppesDict")
237+
JSON2.read(packedProps["ppeDict"], Dict{Symbol, MeanMaxPPE})
238+
elseif unpackPPEs && haskey(packedProps,"ppes") && packedProps["ppes"] isa AbstractVector
239+
# these different cases are not well covered in tests, but first fix #867
240+
# TODO dont hardcode the ppeType (which is already discovered for each entry in _updatePPE)
241+
ppedict = Dict{Symbol, MeanMaxPPE}()
242+
for pd in packedProps["ppes"]
243+
_type = get(pd, "_type", "DistributedFactorGraphs.MeanMaxPPE")
244+
ppedict[Symbol(pd["solveKey"])] = _unpackPPE(pd; _type)
245+
end
246+
ppedict
162247
else
163-
packedProps["variableType"]
248+
Dict{Symbol, MeanMaxPPE}()
164249
end
165250

251+
smallData = JSON2.read(packedProps["smallData"], Dict{Symbol, SmallDataTypes})
252+
253+
variableTypeString = packedProps["variableType"]
254+
166255
variableType = getTypeFromSerializationModule(variableTypeString)
167256
isnothing(variableType) && error("Cannot deserialize variableType '$variableTypeString' in variable '$label'")
168257
pointType = getPointType(variableType)
169258

170-
if unpackSolverData
259+
# FIXME, drop nested packing, see DFG #867
260+
solverData = if unpackSolverData && haskey(packedProps, "solverDataDict")
171261
packed = JSON2.read(packedProps["solverDataDict"], Dict{String, PackedVariableNodeData})
172-
solverData = Dict{Symbol, VariableNodeData{variableType, pointType}}(Symbol.(keys(packed)) .=> map(p -> unpackVariableNodeData(dfg, p), values(packed)))
262+
Dict{Symbol, VariableNodeData{variableType, pointType}}(Symbol.(keys(packed)) .=> map(p -> unpackVariableNodeData(dfg, p), values(packed)))
263+
elseif unpackPPEs && haskey(packedProps,"solverData") && packedProps["solverData"] isa AbstractVector
264+
solverdict = Dict{Symbol, VariableNodeData{variableType, pointType}}()
265+
for sd in packedProps["solverData"]
266+
solverdict[Symbol(sd["solveKey"])] = _unpackVariableNodeData(dfg, sd)
267+
end
268+
solverdict
173269
else
174-
solverData = Dict{Symbol, VariableNodeData{variableType, pointType}}()
270+
Dict{Symbol, VariableNodeData{variableType, pointType}}()
175271
end
176272
# Rebuild DFGVariable using the first solver variableType in solverData
177273
# @info "dbg Serialization 171" variableType Symbol(packedProps["label"]) timestamp nstime ppeDict solverData smallData Dict{Symbol,AbstractDataEntry}() Ref(packedProps["solvable"])
@@ -191,23 +287,12 @@ function unpackVariable(dfg::G,
191287
# Now rehydrate complete DataEntry type.
192288
if unpackBigData
193289
#TODO Deprecate - for backward compatibility between v0.8 and v0.9, remove in v0.10
194-
if haskey(packedProps, "bigDataElemType")
195-
@warn "`bigDataElemType` is deprecate, please save data again with new version that uses `dataEntryType`"
196-
dataElemTypes = JSON2.read(packedProps["bigDataElemType"], Dict{Symbol, Symbol})
197-
else
198-
dataElemTypes = JSON2.read(packedProps["dataEntryType"], Dict{Symbol, Symbol})
199-
for (k,name) in dataElemTypes
200-
dataElemTypes[k] = Symbol(split(string(name), '.')[end])
201-
end
290+
dataElemTypes = JSON2.read(packedProps["dataEntryType"], Dict{Symbol, Symbol})
291+
for (k,name) in dataElemTypes
292+
dataElemTypes[k] = Symbol(split(string(name), '.')[end])
202293
end
203294

204-
#TODO Deprecate - for backward compatibility between v0.8 and v0.9, remove in v0.10
205-
if haskey(packedProps, "bigData")
206-
@warn "`bigData` is deprecate, please save data again with new version"
207-
dataIntermed = JSON2.read(packedProps["bigData"], Dict{Symbol, String})
208-
else
209-
dataIntermed = JSON2.read(packedProps["dataEntry"], Dict{Symbol, String})
210-
end
295+
dataIntermed = JSON2.read(packedProps["dataEntry"], Dict{Symbol, String})
211296

212297
for (k,bdeInter) in dataIntermed
213298
interm = JSON.parse(bdeInter)
@@ -452,20 +537,4 @@ end
452537
## Serialization
453538
##==============================================================================
454539

455-
"""
456-
$(SIGNATURES)
457-
Get a type from the serialization module inside DFG.
458-
"""
459-
function getTypeFromSerializationModule(dfg::G, moduleType::Symbol) where G <: AbstractDFG
460-
st = nothing
461-
try
462-
st = getfield(Main, Symbol(moduleType))
463-
catch ex
464-
@error "Unable to deserialize packed variableType $(moduleType)"
465-
io = IOBuffer()
466-
showerror(io, ex, catch_backtrace())
467-
err = String(take!(io))
468-
@error(err)
469-
end
470-
return st
471-
end
540+

0 commit comments

Comments
 (0)