|
| 1 | + |
| 2 | +function _packVariable(dfg::G, v::DFGVariable)::Dict{String, Any} where G <: AbstractDFG |
| 3 | + props = Dict{String, Any}() |
| 4 | + props["label"] = string(v.label) |
| 5 | + props["timestamp"] = string(v.timestamp) |
| 6 | + props["tags"] = JSON2.write(v.tags) |
| 7 | + props["estimateDict"] = JSON2.write(v.estimateDict) |
| 8 | + props["solverDataDict"] = JSON2.write(Dict(keys(v.solverDataDict) .=> map(vnd -> pack(dfg, vnd), values(v.solverDataDict)))) |
| 9 | + props["smallData"] = JSON2.write(v.smallData) |
| 10 | + props["ready"] = v.ready |
| 11 | + props["backendset"] = v.backendset |
| 12 | + return props |
| 13 | +end |
| 14 | + |
| 15 | +function _unpackVariable(dfg::G, packedProps::Dict{String, Any})::DFGVariable where G <: AbstractDFG |
| 16 | + label = Symbol(packedProps["label"]) |
| 17 | + timestamp = DateTime(packedProps["timestamp"]) |
| 18 | + tags = JSON2.read(packedProps["tags"], Vector{Symbol}) |
| 19 | + estimateDict = JSON2.read(packedProps["estimateDict"], Dict{Symbol, VariableEstimate}) |
| 20 | + smallData = nothing |
| 21 | + smallData = JSON2.read(packedProps["smallData"], Dict{String, String}) |
| 22 | + |
| 23 | + packed = JSON2.read(packedProps["solverDataDict"], Dict{String, PackedVariableNodeData}) |
| 24 | + solverData = Dict(Symbol.(keys(packed)) .=> map(p -> unpack(dfg, p), values(packed))) |
| 25 | + |
| 26 | + # Rebuild DFGVariable |
| 27 | + variable = DFGVariable(Symbol(packedProps["label"])) |
| 28 | + variable.timestamp = timestamp |
| 29 | + variable.tags = tags |
| 30 | + variable.estimateDict = estimateDict |
| 31 | + variable.solverDataDict = solverData |
| 32 | + variable.smallData = smallData |
| 33 | + variable.ready = packedProps["ready"] |
| 34 | + variable.backendset = packedProps["backendset"] |
| 35 | + |
| 36 | + return variable |
| 37 | +end |
| 38 | + |
| 39 | +function _packFactor(dfg::G, f::DFGFactor)::Dict{String, Any} where G <: AbstractDFG |
| 40 | + # Construct the properties to save |
| 41 | + props = Dict{String, Any}() |
| 42 | + props["label"] = string(f.label) |
| 43 | + props["tags"] = JSON2.write(f.tags) |
| 44 | + # Pack the node data |
| 45 | + fnctype = f.data.fnc.usrfnc! |
| 46 | + packtype = getfield(_getmodule(fnctype), Symbol("Packed$(_getname(fnctype))")) |
| 47 | + packed = convert(PackedFunctionNodeData{packtype}, f.data) |
| 48 | + props["data"] = JSON2.write(packed) |
| 49 | + # Include the type |
| 50 | + props["fnctype"] = String(_getname(fnctype)) |
| 51 | + props["_variableOrderSymbols"] = JSON2.write(f._variableOrderSymbols) |
| 52 | + props["backendset"] = f.backendset |
| 53 | + props["ready"] = f.ready |
| 54 | + |
| 55 | + return props |
| 56 | +end |
| 57 | + |
| 58 | + |
| 59 | +function _unpackFactor(dfg::G, packedProps::Dict{String, Any}, iifModule)::DFGFactor where G <: AbstractDFG |
| 60 | + label = packedProps["label"] |
| 61 | + tags = JSON2.read(packedProps["tags"], Vector{Symbol}) |
| 62 | + |
| 63 | + data = packedProps["data"] |
| 64 | + datatype = packedProps["fnctype"] |
| 65 | + packtype = getfield(Main, Symbol("Packed"*datatype)) |
| 66 | + packed = JSON2.read(data, GenericFunctionNodeData{packtype,String}) |
| 67 | + fullFactor = iifModule.decodePackedType(dfg, packed) |
| 68 | + # fullFactor = dfg.decodePackedTypeFunc(dfg, packed) |
| 69 | + |
| 70 | + # Include the type |
| 71 | + _variableOrderSymbols = JSON2.read(packedProps["_variableOrderSymbols"], Vector{Symbol}) |
| 72 | + backendset = packedProps["backendset"] |
| 73 | + ready = packedProps["ready"] |
| 74 | + |
| 75 | + # Rebuild DFGVariable |
| 76 | + factor = DFGFactor{typeof(fullFactor.fnc), Symbol}(Symbol(label)) |
| 77 | + factor.tags = tags |
| 78 | + factor.data = fullFactor |
| 79 | + factor._variableOrderSymbols = _variableOrderSymbols |
| 80 | + factor.ready = ready |
| 81 | + factor.backendset = backendset |
| 82 | + |
| 83 | + # GUARANTEED never to bite us in the ass in the future... |
| 84 | + # ... TODO: refactor if changed: https://github.com/JuliaRobotics/IncrementalInference.jl/issues/350 |
| 85 | + getData(factor).fncargvID = _variableOrderSymbols |
| 86 | + |
| 87 | + # Note, once inserted, you still need to call IIF.rebuildFactorMetadata! |
| 88 | + return factor |
| 89 | +end |
| 90 | + |
| 91 | +function saveDFG(dfg::G, folder::String) where G <: AbstractDFG |
| 92 | + variables = getVariables(dfg) |
| 93 | + factors = getFactors(dfg) |
| 94 | + varFolder = "$folder/variables" |
| 95 | + factorFolder = "$folder/factors" |
| 96 | + # Folder preparations |
| 97 | + if !isdir(folder) |
| 98 | + @info "Folder '$folder' doesn't exist, creating..." |
| 99 | + mkpath(folder) |
| 100 | + end |
| 101 | + !isdir(varFolder) && mkpath(varFolder) |
| 102 | + !isdir(factorFolder) && mkpath(factorFolder) |
| 103 | + # Clearing out the folders |
| 104 | + map(f -> rm("$varFolder/$f"), readdir(varFolder)) |
| 105 | + map(f -> rm("$factorFolder/$f"), readdir(factorFolder)) |
| 106 | + # Variables |
| 107 | + for v in variables |
| 108 | + vPacked = _packVariable(dfg, v) |
| 109 | + io = open("$varFolder/$(v.label).json", "w") |
| 110 | + JSON2.write(io, vPacked) |
| 111 | + close(io) |
| 112 | + end |
| 113 | + # Factors |
| 114 | + for f in factors |
| 115 | + fPacked = _packFactor(dfg, f) |
| 116 | + io = open("$folder/factors/$(f.label).json", "w") |
| 117 | + JSON2.write(io, fPacked) |
| 118 | + close(io) |
| 119 | + end |
| 120 | +end |
| 121 | + |
| 122 | +function loadDFG(folder::String, iifModule, dfgLoadInto::G=GraphsDFG{NoSolverParams}()) where G <: AbstractDFG |
| 123 | + variables = DFGVariable[] |
| 124 | + factors = DFGFactor[] |
| 125 | + varFolder = "$folder/variables" |
| 126 | + factorFolder = "$folder/factors" |
| 127 | + # Folder preparations |
| 128 | + !isdir(folder) && error("Can't load DFG graph - folder '$folder' doesn't exist") |
| 129 | + !isdir(varFolder) && error("Can't load DFG graph - folder '$folder' doesn't exist") |
| 130 | + !isdir(factorFolder) && error("Can't load DFG graph - folder '$folder' doesn't exist") |
| 131 | + |
| 132 | + varFiles = readdir(varFolder) |
| 133 | + factorFiles = readdir(factorFolder) |
| 134 | + for varFile in varFiles |
| 135 | + io = open("$varFolder/$varFile") |
| 136 | + packedData = JSON2.read(io, Dict{String, Any}) |
| 137 | + push!(variables, _unpackVariable(dfgLoadInto, packedData)) |
| 138 | + end |
| 139 | + @info "Loaded $(length(variables)) variables - $(map(v->v.label, variables))" |
| 140 | + @info "Inserting variables into graph..." |
| 141 | + # Adding variables |
| 142 | + map(v->addVariable!(dfgLoadInto, v), variables) |
| 143 | + |
| 144 | + for factorFile in factorFiles |
| 145 | + io = open("$factorFolder/$factorFile") |
| 146 | + packedData = JSON2.read(io, Dict{String, Any}) |
| 147 | + push!(factors, _unpackFactor(dfgLoadInto, packedData, iifModule)) |
| 148 | + end |
| 149 | + @info "Loaded $(length(variables)) factors - $(map(f->f.label, factors))" |
| 150 | + @info "Inserting factors into graph..." |
| 151 | + # # Adding factors |
| 152 | + map(f->addFactor!(dfgLoadInto, f._variableOrderSymbols, f), factors) |
| 153 | + |
| 154 | + # Finally, rebuild the CCW's for the factors to completely reinflate them |
| 155 | + @info "Rebuilding CCW's for the factors..." |
| 156 | + for factor in factors |
| 157 | + iifModule.rebuildFactorMetadata!(dfgLoadInto, factor) |
| 158 | + end |
| 159 | + |
| 160 | + return dfgLoadInto |
| 161 | +end |
0 commit comments