diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index fb0c4ff7..183afbb3 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1,4 +1,4 @@ -indent = 2 +indent = 4 always_for_in = false # whitespace_typedefs = true whitespace_ops_in_indices = true diff --git a/attic/DataBlobs/FileDataEntryBlob.jl b/attic/DataBlobs/FileDataEntryBlob.jl index 57da0075..25ae2580 100644 --- a/attic/DataBlobs/FileDataEntryBlob.jl +++ b/attic/DataBlobs/FileDataEntryBlob.jl @@ -1,5 +1,4 @@ - # @generated function ==(x::BlobEntry, y::BlobEntry) # mapreduce(n -> :(x.$n == y.$n), (a,b)->:($a && $b), fieldnames(x)) # end @@ -7,13 +6,11 @@ # # getHash(entry::AbstractBlobEntry) = hex2bytes(entry.hash) - ##============================================================================== ## BlobEntry Common ##============================================================================== -blobfilename(entry::BlobEntry) = joinpath(entry.folder,"$(entry.id).dat") -entryfilename(entry::BlobEntry) = joinpath(entry.folder,"$(entry.id).json") - +blobfilename(entry::BlobEntry) = joinpath(entry.folder, "$(entry.id).dat") +entryfilename(entry::BlobEntry) = joinpath(entry.folder, "$(entry.id).json") ##============================================================================== ## BlobEntry Blob CRUD @@ -37,10 +34,10 @@ function addBlob!(dfg::AbstractDFG, entry::BlobEntry, data::Vector{UInt8}) error("Key '$(entry.id)' entry already exists, but no blob.") else open(blobfilename(entry), "w") do f - write(f, data) + return write(f, data) end open(entryfilename(entry), "w") do f - JSON.print(f, entry) + return JSON.print(f, entry) end # FIXME update for entry.blobId vs entry.originId return UUID(entry.id) @@ -71,11 +68,20 @@ end ## BlobEntry CRUD Helpers ##============================================================================== -function addData!(::Type{BlobEntry}, dfg::AbstractDFG, label::Symbol, key::Symbol, folder::String, blob::Vector{UInt8}, timestamp=now(localzone()); - id::UUID = uuid4(), hashfunction = sha256) +function addData!( + ::Type{BlobEntry}, + dfg::AbstractDFG, + label::Symbol, + key::Symbol, + folder::String, + blob::Vector{UInt8}, + timestamp = now(localzone()); + id::UUID = uuid4(), + hashfunction = sha256, +) fde = BlobEntry(key, id, folder, bytes2hex(hashfunction(blob)), timestamp) blobId = addBlob!(dfg, fde, blob) |> UUID - newEntry = BlobEntry(fde; id=blobId, blobId) + newEntry = BlobEntry(fde; id = blobId, blobId) de = addBlobEntry!(dfg, label, newEntry) return de # de=>db end diff --git a/attic/SerializationOld.jl b/attic/SerializationOld.jl index c60f385e..e8c74b96 100644 --- a/attic/SerializationOld.jl +++ b/attic/SerializationOld.jl @@ -10,27 +10,35 @@ using JSON import JSON.show_json import JSON.Writer: StructuralContext, JSONContext, show_json import JSON.Serializations: CommonSerialization, StandardSerialization -JSON.show_json(io::JSONContext, serialization::CommonSerialization, uuid::UUID) = print(io.io, "\"$uuid\"") - +function JSON.show_json(io::JSONContext, serialization::CommonSerialization, uuid::UUID) + return print(io.io, "\"$uuid\"") +end ## Version checking # FIXME return VersionNumber function _getDFGVersion() if haskey(Pkg.dependencies(), Base.UUID("b5cc3c7e-6572-11e9-2517-99fb8daf2f04")) - return string(Pkg.dependencies()[Base.UUID("b5cc3c7e-6572-11e9-2517-99fb8daf2f04")].version) |> VersionNumber + return string( + Pkg.dependencies()[Base.UUID("b5cc3c7e-6572-11e9-2517-99fb8daf2f04")].version, + ) |> VersionNumber else # This is arguably slower, but needed for Travis. - return Pkg.TOML.parse(read(joinpath(dirname(pathof(@__MODULE__)), "..", "Project.toml"), String))["version"] |> VersionNumber + return Pkg.TOML.parse( + read(joinpath(dirname(pathof(@__MODULE__)), "..", "Project.toml"), String), + )["version"] |> VersionNumber end end function _versionCheck(props::Dict{String, Any}) if haskey(props, "_version") if VersionNumber(props["_version"]) < _getDFGVersion() - @warn "This data was serialized using DFG $(props["_version"]) but you have $(_getDFGVersion()) installed, there may be deserialization issues." maxlog=10 + @warn "This data was serialized using DFG $(props["_version"]) but you have $(_getDFGVersion()) installed, there may be deserialization issues." maxlog = + 10 end else - error("There isn't a version tag in this data so it's older than v0.10, deserialization expected to fail.") + error( + "There isn't a version tag in this data so it's older than v0.10, deserialization expected to fail.", + ) end end @@ -38,10 +46,10 @@ end # Regex parser that converts clauses like ":59.82-" to well formatted ":59.820-" function _fixSubseconds(a) - length(a) == 4 && return a[1:3]*".000"*a[4] - frac = a[5:length(a)-1] - frac = length(frac) > 3 ? frac[1:3] : frac*'0'^(3-length(frac)) - return a[1:4]*frac*a[length(a)] + length(a) == 4 && return a[1:3] * ".000" * a[4] + frac = a[5:(length(a) - 1)] + frac = length(frac) > 3 ? frac[1:3] : frac * '0'^(3 - length(frac)) + return a[1:4] * frac * a[length(a)] end function getStandardZDTString(stringTimestamp::String) @@ -62,20 +70,19 @@ end # Corrects any `::ZonedDateTime` fields of T in corresponding `interm::Dict` as `dateformat"yyyy-mm-ddTHH:MM:SS.ssszzz"` function standardizeZDTStrings!(T, interm::Dict) - for (name, typ) in zip(fieldnames(T), T.types) if typ <: ZonedDateTime && haskey(interm, name) namestr = string(name) interm[namestr] = getStandardZDTString(interm[namestr]) end end - nothing + return nothing end # variableType module.type string functions function typeModuleName(variableType::InferenceVariable) io = IOBuffer() - ioc = IOContext(io, :module=>DistributedFactorGraphs) + ioc = IOContext(io, :module => DistributedFactorGraphs) show(ioc, typeof(variableType)) return String(take!(io)) end @@ -97,7 +104,7 @@ function getTypeFromSerializationModule(_typeString::AbstractString) else m = Main end - noparams = split(split_st[end], r"{") + noparams = split(split_st[end], r"{") ret = if 1 < length(noparams) # fix #671, but does not work with specific module yet bidx = findfirst(r"{", split_st[end])[1] @@ -107,7 +114,7 @@ function getTypeFromSerializationModule(_typeString::AbstractString) getfield(m, Symbol(split_st[end])) end - return ret + return ret catch ex @error "Unable to deserialize type $(_typeString)" @@ -116,7 +123,7 @@ function getTypeFromSerializationModule(_typeString::AbstractString) err = String(take!(io)) @error(err) end - nothing + return nothing end ## ============================================================================= @@ -183,89 +190,91 @@ T2 = transcodeType(HardType, imd) T3 = transcodeType(HardType, iod) ``` """ -function transcodeType( - ::Type{T}, - inObj -) where T +function transcodeType(::Type{T}, inObj) where {T} # # specializations as inner functions (don't have to be inners) # these few special cases came up with examples below, note recursions _instance(S::Type, x) = S(x) _instance(S::Type{Union{Nothing, UUID}}, x::String) = UUID(x) # special case - _instance(_::Type{S}, x::S) where S = x # if ambiguous, delete and do alternative `_instance(S::Type, x) = S===Any ? x : S(x)` - _instance(S::Type{I}, x::AbstractString) where I <: Number = Base.parse(I, x) - _instance(S::Type{E}, x::AbstractVector) where E <: AbstractVector = _instance.(eltype(E),x) - _instance(S::Type{<:AbstractDict{K,V}}, x::AbstractDict) where {K,V} = (tup=(Symbol.(keys(x)) .=> _instance.(V,values(x)) ) ; S(tup...) ) + _instance(_::Type{S}, x::S) where {S} = x # if ambiguous, delete and do alternative `_instance(S::Type, x) = S===Any ? x : S(x)` + _instance(S::Type{I}, x::AbstractString) where {I <: Number} = Base.parse(I, x) + function _instance(S::Type{E}, x::AbstractVector) where {E <: AbstractVector} + return _instance.(eltype(E), x) + end + function _instance(S::Type{<:AbstractDict{K, V}}, x::AbstractDict) where {K, V} + return (tup = (Symbol.(keys(x)) .=> _instance.(V, values(x))); S(tup...)) + end # what the struct wants _types = fieldtypes(T) _names = fieldnames(T) # (closure) resolve random ordering problem - _getIdx(s::Symbol) = findfirst(x->x==s, _names) + _getIdx(s::Symbol) = findfirst(x -> x == s, _names) # (closure) create an instance of a field - makething(k::Symbol, v) = begin + makething(k::Symbol, v) = begin idx = _getIdx(k) if !isnothing(idx) # this field is in the output type and should be included k => _instance(_types[_getIdx(k)], v) else # this field should be ignored in the output type - Symbol(:VOID_,rand(1:1000000)) => nothing + Symbol(:VOID_, rand(1:1000000)) => nothing end end # zip together keys/fields and values for either dict or intermediate type _srckeys(s::AbstractDict) = keys(s) _srckeys(s) = fieldnames(typeof(s)) _srcvals(s::AbstractDict) = values(s) - _srcvals(s) = map(k->getproperty(s,k), _srckeys(s)) + _srcvals(s) = map(k -> getproperty(s, k), _srckeys(s)) # NOTE, improvement, filter extraneous fields not in _names - arr = [makething(Symbol(k),v) for (k,v) in zip(_srckeys(inObj),_srcvals(inObj))] - filter!(s->s[1] in _names, arr) + arr = [makething(Symbol(k), v) for (k, v) in zip(_srckeys(inObj), _srcvals(inObj))] + filter!(s -> s[1] in _names, arr) # create dict provided fields into a NamedTuple as a type stable "pre-struct" - nt = (;arr...) + nt = (; arr...) # use keyword constructors provided by Base.@kwdef to resolve random ordering, incomplete dicts, and defaults - T(;nt...) + return T(; nt...) end - - ##============================================================================== ## Variable Packing and unpacking ##============================================================================== -function packVariable(v::DFGVariable) +function packVariable(v::DFGVariable) props = Dict{String, Any}() props["label"] = string(v.label) - props["timestamp"] = v.timestamp + props["timestamp"] = v.timestamp props["nstime"] = v.nstime.value - props["tags"] = v.tags - props["ppeDict"] = v.ppeDict - props["solverDataDict"] = (Dict(keys(v.solverDataDict) .=> map(vnd -> packVariableNodeData(vnd), values(v.solverDataDict)))) - props["metadata"] = v.smallData + props["tags"] = v.tags + props["ppeDict"] = v.ppeDict + props["solverDataDict"] = (Dict( + keys(v.solverDataDict) .=> + map(vnd -> packVariableNodeData(vnd), values(v.solverDataDict)), + )) + props["metadata"] = v.smallData props["solvable"] = v.solvable props["variableType"] = typeModuleName(getVariableType(v)) props["dataEntry"] = (Dict(keys(v.dataDict) .=> values(v.dataDict))) # map(bde -> JSON.json(bde), values(v.dataDict)))) - props["dataEntryType"] = (Dict(keys(v.dataDict) .=> map(bde -> typeof(bde), values(v.dataDict)))) + props["dataEntryType"] = + (Dict(keys(v.dataDict) .=> map(bde -> typeof(bde), values(v.dataDict)))) props["_version"] = string(_getDFGVersion()) return props #::Dict{String, Any} end - """ $(SIGNATURES) Common unpack a Dict{String, Any} into a PPE. """ function _unpackPPE( - packedPPE::Dict{String, Any}; - _type = pop!(packedPPE, "_type") # required for generic use - ) + packedPPE::Dict{String, Any}; + _type = pop!(packedPPE, "_type"), # required for generic use +) # !haskey(packedPPE, "_type") && error("Cannot find type key '_type' in packed PPE data") if (_type === nothing || _type == "") @warn "Cannot deserialize PPE, unknown type key, trying DistributedFactorGraphs.MeanMaxPPE" _type _type = "DistributedFactorGraphs.MeanMaxPPE" end ppeType = getTypeFromSerializationModule(_type) - + pee = transcodeType.(ppeType, packedPPE) # from Dict to hard type # ppe = Unmarshal.unmarshal( # ppeType, @@ -286,17 +295,21 @@ DevNotes function unpackVariable( dfg::AbstractDFG, packedProps::Dict{String, Any}; - unpackPPEs::Bool=true, - unpackSolverData::Bool=true, - unpackBigData::Bool = haskey(packedProps,"dataEntryType") && haskey(packedProps, "dataEntry"), - skipVersionCheck::Bool=false, + unpackPPEs::Bool = true, + unpackSolverData::Bool = true, + unpackBigData::Bool = haskey(packedProps, "dataEntryType") && + haskey(packedProps, "dataEntry"), + skipVersionCheck::Bool = false, ) # @debug "Unpacking variable:\r\n$packedProps" # Version checking. !skipVersionCheck && _versionCheck(packedProps) - id = if haskey(packedProps, "id") - UUID(packedProps["id"]) else nothing end + id = if haskey(packedProps, "id") + UUID(packedProps["id"]) + else + nothing + end label = Symbol(packedProps["label"]) # Make sure that the timestamp is correctly formatted with subseconds packedProps["timestamp"] = getStandardZDTString(packedProps["timestamp"]) @@ -313,9 +326,11 @@ function unpackVariable( end # FIXME, drop nested packing, see DFG #867 - ppeDict = if unpackPPEs && haskey(packedProps,"ppesDict") + ppeDict = if unpackPPEs && haskey(packedProps, "ppesDict") JSON2.read(packedProps["ppeDict"], Dict{Symbol, MeanMaxPPE}) - elseif unpackPPEs && haskey(packedProps,"ppes") && packedProps["ppes"] isa AbstractVector + elseif unpackPPEs && + haskey(packedProps, "ppes") && + packedProps["ppes"] isa AbstractVector # these different cases are not well covered in tests, but first fix #867 # TODO dont hardcode the ppeType (which is already discovered for each entry in _updatePPE) ppedict = Dict{Symbol, MeanMaxPPE}() @@ -329,13 +344,17 @@ function unpackVariable( end smallData = if haskey(packedProps, "metadata") - if packedProps["metadata"] isa String + if packedProps["metadata"] isa String JSON2.read(packedProps["metadata"], Dict{Symbol, SmallDataTypes}) elseif packedProps["metadata"] isa Dict - Dict{Symbol, SmallDataTypes}( Symbol.(keys(packedProps["metadata"])) .=> values(packedProps["metadata"]) ) + Dict{Symbol, SmallDataTypes}( + Symbol.(keys(packedProps["metadata"])) .=> + values(packedProps["metadata"]), + ) # packedProps["metadata"] else - @warn "unknown metadata deserialization on $label, type $(typeof(packedProps["metadata"]))" maxlog=10 + @warn "unknown metadata deserialization on $label, type $(typeof(packedProps["metadata"]))" maxlog = + 10 Dict{Symbol, SmallDataTypes}() end else @@ -345,21 +364,21 @@ function unpackVariable( variableTypeString = packedProps["variableType"] variableType = getTypeFromSerializationModule(variableTypeString) - isnothing(variableType) && error("Cannot deserialize variableType '$variableTypeString' in variable '$label'") + isnothing(variableType) && + error("Cannot deserialize variableType '$variableTypeString' in variable '$label'") pointType = getPointType(variableType) - function _unpackSolverData( - packedSolverData; - oldkeys=false - ) - _ensureid!(s::Dict) = begin s["id"] = haskey(s, "id") ? s["id"] : nothing end + function _unpackSolverData(packedSolverData; oldkeys = false) + _ensureid!(s::Dict) = begin + s["id"] = haskey(s, "id") ? s["id"] : nothing + end _ensureid!(s::PackedVariableNodeData) = s packed = if packedSolverData isa String # JSON2.read(packedSolverData, Dict{String, PackedVariableNodeData}) # JSON3.read(packedSolverData, Dict{String, PackedVariableNodeData}) jdc = JSON.parse(packedSolverData) - jpvd = Dict{String,PackedVariableNodeData}() - for (k,v) in jdc + jpvd = Dict{String, PackedVariableNodeData}() + for (k, v) in jdc _ensureid!(v) jpvd[k] = transcodeType(PackedVariableNodeData, v) end @@ -373,13 +392,13 @@ function unpackVariable( # TODO deprecate, this is for DFG18 compat only packed_ = transcodeType.(PackedVariableNodeData, packedvals) # from Dict to hard type unpacked_ = map(p -> unpackVariableNodeData(p), packed_) - keys_ = oldkeys ? Symbol.(keys(packed_)) : map(s->s.solveKey, unpacked_) - Dict{Symbol, VariableNodeData{variableType, pointType}}(keys_ .=> unpacked_) + keys_ = oldkeys ? Symbol.(keys(packed_)) : map(s -> s.solveKey, unpacked_) + return Dict{Symbol, VariableNodeData{variableType, pointType}}(keys_ .=> unpacked_) end # FIXME, drop nested packing, see DFG #867 solverData = if unpackSolverData && haskey(packedProps, "solverDataDict") - _unpackSolverData(packedProps["solverDataDict"]; oldkeys=false) + _unpackSolverData(packedProps["solverDataDict"]; oldkeys = false) elseif unpackSolverData && haskey(packedProps, "solverData") _unpackSolverData(packedProps["solverData"]) else @@ -388,19 +407,19 @@ function unpackVariable( # Rebuild DFGVariable using the first solver variableType in solverData # @info "dbg Serialization 171" variableType Symbol(packedProps["label"]) timestamp nstime ppeDict solverData smallData Dict{Symbol,AbstractBlobEntry}() Ref(packedProps["solvable"]) # variable = DFGVariable{variableType}(Symbol(packedProps["label"]), timestamp, nstime, Set(tags), ppeDict, solverData, smallData, Dict{Symbol,AbstractBlobEntry}(), Ref(packedProps["solvable"])) - + variable = DFGVariable{variableType}(; id, - label = Symbol(packedProps["label"]), + label = Symbol(packedProps["label"]), # variableType = variableType, - timestamp, - nstime, - tags = Set{Symbol}(tags_), - ppeDict, - solverDataDict = solverData, - smallData= smallData, - dataDict = Dict{Symbol,AbstractBlobEntry}(), - solvable = Ref(Int(packedProps["solvable"])) + timestamp, + nstime, + tags = Set{Symbol}(tags_), + ppeDict, + solverDataDict = solverData, + smallData = smallData, + dataDict = Dict{Symbol, AbstractBlobEntry}(), + solvable = Ref(Int(packedProps["solvable"])), ) # @@ -411,36 +430,40 @@ function unpackVariable( JSON2.read(packedProps["dataEntryType"], Dict{Symbol, String}) else # packedProps["dataEntryType"] - Dict{Symbol, String}( Symbol.(keys(packedProps["dataEntryType"])) .=> values(packedProps["dataEntryType"]) ) + Dict{Symbol, String}( + Symbol.(keys(packedProps["dataEntryType"])) .=> + values(packedProps["dataEntryType"]), + ) end - for (k,name) in dataElemTypes + for (k, name) in dataElemTypes val = split(string(name), '.')[end] dataElemTypes[k] = val end - + dataIntermed = if packedProps["dataEntry"] isa String JSON2.read(packedProps["dataEntry"], Dict{Symbol, String}) elseif packedProps["dataEntry"] isa NamedTuple # case where JSON2 did unpacking of all fields as hard types (no longer String) # Dict{Symbol, String}( Symbol.(keys(packedProps["dataEntry"])) .=> values(packedProps["dataEntry"]) ) - for i in 1:length(packedProps["dataEntry"]) + for i = 1:length(packedProps["dataEntry"]) k = keys(packedProps["dataEntry"])[i] bdeInter = values(packedProps["dataEntry"])[i] objType = getfield(DistributedFactorGraphs, Symbol(dataElemTypes[k])) # standardizeZDTStrings!(objType, bdeInter) # fullVal = Unmarshal.unmarshal(objType, bdeInter) - variable.dataDict[k] = objType(;bdeInter...) + variable.dataDict[k] = objType(; bdeInter...) end # forcefully skip, since variabe.dataDict already populated here - Dict{Symbol,String}() + Dict{Symbol, String}() else - Dict( Symbol.(keys(packedProps["dataEntry"])) .=> values(packedProps["dataEntry"]) ) + Dict(Symbol.(keys(packedProps["dataEntry"])) .=> + values(packedProps["dataEntry"])) end _doparse(s) = s _doparse(s::String) = JSON.parse(s) - for (k,bdeInter) in dataIntermed + for (k, bdeInter) in dataIntermed interm = _doparse(bdeInter) # JSON.parse(bdeInter) # bdeInter objType = getfield(DistributedFactorGraphs, Symbol(dataElemTypes[k])) standardizeZDTStrings!(objType, interm) @@ -453,32 +476,39 @@ function unpackVariable( return variable end - # returns a PackedVariableNodeData function packVariableNodeData(d::VariableNodeData{T}) where {T <: InferenceVariable} - @debug "Dispatching conversion variable -> packed variable for type $(string(d.variableType))" - castval = if 0 < length(d.val) - precast = getCoordinates.(T, d.val) - @cast castval[i,j] := precast[j][i] - castval - else - zeros(1,0) - end - _val = castval[:] - return PackedVariableNodeData(d.id, _val, size(castval,1), - d.bw[:], size(d.bw,1), - d.BayesNetOutVertIDs, - d.dimIDs, d.dims, d.eliminated, - d.BayesNetVertID, d.separator, - typeModuleName(d.variableType), - d.initialized, - d.infoPerCoord, - d.ismargin, - d.dontmargin, - d.solveInProgress, - d.solvedCount, - d.solveKey, - string(_getDFGVersion())) + @debug "Dispatching conversion variable -> packed variable for type $(string(d.variableType))" + castval = if 0 < length(d.val) + precast = getCoordinates.(T, d.val) + @cast castval[i, j] := precast[j][i] + castval + else + zeros(1, 0) + end + _val = castval[:] + return PackedVariableNodeData( + d.id, + _val, + size(castval, 1), + d.bw[:], + size(d.bw, 1), + d.BayesNetOutVertIDs, + d.dimIDs, + d.dims, + d.eliminated, + d.BayesNetVertID, + d.separator, + typeModuleName(d.variableType), + d.initialized, + d.infoPerCoord, + d.ismargin, + d.dontmargin, + d.solveInProgress, + d.solvedCount, + d.solveKey, + string(_getDFGVersion()), + ) end function unpackVariableNodeData(d::PackedVariableNodeData) @@ -487,56 +517,56 @@ function unpackVariableNodeData(d::PackedVariableNodeData) # TODO deprecated remove in v0.11 - for backward compatibility for saved variableTypes. ststring = string(split(d.variableType, "(")[1]) T = getTypeFromSerializationModule(ststring) - isnothing(T) && error("The variable doesn't seem to have a variableType. It needs to set up with an InferenceVariable from IIF. This will happen if you use DFG to add serialized variables directly and try use them. Please use IncrementalInference.addVariable().") - + isnothing(T) && error( + "The variable doesn't seem to have a variableType. It needs to set up with an InferenceVariable from IIF. This will happen if you use DFG to add serialized variables directly and try use them. Please use IncrementalInference.addVariable().", + ) + r3 = d.dimval - c3 = r3 > 0 ? floor(Int,length(d.vecval)/r3) : 0 - M3 = reshape(d.vecval,r3,c3) - @cast val_[j][i] := M3[i,j] + c3 = r3 > 0 ? floor(Int, length(d.vecval) / r3) : 0 + M3 = reshape(d.vecval, r3, c3) + @cast val_[j][i] := M3[i, j] vals = Vector{getPointType(T)}(undef, length(val_)) # vals = getPoint.(T, val_) - for (i,v) in enumerate(val_) - vals[i] = getPoint(T, v) + for (i, v) in enumerate(val_) + vals[i] = getPoint(T, v) end - + r4 = d.dimbw - c4 = r4 > 0 ? floor(Int,length(d.vecbw)/r4) : 0 - BW = reshape(d.vecbw,r4,c4) + c4 = r4 > 0 ? floor(Int, length(d.vecbw) / r4) : 0 + BW = reshape(d.vecbw, r4, c4) # return VariableNodeData{T, getPointType(T)}( d.id, - vals, - BW, + vals, + BW, Symbol.(d.BayesNetOutVertIDs), - d.dimIDs, - d.dims, - d.eliminated, - Symbol(d.BayesNetVertID), + d.dimIDs, + d.dims, + d.eliminated, + Symbol(d.BayesNetVertID), Symbol.(d.separator), - T(), - d.initialized, - d.infoPerCoord, - d.ismargin, - d.dontmargin, - d.solveInProgress, - d.solvedCount, + T(), + d.initialized, + d.infoPerCoord, + d.ismargin, + d.dontmargin, + d.solveInProgress, + d.solvedCount, Symbol(d.solveKey), - Dict{Symbol,Threads.Condition}() ) + Dict{Symbol, Threads.Condition}(), + ) end ##============================================================================== ## Factor Packing and unpacking ##============================================================================== - -function _packSolverData( - f::DFGFactor, - fnctype::AbstractFactor) +function _packSolverData(f::DFGFactor, fnctype::AbstractFactor) # packtype = convertPackedType(fnctype) try - packed = convert( PackedFunctionNodeData{packtype}, getSolverData(f) ) + packed = convert(PackedFunctionNodeData{packtype}, getSolverData(f)) packedJson = packed return packedJson catch ex @@ -557,7 +587,7 @@ function packFactor(dfg::AbstractDFG, f::DFGFactor) props["timestamp"] = string(f.timestamp) props["nstime"] = f.nstime.value props["tags"] = f.tags - props["metadata"] = f.smallData + props["metadata"] = f.smallData # Pack the node data fnctype = getSolverData(f).fnc.usrfnc! props["data"] = _packSolverData(f, fnctype) @@ -571,7 +601,12 @@ end function reconstFactorData() end -function decodePackedType(dfg::AbstractDFG, varOrder::AbstractVector{Symbol}, ::Type{T}, packeddata::GenericFunctionNodeData{PT}) where {T<:FactorOperationalMemory, PT} +function decodePackedType( + dfg::AbstractDFG, + varOrder::AbstractVector{Symbol}, + ::Type{T}, + packeddata::GenericFunctionNodeData{PT}, +) where {T <: FactorOperationalMemory, PT} # # TODO, to solve IIF 1424 # variables = map(lb->getVariable(dfg, lb), varOrder) @@ -603,7 +638,10 @@ end # end # TODO: REFACTOR THIS AS A JSON3 STRUCT DESERIALIZER. -function fncStringToData(packtype::Type{<:AbstractPackedFactor}, data::Union{String, <:NamedTuple}) +function fncStringToData( + packtype::Type{<:AbstractPackedFactor}, + data::Union{String, <:NamedTuple}, +) # Convert string to Named Tuples for kwargs fncData = data isa AbstractString ? JSON2.read(data) : data @@ -612,7 +650,7 @@ function fncStringToData(packtype::Type{<:AbstractPackedFactor}, data::Union{Str fncData.potentialused, fncData.edgeIDs, # NamedTuple args become kwargs with the splat - packtype(;fncData.fnc...), + packtype(; fncData.fnc...), fncData.multihypo, fncData.certainhypo, fncData.nullhypo, @@ -621,18 +659,28 @@ function fncStringToData(packtype::Type{<:AbstractPackedFactor}, data::Union{Str ) return packed end -fncStringToData(::Type{T}, data::PackedFunctionNodeData{T}) where {T <: AbstractPackedFactor} = data -function fncStringToData(fncType::String, data::PackedFunctionNodeData{T}) where {T <: AbstractPackedFactor} - packtype = DFG.getTypeFromSerializationModule("Packed"*fncType) +function fncStringToData( + ::Type{T}, + data::PackedFunctionNodeData{T}, +) where {T <: AbstractPackedFactor} + return data +end +function fncStringToData( + fncType::String, + data::PackedFunctionNodeData{T}, +) where {T <: AbstractPackedFactor} + packtype = DFG.getTypeFromSerializationModule("Packed" * fncType) if packtype == T data else - error("Unknown type conversion\n$(fncType)\n$packtype\n$(PackedFunctionNodeData{T})") + error( + "Unknown type conversion\n$(fncType)\n$packtype\n$(PackedFunctionNodeData{T})", + ) end end function fncStringToData(fncType::String, data::T) where {T <: AbstractPackedFactor} - packtype = DFG.getTypeFromSerializationModule("Packed"*fncType) + packtype = DFG.getTypeFromSerializationModule("Packed" * fncType) if packtype == T # || T <: packtype data else @@ -640,22 +688,24 @@ function fncStringToData(fncType::String, data::T) where {T <: AbstractPackedFac end end function fncStringToData(fncType::String, data::Union{String, <:NamedTuple}) - packtype = DFG.getTypeFromSerializationModule("Packed"*fncType) - fncStringToData(packtype, data) + packtype = DFG.getTypeFromSerializationModule("Packed" * fncType) + return fncStringToData(packtype, data) end - # Returns `::DFGFactor` function unpackFactor( - dfg::G, + dfg::G, packedProps::Dict{String, Any}; - skipVersionCheck::Bool=false -) where G <: AbstractDFG + skipVersionCheck::Bool = false, +) where {G <: AbstractDFG} # Version checking. !skipVersionCheck && _versionCheck(packedProps) - id = if haskey(packedProps, "id") && packedProps["id"] !== nothing - UUID(packedProps["id"]) else nothing end + id = if haskey(packedProps, "id") && packedProps["id"] !== nothing + UUID(packedProps["id"]) + else + nothing + end label = packedProps["label"] # various formats in which the timestamp might be stored @@ -670,7 +720,7 @@ function unpackFactor( _variableOrderSymbols = Symbol.(packedProps["_variableOrderSymbols"]) data = packedProps["data"] - if(data isa AbstractString) + if (data isa AbstractString) data = JSON2.read(data) end datatype = packedProps["fnctype"] @@ -680,7 +730,7 @@ function unpackFactor( # FIXME type instability from nothing to T packed = nothing fullFactorData = nothing - + try packed = fncStringToData(datatype, data) #convert(GenericFunctionNodeData{packtype}, data) decodeType = getFactorOperationalMemoryType(dfg) @@ -695,28 +745,33 @@ function unpackFactor( solvable = packedProps["solvable"] - smallData = haskey(packedProps, "metadata") ? Dict{Symbol, SmallDataTypes}( Symbol.(keys(packedProps["metadata"])) .=> values(packedProps["metadata"]) ) : Dict{Symbol, SmallDataTypes}() + smallData = if haskey(packedProps, "metadata") + Dict{Symbol, SmallDataTypes}( + Symbol.(keys(packedProps["metadata"])) .=> values(packedProps["metadata"]), + ) + else + Dict{Symbol, SmallDataTypes}() + end # Rebuild DFGFactor #TODO use constuctor to create factor - factor = DFGFactor( Symbol(label), - timestamp, - nstime, - Set(tags), - fullFactorData, - solvable, - Tuple(_variableOrderSymbols), - id = id, - smallData = smallData) + factor = DFGFactor( + Symbol(label), + timestamp, + nstime, + Set(tags), + fullFactorData, + solvable, + Tuple(_variableOrderSymbols); + id = id, + smallData = smallData, + ) # # Note, once inserted, you still need to call rebuildFactorMetadata! return factor end - ##============================================================================== ## Serialization ##============================================================================== - - diff --git a/attic/tests/testTranscodeTypeUnmarshaling.jl b/attic/tests/testTranscodeTypeUnmarshaling.jl index 50231608..f8d7965a 100644 --- a/attic/tests/testTranscodeTypeUnmarshaling.jl +++ b/attic/tests/testTranscodeTypeUnmarshaling.jl @@ -1,7 +1,6 @@ # test transcoding and unmarshal util - using Test using DistributedFactorGraphs using DataStructures: OrderedDict @@ -9,99 +8,94 @@ using Dates ## - Base.@kwdef struct HardType name::String time::DateTime = now(UTC) val::Float64 = 0.0 end - # # slight human overhead for each type to ignore extraneous field construction - # # TODO, devnote drop this requirement with filter of _names in transcodeType - # HardType(; - # name::String, - # time::DateTime = now(UTC), - # val::Float64 = 0.0, - # ignorekws... - # ) = HardType(name,time,val) +# # slight human overhead for each type to ignore extraneous field construction +# # TODO, devnote drop this requirement with filter of _names in transcodeType +# HardType(; +# name::String, +# time::DateTime = now(UTC), +# val::Float64 = 0.0, +# ignorekws... +# ) = HardType(name,time,val) @testset "Test transcoding of Intermediate, Dict, OrderedDict to a HardType" begin - -struct IntermediateType - _version - _type - name - time - val -end - -# somehow one gets an intermediate type -imt = IntermediateType( - v"1.0", - "NotUsedYet", - "test", - now(UTC), - 1.0 -) -# or dict (testing string keys) -imd = Dict( - "_version" => v"1.0", - "_type" => "NotUsedYet", - "name" => "test", - "time" => now(UTC), - "val" => 1.0 -) -# ordered dict (testing symbol keys) -iod = OrderedDict( - :_version => v"1.0", - :_type => "NotUsedYet", - :name => "test", - :time => now(UTC), - # :val => 1.0 -) - -# do the transcoding to a slighly different hard type -T1 = DistributedFactorGraphs.transcodeType(HardType, imt) -T2 = DistributedFactorGraphs.transcodeType(HardType, imd) -T3 = DistributedFactorGraphs.transcodeType(HardType, iod) - + struct IntermediateType + _version::Any + _type::Any + name::Any + time::Any + val::Any + end + + # somehow one gets an intermediate type + imt = IntermediateType(v"1.0", "NotUsedYet", "test", now(UTC), 1.0) + # or dict (testing string keys) + imd = Dict( + "_version" => v"1.0", + "_type" => "NotUsedYet", + "name" => "test", + "time" => now(UTC), + "val" => 1.0, + ) + # ordered dict (testing symbol keys) + iod = OrderedDict( + :_version => v"1.0", + :_type => "NotUsedYet", + :name => "test", + :time => now(UTC), + # :val => 1.0 + ) + + # do the transcoding to a slighly different hard type + T1 = DistributedFactorGraphs.transcodeType(HardType, imt) + T2 = DistributedFactorGraphs.transcodeType(HardType, imd) + T3 = DistributedFactorGraphs.transcodeType(HardType, iod) end Base.@kwdef struct MyType{T <: Real} - tags::Vector{Symbol} = Symbol[] - count::Int - funfun::Complex{T} = 1 + 5im - somedata::Dict{Symbol,Any} = Dict{Symbol, Any}() - data::Vector{Float64} = zeros(0) - binary::Vector{UInt8} = Vector{UInt8}() + tags::Vector{Symbol} = Symbol[] + count::Int + funfun::Complex{T} = 1 + 5im + somedata::Dict{Symbol, Any} = Dict{Symbol, Any}() + data::Vector{Float64} = zeros(0) + binary::Vector{UInt8} = Vector{UInt8}() end @testset "More super unmarshaling tests of various test dicts" begin + d = Dict("count" => 3) + DistributedFactorGraphs.transcodeType(MyType, d) -d = Dict("count" => 3) -DistributedFactorGraphs.transcodeType(MyType, d) - -d2 = Dict("count" => 3, "tags" => Any["hi", "okay"]) -DistributedFactorGraphs.transcodeType(MyType, d2) + d2 = Dict("count" => 3, "tags" => Any["hi", "okay"]) + DistributedFactorGraphs.transcodeType(MyType, d2) -d3 = Dict("count" => "3", "tags" => String["hi", "okay"]) -DistributedFactorGraphs.transcodeType(MyType, d3) + d3 = Dict("count" => "3", "tags" => String["hi", "okay"]) + DistributedFactorGraphs.transcodeType(MyType, d3) -d4 = Dict("count" => 3.0, "funfun" => "8 - 3im", "tags" => Any["hi", "okay"]) -DistributedFactorGraphs.transcodeType(MyType{Float32}, d4) + d4 = Dict("count" => 3.0, "funfun" => "8 - 3im", "tags" => Any["hi", "okay"]) + DistributedFactorGraphs.transcodeType(MyType{Float32}, d4) -d5 = Dict("count" => 3, "somedata" => Dict{String,Any}("calibration"=>[1.1;2.2], "description"=>"this is a test")) -DistributedFactorGraphs.transcodeType(MyType{Float64}, d5) + d5 = Dict( + "count" => 3, + "somedata" => Dict{String, Any}( + "calibration" => [1.1; 2.2], + "description" => "this is a test", + ), + ) + DistributedFactorGraphs.transcodeType(MyType{Float64}, d5) -d6 = Dict("count" => 3.0, "data" => Any[10, 60]) -DistributedFactorGraphs.transcodeType(MyType, d6) + d6 = Dict("count" => 3.0, "data" => Any[10, 60]) + DistributedFactorGraphs.transcodeType(MyType, d6) -d7 = Dict("count" => 3.0, "data" => String["10", "60"]) -DistributedFactorGraphs.transcodeType(MyType, d7) + d7 = Dict("count" => 3.0, "data" => String["10", "60"]) + DistributedFactorGraphs.transcodeType(MyType, d7) -d8 = Dict("count" => 4, "binary" => take!(IOBuffer("hello world"))) -DistributedFactorGraphs.transcodeType(MyType, d8) + d8 = Dict("count" => 4, "binary" => take!(IOBuffer("hello world"))) + DistributedFactorGraphs.transcodeType(MyType, d8) -d9 = Dict("count" => 4, "somedata" => Dict{Symbol,Any}(:test => "no ambiguity")) -DistributedFactorGraphs.transcodeType(MyType, d9) - -end \ No newline at end of file + d9 = Dict("count" => 4, "somedata" => Dict{Symbol, Any}(:test => "no ambiguity")) + DistributedFactorGraphs.transcodeType(MyType, d9) +end diff --git a/docs/make.jl b/docs/make.jl index 5f6dbf28..aeebdaa7 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,9 +1,9 @@ using Documenter using GraphPlot -push!(ENV,"DFG_USE_CGDFG"=>"true") +push!(ENV, "DFG_USE_CGDFG" => "true") using DistributedFactorGraphs -makedocs( +makedocs(; modules = [DistributedFactorGraphs], format = Documenter.HTML(), sitename = "DistributedFactorGraphs.jl", @@ -14,15 +14,15 @@ makedocs( "Building Graphs" => "BuildingGraphs.md", "Using Graph Elements" => "GraphData.md", "Drawing Graphs" => "DrawingGraphs.md", - "Quick API Reference" => "ref_api.md" + "Quick API Reference" => "ref_api.md", ], - "Function Reference" => "func_ref.md" - ] + "Function Reference" => "func_ref.md", + ], # html_prettyurls = !("local" in ARGS), - ) +) -deploydocs( - repo = "github.com/JuliaRobotics/DistributedFactorGraphs.jl.git", +deploydocs(; + repo = "github.com/JuliaRobotics/DistributedFactorGraphs.jl.git", target = "build", # deps = Deps.pip("mkdocs", "python-markdown-math") ) diff --git a/ext/DFGPlots.jl b/ext/DFGPlots.jl index 2a3975fc..89d1496c 100644 --- a/ext/DFGPlots.jl +++ b/ext/DFGPlots.jl @@ -10,26 +10,26 @@ using DistributedFactorGraphs import DistributedFactorGraphs.plotDFG -export - plotDFG, - DFGPlotProps +export plotDFG, DFGPlotProps struct DFGPlotProps - nodefillc::NamedTuple{(:var,:fac),Tuple{RGB,RGB}} - nodesize::NamedTuple{(:var,:fac),Tuple{Float64,Float64}} - shape::NamedTuple{(:var,:fac),Tuple{Symbol,Symbol}} #not upported yet + nodefillc::NamedTuple{(:var, :fac), Tuple{RGB, RGB}} + nodesize::NamedTuple{(:var, :fac), Tuple{Float64, Float64}} + shape::NamedTuple{(:var, :fac), Tuple{Symbol, Symbol}} #not upported yet layout::Function #spring_layout, spectral_layout drawlabels::Bool end -DFGPlotProps() = DFGPlotProps( (var=colorant"seagreen", fac=colorant"cyan3"), - (var=1.0, fac=0.3), - (var=:box, fac=:elipse), - spring_layout, - true) - - +function DFGPlotProps() + return DFGPlotProps( + (var = colorant"seagreen", fac = colorant"cyan3"), + (var = 1.0, fac = 0.3), + (var = :box, fac = :elipse), + spring_layout, + true, + ) +end """ $(SIGNATURES) @@ -51,47 +51,58 @@ draw(PDF("/tmp/graph.pdf", 16cm, 16cm), plotDFG(fg)) More information at [GraphPlot.jl](https://github.com/JuliaGraphs/GraphPlot.jl) """ function plotDFG(dfg::GraphsDFG, p::DFGPlotProps = DFGPlotProps()) - nodetypes = [haskey(dfg.g.variables, s) for s in dfg.g.labels] nodesize = [isVar ? p.nodesize.var : p.nodesize.fac for isVar in nodetypes] # nodelabel = [isVar ? string(get_prop(dfg.g,i,:label)) : "" for (i,isVar) in enumerate(nodetypes)] if p.drawlabels - nodelabel = [nodetypes[i] ? string(s) : "" for (i,s) in enumerate(dfg.g.labels)] + nodelabel = [nodetypes[i] ? string(s) : "" for (i, s) in enumerate(dfg.g.labels)] else nodelabel = nothing end nodefillc = [isVar ? p.nodefillc.var : p.nodefillc.fac for isVar in nodetypes] - gplot(dfg.g, nodelabel=nodelabel, nodesize=nodesize, nodefillc=nodefillc, layout=p.layout) - + return gplot( + dfg.g; + nodelabel = nodelabel, + nodesize = nodesize, + nodefillc = nodefillc, + layout = p.layout, + ) end function plotDFG(dfg::AbstractDFG, p::DFGPlotProps = DFGPlotProps()) # TODO implement convert functions ldfg = GraphsDFG{NoSolverParams}() - copyGraph!(ldfg, dfg, listVariables(dfg), listFactors(dfg), copyGraphMetadata=false) - plotDFG(ldfg, p) + copyGraph!(ldfg, dfg, listVariables(dfg), listFactors(dfg); copyGraphMetadata = false) + return plotDFG(ldfg, p) end function gplot(dfg::GraphsDFG; keyargs...) - gplot(dfg.g; keyargs...) + return gplot(dfg.g; keyargs...) end #TODO decide if we want to overload show for display in juno, It's a bit annoying with development # function Base.show(io::IO, ::MIME"application/prs.juno.plotpane+html", dfg::AbstractDFG) function plotDFG(io::IO, ::MIME"application/prs.juno.plotpane+html", dfg::AbstractDFG) - if length(ls(dfg)) != 0 size = get(io, :juno_plotsize, [100, 100]) plot_output = IOBuffer() - GraphPlot.draw(GraphPlot.SVGJS(plot_output, GraphPlot.Compose.default_graphic_width, - GraphPlot.Compose.default_graphic_width, false), plotDFG(dfg)) + GraphPlot.draw( + GraphPlot.SVGJS( + plot_output, + GraphPlot.Compose.default_graphic_width, + GraphPlot.Compose.default_graphic_width, + false, + ), + plotDFG(dfg), + ) plotsvg = String(take!(plot_output)) - print(io, + print( + io, """
$(plotsvg)
- """) + """, + ) else - Base.show(io, dfg) + Base.show(io, dfg) end - end - end diff --git a/src/Common.jl b/src/Common.jl index 00f6c21f..9345a304 100644 --- a/src/Common.jl +++ b/src/Common.jl @@ -1,16 +1,17 @@ ## Utility functions for getting type names and modules (from IncrementalInference) -_getmodule(t::T) where T = T.name.module -_getname(t::T) where T = T.name.name +_getmodule(t::T) where {T} = T.name.module +_getname(t::T) where {T} = T.name.name - -convertPackedType(t::Union{T, Type{T}}) where {T <: AbstractFactor} = getfield(_getmodule(t), Symbol("Packed$(_getname(t))")) +function convertPackedType(t::Union{T, Type{T}}) where {T <: AbstractFactor} + return getfield(_getmodule(t), Symbol("Packed$(_getname(t))")) +end function convertStructType(::Type{PT}) where {PT <: AbstractPackedFactor} # see #668 for expanded reasoning. PT may be ::UnionAll if the type is of template type. ptt = PT isa DataType ? PT.name.name : PT moduleName = PT isa DataType ? PT.name.module : Main symbolName = Symbol(string(ptt)[7:end]) - getfield(moduleName, symbolName) + return getfield(moduleName, symbolName) end ##============================================================================== @@ -22,12 +23,14 @@ end # split at digit to not digit change splitbynum(x::AbstractString) = split(x, r"(?<=\D)(?=\d)|(?<=\d)(?=\D)") #parse to Int -numstringtonum(arr::Vector{<:AbstractString}) = [(n = tryparse(Int, e)) != nothing ? n : e for e in arr] +function numstringtonum(arr::Vector{<:AbstractString}) + return [(n = tryparse(Int, e)) != nothing ? n : e for e in arr] +end #natural less than -function natural_lt(x::T, y::T) where T <: AbstractString +function natural_lt(x::T, y::T) where {T <: AbstractString} xarr = numstringtonum(splitbynum(x)) yarr = numstringtonum(splitbynum(y)) - for i in 1:min(length(xarr), length(yarr)) + for i = 1:min(length(xarr), length(yarr)) if typeof(xarr[i]) != typeof(yarr[i]) return isa(xarr[i], Int) elseif xarr[i] == yarr[i] @@ -39,7 +42,7 @@ function natural_lt(x::T, y::T) where T <: AbstractString return length(xarr) < length(yarr) end -natural_lt(x::Symbol, y::Symbol) = natural_lt(string(x),string(y)) +natural_lt(x::Symbol, y::Symbol) = natural_lt(string(x), string(y)) """ $SIGNATURES @@ -61,16 +64,25 @@ Related ls, lsf """ -sortDFG(vars::Vector{<:DFGNode}; by=getTimestamp, kwargs...) = sort(vars; by=by, kwargs...) -sortDFG(vars::Vector{Symbol}; lt=natural_lt, kwargs...) = sort(vars; lt=lt, kwargs...) +function sortDFG(vars::Vector{<:DFGNode}; by = getTimestamp, kwargs...) + return sort(vars; by = by, kwargs...) +end +sortDFG(vars::Vector{Symbol}; lt = natural_lt, kwargs...) = sort(vars; lt = lt, kwargs...) ##============================================================================== ## Validation of session, robot, and user IDs. ##============================================================================== global _invalidIds = [ - "USER", "ROBOT", "SESSION", - "VARIABLE", "FACTOR", "ENVIRONMENT", - "PPE", "DATA_ENTRY", "FACTORGRAPH"] + "USER", + "ROBOT", + "SESSION", + "VARIABLE", + "FACTOR", + "ENVIRONMENT", + "PPE", + "DATA_ENTRY", + "FACTORGRAPH", +] global _validLabelRegex = r"^[a-zA-Z][-\w\.\@]*$" @@ -83,10 +95,10 @@ function isValidLabel(id::Union{Symbol, String})::Bool if typeof(id) == Symbol id = String(id) end - return all(t -> t != uppercase(id), _invalidIds) && match(_validLabelRegex, id) !== nothing + return all(t -> t != uppercase(id), _invalidIds) && + match(_validLabelRegex, id) !== nothing end - """ $SIGNATURES @@ -104,9 +116,10 @@ DevNotes - make prefix Regex based for longer -- i.e. `:apriltag578`, `:lm1_4` """ -getVariableLabelNumber(vs::Symbol, prefix=string(vs)[1]) = parse(Int, string(vs)[(length(prefix)+1):end]) - - +function getVariableLabelNumber(vs::Symbol, prefix = string(vs)[1]) + return parse(Int, string(vs)[(length(prefix) + 1):end]) +end + ## ================================= ## Additional Downstream dispatches ## ================================= diff --git a/src/DataBlobs/entities/BlobEntry.jl b/src/DataBlobs/entities/BlobEntry.jl index e7a33753..af0ed19d 100644 --- a/src/DataBlobs/entities/BlobEntry.jl +++ b/src/DataBlobs/entities/BlobEntry.jl @@ -13,11 +13,11 @@ is also a equivalent to a bridging entry between local `.originId` and a remotel Notes: - All `.blobId`s are unique across the entire distributed system and are immutable. The `.originId` should be globally unique except for stochastic `uuid4` collisions that cannot be checked from a main reference owing to practical limitations such as network connectivity. """ -@Base.kwdef struct BlobEntry +Base.@kwdef struct BlobEntry """ Remotely assigned and globally unique identifier for the `BlobEntry` itself (not the `.blobId`). """ - id::Union{UUID, Nothing} = nothing + id::Union{UUID, Nothing} = nothing """ Machine friendly and globally unique identifier of the 'Blob', usually assigned from a common point in the system. This can be used to guarantee unique retrieval of the large data blob. """ - blobId::Union{UUID, Nothing} = nothing + blobId::Union{UUID, Nothing} = nothing """ Machine friendly and locally assigned identifier of the 'Blob'. `.originId`s are mandatory upon first creation at the origin regardless of network access. Separate from `.blobId` since some architectures do not allow edge processes to assign a uuid4 to data store elements. """ originId::UUID = uuid4() """ Human friendly label of the `Blob` and also used as unique identifier per node on which a `BlobEntry` is added. E.g. do "LEFTCAM_1", "LEFTCAM_2", ... of you need to repeat a label on the same variable. """ @@ -27,7 +27,7 @@ Notes: """ A hash value to ensure data consistency which must correspond to the stored hash upon retrieval. Use `bytes2hex(sha256(blob))`. [Legacy: some usage functions allow the check to be skipped if needed.] """ hash::String # Probably https://docs.julialang.org/en/v1/stdlib/SHA """ Context from which a BlobEntry=>Blob was first created. E.g. user|robot|session|varlabel. """ - origin::String + origin::String """ number of bytes in blob """ size::Union{Int, Nothing} = nothing """ Additional information that can help a different user of the Blob. """ @@ -39,18 +39,17 @@ Notes: """ When the Blob itself was first created. """ timestamp::ZonedDateTime = now(localzone()) """ When the BlobEntry was created. """ - createdTimestamp::Union{ZonedDateTime,Nothing} = nothing + createdTimestamp::Union{ZonedDateTime, Nothing} = nothing """ Use carefully, but necessary to support advanced usage such as time synchronization over Blob data. """ - lastUpdatedTimestamp::Union{ZonedDateTime,Nothing} = nothing + lastUpdatedTimestamp::Union{ZonedDateTime, Nothing} = nothing """ Self type declaration for when duck-typing happens. """ _type::String = "DistributedFactorGraph.BlobEntry" """ Type version of this BlobEntry. TBD.jl consider upgrading to `::VersionNumber`. """ _version::String = string(_getDFGVersion()) end - StructTypes.StructType(::Type{BlobEntry}) = StructTypes.UnorderedStruct() StructTypes.idproperty(::Type{BlobEntry}) = :id StructTypes.omitempties(::Type{BlobEntry}) = (:id,) -_fixtimezone(cts::NamedTuple) = ZonedDateTime(cts.utc_datetime*"+00") +_fixtimezone(cts::NamedTuple) = ZonedDateTime(cts.utc_datetime * "+00") diff --git a/src/DataBlobs/entities/BlobStores.jl b/src/DataBlobs/entities/BlobStores.jl index fcc656b9..3b5e04d2 100644 --- a/src/DataBlobs/entities/BlobStores.jl +++ b/src/DataBlobs/entities/BlobStores.jl @@ -1 +1 @@ -abstract type AbstractBlobStore{T} end \ No newline at end of file +abstract type AbstractBlobStore{T} end diff --git a/src/DataBlobs/services/BlobEntry.jl b/src/DataBlobs/services/BlobEntry.jl index cd8342cf..967a9941 100644 --- a/src/DataBlobs/services/BlobEntry.jl +++ b/src/DataBlobs/services/BlobEntry.jl @@ -5,11 +5,10 @@ import Base: == -@generated function ==(x::T, y::T) where T <: BlobEntry - mapreduce(n -> :(x.$n == y.$n), (a,b)->:($a && $b), fieldnames(x)) +@generated function ==(x::T, y::T) where {T <: BlobEntry} + return mapreduce(n -> :(x.$n == y.$n), (a, b) -> :($a && $b), fieldnames(x)) end - ##============================================================================== ## BlobEntry - common ##============================================================================== @@ -18,9 +17,9 @@ end $(SIGNATURES) Function to generate source string - userLabel|robotLabel|sessionLabel|varLabel """ -buildSourceString(dfg::AbstractDFG, label::Symbol) = - "$(getUserLabel(dfg))|$(getRobotLabel(dfg))|$(getSessionLabel(dfg))|$label" - +function buildSourceString(dfg::AbstractDFG, label::Symbol) + return "$(getUserLabel(dfg))|$(getRobotLabel(dfg))|$(getSessionLabel(dfg))|$label" +end ##============================================================================== ## BlobEntry - Defined in src/entities/AbstractDFG.jl @@ -34,33 +33,30 @@ getId(entry::BlobEntry) = entry.id getHash(entry::BlobEntry) = hex2bytes(entry.hash) getTimestamp(entry::BlobEntry) = entry.timestamp - - function assertHash(de::BlobEntry, db; hashfunction::Function = sha256) getHash(de) === nothing && @warn "Missing hash?" && return true - if hashfunction(db) == getHash(de) + if hashfunction(db) == getHash(de) return true #or nothing? else error("Stored hash and data blob hash do not match") end end - function Base.show(io::IO, ::MIME"text/plain", entry::BlobEntry) println(io, "_type=BlobEntry {") - println(io, " id: ", entry.id) - println(io, " blobId: ", entry.blobId) - println(io, " originId: ", entry.originId) - println(io, " label: ", entry.label) - println(io, " blobstore: ", entry.blobstore) - println(io, " hash: ", entry.hash) - println(io, " origin: ", entry.origin) - println(io, " description: ", entry.description) + println(io, " id: ", entry.id) + println(io, " blobId: ", entry.blobId) + println(io, " originId: ", entry.originId) + println(io, " label: ", entry.label) + println(io, " blobstore: ", entry.blobstore) + println(io, " hash: ", entry.hash) + println(io, " origin: ", entry.origin) + println(io, " description: ", entry.description) println(io, " mimeType: ", entry.mimeType) println(io, " timestamp ", entry.timestamp) - println(io, " _version: ", entry._version) - println(io, "}") -end + println(io, " _version: ", entry._version) + return println(io, "}") +end ##============================================================================== ## BlobEntry - CRUD @@ -74,27 +70,33 @@ Also see: [`addBlobEntry`](@ref), [`getBlob`](@ref), [`listBlobEntries`](@ref) """ function getBlobEntry(var::AbstractDFGVariable, key::Symbol) if !hasBlobEntry(var, key) - throw(KeyError("No dataEntry label $(key) found in variable $(getLabel(var)). Available keys: $(keys(var.dataDict))")) + throw( + KeyError( + "No dataEntry label $(key) found in variable $(getLabel(var)). Available keys: $(keys(var.dataDict))", + ), + ) end return var.dataDict[key] end -function getBlobEntry(var::PackedVariable, key::Symbol) +function getBlobEntry(var::PackedVariable, key::Symbol) if !hasBlobEntry(var, key) - throw(KeyError("No dataEntry label $(key) found in variable $(getLabel(var)). Available keys: $(keys(var.dataDict))")) - end - return var.blobEntries[findfirst(x->x.label == key, var.blobEntries)] + throw( + KeyError( + "No dataEntry label $(key) found in variable $(getLabel(var)). Available keys: $(keys(var.dataDict))", + ), + ) + end + return var.blobEntries[findfirst(x -> x.label == key, var.blobEntries)] end function getBlobEntry(var::AbstractDFGVariable, blobId::UUID) - for (k,v) in var.dataDict + for (k, v) in var.dataDict if blobId in [v.originId, v.blobId] return v end end - throw( - KeyError("No blobEntry with blobId $(blobId) found in variable $(getLabel(var))") - ) + throw(KeyError("No blobEntry with blobId $(blobId) found in variable $(getLabel(var))")) end """ @@ -104,31 +106,38 @@ Finds and returns the first blob entry that matches the regex. Also see: [`getBlobEntry`](@ref) """ function getBlobEntryFirst(var::AbstractDFGVariable, key::Regex) - for (k,v) in var.dataDict + for (k, v) in var.dataDict if occursin(key, string(v.label)) return v end end throw( - KeyError("No blobEntry with label matching regex $(key) found in variable $(getLabel(var))") + KeyError( + "No blobEntry with label matching regex $(key) found in variable $(getLabel(var))", + ), ) end -function getBlobEntryFirst(var::Variable, key::Regex) - firstIdx = findfirst(x->contains(string(x.label), key), var.blobEntries) +function getBlobEntryFirst(var::Variable, key::Regex) + firstIdx = findfirst(x -> contains(string(x.label), key), var.blobEntries) if isnothing(firstIdx) throw(KeyError("$key")) end return var.blobEntries[firstIdx] end -getBlobEntry(var::AbstractDFGVariable, key::AbstractString) = getBlobEntry(var,Regex(key)) +getBlobEntry(var::AbstractDFGVariable, key::AbstractString) = getBlobEntry(var, Regex(key)) #TODO split betweeen getfirstBlobEntry and getBlobEntry -getBlobEntry(dfg::AbstractDFG, label::Symbol, key::Union{Symbol, UUID, <:AbstractString, Regex}) = getBlobEntry(getVariable(dfg, label), key) +function getBlobEntry( + dfg::AbstractDFG, + label::Symbol, + key::Union{Symbol, UUID, <:AbstractString, Regex}, +) + return getBlobEntry(getVariable(dfg, label), key) +end # getBlobEntry(dfg::AbstractDFG, label::Symbol, key::Symbol) = getBlobEntry(getVariable(dfg, label), key) - """ $(SIGNATURES) Add Data Entry to a DFG variable @@ -136,36 +145,27 @@ Should be extended if DFG variable is not returned by reference. Also see: [`getBlobEntry`](@ref), [`addBlob!`](@ref), [`mergeBlobEntries!`](@ref) """ -function addBlobEntry!( - var::AbstractDFGVariable, - entry::BlobEntry; -) +function addBlobEntry!(var::AbstractDFGVariable, entry::BlobEntry;) # see https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/985 # blobId::Union{UUID,Nothing} = (isnothing(entry.blobId) ? entry.id : entry.blobId), # blobSize::Int = (hasfield(BlobEntry, :size) ? entry.size : -1) - haskey(var.dataDict, entry.label) && error("blobEntry $(entry.label) already exists on variable $(getLabel(var))") + haskey(var.dataDict, entry.label) && + error("blobEntry $(entry.label) already exists on variable $(getLabel(var))") var.dataDict[entry.label] = entry return entry end -function addBlobEntry!( - var::PackedVariable, - entry::BlobEntry, -) - entry.label in getproperty.(var.blobEntries,:label) && error("blobEntry $(entry.label) already exists on variable $(getLabel(var))") +function addBlobEntry!(var::PackedVariable, entry::BlobEntry) + entry.label in getproperty.(var.blobEntries, :label) && + error("blobEntry $(entry.label) already exists on variable $(getLabel(var))") push!(var.blobEntries, entry) return entry end -function addBlobEntry!( - dfg::AbstractDFG, - vLbl::Symbol, - entry::BlobEntry; -) +function addBlobEntry!(dfg::AbstractDFG, vLbl::Symbol, entry::BlobEntry;) return addBlobEntry!(getVariable(dfg, vLbl), entry) end - """ $(SIGNATURES) Update data entry @@ -173,12 +173,13 @@ Update data entry DevNote - DF, unclear if `update` verb is applicable in this case, see #404 """ -function updateBlobEntry!(var::AbstractDFGVariable, bde::BlobEntry) - !haskey(var.dataDict, bde.label) && (@warn "$(bde.label) does not exist in variable $(getLabel(var)), adding") +function updateBlobEntry!(var::AbstractDFGVariable, bde::BlobEntry) + !haskey(var.dataDict, bde.label) && + (@warn "$(bde.label) does not exist in variable $(getLabel(var)), adding") var.dataDict[bde.label] = bde return bde end -function updateBlobEntry!(dfg::AbstractDFG, label::Symbol, bde::BlobEntry) +function updateBlobEntry!(dfg::AbstractDFG, label::Symbol, bde::BlobEntry) # !isVariable(dfg, label) && return nothing return updateBlobEntry!(getVariable(dfg, label), bde) end @@ -205,9 +206,6 @@ function deleteBlobEntry!(var::AbstractDFGVariable, entry::BlobEntry) return deleteBlobEntry!(var, entry.label) end - - - ##============================================================================== ## BlobEntry - Helper functions, Lists, etc ##============================================================================== @@ -230,28 +228,33 @@ Get blob entries, Vector{BlobEntry} """ function getBlobEntries(var::AbstractDFGVariable) #or should we return the iterator, Base.ValueIterator{Dict{Symbol,BlobEntry}}? - collect(values(var.dataDict)) + return collect(values(var.dataDict)) end function getBlobEntries(var::PackedVariable) - var.blobEntries + return var.blobEntries end function getBlobEntries(dfg::AbstractDFG, label::Symbol) # !isVariable(dfg, label) && return nothing #or should we return the iterator, Base.ValueIterator{Dict{Symbol,BlobEntry}}? - getBlobEntries(getVariable(dfg, label)) + return getBlobEntries(getVariable(dfg, label)) end function getBlobEntries(dfg::AbstractDFG, label::Symbol, regex::Regex) entries = getBlobEntries(dfg, label) return filter(entries) do e - occursin(regex, string(e.label)) - end + return occursin(regex, string(e.label)) + end end -getBlobEntries(dfg::AbstractDFG, label::Symbol, skey::Union{Symbol, <:AbstractString}) = getBlobEntries(dfg, label, Regex(string(skey))) - +function getBlobEntries( + dfg::AbstractDFG, + label::Symbol, + skey::Union{Symbol, <:AbstractString}, +) + return getBlobEntries(dfg, label, Regex(string(skey))) +end """ $(SIGNATURES) @@ -265,30 +268,26 @@ Notes function getBlobEntriesVariables( dfg::AbstractDFG, bLblPattern::Regex; - varList::AbstractVector{Symbol} = sort(listVariables(dfg); lt=natural_lt), - dropEmpties::Bool = false + varList::AbstractVector{Symbol} = sort(listVariables(dfg); lt = natural_lt), + dropEmpties::Bool = false, ) RETLIST = Vector{Vector{BlobEntry}}() @showprogress "Get entries matching $bLblPattern" for vl in varList - bes = filter( - s->occursin(bLblPattern,string(s.label)), - listBlobEntries(dfg,vl) - ) + bes = filter(s -> occursin(bLblPattern, string(s.label)), listBlobEntries(dfg, vl)) # only push to list if there are entries on this variable (!dropEmpties || 0 < length(bes)) ? nothing : continue push!(RETLIST, bes) end - + return RETLIST end - """ $(SIGNATURES) List the blob entries associated with a particular variable. """ function listBlobEntries(var::AbstractDFGVariable) - collect(keys(var.dataDict)) + return collect(keys(var.dataDict)) end function listBlobEntries(var::PackedVariable) @@ -297,7 +296,7 @@ end function listBlobEntries(dfg::AbstractDFG, label::Symbol) # !isVariable(dfg, label) && return nothing - listBlobEntries(getVariable(dfg, label)) + return listBlobEntries(getVariable(dfg, label)) end """ @@ -319,15 +318,17 @@ listBlobEntrySequence(fg, :x0, r"IMG_CENTER", sortDFG) ... ``` """ -function listBlobEntrySequence( dfg::AbstractDFG, - lb::Symbol, - pattern::Regex, - _sort::Function=(x)->x) +function listBlobEntrySequence( + dfg::AbstractDFG, + lb::Symbol, + pattern::Regex, + _sort::Function = (x) -> x, +) # ents_ = listBlobEntries(dfg, lb) - entReg = map(l->match(pattern, string(l)), ents_) + entReg = map(l -> match(pattern, string(l)), ents_) entMsk = entReg .!== nothing - ents_[findall(entMsk)] |> _sort + return ents_[findall(entMsk)] |> _sort end """ @@ -339,11 +340,11 @@ in a source variable. See also: [`addBlobEntry!`](@ref), [`getBlobEntry`](@ref), [`listBlobEntries`](@ref), [`getBlob`](@ref) """ function mergeBlobEntries!( - dst::AbstractDFG, - dlbl::Symbol, - src::AbstractDFG, - slbl::Symbol, - bllb::Union{Symbol, UUID, <:AbstractString, Regex} + dst::AbstractDFG, + dlbl::Symbol, + src::AbstractDFG, + slbl::Symbol, + bllb::Union{Symbol, UUID, <:AbstractString, Regex}, ) # _makevec(s) = [s;] @@ -352,29 +353,29 @@ function mergeBlobEntries!( des = _makevec(des_) # don't add data entries that already exist dde = listBlobEntries(dst, dlbl) - # HACK, verb list should just return vector of Symbol. NCE36 - _getid(s) = s - _getid(s::BlobEntry) = s.id + # HACK, verb list should just return vector of Symbol. NCE36 + _getid(s) = s + _getid(s::BlobEntry) = s.id uids = _getid.(dde) # (s->s.id).(dde) filter!(s -> !(_getid(s) in uids), des) # add any data entries not already in the destination variable, by uuid - addBlobEntry!.(dst, dlbl, des) + return addBlobEntry!.(dst, dlbl, des) end function mergeBlobEntries!( - dst::AbstractDFG, - dlbl::Symbol, - src::AbstractDFG, - slbl::Symbol, - ::Colon=: + dst::AbstractDFG, + dlbl::Symbol, + src::AbstractDFG, + slbl::Symbol, + ::Colon = :, ) des = listBlobEntries(src, slbl) # don't add data entries that already exist uids = listBlobEntries(dst, dlbl) # verb list should just return vector of Symbol. NCE36 filter!(s -> !(s in uids), des) - if 0 < length(des) - union(((s->mergeBlobEntries!(dst, dlbl, src, slbl, s)).(des))...) + if 0 < length(des) + union(((s -> mergeBlobEntries!(dst, dlbl, src, slbl, s)).(des))...) end end @@ -382,12 +383,12 @@ function mergeBlobEntries!( dest::AbstractDFG, src::AbstractDFG, w...; - varList::AbstractVector = listVariables(dest) |> sortDFG + varList::AbstractVector = listVariables(dest) |> sortDFG, ) @showprogress 1 "merging data entries" for vl in varList mergeBlobEntries!(dest, vl, src, vl, w...) end - varList + return varList end """ @@ -399,21 +400,21 @@ If the blob label `datalabel_1` already exists, then this function will return t function incrDataLabelSuffix( dfg::AbstractDFG, vla, - bllb::S; - datalabel=Ref("") + bllb::S; + datalabel = Ref(""), ) where {S <: Union{Symbol, <:AbstractString}} count = 1 hasund = false len = 0 try - de,_ = getData(dfg, Symbol(vla), bllb) + de, _ = getData(dfg, Symbol(vla), bllb) bllb = string(bllb) # bllb *= bllb[end] != '_' ? "_" : "" datalabel[] = string(de.label) dlb = match(r"\d*", reverse(datalabel[])) # slightly complicated search if blob name already has an underscore number suffix, e.g. `_4` - count, hasund, len = if occursin(Regex(dlb.match*"_"), reverse(datalabel[])) - parse(Int, dlb.match |> reverse)+1, true, length(dlb.match) + count, hasund, len = if occursin(Regex(dlb.match * "_"), reverse(datalabel[])) + parse(Int, dlb.match |> reverse) + 1, true, length(dlb.match) else 1, datalabel[][end] == '_', 0 end @@ -424,11 +425,11 @@ function incrDataLabelSuffix( end end # the piece from old label without the suffix count number - bllb = datalabel[][1:(end-len)] + bllb = datalabel[][1:(end - len)] if !hasund || bllb[end] != '_' bllb *= "_" end bllb *= string(count) - S(bllb) + return S(bllb) end diff --git a/src/DataBlobs/services/BlobPacking.jl b/src/DataBlobs/services/BlobPacking.jl index 82a4df74..2f4a9b1f 100644 --- a/src/DataBlobs/services/BlobPacking.jl +++ b/src/DataBlobs/services/BlobPacking.jl @@ -12,11 +12,11 @@ # - image/png const _MIMETypes = OrderedDict{MIME, DataType}() -push!(_MIMETypes, MIME("application/octet-stream/json")=>format"JSON") -push!(_MIMETypes, MIME("application/bson")=>format"BSON") -push!(_MIMETypes, MIME("image/png")=>format"PNG") -push!(_MIMETypes, MIME("image/jpeg")=>format"JPG") -push!(_MIMETypes, MIME("application/octet-stream; ext=las")=>format"LAS") +push!(_MIMETypes, MIME("application/octet-stream/json") => format"JSON") +push!(_MIMETypes, MIME("application/bson") => format"BSON") +push!(_MIMETypes, MIME("image/png") => format"PNG") +push!(_MIMETypes, MIME("image/jpeg") => format"JPG") +push!(_MIMETypes, MIME("application/octet-stream; ext=las") => format"LAS") """ packBlob @@ -38,7 +38,6 @@ function unpackBlob(T::MIME, blob) return unpackBlob(dataformat, blob) end - # 1. JSON strings are saved as is function packBlob(::Type{format"JSON"}, json_str::String) mimetype = findfirst(==(format"JSON"), _MIMETypes) @@ -54,9 +53,8 @@ end unpackBlob(entry::BlobEntry, blob::Vector{UInt8}) = unpackBlob(entry.mimeType, blob) unpackBlob(eb::Pair{<:BlobEntry, Vector{UInt8}}) = unpackBlob(eb[1], eb[2]) - # 2/ FileIO -function packBlob(::Type{T}, data::Any; kwargs...) where T <: DataFormat +function packBlob(::Type{T}, data::Any; kwargs...) where {T <: DataFormat} io = IOBuffer() save(Stream{T}(io), data; kwargs...) blob = take!(io) @@ -68,14 +66,11 @@ function packBlob(::Type{T}, data::Any; kwargs...) where T <: DataFormat return blob, mimetype end -function unpackBlob(::Type{T}, blob::Vector{UInt8}) where T <: DataFormat +function unpackBlob(::Type{T}, blob::Vector{UInt8}) where {T <: DataFormat} io = IOBuffer(blob) return load(Stream{T}(io)) end - - - # if false # json_str = "{\"name\":\"John\"}" # blob, mimetype = packBlob(format"JSON", json_str) @@ -83,7 +78,6 @@ end # @assert json_str == unpackBlob(MIME("application/octet-stream/json"), blob) # @assert json_str == unpackBlob("application/octet-stream/json", blob) - # blob,mime = packBlob(format"PNG", img) # up_img = unpackBlob(format"PNG", blob) @@ -91,8 +85,4 @@ end # packBlob(format"BSON", Dict("name"=>"John")) # unpackBlob(format"BSON", Dict("name"=>"John")) - # end - - - diff --git a/src/DataBlobs/services/BlobStores.jl b/src/DataBlobs/services/BlobStores.jl index 7fdce578..7435cde8 100644 --- a/src/DataBlobs/services/BlobStores.jl +++ b/src/DataBlobs/services/BlobStores.jl @@ -2,7 +2,6 @@ ## Blob CRUD interface ##============================================================================== - """ Get the data blob for the specified blobstore or dfg. @@ -56,27 +55,27 @@ function listBlobs end ##============================================================================== function getBlob(store::AbstractBlobStore, ::UUID) - error("$(typeof(store)) doesn't override 'getBlob'.") + return error("$(typeof(store)) doesn't override 'getBlob'.") end function addBlob!(store::AbstractBlobStore{T}, ::UUID, ::T) where {T} - error("$(typeof(store)) doesn't override 'addBlob!'.") + return error("$(typeof(store)) doesn't override 'addBlob!'.") end function updateBlob!(store::AbstractBlobStore{T}, ::UUID, ::T) where {T} - error("$(typeof(store)) doesn't override 'updateBlob!'.") + return error("$(typeof(store)) doesn't override 'updateBlob!'.") end function deleteBlob!(store::AbstractBlobStore, ::UUID) - error("$(typeof(store)) doesn't override 'deleteBlob!'.") + return error("$(typeof(store)) doesn't override 'deleteBlob!'.") end function listBlobs(store::AbstractBlobStore) - error("$(typeof(store)) doesn't override 'listBlobs'.") + return error("$(typeof(store)) doesn't override 'listBlobs'.") end function hasBlob(store::AbstractBlobStore, ::UUID) - error("$(typeof(store)) doesn't override 'hasBlob'.") + return error("$(typeof(store)) doesn't override 'hasBlob'.") end ##============================================================================== @@ -98,56 +97,59 @@ function getBlob(dfg::AbstractDFG, entry::BlobEntry) end throw( KeyError( - "could not find $(entry.label), uuid $(entry.blobId) in any of the listed blobstores:\n $([s->getKey(s) for (s,v) in stores]))" - ) + "could not find $(entry.label), uuid $(entry.blobId) in any of the listed blobstores:\n $([s->getKey(s) for (s,v) in stores]))", + ), ) end function getBlob(store::AbstractBlobStore, entry::BlobEntry) blobId = isnothing(entry.blobId) ? entry.originId : entry.blobId - getBlob(store, blobId) + return getBlob(store, blobId) end #add -addBlob!(dfg::AbstractDFG, entry::BlobEntry, data) = - addBlob!(getBlobStore(dfg, entry.blobstore), entry, data) +function addBlob!(dfg::AbstractDFG, entry::BlobEntry, data) + return addBlob!(getBlobStore(dfg, entry.blobstore), entry, data) +end function addBlob!(store::AbstractBlobStore, entry::BlobEntry, data) blobId = isnothing(entry.blobId) ? entry.originId : entry.blobId - addBlob!(store, blobId, data) + return addBlob!(store, blobId, data) end # also creates an originId as uuid4 -addBlob!(store::AbstractBlobStore, data) = - addBlob!(store, uuid4(), data) +addBlob!(store::AbstractBlobStore, data) = addBlob!(store, uuid4(), data) #fallback as not all blobStores use filename -addBlob!(store::AbstractBlobStore, blobId::UUID, data, ::String) = - addBlob!(store, blobId, data) +function addBlob!(store::AbstractBlobStore, blobId::UUID, data, ::String) + return addBlob!(store, blobId, data) +end -addBlob!(store::AbstractBlobStore, data, ::String) = - addBlob!(store, uuid4(), data) +addBlob!(store::AbstractBlobStore, data, ::String) = addBlob!(store, uuid4(), data) #update -updateBlob!(dfg::AbstractDFG, entry::BlobEntry, data::T) where {T} = - updateBlob!(getBlobStore(dfg, entry.blobstore), entry, data) +function updateBlob!(dfg::AbstractDFG, entry::BlobEntry, data::T) where {T} + return updateBlob!(getBlobStore(dfg, entry.blobstore), entry, data) +end function updateBlob!(store::AbstractBlobStore, entry::BlobEntry, data) blobId = isnothing(entry.blobId) ? entry.originId : entry.blobId - updateBlob!(store, blobId, data) + return updateBlob!(store, blobId, data) end #delete -deleteBlob!(dfg::AbstractDFG, entry::BlobEntry) = - deleteBlob!(getBlobStore(dfg, entry.blobstore), entry) +function deleteBlob!(dfg::AbstractDFG, entry::BlobEntry) + return deleteBlob!(getBlobStore(dfg, entry.blobstore), entry) +end function deleteBlob!(store::AbstractBlobStore, entry::BlobEntry) blobId = isnothing(entry.blobId) ? entry.originId : entry.blobId - deleteBlob!(store, blobId) + return deleteBlob!(store, blobId) end - #has -hasBlob(dfg::AbstractDFG, entry::BlobEntry) = hasBlob(getBlobStore(dfg, entry.blobstore), entry.originId) +function hasBlob(dfg::AbstractDFG, entry::BlobEntry) + return hasBlob(getBlobStore(dfg, entry.blobstore), entry.originId) +end #TODO # """ @@ -169,7 +171,6 @@ hasBlob(dfg::AbstractDFG, entry::BlobEntry) = hasBlob(getBlobStore(dfg, entry.bl # return sourceEntries # end - ##============================================================================== ## FolderStore ##============================================================================== @@ -186,7 +187,9 @@ struct FolderStore{T} <: AbstractBlobStore{T} end end -FolderStore(foldername::String) = FolderStore{Vector{UInt8}}(:default_folder_store, foldername) +function FolderStore(foldername::String) + return FolderStore{Vector{UInt8}}(:default_folder_store, foldername) +end blobfilename(store::FolderStore, blobId::UUID) = joinpath(store.folder, "$blobId.dat") @@ -207,7 +210,7 @@ function addBlob!(store::FolderStore{T}, blobId::UUID, data::T) where {T} throw(KeyError("Key '$blobId' blob already exists.")) else open(blobfilename, "w") do f - write(f, data) + return write(f, data) end # return data return blobId @@ -220,13 +223,12 @@ function updateBlob!(store::FolderStore{T}, blobId::UUID, data::T) where {T} @warn "Key '$blobId' doesn't exist." else open(blobfilename, "w") do f - write(f, data) + return write(f, data) end return data end end - function deleteBlob!(store::FolderStore{T}, blobId::UUID) where {T} blobfilename = joinpath(store.folder, "$blobId.dat") @@ -238,23 +240,26 @@ end #hasBlob or existsBlob? function hasBlob(store::FolderStore, blobId::UUID) blobfilename = joinpath(store.folder, "$blobId.dat") - isfile(blobfilename) + return isfile(blobfilename) end hasBlob(store::FolderStore, entry::BlobEntry) = hasBlob(store, entry.originId) - ##============================================================================== ## InMemoryBlobStore ##============================================================================== struct InMemoryBlobStore{T} <: AbstractBlobStore{T} key::Symbol - blobs::Dict{UUID,T} + blobs::Dict{UUID, T} end -InMemoryBlobStore{T}(storeKey::Symbol) where {T} = InMemoryBlobStore{Vector{UInt8}}(storeKey, Dict{UUID,T}()) -InMemoryBlobStore(storeKey::Symbol=:default_inmemory_store) = InMemoryBlobStore{Vector{UInt8}}(storeKey) +function InMemoryBlobStore{T}(storeKey::Symbol) where {T} + return InMemoryBlobStore{Vector{UInt8}}(storeKey, Dict{UUID, T}()) +end +function InMemoryBlobStore(storeKey::Symbol = :default_inmemory_store) + return InMemoryBlobStore{Vector{UInt8}}(storeKey) +end function getBlob(store::InMemoryBlobStore, blobId::UUID) return store.blobs[blobId] @@ -297,7 +302,7 @@ struct LinkStore <: AbstractBlobStore{String} @info "File '$csvfile' doesn't exist - creating." # create new folder open(csvfile, "w") do io - println(io, "blobid,path") + return println(io, "blobid,path") end return new(key, csvfile, Dict{UUID, String}()) else @@ -310,25 +315,24 @@ end function getBlob(store::LinkStore, blobId::UUID) fname = get(store.cache, blobId, nothing) - read(fname) + return read(fname) end function addBlob!(store::LinkStore, entry::BlobEntry, linkfile::String) - addBlob!(store, entry.originId, nothing, linkfile::String) + return addBlob!(store, entry.originId, nothing, linkfile::String) end -function addBlob!(store::LinkStore, blobId::UUID, blob::Any, linkfile::String) +function addBlob!(store::LinkStore, blobId::UUID, blob::Any, linkfile::String) if haskey(store.cache, blobId) error("blobId $blobId already exists in the store") end - push!(store.cache, blobId=>linkfile) + push!(store.cache, blobId => linkfile) open(store.csvfile, "a") do f - println(f, blobId,",",linkfile) + return println(f, blobId, ",", linkfile) end - getBlob(store, blobId) + return getBlob(store, blobId) end function deleteBlob!(store::LinkStore, args...) - error("deleteDataBlob(::LinkStore) not supported") + return error("deleteDataBlob(::LinkStore) not supported") end - diff --git a/src/DataBlobs/services/HelpersDataWrapEntryBlob.jl b/src/DataBlobs/services/HelpersDataWrapEntryBlob.jl index 38ea1f34..06daaaac 100644 --- a/src/DataBlobs/services/HelpersDataWrapEntryBlob.jl +++ b/src/DataBlobs/services/HelpersDataWrapEntryBlob.jl @@ -1,5 +1,4 @@ - ##============================================================================== ## Data CRUD interface ##============================================================================== @@ -41,56 +40,57 @@ $(METHODLIST) """ function deleteData! end - # construction helper from existing BlobEntry for user overriding via kwargs -BlobEntry( +function BlobEntry( entry::BlobEntry; - id::Union{UUID,Nothing} = entry.id, - blobId::Union{UUID,Nothing} = entry.blobId, - originId::UUID = entry.originId, - label::Symbol = entry.label, - blobstore::Symbol = entry.blobstore, + id::Union{UUID, Nothing} = entry.id, + blobId::Union{UUID, Nothing} = entry.blobId, + originId::UUID = entry.originId, + label::Symbol = entry.label, + blobstore::Symbol = entry.blobstore, hash::String = entry.hash, - size::Union{Int,Nothing} = entry.size, + size::Union{Int, Nothing} = entry.size, origin::String = entry.origin, - description::String = entry.description, - mimeType::String = entry.mimeType, - metadata::String = entry.metadata, - timestamp::ZonedDateTime = entry.timestamp, + description::String = entry.description, + mimeType::String = entry.mimeType, + metadata::String = entry.metadata, + timestamp::ZonedDateTime = entry.timestamp, createdTimestamp = entry.createdTimestamp, lastUpdatedTimestamp = entry.lastUpdatedTimestamp, - _type::String = entry._type, + _type::String = entry._type, _version::String = entry._version, -) = BlobEntry(; - id, - blobId, - originId, - label, - blobstore, - hash, - origin, - size, - description, - mimeType, - metadata, - timestamp, - createdTimestamp, - lastUpdatedTimestamp, - _type, - _version ) + return BlobEntry(; + id, + blobId, + originId, + label, + blobstore, + hash, + origin, + size, + description, + mimeType, + metadata, + timestamp, + createdTimestamp, + lastUpdatedTimestamp, + _type, + _version, + ) +end function getData( - dfg::AbstractDFG, - vlabel::Symbol, - key::Union{Symbol,UUID, <:AbstractString, Regex}; + dfg::AbstractDFG, + vlabel::Symbol, + key::Union{Symbol, UUID, <:AbstractString, Regex}; hashfunction = sha256, - checkhash::Bool=true, - getlast::Bool=true + checkhash::Bool = true, + getlast::Bool = true, ) de_ = getBlobEntries(dfg, vlabel, key) - lbls = (s->s.label).(de_) - idx = sortperm(lbls; rev=getlast) + lbls = (s -> s.label).(de_) + idx = sortperm(lbls; rev = getlast) _first(s) = s _first(s::AbstractVector) = 0 < length(s) ? s[1] : nothing de = _first(de_[idx]) @@ -100,137 +100,136 @@ function getData( end db = getBlob(dfg, de) - checkhash && assertHash(de, db, hashfunction=hashfunction) - return de=>db + checkhash && assertHash(de, db; hashfunction = hashfunction) + return de => db end # This is the normal one function getData( - dfg::AbstractDFG, - blobstore::AbstractBlobStore, - label::Symbol, - key::Symbol; + dfg::AbstractDFG, + blobstore::AbstractBlobStore, + label::Symbol, + key::Symbol; hashfunction = sha256, - checkhash::Bool=true, - getlast::Bool=true + checkhash::Bool = true, + getlast::Bool = true, ) de = getBlobEntry(dfg, label, key) db = getBlob(blobstore, de) checkhash && assertHash(de, db; hashfunction) - return de=>db + return de => db end - function addData!( - dfg::AbstractDFG, - label::Symbol, - entry::BlobEntry, - blob::Vector{UInt8}; + dfg::AbstractDFG, + label::Symbol, + entry::BlobEntry, + blob::Vector{UInt8}; hashfunction = sha256, - checkhash::Bool=false + checkhash::Bool = false, ) checkhash && assertHash(entry, blob; hashfunction) blobId = addBlob!(dfg, entry, blob) |> UUID newEntry = BlobEntry(entry; blobId) #, size=length(blob)) - addBlobEntry!(dfg, label, newEntry) + return addBlobEntry!(dfg, label, newEntry) end function addData!( - dfg::AbstractDFG, - blobstore::AbstractBlobStore, - label::Symbol, - entry::BlobEntry, - blob::Vector{UInt8}; + dfg::AbstractDFG, + blobstore::AbstractBlobStore, + label::Symbol, + entry::BlobEntry, + blob::Vector{UInt8}; hashfunction = sha256, - checkhash::Bool=false, + checkhash::Bool = false, ) checkhash && assertHash(entry, blob; hashfunction) blobId = addBlob!(blobstore, entry, blob) |> UUID newEntry = BlobEntry(entry; blobId) #, size=length(blob)) - addBlobEntry!(dfg, label, newEntry) + return addBlobEntry!(dfg, label, newEntry) end - -addData!( - dfg::AbstractDFG, - blobstorekey::Symbol, - vLbl::Symbol, - bLbl::Symbol, +function addData!( + dfg::AbstractDFG, + blobstorekey::Symbol, + vLbl::Symbol, + bLbl::Symbol, blob::Vector{UInt8}, - timestamp=now(localzone()); - kwargs... -) = addData!( - dfg, - getBlobStore(dfg, blobstorekey), - vLbl, - bLbl, - blob, - timestamp; - kwargs... + timestamp = now(localzone()); + kwargs..., ) + return addData!( + dfg, + getBlobStore(dfg, blobstorekey), + vLbl, + bLbl, + blob, + timestamp; + kwargs..., + ) +end #FIXME id used wrong function addData!( - dfg::AbstractDFG, - blobstore::AbstractBlobStore, - vLbl::Symbol, + dfg::AbstractDFG, + blobstore::AbstractBlobStore, + vLbl::Symbol, bLbl::Symbol, - blob::Vector{UInt8}, - timestamp=now(localzone()); - description="", + blob::Vector{UInt8}, + timestamp = now(localzone()); + description = "", metadata = "", - mimeType::String = "application/octet-stream", - id::Union{UUID,Nothing} = nothing, #only assign if blobstore issued you an id + mimeType::String = "application/octet-stream", + id::Union{UUID, Nothing} = nothing, #only assign if blobstore issued you an id originId::UUID = uuid4(), - hashfunction = sha256 + hashfunction = sha256, ) # - @warn "ID's and origin IDs should be reconciled here in DFG.addData!." maxlog=50 + @warn "ID's and origin IDs should be reconciled here in DFG.addData!." maxlog = 50 entry = BlobEntry(; - id, + id, originId, - label = bLbl, - blobstore = blobstore.key, + label = bLbl, + blobstore = blobstore.key, hash = string(bytes2hex(hashfunction(blob))), origin = buildSourceString(dfg, vLbl), - description, - mimeType, - metadata, - timestamp) + description, + mimeType, + metadata, + timestamp, + ) - addData!(dfg, blobstore, vLbl, entry, blob; hashfunction) + return addData!(dfg, blobstore, vLbl, entry, blob; hashfunction) end - function updateData!( - dfg::AbstractDFG, - label::Symbol, - entry::BlobEntry, + dfg::AbstractDFG, + label::Symbol, + entry::BlobEntry, blob::Vector{UInt8}; hashfunction = sha256, - checkhash::Bool=true + checkhash::Bool = true, ) checkhash && assertHash(entry, blob; hashfunction) # order of ops with unknown new blobId not tested de = updateBlobEntry!(dfg, label, entry) db = updateBlob!(dfg, de, blob) - return de=>db + return de => db end - function updateData!( - dfg::AbstractDFG, - blobstore::AbstractBlobStore, - label::Symbol, - entry::BlobEntry, - blob::Vector{UInt8}; - hashfunction = sha256 + dfg::AbstractDFG, + blobstore::AbstractBlobStore, + label::Symbol, + entry::BlobEntry, + blob::Vector{UInt8}; + hashfunction = sha256, ) # Recalculate the hash - NOTE Assuming that this is going to be a BlobEntry. TBD. # order of operations with unknown new blobId not tested newEntry = BlobEntry( entry; # and kwargs to override new values - blobstore = blobstore.key, + blobstore = blobstore.key, hash = string(bytes2hex(hashfunction(blob))), origin = buildSourceString(dfg, label), _version = string(_getDFGVersion()), @@ -238,41 +237,31 @@ function updateData!( de = updateBlobEntry!(dfg, label, newEntry) db = updateBlob!(blobstore, de, blob) - return de=>db + return de => db end -function deleteData!( - dfg::AbstractDFG, - vLbl::Symbol, - bLbl::Symbol -) +function deleteData!(dfg::AbstractDFG, vLbl::Symbol, bLbl::Symbol) de = deleteBlobEntry!(dfg, vLbl, bLbl) db = deleteBlob!(dfg, de) - return de=>db + return de => db end - function deleteData!( - dfg::AbstractDFG, - blobstore::AbstractBlobStore, - vLbl::Symbol, - entry::BlobEntry -) - return deleteData!( - dfg, - blobstore, - vLbl, - entry.label - ) + dfg::AbstractDFG, + blobstore::AbstractBlobStore, + vLbl::Symbol, + entry::BlobEntry, +) + return deleteData!(dfg, blobstore, vLbl, entry.label) end function deleteData!( - dfg::AbstractDFG, - blobstore::AbstractBlobStore, - vLbl::Symbol, - bLbl::Symbol + dfg::AbstractDFG, + blobstore::AbstractBlobStore, + vLbl::Symbol, + bLbl::Symbol, ) de = deleteBlobEntry!(dfg, vLbl, bLbl) db = deleteBlob!(blobstore, de) - return de=>db + return de => db end diff --git a/src/Deprecated.jl b/src/Deprecated.jl index 18099b1a..8d842e74 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -5,12 +5,42 @@ #NOTE free up getNeighbors to return the variables or factors @deprecate getNeighbors(args...; kwargs...) listNeighbors(args...; kwargs...) - ## ================================================================================ ## Remove in v0.23 ##================================================================================= -@deprecate BlobEntry(id, blobId, originId::UUID, label::Symbol, blobstore::Symbol, hash::String, origin::String, description::String, mimeType::String, metadata::String, timestamp::ZonedDateTime, _type::String, _version::String) BlobEntry(id, blobId, originId, label, blobstore, hash, origin, -1, description, mimeType, metadata, timestamp, nothing, nothing, _type, _version) +@deprecate BlobEntry( + id, + blobId, + originId::UUID, + label::Symbol, + blobstore::Symbol, + hash::String, + origin::String, + description::String, + mimeType::String, + metadata::String, + timestamp::ZonedDateTime, + _type::String, + _version::String, +) BlobEntry( + id, + blobId, + originId, + label, + blobstore, + hash, + origin, + -1, + description, + mimeType, + metadata, + timestamp, + nothing, + nothing, + _type, + _version, +) ## ================================================================================ ## Remove in v0.22 @@ -55,33 +85,25 @@ abstract type AbstractBlobEntry end origin::String, description::String, mimeType::String, - createdTimestamp::ZonedDateTime) BlobEntry(; - originId=id, - label, - blobstore, - hash, - origin, - description, - mimeType, - ) - - -@deprecate hasDataEntry(w...;kw...) hasBlobEntry(w...;kw...) -@deprecate getDataEntry(w...;kw...) getBlobEntry(w...;kw...) -@deprecate getDataEntries(w...;kw...) getBlobEntries(w...;kw...) -@deprecate addDataEntry!(w...;kw...) addBlobEntry!(w...;kw...) -@deprecate updateDataEntry!(w...;kw...) updateBlobEntry!(w...;kw...) -@deprecate deleteDataEntry!(w...;kw...) deleteBlobEntry!(w...;kw...) -@deprecate listDataEntry(w...;kw...) listBlobEntry(w...;kw...) -@deprecate listDataEntrySequence(w...;kw...) listBlobEntrySequence(w...;kw...) -@deprecate mergeDataEntry!(w...;kw...) mergeBlobEntry!(w...;kw...) + createdTimestamp::ZonedDateTime, +) BlobEntry(; originId = id, label, blobstore, hash, origin, description, mimeType) + +@deprecate hasDataEntry(w...; kw...) hasBlobEntry(w...; kw...) +@deprecate getDataEntry(w...; kw...) getBlobEntry(w...; kw...) +@deprecate getDataEntries(w...; kw...) getBlobEntries(w...; kw...) +@deprecate addDataEntry!(w...; kw...) addBlobEntry!(w...; kw...) +@deprecate updateDataEntry!(w...; kw...) updateBlobEntry!(w...; kw...) +@deprecate deleteDataEntry!(w...; kw...) deleteBlobEntry!(w...; kw...) +@deprecate listDataEntry(w...; kw...) listBlobEntry(w...; kw...) +@deprecate listDataEntrySequence(w...; kw...) listBlobEntrySequence(w...; kw...) +@deprecate mergeDataEntry!(w...; kw...) mergeBlobEntry!(w...; kw...) # @deprecate getData(w...;kw...) getBlob(w...;kw...) -@deprecate getDataBlob(w...;kw...) getBlob(w...;kw...) -@deprecate addDataBlob!(w...;kw...) addBlob!(w...;kw...) -@deprecate updateDataBlob!(w...;kw...) updateBlob!(w...;kw...) -@deprecate deleteDataBlob!(w...;kw...) deleteBlob!(w...;kw...) -@deprecate listDataBlobs(w...;kw...) listBlobs(w...;kw...) +@deprecate getDataBlob(w...; kw...) getBlob(w...; kw...) +@deprecate addDataBlob!(w...; kw...) addBlob!(w...; kw...) +@deprecate updateDataBlob!(w...; kw...) updateBlob!(w...; kw...) +@deprecate deleteDataBlob!(w...; kw...) deleteBlob!(w...; kw...) +@deprecate listDataBlobs(w...; kw...) listBlobs(w...; kw...) # function updateBlob!( # dfg::AbstractDFG, @@ -105,5 +127,3 @@ abstract type AbstractBlobEntry end # db = getBlob(dfg, entry) # return de=>db # end - - diff --git a/src/DistributedFactorGraphs.jl b/src/DistributedFactorGraphs.jl index b7612a68..651ba754 100644 --- a/src/DistributedFactorGraphs.jl +++ b/src/DistributedFactorGraphs.jl @@ -50,7 +50,6 @@ using StaticArrays import Base: getindex - ##============================================================================== # Exports ##============================================================================== @@ -66,41 +65,47 @@ export AbstractBlobStore # accessors & crud export getUserLabel, getRobotLabel, getSessionLabel export getDFGInfo -export getDescription, setDescription!, - getSolverParams, setSolverParams!, - getUserData, setUserData!, - getRobotData, setRobotData!, - getSessionData, setSessionData!, - getAddHistory - -export getSessionBlobEntry, - getSessionBlobEntries, - addSessionBlobEntry!, - addSessionBlobEntries!, - updateSessionBlobEntry!, - deleteSessionBlobEntry!, - getRobotBlobEntry, - getRobotBlobEntries, - addRobotBlobEntry!, - addRobotBlobEntries!, - updateRobotBlobEntry!, - deleteRobotBlobEntry!, - getUserBlobEntry, - getUserBlobEntries, - addUserBlobEntry!, - addUserBlobEntries!, - updateUserBlobEntry!, - deleteUserBlobEntry! +export getDescription, + setDescription!, + getSolverParams, + setSolverParams!, + getUserData, + setUserData!, + getRobotData, + setRobotData!, + getSessionData, + setSessionData!, + getAddHistory + +export getSessionBlobEntry, + getSessionBlobEntries, + addSessionBlobEntry!, + addSessionBlobEntries!, + updateSessionBlobEntry!, + deleteSessionBlobEntry!, + getRobotBlobEntry, + getRobotBlobEntries, + addRobotBlobEntry!, + addRobotBlobEntries!, + updateRobotBlobEntry!, + deleteRobotBlobEntry!, + getUserBlobEntry, + getUserBlobEntries, + addUserBlobEntry!, + addUserBlobEntries!, + updateUserBlobEntry!, + deleteUserBlobEntry! export getBlobStore, - addBlobStore!, - updateBlobStore!, - deleteBlobStore!, - emptyBlobStore!, - listBlobStores + addBlobStore!, updateBlobStore!, deleteBlobStore!, emptyBlobStore!, listBlobStores # TODO Not sure these are needed or should work everywhere, implement in cloud? -export updateUserData!, updateRobotData!, updateSessionData!, deleteUserData!, deleteRobotData!, deleteSessionData! +export updateUserData!, + updateRobotData!, + updateSessionData!, + deleteUserData!, + deleteRobotData!, + deleteSessionData! export emptyUserData!, emptyRobotData!, emptySessionData! # Graph Types: exported from modules or @reexport @@ -108,14 +113,22 @@ export InMemoryDFGTypes, LocalDFG # AbstractDFG Interface export exists, - addVariable!, addFactor!, - getVariable, getFactor, - updateVariable!, updateFactor!, - deleteVariable!, deleteFactor!, - listVariables, listFactors, - listSolveKeys, listSupersolves, - getVariables, getFactors, - isVariable, isFactor + addVariable!, + addFactor!, + getVariable, + getFactor, + updateVariable!, + updateFactor!, + deleteVariable!, + deleteFactor!, + listVariables, + listFactors, + listSolveKeys, + listSupersolves, + getVariables, + getFactors, + isVariable, + isFactor export getindex @@ -175,19 +188,23 @@ export getPointIdentity, getPoint, getCoordinates export getManifolds # TODO Deprecate? # Small Data CRUD -export SmallDataTypes, getSmallData, addSmallData!, updateSmallData!, deleteSmallData!, listSmallData, emptySmallData! +export SmallDataTypes, + getSmallData, + addSmallData!, + updateSmallData!, + deleteSmallData!, + listSmallData, + emptySmallData! export getSmallData, setSmallData! - # CRUD & SET export getVariableSolverData, - addVariableSolverData!, - updateVariableSolverData!, - deleteVariableSolverData!, - listVariableSolverData, - mergeVariableSolverData!, - cloneSolveKey! - + addVariableSolverData!, + updateVariableSolverData!, + deleteVariableSolverData!, + listVariableSolverData, + mergeVariableSolverData!, + cloneSolveKey! # PPE ##------------------------------------------------------------------------------ @@ -202,14 +219,7 @@ export getPPEDict, getVariablePPEDict, getVariablePPE # CRUD & SET export getPPE, - getPPEs, - getVariablePPE, - addPPE!, - updatePPE!, - deletePPE!, - listPPEs, - mergePPEs! #TODO look at rename to just mergePPE to match with cloud? - + getPPEs, getVariablePPE, addPPE!, updatePPE!, deletePPE!, listPPEs, mergePPEs! #TODO look at rename to just mergePPE to match with cloud? # Variable Node Data ##------------------------------------------------------------------------------ @@ -217,7 +227,8 @@ export VariableNodeData, PackedVariableNodeData export packVariableNodeData, unpackVariableNodeData -export getSolvedCount, isSolved, setSolvedCount!, isInitialized, isMarginalized, setMarginalized! +export getSolvedCount, + isSolved, setSolvedCount!, isInitialized, isMarginalized, setMarginalized! export getNeighborhood, listNeighbors, _getDuplicatedEmptyDFG export findFactorsBetweenNaive @@ -226,7 +237,14 @@ export copyGraph!, deepcopyGraph, deepcopyGraph!, buildSubgraph, mergeGraph! # Entry Blob Data ##------------------------------------------------------------------------------ -export hasBlobEntry,getBlobEntry,addBlobEntry!,updateBlobEntry!,deleteBlobEntry!,listBlobEntry,listBlobEntrySequence,mergeBlobEntry! +export hasBlobEntry, + getBlobEntry, + addBlobEntry!, + updateBlobEntry!, + deleteBlobEntry!, + listBlobEntry, + listBlobEntrySequence, + mergeBlobEntry! export incrDataLabelSuffix export getBlobEntries, listDataEntries, hasDataEntry, hasDataEntry @@ -292,8 +310,7 @@ export findShortestPathDijkstra export isPathFactorsHomogeneous # Comparisons -export - compare, +export compare, compareField, compareFields, compareAll, @@ -306,7 +323,6 @@ export compareSimilarFactors, compareFactorGraphs - ## Deprecated exports should be listed in Deprecated.jl if possible, otherwise here ## CustomPrinting.jl @@ -379,6 +395,4 @@ include("Common.jl") function plotDFG end - - end diff --git a/src/FileDFG/services/FileDFG.jl b/src/FileDFG/services/FileDFG.jl index faa60f62..eb87ccf2 100644 --- a/src/FileDFG/services/FileDFG.jl +++ b/src/FileDFG/services/FileDFG.jl @@ -17,12 +17,12 @@ v1 = addVariable!(dfg, :a, ContinuousScalar, tags = [:POSE], solvable=0) saveDFG(dfg, "/tmp/saveDFG.tar.gz") ``` """ -function saveDFG(folder::AbstractString, dfg::AbstractDFG; saveMetadata::Bool=true) +function saveDFG(folder::AbstractString, dfg::AbstractDFG; saveMetadata::Bool = true) # TODO: Deprecate the folder functionality # Clean up save path if a file is specified - savepath = folder[end] == '/' ? folder[1:end-1] : folder + savepath = folder[end] == '/' ? folder[1:(end - 1)] : folder savepath = splitext(splitext(savepath)[1])[1] # In case of .tar.gz variables = getVariables(dfg) @@ -60,17 +60,17 @@ function saveDFG(folder::AbstractString, dfg::AbstractDFG; saveMetadata::Bool=tr savedir = dirname(savepath) # is this a path of just local name? #344 -- workaround with unique names savename = basename(string(savepath)) @assert savename != "" - destfile = joinpath(savedir, savename*".tar.gz") - + destfile = joinpath(savedir, savename * ".tar.gz") + #create Tarbal using Tar.jl #351 - tar_gz = open(destfile, write=true) + tar_gz = open(destfile; write = true) tar = CodecZlib.GzipCompressorStream(tar_gz) - Tar.create(joinpath(savedir,savename), tar) + Tar.create(joinpath(savedir, savename), tar) close(tar) #not compressed version # Tar.create(joinpath(savedir,savename), destfile) - Base.rm(joinpath(savedir,savename), recursive=true) + return Base.rm(joinpath(savedir, savename); recursive = true) end # support both argument orders, #581 saveDFG(dfg::AbstractDFG, folder::AbstractString) = saveDFG(folder, dfg) @@ -92,11 +92,16 @@ loadDFG!(dfg, "/tmp/savedgraph.tar.gz") ls(dfg) ``` """ -function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMetadata::Bool=true, useDeprExtract::Bool=false) +function loadDFG!( + dfgLoadInto::AbstractDFG, + dst::AbstractString; + overwriteDFGMetadata::Bool = true, + useDeprExtract::Bool = false, +) # # loaddir gets deleted so needs to be unique - loaddir=split(joinpath("/","tmp","caesar","random", string(uuid1())), '-')[1] + loaddir = split(joinpath("/", "tmp", "caesar", "random", string(uuid1())), '-')[1] # Check if zipped destination (dst) by first doing fuzzy search from user supplied dst folder = dst # working directory for fileDFG variable and factor operations dstname = dst # path name could either be legacy FileDFG dir or .tar.gz file of FileDFG files. @@ -115,13 +120,13 @@ function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMet @assert isfile(dstname) "cannot find file $dstname" # TODO -- what if it is not a tar.gz but classic folder instead? # do actual unzipping - filename = lastdirname[1:(end-length(".tar.gz"))] |> string + filename = lastdirname[1:(end - length(".tar.gz"))] |> string if unzip @show sfolder = split(dstname, '.') Base.mkpath(loaddir) folder = joinpath(loaddir, filename) #splitpath(string(sfolder[end-2]))[end] @info "loadDFG! detected a gzip $dstname -- unpacking via $loaddir now..." - Base.rm(folder, recursive=true, force=true) + Base.rm(folder; recursive = true, force = true) # unzip the tar file # TODO deprecated, remove. Kept for legacy support if older tarbals @@ -155,10 +160,11 @@ function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMet # Folder preparations !isdir(folder) && error("Can't load DFG graph - folder '$folder' doesn't exist") !isdir(varFolder) && error("Can't load DFG graph - folder '$varFolder' doesn't exist") - !isdir(factorFolder) && error("Can't load DFG graph - folder '$factorFolder' doesn't exist") + !isdir(factorFolder) && + error("Can't load DFG graph - folder '$factorFolder' doesn't exist") - varFiles = sort(readdir(varFolder; sort=false); lt=natural_lt) - factorFiles = sort(readdir(factorFolder; sort=false); lt=natural_lt) + varFiles = sort(readdir(varFolder; sort = false); lt = natural_lt) + factorFiles = sort(readdir(factorFolder; sort = false); lt = natural_lt) if isa(dfgLoadInto, GraphsDFG) && GraphsDFGs._variablestype(dfgLoadInto) == Variable variables = @showprogress 1 "loading variables" map(varFiles) do varFile @@ -173,7 +179,9 @@ function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMet packedData = JSON3.read(jstr, PackedVariable) push!(variables, unpackVariable(packedData)) catch ex - @error("JSON3 is having trouble reading $varFolder/$varFile into a PackedVariable") + @error( + "JSON3 is having trouble reading $varFolder/$varFile into a PackedVariable" + ) @show jstr throw(ex) end @@ -183,7 +191,7 @@ function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMet @info "Loaded $(length(variables)) variables"#- $(map(v->v.label, variables))" @info "Inserting variables into graph..." # Adding variables - map(v->addVariable!(dfgLoadInto, v), variables) + map(v -> addVariable!(dfgLoadInto, v), variables) if isa(dfgLoadInto, GraphsDFG) && GraphsDFGs._factorstype(dfgLoadInto) == PackedFactor factors = @showprogress 1 "loading factors" map(factorFiles) do factorFile @@ -197,7 +205,9 @@ function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMet packedData = JSON3.read(jstr, PackedFactor) push!(factors, unpackFactor(dfgLoadInto, packedData)) catch ex - @error("JSON3 is having trouble reading $factorFolder/$factorFile into a PackedFactor") + @error( + "JSON3 is having trouble reading $factorFolder/$factorFile into a PackedFactor" + ) @show jstr throw(ex) end @@ -206,7 +216,7 @@ function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMet @info "Loaded $(length(factors)) factors"# - $(map(f->f.label, factors))" @info "Inserting factors into graph..." # # Adding factors - map(f->addFactor!(dfgLoadInto, f), factors) + map(f -> addFactor!(dfgLoadInto, f), factors) if isa(dfgLoadInto, GraphsDFG) && GraphsDFGs._factorstype(dfgLoadInto) != PackedFactor # Finally, rebuild the CCW's for the factors to completely reinflate them @@ -221,7 +231,7 @@ function loadDFG!(dfgLoadInto::AbstractDFG, dst::AbstractString; overwriteDFGMet if unzip @info "DFG.loadDFG! is deleting a temp folder created during unzip, $loaddir" # need this because the number of files created in /tmp/caesar/random is becoming redonkulous. - Base.rm(loaddir, recursive=true, force=true) + Base.rm(loaddir; recursive = true, force = true) end return dfgLoadInto @@ -229,29 +239,27 @@ end function loadDFG(file::AbstractString) - # add if doesn't have .tar.gz extension + # add if doesn't have .tar.gz extension if !contains(basename(file), ".tar.gz") file *= ".tar.gz" end # check the file actually exists @assert isfile(file) "cannot find file $file" - + # only extract dfg.json to rebuild DFG object tar_gz = open(file) tar = CodecZlib.GzipDecompressorStream(tar_gz) loaddir = Tar.extract(hdr -> contains(hdr.path, "dfg.json"), tar) close(tar) - + #Only GraphsDFG metadata supported jstr = read("$loaddir/dfg.json", String) fgPacked = JSON3.read(jstr, GraphsDFGs.PackedGraphsDFG) dfg = GraphsDFGs.unpackDFGMetadata(fgPacked) - @debug "DFG.loadDFG! is deleting a temp folder created during unzip, $loaddir" # cleanup temporary folder - Base.rm(loaddir, recursive=true, force=true) + Base.rm(loaddir; recursive = true, force = true) return loadDFG!(dfg, file) - -end \ No newline at end of file +end diff --git a/src/GraphsDFG/FactorGraphs/BiMaps.jl b/src/GraphsDFG/FactorGraphs/BiMaps.jl index 382713b1..0fbfa1b4 100644 --- a/src/GraphsDFG/FactorGraphs/BiMaps.jl +++ b/src/GraphsDFG/FactorGraphs/BiMaps.jl @@ -1,19 +1,18 @@ # import Base: getindex, setindex!, firstindex, lastindex, iterate, keys, isempty struct BiDictMap{T <: Integer} - int_sym::Dict{T,Symbol} - sym_int::Dict{Symbol,T} + int_sym::Dict{T, Symbol} + sym_int::Dict{Symbol, T} end -BiDictMap{T}(;sizehint=100) where T<:Integer = begin - int_sym = Dict{T,Symbol}() +BiDictMap{T}(; sizehint = 100) where {T <: Integer} = begin + int_sym = Dict{T, Symbol}() sizehint!(int_sym, sizehint) - sym_int = Dict{Symbol,T}() + sym_int = Dict{Symbol, T}() sizehint!(sym_int, sizehint) BiDictMap{T}(int_sym, sym_int) end -BiDictMap(;sizehint=100) = BiDictMap{Int}(;sizehint=sizehint) - +BiDictMap(; sizehint = 100) = BiDictMap{Int}(; sizehint = sizehint) Base.getindex(b::BiDictMap, key::Int) = b.int_sym[key] Base.getindex(b::BiDictMap, key::Symbol) = b.sym_int[key] @@ -24,7 +23,7 @@ function Base.setindex!(b::BiDictMap, s::Symbol, i::Int) haskey(b.int_sym, i) && delete!(b.sym_int, b[i]) b.int_sym[i] = s - b.sym_int[s] = i + return b.sym_int[s] = i end function Base.setindex!(b::BiDictMap, i::Int, s::Symbol) @@ -32,7 +31,7 @@ function Base.setindex!(b::BiDictMap, i::Int, s::Symbol) haskey(b.sym_int, s) && delete!(b.int_sym, b[s]) b.int_sym[i] = s - b.sym_int[s] = i + return b.sym_int[s] = i end function Base.delete!(b::BiDictMap, i::Int) @@ -49,6 +48,8 @@ Base.length(b::BiDictMap) = length(b.int_sym) #NOTE to future self: This will work only with GraphsGraphs that always follows a 1:nv(g) index Base.firstindex(v::BiDictMap) = 1 Base.lastindex(v::BiDictMap) = length(v.int_sym) -Base.iterate(v::BiDictMap, i=1) = (length(v.int_sym) < i ? nothing : (v.int_sym[i], i + 1)) +function Base.iterate(v::BiDictMap, i = 1) + return (length(v.int_sym) < i ? nothing : (v.int_sym[i], i + 1)) +end Base.keys(v::BiDictMap) = Base.OneTo(length(v.int_sym)) Base.isempty(v::BiDictMap) = (length(v.int_sym) == 0) diff --git a/src/GraphsDFG/FactorGraphs/FactorGraphs.jl b/src/GraphsDFG/FactorGraphs/FactorGraphs.jl index 3d469228..77097953 100644 --- a/src/GraphsDFG/FactorGraphs/FactorGraphs.jl +++ b/src/GraphsDFG/FactorGraphs/FactorGraphs.jl @@ -3,35 +3,48 @@ using Graphs using OrderedCollections -import Base: - eltype, show, ==, Pair, - Tuple, copy, length, size, - issubset, zero, getindex +import Base: eltype, show, ==, Pair, Tuple, copy, length, size, issubset, zero, getindex # import Random: # randstring, seed! import Graphs: - AbstractGraph, src, dst, edgetype, nv, - ne, vertices, edges, is_directed, - add_vertex!, add_edge!, rem_vertex!, rem_edge!, - has_vertex, has_edge, inneighbors, outneighbors, - weights, indegree, outdegree, degree, + AbstractGraph, + src, + dst, + edgetype, + nv, + ne, + vertices, + edges, + is_directed, + add_vertex!, + add_edge!, + rem_vertex!, + rem_edge!, + has_vertex, + has_edge, + inneighbors, + outneighbors, + weights, + indegree, + outdegree, + degree, induced_subgraph, - loadgraph, savegraph, AbstractGraphFormat, + loadgraph, + savegraph, + AbstractGraphFormat, reverse import Graphs.SimpleGraphs: - AbstractSimpleGraph, SimpleGraph, SimpleDiGraph, - SimpleEdge, fadj, badj - -export - FactorGraph - # addVariable!, - # addFactor!, - # GraphsBayesGraph, - # filter_edges, - # filter_vertices, - # reverse + AbstractSimpleGraph, SimpleGraph, SimpleDiGraph, SimpleEdge, fadj, badj + +export FactorGraph +# addVariable!, +# addFactor!, +# GraphsBayesGraph, +# filter_edges, +# filter_vertices, +# reverse # import DistributedFactorGraphs: DFGNode # const AbstractNodeType = DFGNode @@ -41,22 +54,26 @@ const AbstractFactorType = AbstractDFGFactor include("BiMaps.jl") -struct FactorGraph{T <: Integer,V <: AbstractVariableType, F <: AbstractFactorType} <: AbstractGraph{T} +struct FactorGraph{T <: Integer, V <: AbstractVariableType, F <: AbstractFactorType} <: + AbstractGraph{T} graph::SimpleGraph{T} labels::BiDictMap{T} - variables::OrderedDict{Symbol,V} - factors::OrderedDict{Symbol,F} + variables::OrderedDict{Symbol, V} + factors::OrderedDict{Symbol, F} end -function FactorGraph{T, V, F}(nv::Int=100, nf::Int=100) where {T <: Integer, V <: AbstractVariableType, F <: AbstractFactorType} +function FactorGraph{T, V, F}( + nv::Int = 100, + nf::Int = 100, +) where {T <: Integer, V <: AbstractVariableType, F <: AbstractFactorType} fadjlist = Vector{Vector{T}}() - sizehint!(fadjlist, nv + nf) + sizehint!(fadjlist, nv + nf) g = SimpleGraph{T}(0, fadjlist) - labels = BiDictMap{T}(sizehint=nv+nf) - variables = OrderedDict{Symbol,V}() - sizehint!(variables, nv) - factors = OrderedDict{Symbol,F}() - sizehint!(factors, nf) + labels = BiDictMap{T}(; sizehint = nv + nf) + variables = OrderedDict{Symbol, V}() + sizehint!(variables, nv) + factors = OrderedDict{Symbol, F}() + sizehint!(factors, nf) return FactorGraph{T, V, F}(g, labels, variables, factors) end @@ -65,16 +82,14 @@ end FactorGraph() = FactorGraph{Int, AbstractVariableType, AbstractFactorType}() # FactorGraph{V,F}() where {V <: AbstractVariableType, F <: AbstractFactorType} = FactorGraph{Int, V, F}() - function show(io::IO, ::MIME"text/plain", g::FactorGraph) dir = is_directed(g) ? "directed" : "undirected" - print(io, "{$(nv(g)), $(ne(g))} $dir $(eltype(g)) $(typeof(g))") + return print(io, "{$(nv(g)), $(ne(g))} $dir $(eltype(g)) $(typeof(g))") end @inline fadj(g::FactorGraph, x...) = fadj(g.graph, x...) @inline badj(g::FactorGraph, x...) = badj(g.graph, x...) - eltype(g::FactorGraph) = eltype(g.graph) edgetype(g::FactorGraph) = edgetype(g.graph) nv(g::FactorGraph) = nv(g.graph) @@ -90,10 +105,10 @@ inneighbors(g::FactorGraph, v::Integer) = inneighbors(g.graph, v) outneighbors(g::FactorGraph, v::Integer) = fadj(g.graph, v) is_directed(::Type{FactorGraph}) = false -is_directed(::Type{FactorGraph{T,V,F}}) where {T,V,F} = false +is_directed(::Type{FactorGraph{T, V, F}}) where {T, V, F} = false is_directed(g::FactorGraph) = false -zero(g::FactorGraph{T,V,F}) where {T,V,F} = FactorGraph{T,V,F}(0,0) +zero(g::FactorGraph{T, V, F}) where {T, V, F} = FactorGraph{T, V, F}(0, 0) # TODO issubset(g::T, h::T) where T <: FactorGraph = issubset(g.graph, h.graph) @@ -101,9 +116,7 @@ zero(g::FactorGraph{T,V,F}) where {T,V,F} = FactorGraph{T,V,F}(0,0) @inline rem_edge!(g::FactorGraph, x...) = rem_edge!(g.graph, x...) - function addVariable!(g::FactorGraph{T, V, F}, variable::V) where {T, V, F} - label = variable.label haskey(g.labels, label) && (@error "Label already in fg"; return false) #TODO debug error or exception? @@ -112,24 +125,30 @@ function addVariable!(g::FactorGraph{T, V, F}, variable::V) where {T, V, F} g.labels[nv(g.graph)] = label - push!(g.variables, label=>variable) + push!(g.variables, label => variable) return true end -function addFactor!(g::FactorGraph{T, V, F}, variableLabels::Vector{Symbol}, factor::F)::Bool where {T, V, F} - - haskey(g.labels, factor.label) && (@error "Label $(factor.label) already in fg"; return false) +function addFactor!( + g::FactorGraph{T, V, F}, + variableLabels::Vector{Symbol}, + factor::F, +)::Bool where {T, V, F} + haskey(g.labels, factor.label) && + (@error "Label $(factor.label) already in fg"; return false) for vlabel in variableLabels - !haskey(g.labels, vlabel) && (@error "Variable '$(vlabel)' not found in graph when creating Factor '$(factor.label)'"; return false) #TODO debug error or exception? + !haskey(g.labels, vlabel) && ( + @error "Variable '$(vlabel)' not found in graph when creating Factor '$(factor.label)'"; return false + ) #TODO debug error or exception? end add_vertex!(g.graph) || return false g.labels[nv(g.graph)] = factor.label - push!(g.factors, factor.label=>factor) + push!(g.factors, factor.label => factor) # add the edges for vlabel in variableLabels @@ -139,9 +158,7 @@ function addFactor!(g::FactorGraph{T, V, F}, variableLabels::Vector{Symbol}, fac return true end - - -function rem_vertex!(g::FactorGraph{T,V,F}, v::Integer) where {T,V,F} +function rem_vertex!(g::FactorGraph{T, V, F}, v::Integer) where {T, V, F} v in vertices(g) || return false lastv = nv(g) @@ -150,7 +167,7 @@ function rem_vertex!(g::FactorGraph{T,V,F}, v::Integer) where {T,V,F} label = g.labels[v] delete!(g.variables, label) delete!(g.factors, label) - + OrderedCollections.rehash!(g.variables) OrderedCollections.rehash!(g.factors) @@ -163,6 +180,4 @@ function rem_vertex!(g::FactorGraph{T,V,F}, v::Integer) where {T,V,F} return true end - - end diff --git a/src/GraphsDFG/GraphsDFG.jl b/src/GraphsDFG/GraphsDFG.jl index 36a0b9d6..6a555361 100644 --- a/src/GraphsDFG/GraphsDFG.jl +++ b/src/GraphsDFG/GraphsDFG.jl @@ -12,46 +12,47 @@ using ...DistributedFactorGraphs # import ...DistributedFactorGraphs: AbstractDFG, DFGNode, AbstractDFGVariable, AbstractDFGFactor, DFGSummary, AbstractParams, NoSolverParams, DFGVariable, DFGFactor # import DFG functions to extend -import ...DistributedFactorGraphs: setSolverParams!, - getFactor, - # getLabelDict, - getUserData, - setUserData!, - getRobotData, - setRobotData!, - getSessionData, - setSessionData!, - addVariable!, - getVariable, - getAddHistory, - addFactor!, - getSolverParams, - exists, - isVariable, - isFactor, - updateVariable!, - updateFactor!, - deleteVariable!, - deleteFactor!, - getVariables, - listVariables, - ls, - getFactors, - listFactors, - lsf, - isConnected, - listNeighbors, - buildSubgraph, - copyGraph!, - getBiadjacencyMatrix, - _getDuplicatedEmptyDFG, - toDot, - toDotFile, - findShortestPathDijkstra, - getSessionBlobEntry, - getSessionBlobEntries, - addSessionBlobEntry!, - addSessionBlobEntries! +import ...DistributedFactorGraphs: + setSolverParams!, + getFactor, + # getLabelDict, + getUserData, + setUserData!, + getRobotData, + setRobotData!, + getSessionData, + setSessionData!, + addVariable!, + getVariable, + getAddHistory, + addFactor!, + getSolverParams, + exists, + isVariable, + isFactor, + updateVariable!, + updateFactor!, + deleteVariable!, + deleteFactor!, + getVariables, + listVariables, + ls, + getFactors, + listFactors, + lsf, + isConnected, + listNeighbors, + buildSubgraph, + copyGraph!, + getBiadjacencyMatrix, + _getDuplicatedEmptyDFG, + toDot, + toDotFile, + findShortestPathDijkstra, + getSessionBlobEntry, + getSessionBlobEntries, + addSessionBlobEntry!, + addSessionBlobEntries! include("FactorGraphs/FactorGraphs.jl") using .FactorGraphs @@ -65,5 +66,4 @@ include("services/GraphsDFGSerialization.jl") # Exports export GraphsDFG - end diff --git a/src/GraphsDFG/entities/GraphsDFG.jl b/src/GraphsDFG/entities/GraphsDFG.jl index 2e2b1f82..c909b5f1 100644 --- a/src/GraphsDFG/entities/GraphsDFG.jl +++ b/src/GraphsDFG/entities/GraphsDFG.jl @@ -7,7 +7,11 @@ An in-memory DistributedFactorGraph based on Graphs.jl with parameters: - V: Variable type - F: Factor type """ -mutable struct GraphsDFG{T <: AbstractParams, V <: AbstractDFGVariable, F <:AbstractDFGFactor} <: AbstractDFG{T} +mutable struct GraphsDFG{ + T <: AbstractParams, + V <: AbstractDFGVariable, + F <: AbstractDFGFactor, +} <: AbstractDFG{T} g::FactorGraph{Int, V, F} description::String userLabel::String @@ -32,12 +36,12 @@ Create an in-memory GraphsDFG with the following parameters: - V: Variable type - F: Factor type """ -function GraphsDFG{T,V,F}( - g::FactorGraph{Int,V,F}=FactorGraph{Int,V,F}(); - description::String="Graphs.jl implementation", - userLabel::String="DefaultUser", - robotLabel::String="DefaultRobot", - sessionLabel::String="Session_$(string(uuid4())[1:6])", +function GraphsDFG{T, V, F}( + g::FactorGraph{Int, V, F} = FactorGraph{Int, V, F}(); + description::String = "Graphs.jl implementation", + userLabel::String = "DefaultUser", + robotLabel::String = "DefaultRobot", + sessionLabel::String = "Session_$(string(uuid4())[1:6])", userData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), robotData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), sessionData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), @@ -45,15 +49,15 @@ function GraphsDFG{T,V,F}( robotBlobEntries::OrderedDict{Symbol, BlobEntry} = OrderedDict{Symbol, BlobEntry}(), sessionBlobEntries::OrderedDict{Symbol, BlobEntry} = OrderedDict{Symbol, BlobEntry}(), addHistory::Vector{Symbol} = Symbol[], - solverParams::T=T(), - blobStores=Dict{Symbol, AbstractBlobStore}(), -) where {T <: AbstractParams, V <:AbstractDFGVariable, F<:AbstractDFGFactor} + solverParams::T = T(), + blobStores = Dict{Symbol, AbstractBlobStore}(), +) where {T <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} # Validate the userLabel, robotLabel, and sessionLabel !isValidLabel(userLabel) && error("'$userLabel' is not a valid User label") !isValidLabel(robotLabel) && error("'$robotLabel' is not a valid Robot label") !isValidLabel(sessionLabel) && error("'$sessionLabel' is not a valid Session label") - return GraphsDFG{T,V,F}( + return GraphsDFG{T, V, F}( g, description, userLabel, @@ -67,23 +71,27 @@ function GraphsDFG{T,V,F}( sessionBlobEntries, addHistory, solverParams, - blobStores + blobStores, ) end # GraphsDFG{T}(; kwargs...) where T <: AbstractParams = GraphsDFG{T,DFGVariable,DFGFactor}(;kwargs...) -function GraphsDFG{T}(g::FactorGraph{Int,DFGVariable,DFGFactor}=FactorGraph{Int,DFGVariable,DFGFactor}(); - kwargs...) where T <: AbstractParams - return GraphsDFG{T,DFGVariable,DFGFactor}(g; kwargs...) +function GraphsDFG{T}( + g::FactorGraph{Int, DFGVariable, DFGFactor} = FactorGraph{Int, DFGVariable, DFGFactor}(); + kwargs..., +) where {T <: AbstractParams} + return GraphsDFG{T, DFGVariable, DFGFactor}(g; kwargs...) end -function GraphsDFG(g::FactorGraph{Int,DFGVariable,DFGFactor}=FactorGraph{Int,DFGVariable,DFGFactor}(); - solverParams::T=NoSolverParams(), kwargs...) where T - return GraphsDFG{T,DFGVariable,DFGFactor}(g; solverParams, kwargs...) +function GraphsDFG( + g::FactorGraph{Int, DFGVariable, DFGFactor} = FactorGraph{Int, DFGVariable, DFGFactor}(); + solverParams::T = NoSolverParams(), + kwargs..., +) where {T} + return GraphsDFG{T, DFGVariable, DFGFactor}(g; solverParams, kwargs...) end - -GraphsDFG( +function GraphsDFG( description::String, userLabel::String, robotLabel::String, @@ -92,9 +100,10 @@ GraphsDFG( robotData::Dict{Symbol, SmallDataTypes}, sessionData::Dict{Symbol, SmallDataTypes}, solverParams::AbstractParams, - blobStores=Dict{Symbol, AbstractBlobStore}() -) = GraphsDFG{typeof(solverParams),DFGVariable,DFGFactor}( - FactorGraph{Int,DFGVariable,DFGFactor}(); + blobStores = Dict{Symbol, AbstractBlobStore}(), +) + return GraphsDFG{typeof(solverParams), DFGVariable, DFGFactor}( + FactorGraph{Int, DFGVariable, DFGFactor}(); description, userLabel, robotLabel, @@ -103,11 +112,11 @@ GraphsDFG( robotData, sessionData, solverParams, - blobStores + blobStores, ) +end - -function GraphsDFG{T,V,F}( +function GraphsDFG{T, V, F}( description::String, userLabel::String, robotLabel::String, @@ -116,10 +125,10 @@ function GraphsDFG{T,V,F}( robotData::Dict{Symbol, SmallDataTypes}, sessionData::Dict{Symbol, SmallDataTypes}, solverParams::T, - blobStores=Dict{Symbol, AbstractBlobStore}() -) where {T <: AbstractParams, V <:AbstractDFGVariable, F<:AbstractDFGFactor} - return GraphsDFG{T,V,F}( - FactorGraph{Int,V,F}(); + blobStores = Dict{Symbol, AbstractBlobStore}(), +) where {T <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} + return GraphsDFG{T, V, F}( + FactorGraph{Int, V, F}(); description, userLabel, robotLabel, @@ -128,6 +137,6 @@ function GraphsDFG{T,V,F}( robotData, sessionData, solverParams, - blobStores + blobStores, ) -end \ No newline at end of file +end diff --git a/src/GraphsDFG/services/GraphsDFG.jl b/src/GraphsDFG/services/GraphsDFG.jl index d7c031e1..a05c43f6 100644 --- a/src/GraphsDFG/services/GraphsDFG.jl +++ b/src/GraphsDFG/services/GraphsDFG.jl @@ -1,16 +1,22 @@ -function getDFGMetadata(fg::GraphsDFG) +function getDFGMetadata(fg::GraphsDFG) metafields = Set(fieldnames(GraphsDFG)) setdiff!(metafields, [:g, :solverParams]) metaprops = NamedTuple(k => getproperty(fg, k) for k in metafields) return metaprops end -function exists(dfg::GraphsDFG{P,V,F}, node::V) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} +function exists( + dfg::GraphsDFG{P, V, F}, + node::V, +) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} return haskey(dfg.g.variables, node.label) end -function exists(dfg::GraphsDFG{P,V,F}, node::F) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} +function exists( + dfg::GraphsDFG{P, V, F}, + node::F, +) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} return haskey(dfg.g.factors, node.label) end @@ -18,16 +24,24 @@ exists(dfg::GraphsDFG, nId::Symbol) = haskey(dfg.g.labels, nId) exists(dfg::GraphsDFG, node::DFGNode) = exists(dfg, node.label) -function isVariable(dfg::GraphsDFG{P,V,F}, sym::Symbol) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} +function isVariable( + dfg::GraphsDFG{P, V, F}, + sym::Symbol, +) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} return haskey(dfg.g.variables, sym) end -function isFactor(dfg::GraphsDFG{P,V,F}, sym::Symbol) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} +function isFactor( + dfg::GraphsDFG{P, V, F}, + sym::Symbol, +) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} return haskey(dfg.g.factors, sym) end - -function addVariable!(dfg::GraphsDFG{<:AbstractParams, V, <:AbstractDFGFactor}, variable::V)::V where V <: AbstractDFGVariable +function addVariable!( + dfg::GraphsDFG{<:AbstractParams, V, <:AbstractDFGFactor}, + variable::V, +)::V where {V <: AbstractDFGVariable} #TODO should this be an error if haskey(dfg.g.variables, variable.label) error("Variable '$(variable.label)' already exists in the factor graph") @@ -41,12 +55,13 @@ function addVariable!(dfg::GraphsDFG{<:AbstractParams, V, <:AbstractDFGFactor}, return variable end -function addVariable!(dfg::GraphsDFG{<:AbstractParams, VD, <:AbstractDFGFactor}, - variable::AbstractDFGVariable)::VD where VD <: AbstractDFGVariable +function addVariable!( + dfg::GraphsDFG{<:AbstractParams, VD, <:AbstractDFGFactor}, + variable::AbstractDFGVariable, +)::VD where {VD <: AbstractDFGVariable} return addVariable!(dfg, VD(variable)) end - #moved to abstract # function addFactor!(dfg::GraphsDFG{<:AbstractParams, V, F}, variables::Vector{<:V}, factor::F)::F where {V <: AbstractDFGVariable, F <: AbstractDFGFactor} # @@ -84,8 +99,10 @@ end # return factor # end - -function addFactor!(dfg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, F}, factor::F) where F <: AbstractDFGFactor +function addFactor!( + dfg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, F}, + factor::F, +) where {F <: AbstractDFGFactor} if haskey(dfg.g.factors, factor.label) error("Factor '$(factor.label)' already exists in the factor graph") end @@ -95,8 +112,10 @@ function addFactor!(dfg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, F}, return factor end -function addFactor!(dfg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, F}, - factor::AbstractDFGFactor) where F <: AbstractDFGFactor +function addFactor!( + dfg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, F}, + factor::AbstractDFGFactor, +) where {F <: AbstractDFGFactor} return addFactor!(dfg, F(factor)) end @@ -115,23 +134,34 @@ function getFactor(dfg::GraphsDFG, label::Symbol) return dfg.g.factors[label] end -function updateVariable!(dfg::GraphsDFG, variable::AbstractDFGVariable; warn_if_absent::Bool=true) +function updateVariable!( + dfg::GraphsDFG, + variable::AbstractDFGVariable; + warn_if_absent::Bool = true, +) if !haskey(dfg.g.variables, variable.label) - warn_if_absent && @warn "Variable label '$(variable.label)' does not exist in the factor graph, adding" + warn_if_absent && + @warn "Variable label '$(variable.label)' does not exist in the factor graph, adding" return addVariable!(dfg, variable) end dfg.g.variables[variable.label] = variable return variable end -function updateFactor!(dfg::GraphsDFG, factor::AbstractDFGFactor; warn_if_absent::Bool=true) +function updateFactor!( + dfg::GraphsDFG, + factor::AbstractDFGFactor; + warn_if_absent::Bool = true, +) if !haskey(dfg.g.factors, factor.label) - warn_if_absent && @warn "Factor label '$(factor.label)' does not exist in the factor graph, adding" + warn_if_absent && + @warn "Factor label '$(factor.label)' does not exist in the factor graph, adding" return addFactor!(dfg, factor) end # Confirm that we're not updating the neighbors - dfg.g.factors[factor.label]._variableOrderSymbols != factor._variableOrderSymbols && error("Cannot update the factor, the neighbors are not the same.") + dfg.g.factors[factor.label]._variableOrderSymbols != factor._variableOrderSymbols && + error("Cannot update the factor, the neighbors are not the same.") dfg.g.factors[factor.label] = factor return factor @@ -144,7 +174,7 @@ function deleteVariable!(dfg::GraphsDFG, label::Symbol)#::Tuple{AbstractDFGVaria deleteNeighbors = true # reserved, orphaned factors are not supported at this time if deleteNeighbors - neigfacs = map(l->deleteFactor!(dfg, l), listNeighbors(dfg, label)) + neigfacs = map(l -> deleteFactor!(dfg, l), listNeighbors(dfg, label)) end variable = dfg.g.variables[label] rem_vertex!(dfg.g, dfg.g.labels[label]) @@ -152,16 +182,26 @@ function deleteVariable!(dfg::GraphsDFG, label::Symbol)#::Tuple{AbstractDFGVaria return variable, neigfacs end -function deleteFactor!(dfg::GraphsDFG, label::Symbol; suppressGetFactor::Bool=false)::AbstractDFGFactor +function deleteFactor!( + dfg::GraphsDFG, + label::Symbol; + suppressGetFactor::Bool = false, +)::AbstractDFGFactor if !haskey(dfg.g.factors, label) error("Factor label '$(label)' does not exist in the factor graph") end factor = dfg.g.factors[label] - rem_vertex!(dfg.g, dfg.g.labels[label]) + rem_vertex!(dfg.g, dfg.g.labels[label]) return factor end -function getVariables(dfg::GraphsDFG, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0, detail=nothing) +function getVariables( + dfg::GraphsDFG, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, + detail = nothing, +) # variables = map(v -> v.dfgNode, filter(n -> n.dfgNode isa DFGVariable, vertices(dfg.g))) variables = collect(values(dfg.g.variables)) @@ -172,26 +212,41 @@ function getVariables(dfg::GraphsDFG, regexFilter::Union{Nothing, Regex}=nothing variables = filter(v -> _isSolvable(dfg, v.label, solvable), variables) end if length(tags) > 0 - mask = map(v -> length(intersect(v.tags, tags)) > 0, variables ) + mask = map(v -> length(intersect(v.tags, tags)) > 0, variables) return variables[mask] end return variables end -function listVariables(dfg::GraphsDFG, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0) +function listVariables( + dfg::GraphsDFG, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) # variables = map(v -> v.dfgNode, filter(n -> n.dfgNode isa DFGVariable, vertices(dfg.g))) if length(tags) > 0 - return map(v -> v.label, getVariables(dfg, regexFilter, tags=tags, solvable=solvable)) + return map( + v -> v.label, + getVariables(dfg, regexFilter; tags = tags, solvable = solvable), + ) else variables = copy(dfg.g.variables.keys) - regexFilter !== nothing && (variables = filter(v -> occursin(regexFilter, String(v)), variables)) - solvable != 0 && (variables = filter(vId -> _isSolvable(dfg, vId, solvable), variables)) + regexFilter !== nothing && + (variables = filter(v -> occursin(regexFilter, String(v)), variables)) + solvable != 0 && + (variables = filter(vId -> _isSolvable(dfg, vId, solvable), variables)) return variables::Vector{Symbol} end end -function getFactors(dfg::GraphsDFG, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0) +function getFactors( + dfg::GraphsDFG, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) # factors = map(v -> v.dfgNode, filter(n -> n.dfgNode isa DFGFactor, vertices(dfg.g))) factors = collect(values(dfg.g.factors)) if regexFilter != nothing @@ -201,16 +256,24 @@ function getFactors(dfg::GraphsDFG, regexFilter::Union{Nothing, Regex}=nothing; factors = filter(f -> _isSolvable(dfg, f.label, solvable), factors) end if length(tags) > 0 - mask = map(v -> length(intersect(v.tags, tags)) > 0, factors ) + mask = map(v -> length(intersect(v.tags, tags)) > 0, factors) return factors[mask] end return factors end -function listFactors(dfg::GraphsDFG, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0) +function listFactors( + dfg::GraphsDFG, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) # factors = map(v -> v.dfgNode, filter(n -> n.dfgNode isa DFGFactor, vertices(dfg.g))) if length(tags) > 0 - return map(v -> v.label, getFactors(dfg, regexFilter, tags=tags, solvable=solvable)) + return map( + v -> v.label, + getFactors(dfg, regexFilter; tags = tags, solvable = solvable), + ) end factors = copy(dfg.g.factors.keys) if regexFilter != nothing @@ -228,7 +291,6 @@ function isConnected(dfg::GraphsDFG)::Bool end function _isSolvable(dfg::GraphsDFG, label::Symbol, ready::Int)::Bool - haskey(dfg.g.variables, label) && (return dfg.g.variables[label].solvable >= ready) haskey(dfg.g.factors, label) && (return dfg.g.factors[label].solvable >= ready) @@ -237,13 +299,15 @@ function _isSolvable(dfg::GraphsDFG, label::Symbol, ready::Int)::Bool return false end -function listNeighbors(dfg::GraphsDFG, node::DFGNode; solvable::Int=0) +function listNeighbors(dfg::GraphsDFG, node::DFGNode; solvable::Int = 0) label = node.label if !exists(dfg, label) - error("Variable/factor with label '$(node.label)' does not exist in the factor graph") + error( + "Variable/factor with label '$(node.label)' does not exist in the factor graph", + ) end - neighbors_il = FactorGraphs.outneighbors(dfg.g, dfg.g.labels[label]) + neighbors_il = FactorGraphs.outneighbors(dfg.g, dfg.g.labels[label]) neighbors_ll = [dfg.g.labels[i] for i in neighbors_il] # Additional filtering solvable != 0 && filter!(lbl -> _isSolvable(dfg, lbl, solvable), neighbors_ll) @@ -257,13 +321,12 @@ function listNeighbors(dfg::GraphsDFG, node::DFGNode; solvable::Int=0) return neighbors_ll::Vector{Symbol} end - -function listNeighbors(dfg::GraphsDFG, label::Symbol; solvable::Int=0)::Vector{Symbol} +function listNeighbors(dfg::GraphsDFG, label::Symbol; solvable::Int = 0)::Vector{Symbol} if !exists(dfg, label) error("Variable/factor with label '$(label)' does not exist in the factor graph") end - neighbors_il = FactorGraphs.outneighbors(dfg.g, dfg.g.labels[label]) + neighbors_il = FactorGraphs.outneighbors(dfg.g, dfg.g.labels[label]) neighbors_ll = [dfg.g.labels[i] for i in neighbors_il] # Additional filtering solvable != 0 && filter!(lbl -> _isSolvable(dfg, lbl, solvable), neighbors_ll) @@ -275,10 +338,14 @@ function listNeighbors(dfg::GraphsDFG, label::Symbol; solvable::Int=0)::Vector{S end return neighbors_ll - end -function getNeighborhood(dfg::GraphsDFG, variableFactorLabels::Vector{Symbol}, distance::Int; solvable::Int=0)::Vector{Symbol} +function getNeighborhood( + dfg::GraphsDFG, + variableFactorLabels::Vector{Symbol}, + distance::Int; + solvable::Int = 0, +)::Vector{Symbol} # find neighbors at distance to add nbhood = Int[] @@ -291,7 +358,6 @@ function getNeighborhood(dfg::GraphsDFG, variableFactorLabels::Vector{Symbol}, d solvable != 0 && filter!(nlbl -> (getSolvable(dfg, nlbl) >= solvable), allvarfacs) return allvarfacs - end # TODO copy GraphsDFG to GraphsDFG overwrite @@ -303,33 +369,42 @@ end # deepcopyNodes::Bool=false, # verbose::Bool = true) - # Biadjacency Matrix https://en.wikipedia.org/wiki/Adjacency_matrix#Of_a_bipartite_graph -function getBiadjacencyMatrix(dfg::GraphsDFG; solvable::Int=0)::NamedTuple{(:B, :varLabels, :facLabels),Tuple{Graphs.SparseMatrixCSC,Vector{Symbol}, Vector{Symbol}}} - varLabels = listVariables(dfg, solvable=solvable) - factLabels = listFactors(dfg, solvable=solvable) +function getBiadjacencyMatrix( + dfg::GraphsDFG; + solvable::Int = 0, +)::NamedTuple{ + (:B, :varLabels, :facLabels), + Tuple{Graphs.SparseMatrixCSC, Vector{Symbol}, Vector{Symbol}}, +} + varLabels = listVariables(dfg; solvable = solvable) + factLabels = listFactors(dfg; solvable = solvable) varIndex = [dfg.g.labels[s] for s in varLabels] factIndex = [dfg.g.labels[s] for s in factLabels] adj = adjacency_matrix(dfg.g) adjvf = adj[factIndex, varIndex] - return (B=adjvf, varLabels=varLabels, facLabels=factLabels) + return (B = adjvf, varLabels = varLabels, facLabels = factLabels) end """ $(SIGNATURES) Gets an empty and unique GraphsDFG derived from an existing DFG. """ -function _getDuplicatedEmptyDFG(dfg::GraphsDFG{P,V,F}) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} - newDfg = GraphsDFG{P,V,F}(; - userLabel=getUserLabel(dfg), robotLabel=getRobotLabel(dfg), sessionLabel=getSessionLabel(dfg), - solverParams=deepcopy(dfg.solverParams)) - newDfg.description ="(Copy of) $(dfg.description)" +function _getDuplicatedEmptyDFG( + dfg::GraphsDFG{P, V, F}, +) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} + newDfg = GraphsDFG{P, V, F}(; + userLabel = getUserLabel(dfg), + robotLabel = getRobotLabel(dfg), + sessionLabel = getSessionLabel(dfg), + solverParams = deepcopy(dfg.solverParams), + ) + newDfg.description = "(Copy of) $(dfg.description)" return newDfg end - #TODO JT test. """ $(SIGNATURES) @@ -342,18 +417,21 @@ function savedot_attributes(io::IO, dfg::GraphsDFG) write(io, "$vl [color=red, shape=ellipse];\n") end for fl in listFactors(dfg) - write(io, "$fl [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\n") + write( + io, + "$fl [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\n", + ) end for e in edges(dfg.g) write(io, "$(dfg.g.labels[src(e)]) -- $(dfg.g.labels[dst(e)])\n") end - write(io, "}\n") + return write(io, "}\n") end -function toDotFile(dfg::GraphsDFG, fileName::String="/tmp/dfg.dot") +function toDotFile(dfg::GraphsDFG, fileName::String = "/tmp/dfg.dot") open(fileName, "w") do fid - savedot_attributes(fid, dfg) + return savedot_attributes(fid, dfg) end return nothing end @@ -366,7 +444,6 @@ function toDot(dfg::GraphsDFG) return String(data) end - """ $SIGNATURES @@ -395,43 +472,54 @@ Related [`findFactorsBetweenNaive`](@ref), `Graphs.dijkstra_shortest_paths` """ -function findShortestPathDijkstra( dfg::GraphsDFG, - from::Symbol, - to::Symbol; - regexVariables::Union{Nothing, Regex}=nothing, - regexFactors::Union{Nothing, Regex}=nothing, - tagsVariables::Vector{Symbol}=Symbol[], - tagsFactors::Vector{Symbol}=Symbol[], - typeVariables::Union{Nothing, <:AbstractVector}=nothing, - typeFactors::Union{Nothing, <:AbstractVector}=nothing, - solvable::Int=0, - initialized::Union{Nothing,Bool}=nothing ) +function findShortestPathDijkstra( + dfg::GraphsDFG, + from::Symbol, + to::Symbol; + regexVariables::Union{Nothing, Regex} = nothing, + regexFactors::Union{Nothing, Regex} = nothing, + tagsVariables::Vector{Symbol} = Symbol[], + tagsFactors::Vector{Symbol} = Symbol[], + typeVariables::Union{Nothing, <:AbstractVector} = nothing, + typeFactors::Union{Nothing, <:AbstractVector} = nothing, + solvable::Int = 0, + initialized::Union{Nothing, Bool} = nothing, +) # # helper function to filter on vector of types - function _filterTypeList(thelist::Vector{Symbol}, typeList, listfnc=x->ls(dfg, x) ) + function _filterTypeList(thelist::Vector{Symbol}, typeList, listfnc = x -> ls(dfg, x)) thelist_ = Symbol[] for type_ in typeList union!(thelist_, listfnc(type_)) end - intersect( thelist, thelist_ ) + return intersect(thelist, thelist_) end # - duplicate = regexVariables !== nothing || - regexFactors !== nothing || - 0 < length(tagsVariables) || - 0 < length(tagsFactors) || - typeVariables !== nothing || - typeFactors !== nothing || - initialized !== nothing || - solvable != 0 + duplicate = + regexVariables !== nothing || + regexFactors !== nothing || + 0 < length(tagsVariables) || + 0 < length(tagsFactors) || + typeVariables !== nothing || + typeFactors !== nothing || + initialized !== nothing || + solvable != 0 # dfg_ = if duplicate # use copy if filter is being applied - varList = ls(dfg, regexVariables, tags=tagsVariables, solvable=solvable) - fctList = lsf(dfg, regexFactors, tags=tagsFactors, solvable=solvable) - varList = typeVariables !== nothing ? _filterTypeList(varList, typeVariables) : varList - fctList = typeFactors !== nothing ? _filterTypeList(fctList, typeFactors, x->lsf(dfg, x)) : fctList + varList = ls(dfg, regexVariables; tags = tagsVariables, solvable = solvable) + fctList = lsf(dfg, regexFactors; tags = tagsFactors, solvable = solvable) + varList = if typeVariables !== nothing + _filterTypeList(varList, typeVariables) + else + varList + end + fctList = if typeFactors !== nothing + _filterTypeList(fctList, typeFactors, x -> lsf(dfg, x)) + else + fctList + end varList = if initialized !== nothing initmask = isInitialized.(dfg, varList) .== initialized varList[initmask] @@ -453,9 +541,9 @@ function findShortestPathDijkstra( dfg::GraphsDFG, toI = dfg_.g.labels[to] # get shortest path from graph provider - path_state = Graphs.dijkstra_shortest_paths( dfg_.g.graph, [frI;] ) - path = Graphs.enumerate_paths( path_state, toI ) - dijkpath = map( x->dfg_.g.labels[x], path ) + path_state = Graphs.dijkstra_shortest_paths(dfg_.g.graph, [frI;]) + path = Graphs.enumerate_paths(path_state, toI) + dijkpath = map(x -> dfg_.g.labels[x], path) # return the list of symbols return dijkpath @@ -479,19 +567,22 @@ end Return a topological sort of a factor graph as a vector of vertex labels in topological order. Starting from s::Symbol """ -function traverseGraphTopologicalSort(fg::GraphsDFG, s::Symbol, fs_tree=bfs_tree) +function traverseGraphTopologicalSort(fg::GraphsDFG, s::Symbol, fs_tree = bfs_tree) tree = fs_tree(fg, s) list = topological_sort_by_dfs(tree) - symlist = map(s->fg.g.labels[s], list) + symlist = map(s -> fg.g.labels[s], list) return symlist end - # FG blob entries # session blob entries function getBlobEntry(var::AbstractDFGVariable, key::Symbol) if !hasBlobEntry(var, key) - throw(KeyError("No dataEntry label $(key) found in variable $(getLabel(var)). Available keys: $(keys(var.dataDict))")) + throw( + KeyError( + "No dataEntry label $(key) found in variable $(getLabel(var)). Available keys: $(keys(var.dataDict))", + ), + ) end return var.dataDict[key] end @@ -500,23 +591,25 @@ function getSessionBlobEntry(fg::GraphsDFG, label::Symbol) return fg.sessionBlobEntries[label] end -function getSessionBlobEntries(fg::GraphsDFG, startwith::Union{Nothing,String}=nothing) +function getSessionBlobEntries(fg::GraphsDFG, startwith::Union{Nothing, String} = nothing) entries = collect(values(fg.sessionBlobEntries)) - !isnothing(startwith) && filter!(e->startswith(string(e.label), startwith), entries) + !isnothing(startwith) && filter!(e -> startswith(string(e.label), startwith), entries) return entries end function addSessionBlobEntry!(fg::GraphsDFG, entry::BlobEntry) if haskey(fg.sessionBlobEntries, entry.label) - error("BlobEntry '$(entry.label)' already exists in the factor graph's session blob entries.") + error( + "BlobEntry '$(entry.label)' already exists in the factor graph's session blob entries.", + ) end - push!(fg.sessionBlobEntries, entry.label=>entry) + push!(fg.sessionBlobEntries, entry.label => entry) return entry end function addSessionBlobEntries!(fg::GraphsDFG, entries::Vector{BlobEntry}) return map(entries) do entry - addSessionBlobEntry!(fg, entry) + return addSessionBlobEntry!(fg, entry) end end @@ -536,4 +629,4 @@ end # return map(entries) do entry # push!(fg.sessionData, entry.label=>JSON3.write(entry)) # end -# end \ No newline at end of file +# end diff --git a/src/GraphsDFG/services/GraphsDFGSerialization.jl b/src/GraphsDFG/services/GraphsDFGSerialization.jl index c62d0f94..2a9c6332 100644 --- a/src/GraphsDFG/services/GraphsDFGSerialization.jl +++ b/src/GraphsDFG/services/GraphsDFGSerialization.jl @@ -1,6 +1,6 @@ using InteractiveUtils -@kwdef struct PackedGraphsDFG{T<:AbstractParams} +@kwdef struct PackedGraphsDFG{T <: AbstractParams} description::String userLabel::String robotLabel::String @@ -15,8 +15,8 @@ using InteractiveUtils solverParams::T solverParams_type::String = string(typeof(solverParams)) # TODO remove Union.Nothing in DFG v0.24 - typePackedVariable::Union{Nothing,Bool} = false # Are variables packed or full - typePackedFactor::Union{Nothing,Bool} = false # Are factors packed or full + typePackedVariable::Union{Nothing, Bool} = false # Are variables packed or full + typePackedFactor::Union{Nothing, Bool} = false # Are factors packed or full blobStores::Union{Nothing, Dict{Symbol, FolderStore{Vector{UInt8}}}} end @@ -24,13 +24,13 @@ StructTypes.StructType(::Type{PackedGraphsDFG}) = StructTypes.AbstractType() StructTypes.subtypekey(::Type{PackedGraphsDFG}) = :solverParams_type #TODO look at StructTypes.@register_struct_subtype when new StructTypes.jl is tagged (for type field) -function StructTypes.subtypes(::Type{PackedGraphsDFG}) +function StructTypes.subtypes(::Type{PackedGraphsDFG}) subs = subtypes(AbstractParams) - NamedTuple(map(s->Symbol(s)=>PackedGraphsDFG{s}, subs)) + return NamedTuple(map(s -> Symbol(s) => PackedGraphsDFG{s}, subs)) end -_variablestype(fg::GraphsDFG{<:AbstractParams,T,<:AbstractDFGFactor}) where T = T -_factorstype(fg::GraphsDFG{<:AbstractParams,<:AbstractDFGVariable, T}) where T = T +_variablestype(fg::GraphsDFG{<:AbstractParams, T, <:AbstractDFGFactor}) where {T} = T +_factorstype(fg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, T}) where {T} = T ## """ @@ -39,7 +39,7 @@ Packing function to serialize DFG metadata from. """ function packDFGMetadata(fg::GraphsDFG) commonfields = intersect(fieldnames(PackedGraphsDFG), fieldnames(GraphsDFG)) - + setdiff!(commonfields, [:blobStores]) blobStores = Dict{Symbol, FolderStore{Vector{UInt8}}}() foreach(values(fg.blobStores)) do store @@ -55,25 +55,33 @@ function packDFGMetadata(fg::GraphsDFG) typePackedVariable = _variablestype(fg) == Variable, typePackedFactor = _factorstype(fg) == PackedFactor, blobStores, - props... + props..., ) end function unpackDFGMetadata(packed::PackedGraphsDFG) commonfields = intersect(fieldnames(GraphsDFG), fieldnames(PackedGraphsDFG)) - + #FIXME Deprecate remove in DFG v0.24 setdiff!(commonfields, [:blobStores]) blobStores = Dict{Symbol, AbstractBlobStore}() !isnothing(packed.blobStores) && merge!(blobStores, packed.blobStores) - + props = (k => getproperty(packed, k) for k in commonfields) - VT = isnothing(packed.typePackedVariable) || !packed.typePackedVariable ? DFGVariable : Variable - FT = isnothing(packed.typePackedFactor) || !packed.typePackedFactor ? DFGFactor : PackedFactor + VT = if isnothing(packed.typePackedVariable) || !packed.typePackedVariable + DFGVariable + else + Variable + end + FT = if isnothing(packed.typePackedFactor) || !packed.typePackedFactor + DFGFactor + else + PackedFactor + end # VT = isnothing(packed.typePackedVariable) || packed.typePackedVariable ? Variable : DFGVariable # FT = isnothing(packed.typePackedFactor) || packed.typePackedFactor ? PackedFactor : DFGFactor - GraphsDFG{typeof(packed.solverParams), VT, FT}(;blobStores, props...) + return GraphsDFG{typeof(packed.solverParams), VT, FT}(; blobStores, props...) end function unpackDFGMetadata!(dfg::GraphsDFG, packed::PackedGraphsDFG) @@ -84,8 +92,8 @@ function unpackDFGMetadata!(dfg::GraphsDFG, packed::PackedGraphsDFG) !isnothing(packed.blobStores) && merge!(dfg.blobStores, packed.blobStores) props = (k => getproperty(packed, k) for k in commonfields) - foreach(props) do (k,v) - setproperty!(dfg, k, v) - end + foreach(props) do (k, v) + return setproperty!(dfg, k, v) + end return dfg -end \ No newline at end of file +end diff --git a/src/entities/AbstractDFG.jl b/src/entities/AbstractDFG.jl index a7b51d20..9daaf38b 100644 --- a/src/entities/AbstractDFG.jl +++ b/src/entities/AbstractDFG.jl @@ -3,23 +3,19 @@ $(TYPEDEF) Abstract parent struct for DFG variables and factors. """ -abstract type DFGNode -end +abstract type DFGNode end """ $(TYPEDEF) An abstract DFG variable. """ -abstract type AbstractDFGVariable <: DFGNode -end +abstract type AbstractDFGVariable <: DFGNode end """ $(TYPEDEF) An abstract DFG factor. """ -abstract type AbstractDFGFactor <: DFGNode -end - +abstract type AbstractDFGFactor <: DFGNode end """ $(TYPEDEF) @@ -31,7 +27,7 @@ abstract type AbstractParams end $(TYPEDEF) Abstract parent struct for a DFG graph. """ -abstract type AbstractDFG{T<:AbstractParams} end +abstract type AbstractDFG{T <: AbstractParams} end """ $(TYPEDEF) @@ -46,4 +42,13 @@ StructTypes.StructType(::NoSolverParams) = StructTypes.Struct() """ Types valid for small data. """ -const SmallDataTypes = Union{Int, Float64, String, Bool, Vector{Int}, Vector{Float64}, Vector{String}, Vector{Bool}} +const SmallDataTypes = Union{ + Int, + Float64, + String, + Bool, + Vector{Int}, + Vector{Float64}, + Vector{String}, + Vector{Bool}, +} diff --git a/src/entities/AbstractDFGSummary.jl b/src/entities/AbstractDFGSummary.jl index 36680ed1..f4e66166 100644 --- a/src/entities/AbstractDFGSummary.jl +++ b/src/entities/AbstractDFGSummary.jl @@ -4,9 +4,9 @@ Structure for a graph summary. """ struct DFGSummary - variables::Dict{Symbol, DFGVariableSummary} - factors::Dict{Symbol, DFGFactorSummary} - userLabel::String - robotLabel::String - sessionLabel::String + variables::Dict{Symbol, DFGVariableSummary} + factors::Dict{Symbol, DFGFactorSummary} + userLabel::String + robotLabel::String + sessionLabel::String end diff --git a/src/entities/DFGFactor.jl b/src/entities/DFGFactor.jl index edf61489..8552b6dc 100644 --- a/src/entities/DFGFactor.jl +++ b/src/entities/DFGFactor.jl @@ -36,7 +36,9 @@ Designing (WIP) - in DFG.AbstractRelativeMinimize <: AbstractFactor - in Main.SomeFactor <: AbstractRelativeMinimize """ -Base.@kwdef mutable struct GenericFunctionNodeData{T<:Union{<:AbstractPackedFactor, <:AbstractFactor, <:FactorOperationalMemory}} +Base.@kwdef mutable struct GenericFunctionNodeData{ + T <: Union{<:AbstractPackedFactor, <:AbstractFactor, <:FactorOperationalMemory}, +} eliminated::Bool = false potentialused::Bool = false edgeIDs::Vector{Int} = Int[] @@ -53,20 +55,22 @@ end # that way we split solverData <: FactorOperationalMemory and constants # TODO see if above ever changes? - ## Constructors - ##------------------------------------------------------------------------------ ## PackedFunctionNodeData and FunctionNodeData -const PackedFunctionNodeData{T} = GenericFunctionNodeData{T} where T <: AbstractPackedFactor -PackedFunctionNodeData(args...; kw...) = PackedFunctionNodeData{typeof(args[4])}(args...; kw...) +const PackedFunctionNodeData{T} = + GenericFunctionNodeData{T} where {T <: AbstractPackedFactor} +function PackedFunctionNodeData(args...; kw...) + return PackedFunctionNodeData{typeof(args[4])}(args...; kw...) +end -const FunctionNodeData{T} = GenericFunctionNodeData{T} where T <: Union{<:AbstractFactor, <:FactorOperationalMemory} +const FunctionNodeData{T} = GenericFunctionNodeData{ + T, +} where {T <: Union{<:AbstractFactor, <:FactorOperationalMemory}} FunctionNodeData(args...; kw...) = FunctionNodeData{typeof(args[4])}(args...; kw...) - # PackedFunctionNodeData(x2, x3, x4, x6::T, multihypo::Vector{Float64}=[], certainhypo::Vector{Int}=Int[], x9::Int=0) where T <: AbstractPackedFactor = # GenericFunctionNodeData{T}(x2, x3, x4, x6, multihypo, certainhypo, x9) # FunctionNodeData(x2, x3, x4, x6::T, multihypo::Vector{Float64}=[], certainhypo::Vector{Int}=Int[], x9::Int=0) where T <: Union{AbstractFactor, FactorOperationalMemory} = @@ -95,12 +99,12 @@ Base.@kwdef struct PackedFactor <: AbstractDFGFactor data::String metadata::String _version::String = string(_getDFGVersion()) - end - +end + StructTypes.StructType(::Type{PackedFactor}) = StructTypes.UnorderedStruct() StructTypes.idproperty(::Type{PackedFactor}) = :id StructTypes.omitempties(::Type{PackedFactor}) = (:id,) - + ## DFGFactor lv2 """ @@ -126,7 +130,7 @@ Base.@kwdef struct DFGFactor{T, N} <: AbstractDFGFactor tags::Set{Symbol} """Internal cache of the ordering of the neighbor variables. Rather use getVariableOrder to get the list as this is an internal value. Accessors: [`getVariableOrder`](@ref)""" - _variableOrderSymbols::NTuple{N,Symbol} + _variableOrderSymbols::NTuple{N, Symbol} """Variable timestamp. Accessors: [`getTimestamp`](@ref), [`setTimestamp`](@ref)""" timestamp::ZonedDateTime @@ -142,18 +146,29 @@ Base.@kwdef struct DFGFactor{T, N} <: AbstractDFGFactor Accessors: [`getSmallData`](@ref), [`setSmallData!`](@ref)""" smallData::Dict{Symbol, SmallDataTypes} # Inner constructor - function DFGFactor{T}(label::Symbol, - timestamp::Union{DateTime,ZonedDateTime}, - nstime::Nanosecond, - tags::Set{Symbol}, - solverData::GenericFunctionNodeData{T}, - solvable::Int, - _variableOrderSymbols::NTuple{N,Symbol}; - id::Union{UUID, Nothing} = nothing, - smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}()) where {T,N} - return new{T,N}(id, label, tags, _variableOrderSymbols, timestamp, nstime, Ref(solverData), Ref(solvable), smallData) + function DFGFactor{T}( + label::Symbol, + timestamp::Union{DateTime, ZonedDateTime}, + nstime::Nanosecond, + tags::Set{Symbol}, + solverData::GenericFunctionNodeData{T}, + solvable::Int, + _variableOrderSymbols::NTuple{N, Symbol}; + id::Union{UUID, Nothing} = nothing, + smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), + ) where {T, N} + return new{T, N}( + id, + label, + tags, + _variableOrderSymbols, + timestamp, + nstime, + Ref(solverData), + Ref(solvable), + smallData, + ) end - end ##------------------------------------------------------------------------------ @@ -164,51 +179,90 @@ $(SIGNATURES) Construct a DFG factor given a label. """ -DFGFactor(label::Symbol, - timestamp::Union{DateTime,ZonedDateTime}, - nstime::Nanosecond, - tags::Set{Symbol}, - solverData::GenericFunctionNodeData{T}, - solvable::Int, - _variableOrderSymbols::Tuple; - id::Union{UUID, Nothing} = nothing, - smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}()) where {T} = - DFGFactor{T}(label, timestamp, nstime, tags, solverData, solvable, _variableOrderSymbols, id=id, smallData=smallData) - - -DFGFactor{T}(label::Symbol, variableOrderSymbols::Vector{Symbol}, timestamp::Union{DateTime,ZonedDateTime}=now(localzone()), data::GenericFunctionNodeData{T} = GenericFunctionNodeData(fnc=T()); kw...) where {T} = - DFGFactor(label, timestamp, Nanosecond(0), Set{Symbol}(), data, 1, Tuple(variableOrderSymbols); kw...) +function DFGFactor( + label::Symbol, + timestamp::Union{DateTime, ZonedDateTime}, + nstime::Nanosecond, + tags::Set{Symbol}, + solverData::GenericFunctionNodeData{T}, + solvable::Int, + _variableOrderSymbols::Tuple; + id::Union{UUID, Nothing} = nothing, + smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), +) where {T} + return DFGFactor{T}( + label, + timestamp, + nstime, + tags, + solverData, + solvable, + _variableOrderSymbols; + id = id, + smallData = smallData, + ) +end + +function DFGFactor{T}( + label::Symbol, + variableOrderSymbols::Vector{Symbol}, + timestamp::Union{DateTime, ZonedDateTime} = now(localzone()), + data::GenericFunctionNodeData{T} = GenericFunctionNodeData(; fnc = T()); + kw..., +) where {T} + return DFGFactor( + label, + timestamp, + Nanosecond(0), + Set{Symbol}(), + data, + 1, + Tuple(variableOrderSymbols); + kw..., + ) +end # # TODO standardize new fields in kw constructors, .id -DFGFactor(label::Symbol, - variableOrderSymbols::Vector{Symbol}, - data::GenericFunctionNodeData{T}; - tags::Set{Symbol}=Set{Symbol}(), - timestamp::Union{DateTime,ZonedDateTime}=now(localzone()), - solvable::Int=1, - nstime::Nanosecond = Nanosecond(0), - id::Union{UUID, Nothing} = nothing, - smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}()) where {T} = - DFGFactor{T}(label, timestamp, nstime, tags, data, solvable, Tuple(variableOrderSymbols); id, smallData) - - +function DFGFactor( + label::Symbol, + variableOrderSymbols::Vector{Symbol}, + data::GenericFunctionNodeData{T}; + tags::Set{Symbol} = Set{Symbol}(), + timestamp::Union{DateTime, ZonedDateTime} = now(localzone()), + solvable::Int = 1, + nstime::Nanosecond = Nanosecond(0), + id::Union{UUID, Nothing} = nothing, + smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), +) where {T} + return DFGFactor{T}( + label, + timestamp, + nstime, + tags, + data, + solvable, + Tuple(variableOrderSymbols); + id, + smallData, + ) +end -Base.getproperty(x::DFGFactor,f::Symbol) = begin +Base.getproperty(x::DFGFactor, f::Symbol) = begin if f == :solvable || f == :solverData getfield(x, f)[] elseif f == :_variableOrderSymbols - [getfield(x,f)...] + [getfield(x, f)...] else - getfield(x,f) + getfield(x, f) end end -Base.setproperty!(x::DFGFactor,f::Symbol, val) = begin +function Base.setproperty!(x::DFGFactor, f::Symbol, val) if f == :solvable || f == :solverData - getfield(x,f)[] = val + getfield(x, f)[] = val else - setfield!(x,f,val) + setfield!(x, f, val) end end ##------------------------------------------------------------------------------ @@ -270,8 +324,21 @@ end ## Constructors #NOTE I feel like a want to force a variableOrderSymbols -SkeletonDFGFactor(id::Union{UUID, Nothing}, label::Symbol, variableOrderSymbols::Vector{Symbol} = Symbol[]) = SkeletonDFGFactor(id, label, Set{Symbol}(), variableOrderSymbols) -SkeletonDFGFactor(label::Symbol, variableOrderSymbols::Vector{Symbol} = Symbol[]; id::Union{UUID, Nothing}=nothing, tags=Set{Symbol}()) = SkeletonDFGFactor(id, label, tags, variableOrderSymbols) +function SkeletonDFGFactor( + id::Union{UUID, Nothing}, + label::Symbol, + variableOrderSymbols::Vector{Symbol} = Symbol[], +) + return SkeletonDFGFactor(id, label, Set{Symbol}(), variableOrderSymbols) +end +function SkeletonDFGFactor( + label::Symbol, + variableOrderSymbols::Vector{Symbol} = Symbol[]; + id::Union{UUID, Nothing} = nothing, + tags = Set{Symbol}(), +) + return SkeletonDFGFactor(id, label, tags, variableOrderSymbols) +end StructTypes.StructType(::Type{SkeletonDFGFactor}) = StructTypes.OrderedStruct() StructTypes.idproperty(::Type{SkeletonDFGFactor}) = :id @@ -288,8 +355,21 @@ const FactorDataLevel2 = Union{DFGFactor} ## Conversion constructors ##============================================================================== -DFGFactorSummary(f::DFGFactor) = - DFGFactorSummary(f.id, f.label, deepcopy(f.tags), deepcopy(f._variableOrderSymbols), f.timestamp) +function DFGFactorSummary(f::DFGFactor) + return DFGFactorSummary( + f.id, + f.label, + deepcopy(f.tags), + deepcopy(f._variableOrderSymbols), + f.timestamp, + ) +end -SkeletonDFGFactor(f::FactorDataLevel1) = - SkeletonDFGFactor(f.id, f.label, deepcopy(f.tags), deepcopy(f._variableOrderSymbols)) +function SkeletonDFGFactor(f::FactorDataLevel1) + return SkeletonDFGFactor( + f.id, + f.label, + deepcopy(f.tags), + deepcopy(f._variableOrderSymbols), + ) +end diff --git a/src/entities/DFGVariable.jl b/src/entities/DFGVariable.jl index 19e23f8f..8f3eca35 100644 --- a/src/entities/DFGVariable.jl +++ b/src/entities/DFGVariable.jl @@ -19,9 +19,9 @@ N: Manifold dimension. Fields: $(TYPEDFIELDS) """ -Base.@kwdef mutable struct VariableNodeData{T<:InferenceVariable, P, N} +Base.@kwdef mutable struct VariableNodeData{T <: InferenceVariable, P, N} "DEPRECATED remove in DFG v0.22" - variableType::T=T() #tricky deprecation, also change covar to using N and not variableType + variableType::T = T() #tricky deprecation, also change covar to using N and not variableType """ Globally unique identifier. """ @@ -33,9 +33,10 @@ Base.@kwdef mutable struct VariableNodeData{T<:InferenceVariable, P, N} """ Common kernel bandwith parameter used with ManifoldKernelDensity, see field `covar` for the parametric covariance. """ - bw::Matrix{Float64} = zeros(0,0) + bw::Matrix{Float64} = zeros(0, 0) "Parametric (Gaussian) covariance." - covar::Vector{SMatrix{N, N, Float64}} = SMatrix{getDimension(variableType), getDimension(variableType), Float64}[] + covar::Vector{SMatrix{N, N, Float64}} = + SMatrix{getDimension(variableType), getDimension(variableType), Float64}[] BayesNetOutVertIDs::Vector{Symbol} = Symbol[] dimIDs::Vector{Int} = Int[] # TODO Likely deprecate @@ -77,16 +78,18 @@ Base.@kwdef mutable struct VariableNodeData{T<:InferenceVariable, P, N} """ Future proofing field for when more multithreading operations on graph nodes are implemented, these conditions are meant to be used for atomic write transactions to this VND. """ - events::Dict{Symbol,Threads.Condition} = Dict{Symbol,Threads.Condition}() + events::Dict{Symbol, Threads.Condition} = Dict{Symbol, Threads.Condition}() # end - ##------------------------------------------------------------------------------ ## Constructors -VariableNodeData{T}(; kwargs...) where T <: InferenceVariable = VariableNodeData{T,getPointType(T),getDimension(T)}(; kwargs...) -VariableNodeData(variableType::InferenceVariable; kwargs...) = VariableNodeData{typeof(variableType)}(;kwargs...) - +function VariableNodeData{T}(; kwargs...) where {T <: InferenceVariable} + return VariableNodeData{T, getPointType(T), getDimension(T)}(; kwargs...) +end +function VariableNodeData(variableType::InferenceVariable; kwargs...) + return VariableNodeData{typeof(variableType)}(; kwargs...) +end ##============================================================================== ## PackedVariableNodeData.jl @@ -161,12 +164,31 @@ end StructTypes.StructType(::Type{MeanMaxPPE}) = StructTypes.UnorderedStruct() StructTypes.idproperty(::Type{MeanMaxPPE}) = :id -StructTypes.omitempties(::Type{MeanMaxPPE}) = (:id,:createdTimestamp,:lastUpdatedTimestamp) +function StructTypes.omitempties(::Type{MeanMaxPPE}) + return (:id, :createdTimestamp, :lastUpdatedTimestamp) +end ##------------------------------------------------------------------------------ ## Constructors -MeanMaxPPE(solveKey::Symbol, suggested::Vector{Float64}, max::Vector{Float64}, mean::Vector{Float64}) = MeanMaxPPE(nothing, solveKey, suggested, max, mean, "MeanMaxPPE", string(_getDFGVersion()), now(tz"UTC"), now(tz"UTC")) +function MeanMaxPPE( + solveKey::Symbol, + suggested::Vector{Float64}, + max::Vector{Float64}, + mean::Vector{Float64}, +) + return MeanMaxPPE( + nothing, + solveKey, + suggested, + max, + mean, + "MeanMaxPPE", + string(_getDFGVersion()), + now(tz"UTC"), + now(tz"UTC"), + ) +end ## Metadata """ @@ -181,9 +203,8 @@ getEstimateFields(::MeanMaxPPE) = [:suggested, :max, :mean] ## DFG Variables ##============================================================================== - export Variable - + """ $(TYPEDEF) @@ -213,7 +234,7 @@ function Variable( solvable::Int = 1, nanosecondtime::Int64 = 0, smalldata::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), - kwargs... + kwargs..., ) union!(tags, [:VARIABLE]) @@ -225,7 +246,7 @@ function Variable( tags, metadata = base64encode(JSON3.write(smalldata)), timestamp, - kwargs... + kwargs..., ) return pacvar @@ -247,7 +268,7 @@ Complete variable structure for a DistributedFactorGraph variable. Fields: $(TYPEDFIELDS) """ -Base.@kwdef struct DFGVariable{T<:InferenceVariable, P, N} <: AbstractDFGVariable +Base.@kwdef struct DFGVariable{T <: InferenceVariable, P, N} <: AbstractDFGVariable """The ID for the variable""" id::Union{UUID, Nothing} = nothing """Variable label, e.g. :x1. @@ -257,16 +278,18 @@ Base.@kwdef struct DFGVariable{T<:InferenceVariable, P, N} <: AbstractDFGVariabl Accessors: [`getTimestamp`](@ref), [`setTimestamp`](@ref)""" timestamp::ZonedDateTime = now(localzone()) """Nanoseconds since a user-understood epoch (i.e unix epoch, robot boot time, etc.)""" - nstime::Nanosecond = Nanosecond(0) + nstime::Nanosecond = Nanosecond(0) """Variable tags, e.g [:POSE, :VARIABLE, and :LANDMARK]. Accessors: [`getTags`](@ref), [`mergeTags!`](@ref), and [`removeTags!`](@ref)""" tags::Set{Symbol} = Set{Symbol}() """Dictionary of parametric point estimates keyed by solverDataDict keys Accessors: [`addPPE!`](@ref), [`updatePPE!`](@ref), and [`deletePPE!`](@ref)""" - ppeDict::Dict{Symbol, AbstractPointParametricEst} = Dict{Symbol, AbstractPointParametricEst}() + ppeDict::Dict{Symbol, AbstractPointParametricEst} = + Dict{Symbol, AbstractPointParametricEst}() """Dictionary of solver data. May be a subset of all solutions if a solver key was specified in the get call. Accessors: [`addVariableSolverData!`](@ref), [`updateVariableSolverData!`](@ref), and [`deleteVariableSolverData!`](@ref)""" - solverDataDict::Dict{Symbol, VariableNodeData{T,P,N}} = Dict{Symbol, VariableNodeData{T,P,N}}() + solverDataDict::Dict{Symbol, VariableNodeData{T, P, N}} = + Dict{Symbol, VariableNodeData{T, P, N}}() """Dictionary of small data associated with this variable. Accessors: [`getSmallData`](@ref), [`setSmallData!`](@ref)""" smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}() @@ -286,12 +309,12 @@ end The default DFGVariable constructor. """ function DFGVariable( - label::Symbol, + label::Symbol, T::Type{<:InferenceVariable}; - estimateDict=nothing, - timestamp=now(localzone()), - solvable::Union{Int, Base.RefValue{Int}}=Ref(1), - kwargs... + estimateDict = nothing, + timestamp = now(localzone()), + solvable::Union{Int, Base.RefValue{Int}} = Ref(1), + kwargs..., ) #TODO deprecated, remove in v0.21 should have already been deprecated if !isnothing(estimateDict) @@ -299,37 +322,40 @@ function DFGVariable( end if !isa(timestamp, ZonedDateTime) @warn "timestamp<:DateTime is deprecated, timestamp must be a ZonedDateTime, using local zone." - timestamp = ZonedDateTime(timestamp,localzone()) + timestamp = ZonedDateTime(timestamp, localzone()) end solvable isa Int && (solvable = Ref(solvable)) N = getDimension(T) P = getPointType(T) - DFGVariable{T,P,N}(;label, timestamp, solvable, kwargs...) + return DFGVariable{T, P, N}(; label, timestamp, solvable, kwargs...) end -DFGVariable(label::Symbol, variableType::InferenceVariable; kwargs...) = DFGVariable(label, typeof(variableType); kwargs...) +function DFGVariable(label::Symbol, variableType::InferenceVariable; kwargs...) + return DFGVariable(label, typeof(variableType); kwargs...) +end -DFGVariable(label::Symbol, solverData::VariableNodeData; kwargs...) = DFGVariable(;label, solverDataDict=Dict(:default=>solverData), kwargs...) +function DFGVariable(label::Symbol, solverData::VariableNodeData; kwargs...) + return DFGVariable(; label, solverDataDict = Dict(:default => solverData), kwargs...) +end -Base.getproperty(x::DFGVariable,f::Symbol) = begin +Base.getproperty(x::DFGVariable, f::Symbol) = begin if f == :solvable - getfield(x,f)[] + getfield(x, f)[] else - getfield(x,f) + getfield(x, f) end end -Base.setproperty!(x::DFGVariable,f::Symbol, val) = begin +Base.setproperty!(x::DFGVariable, f::Symbol, val) = begin if f == :solvable - getfield(x,f)[] = val + getfield(x, f)[] = val else - setfield!(x,f,val) + setfield!(x, f, val) end end - ##------------------------------------------------------------------------------ ## DFGVariableSummary lv1 ##------------------------------------------------------------------------------ @@ -410,7 +436,13 @@ Base.@kwdef struct SkeletonDFGVariable <: AbstractDFGVariable tags::Set{Symbol} = Set{Symbol}() end -SkeletonDFGVariable(label::Symbol, tags=Set{Symbol}(); id::Union{UUID, Nothing}=nothing) = SkeletonDFGVariable(id, label, tags) +function SkeletonDFGVariable( + label::Symbol, + tags = Set{Symbol}(); + id::Union{UUID, Nothing} = nothing, +) + return SkeletonDFGVariable(id, label, tags) +end StructTypes.StructType(::Type{SkeletonDFGVariable}) = StructTypes.UnorderedStruct() StructTypes.idproperty(::Type{SkeletonDFGVariable}) = :id @@ -419,7 +451,8 @@ StructTypes.omitempties(::Type{SkeletonDFGVariable}) = (:id,) ##============================================================================== # Define variable levels ##============================================================================== -const VariableDataLevel0 = Union{DFGVariable, DFGVariableSummary, Variable, SkeletonDFGVariable} +const VariableDataLevel0 = + Union{DFGVariable, DFGVariableSummary, Variable, SkeletonDFGVariable} const VariableDataLevel1 = Union{DFGVariable, DFGVariableSummary, Variable} const VariableDataLevel2 = Union{DFGVariable} @@ -427,8 +460,18 @@ const VariableDataLevel2 = Union{DFGVariable} ## Convertion constructors ##============================================================================== -DFGVariableSummary(v::DFGVariable) = - DFGVariableSummary(v.id, v.label, v.timestamp, deepcopy(v.tags), deepcopy(v.ppeDict), Symbol(typeof(getVariableType(v))), v.dataDict) +function DFGVariableSummary(v::DFGVariable) + return DFGVariableSummary( + v.id, + v.label, + v.timestamp, + deepcopy(v.tags), + deepcopy(v.ppeDict), + Symbol(typeof(getVariableType(v))), + v.dataDict, + ) +end -SkeletonDFGVariable(v::VariableDataLevel1) = - SkeletonDFGVariable(v.id, v.label, deepcopy(v.tags)) +function SkeletonDFGVariable(v::VariableDataLevel1) + return SkeletonDFGVariable(v.id, v.label, deepcopy(v.tags)) +end diff --git a/src/services/AbstractDFG.jl b/src/services/AbstractDFG.jl index d686230a..03bf3e24 100644 --- a/src/services/AbstractDFG.jl +++ b/src/services/AbstractDFG.jl @@ -31,7 +31,18 @@ Base.Broadcast.broadcastable(dfg::AbstractDFG) = Ref(dfg) $(SIGNATURES) Convenience function to get all the metadata of a DFG """ -getDFGInfo(dfg::AbstractDFG) = (getDescription(dfg), getUserLabel(dfg), getRobotLabel(dfg), getSessionLabel(dfg), getUserData(dfg), getRobotData(dfg), getSessionData(dfg), getSolverParams(dfg)) +function getDFGInfo(dfg::AbstractDFG) + return ( + getDescription(dfg), + getUserLabel(dfg), + getRobotLabel(dfg), + getSessionLabel(dfg), + getUserData(dfg), + getRobotData(dfg), + getSessionData(dfg), + getSolverParams(dfg), + ) +end """ $(SIGNATURES) @@ -68,15 +79,27 @@ getSolverParams(dfg::AbstractDFG) = dfg.solverParams Method must be overloaded by the user for Serialization to work. E.g. IncrementalInference uses `CommonConvWrapper <: FactorOperationalMemory`. """ -getFactorOperationalMemoryType(dummy) = error("Please extend your workspace with function getFactorOperationalMemoryType(<:AbstractParams) for your usecase, e.g. IncrementalInference uses `CommonConvWrapper <: FactorOperationalMemory`") -getFactorOperationalMemoryType(dfg::AbstractDFG) = getFactorOperationalMemoryType(getSolverParams(dfg)) +function getFactorOperationalMemoryType(dummy) + return error( + "Please extend your workspace with function getFactorOperationalMemoryType(<:AbstractParams) for your usecase, e.g. IncrementalInference uses `CommonConvWrapper <: FactorOperationalMemory`", + ) +end +function getFactorOperationalMemoryType(dfg::AbstractDFG) + return getFactorOperationalMemoryType(getSolverParams(dfg)) +end """ $(SIGNATURES) Method must be overloaded by the user for Serialization to work. """ -rebuildFactorMetadata!(dfg::AbstractDFG{<:AbstractParams}, factor::AbstractDFGFactor, neighbors=[]) = error("rebuildFactorMetadata! is not implemented for $(typeof(dfg))") +function rebuildFactorMetadata!( + dfg::AbstractDFG{<:AbstractParams}, + factor::AbstractDFGFactor, + neighbors = [], +) + return error("rebuildFactorMetadata! is not implemented for $(typeof(dfg))") +end ##------------------------------------------------------------------------------ ## Setters @@ -92,7 +115,9 @@ setDescription!(dfg::AbstractDFG, description::String) = dfg.description = descr """ #NOTE a MethodError will be thrown if solverParams type does not mach the one in dfg # TODO Is it ok or do we want any abstract solver paramters -setSolverParams!(dfg::AbstractDFG, solverParams::AbstractParams) = dfg.solverParams = solverParams +function setSolverParams!(dfg::AbstractDFG, solverParams::AbstractParams) + return dfg.solverParams = solverParams +end # Accessors and CRUD for user/robot/session Data """ @@ -155,9 +180,11 @@ getUserData(dfg::AbstractDFG, key::Symbol) = dfg.userData[key] getRobotData(dfg::AbstractDFG, key::Symbol) = dfg.robotData[key] getSessionData(dfg::AbstractDFG, key::Symbol) = dfg.sessionData[key] -updateUserData!(dfg::AbstractDFG, pair::Pair{Symbol,String}) = push!(dfg.userData, pair) -updateRobotData!(dfg::AbstractDFG, pair::Pair{Symbol,String}) = push!(dfg.robotData, pair) -updateSessionData!(dfg::AbstractDFG, pair::Pair{Symbol,String}) = push!(dfg.sessionData, pair) +updateUserData!(dfg::AbstractDFG, pair::Pair{Symbol, String}) = push!(dfg.userData, pair) +updateRobotData!(dfg::AbstractDFG, pair::Pair{Symbol, String}) = push!(dfg.robotData, pair) +function updateSessionData!(dfg::AbstractDFG, pair::Pair{Symbol, String}) + return push!(dfg.sessionData, pair) +end deleteUserData!(dfg::AbstractDFG, key::Symbol) = pop!(dfg.userData, key) deleteRobotData!(dfg::AbstractDFG, key::Symbol) = pop!(dfg.robotData, key) @@ -201,8 +228,12 @@ getKey(store::AbstractBlobStore) = store.key getBlobStores(dfg::AbstractDFG) = dfg.blobStores getBlobStore(dfg::AbstractDFG, key::Symbol) = dfg.blobStores[key] -addBlobStore!(dfg::AbstractDFG, bs::AbstractBlobStore) = push!(dfg.blobStores, getKey(bs)=>bs) -updateBlobStore!(dfg::AbstractDFG, bs::AbstractBlobStore) = push!(dfg.blobStores, getKey(bs)=>bs) +function addBlobStore!(dfg::AbstractDFG, bs::AbstractBlobStore) + return push!(dfg.blobStores, getKey(bs) => bs) +end +function updateBlobStore!(dfg::AbstractDFG, bs::AbstractBlobStore) + return push!(dfg.blobStores, getKey(bs) => bs) +end deleteBlobStore!(dfg::AbstractDFG, key::Symbol) = pop!(dfg.blobStores, key) emptyBlobStore!(dfg::AbstractDFG) = empty!(dfg.blobStores) listBlobStores(dfg::AbstractDFG) = collect(keys(dfg.blobStores)) @@ -218,43 +249,46 @@ listBlobStores(dfg::AbstractDFG) = collect(keys(dfg.blobStores)) True if the variable or factor exists in the graph. """ function exists(dfg::AbstractDFG, node::DFGNode) - error("exists not implemented for $(typeof(dfg))") + return error("exists not implemented for $(typeof(dfg))") end function exists(dfg::AbstractDFG, label::Symbol) - error("exists not implemented for $(typeof(dfg))") + return error("exists not implemented for $(typeof(dfg))") end """ $(SIGNATURES) Add a DFGVariable to a DFG. """ -function addVariable!(dfg::G, variable::V) where {G <: AbstractDFG, V <: AbstractDFGVariable} - error("addVariable! not implemented for $(typeof(dfg))") +function addVariable!( + dfg::G, + variable::V, +) where {G <: AbstractDFG, V <: AbstractDFGVariable} + return error("addVariable! not implemented for $(typeof(dfg))") end """ Add a DFGFactor to a DFG. $(SIGNATURES) """ -function addFactor!(dfg::AbstractDFG, factor::F) where F <: AbstractDFGFactor - error("addFactor! not implemented for $(typeof(dfg))(dfg, factor)") +function addFactor!(dfg::AbstractDFG, factor::F) where {F <: AbstractDFGFactor} + return error("addFactor! not implemented for $(typeof(dfg))(dfg, factor)") end """ $(SIGNATURES) Get a DFGVariable from a DFG using its label. """ -function getVariable(dfg::G, label::Union{Symbol, String}) where G <: AbstractDFG - error("getVariable not implemented for $(typeof(dfg))") +function getVariable(dfg::G, label::Union{Symbol, String}) where {G <: AbstractDFG} + return error("getVariable not implemented for $(typeof(dfg))") end """ $(SIGNATURES) Get a DFGFactor from a DFG using its label. """ -function getFactor(dfg::G, label::Union{Symbol, String}) where G <: AbstractDFG - error("getFactor not implemented for $(typeof(dfg))") +function getFactor(dfg::G, label::Union{Symbol, String}) where {G <: AbstractDFG} + return error("getFactor not implemented for $(typeof(dfg))") end function Base.getindex(dfg::AbstractDFG, lbl::Union{Symbol, String}) @@ -271,8 +305,11 @@ end $(SIGNATURES) Update a complete DFGVariable in the DFG. """ -function updateVariable!(dfg::G, variable::V) where {G <: AbstractDFG, V <: AbstractDFGVariable} - error("updateVariable! not implemented for $(typeof(dfg))") +function updateVariable!( + dfg::G, + variable::V, +) where {G <: AbstractDFG, V <: AbstractDFGVariable} + return error("updateVariable! not implemented for $(typeof(dfg))") end """ @@ -280,7 +317,7 @@ end Update a complete DFGFactor in the DFG. """ function updateFactor!(dfg::G, factor::F) where {G <: AbstractDFG, F <: AbstractDFGFactor} - error("updateFactor! not implemented for $(typeof(dfg))") + return error("updateFactor! not implemented for $(typeof(dfg))") end """ @@ -288,14 +325,18 @@ end Delete a DFGVariable from the DFG using its label. """ function deleteVariable!(dfg::AbstractDFG, label::Symbol) - error("deleteVariable! not implemented for $(typeof(dfg))") + return error("deleteVariable! not implemented for $(typeof(dfg))") end """ $(SIGNATURES) Delete a DFGFactor from the DFG using its label. """ -function deleteFactor!(dfg::G, label::Symbol; suppressGetFactor::Bool=false) where G <: AbstractDFG - error("deleteFactors not implemented for $(typeof(dfg))") +function deleteFactor!( + dfg::G, + label::Symbol; + suppressGetFactor::Bool = false, +) where {G <: AbstractDFG} + return error("deleteFactors not implemented for $(typeof(dfg))") end """ @@ -304,12 +345,18 @@ List the DFGVariables in the DFG. Optionally specify a label regular expression to retrieves a subset of the variables. Tags is a list of any tags that a node must have (at least one match). """ -function getVariables(dfg::G, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0, detail=nothing) where G <: AbstractDFG - error("getVariables not implemented for $(typeof(dfg))") +function getVariables( + dfg::G, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, + detail = nothing, +) where {G <: AbstractDFG} + return error("getVariables not implemented for $(typeof(dfg))") end function getVariables(dfg::AbstractDFG, labels::Vector{Symbol}) - return map(label->getVariable(dfg, label), labels) + return map(label -> getVariable(dfg, label), labels) end """ @@ -317,12 +364,15 @@ end List the DFGFactors in the DFG. Optionally specify a label regular expression to retrieves a subset of the factors. """ -function getFactors(dfg::G, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0) where G <: AbstractDFG - error("getFactors not implemented for $(typeof(dfg))") +function getFactors( + dfg::G, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) where {G <: AbstractDFG} + return error("getFactors not implemented for $(typeof(dfg))") end - - ##------------------------------------------------------------------------------ ## Checking Types ##------------------------------------------------------------------------------ @@ -334,8 +384,8 @@ Return whether `sym::Symbol` represents a variable vertex in the graph DFG. Checks whether it both exists in the graph and is a variable. (If you rather want a quick for type, just do node isa DFGVariable) """ -function isVariable(dfg::G, sym::Symbol) where G <: AbstractDFG - error("isVariable not implemented for $(typeof(dfg))") +function isVariable(dfg::G, sym::Symbol) where {G <: AbstractDFG} + return error("isVariable not implemented for $(typeof(dfg))") end """ @@ -345,11 +395,10 @@ Return whether `sym::Symbol` represents a factor vertex in the graph DFG. Checks whether it both exists in the graph and is a factor. (If you rather want a quicker for type, just do node isa DFGFactor) """ -function isFactor(dfg::G, sym::Symbol) where G <: AbstractDFG - error("isFactor not implemented for $(typeof(dfg))") +function isFactor(dfg::G, sym::Symbol) where {G <: AbstractDFG} + return error("isFactor not implemented for $(typeof(dfg))") end - ##------------------------------------------------------------------------------ ## Neighbors ##------------------------------------------------------------------------------ @@ -358,18 +407,17 @@ end Checks if the graph is fully connected, returns true if so. """ function isConnected(dfg::AbstractDFG) - error("isConnected not implemented for $(typeof(dfg))") + return error("isConnected not implemented for $(typeof(dfg))") end """ $(SIGNATURES) Retrieve a list of labels of the immediate neighbors around a given variable or factor specified by its label. """ -function listNeighbors(dfg::AbstractDFG, label::Symbol; solvable::Int=0) - error("listNeighbors not implemented for $(typeof(dfg))") +function listNeighbors(dfg::AbstractDFG, label::Symbol; solvable::Int = 0) + return error("listNeighbors not implemented for $(typeof(dfg))") end - ##------------------------------------------------------------------------------ ## copy and duplication ##------------------------------------------------------------------------------ @@ -380,10 +428,9 @@ end Gets an empty and unique DFG derived from an existing DFG. """ function _getDuplicatedEmptyDFG(dfg::AbstractDFG) - error("_getDuplicatedEmptyDFG not implemented for $(typeof(dfg))") + return error("_getDuplicatedEmptyDFG not implemented for $(typeof(dfg))") end - ##------------------------------------------------------------------------------ ## CRUD Aliases ##------------------------------------------------------------------------------ @@ -394,7 +441,6 @@ Get a DFGVariable with a specific solver key. In memory types still return a reference, other types returns a variable with only solveKey. """ function getVariable(dfg::AbstractDFG, label::Symbol, solveKey::Symbol) - var = getVariable(dfg, label) if isa(var, DFGVariable) && !haskey(var.solverDataDict, solveKey) @@ -406,47 +452,71 @@ function getVariable(dfg::AbstractDFG, label::Symbol, solveKey::Symbol) return var end - """ $(SIGNATURES) """ -function addFactor!(dfg::AbstractDFG, variables::Vector{<:AbstractDFGVariable}, factor::F) where F <: AbstractDFGFactor - - Base.depwarn("addFactor!(dfg, variables, factor) is deprecated, use addFactor!(dfg, factor)", :addFactor!) - variableLabels = map(v->v.label, variables) +function addFactor!( + dfg::AbstractDFG, + variables::Vector{<:AbstractDFGVariable}, + factor::F, +) where {F <: AbstractDFGFactor} + Base.depwarn( + "addFactor!(dfg, variables, factor) is deprecated, use addFactor!(dfg, factor)", + :addFactor!, + ) + variableLabels = map(v -> v.label, variables) if factor isa DFGFactor f = factor - newfactor = DFGFactor(f.label, f.timestamp, f.nstime, f.tags, f.solverData, f.solvable, Tuple(variableLabels)) + newfactor = DFGFactor( + f.label, + f.timestamp, + f.nstime, + f.tags, + f.solverData, + f.solvable, + Tuple(variableLabels), + ) return addFactor!(dfg, newfactor) else resize!(factor._variableOrderSymbols, length(variableLabels)) factor._variableOrderSymbols .= variableLabels return addFactor!(dfg, factor) end - end """ $(SIGNATURES) """ -function addFactor!(dfg::AbstractDFG, variableLabels::Vector{Symbol}, factor::F) where F <: AbstractDFGFactor - - Base.depwarn("addFactor!(dfg, variables, factor) is deprecated, use addFactor!(dfg, factor)", :addFactor!) +function addFactor!( + dfg::AbstractDFG, + variableLabels::Vector{Symbol}, + factor::F, +) where {F <: AbstractDFGFactor} + Base.depwarn( + "addFactor!(dfg, variables, factor) is deprecated, use addFactor!(dfg, factor)", + :addFactor!, + ) if factor isa DFGFactor f = factor - newfactor = DFGFactor(f.label, f.timestamp, f.nstime, f.tags, f.solverData, f.solvable, Tuple(variableLabels)) + newfactor = DFGFactor( + f.label, + f.timestamp, + f.nstime, + f.tags, + f.solverData, + f.solvable, + Tuple(variableLabels), + ) return addFactor!(dfg, newfactor) else resize!(factor._variableOrderSymbols, length(variableLabels)) factor._variableOrderSymbols .= variableLabels return addFactor!(dfg, factor) end - end - """ $(SIGNATURES) Delete a referenced DFGVariable from the DFG. @@ -462,8 +532,12 @@ end $(SIGNATURES) Delete the referened DFGFactor from the DFG. """ -function deleteFactor!(dfg::G, factor::F; suppressGetFactor::Bool=false) where {G <: AbstractDFG, F <: AbstractDFGFactor} - return deleteFactor!(dfg, factor.label, suppressGetFactor=suppressGetFactor) +function deleteFactor!( + dfg::G, + factor::F; + suppressGetFactor::Bool = false, +) where {G <: AbstractDFG, F <: AbstractDFGFactor} + return deleteFactor!(dfg, factor.label; suppressGetFactor = suppressGetFactor) end # Alias - bit ridiculous but know it'll come up at some point. Does existential and type check. @@ -479,11 +553,10 @@ end ## Connectivity Alias ##------------------------------------------------------------------------------ -function listNeighbors(dfg::AbstractDFG, node::DFGNode; solvable::Int=0) - listNeighbors(dfg, node.label; solvable) +function listNeighbors(dfg::AbstractDFG, node::DFGNode; solvable::Int = 0) + return listNeighbors(dfg, node.label; solvable) end - ##============================================================================== ## Listing and listing aliases ##============================================================================== @@ -507,23 +580,31 @@ listVariables(dfg, r"l", tags=[:APRILTAG;]) See also: [`ls`](@ref) """ -function listVariables( dfg::AbstractDFG, - regexFilter::Union{Nothing, Regex}=nothing; - tags::Vector{Symbol}=Symbol[], - solvable::Int=0 ) +function listVariables( + dfg::AbstractDFG, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) # - vars = getVariables(dfg, regexFilter, tags=tags, solvable=solvable) + vars = getVariables(dfg, regexFilter; tags = tags, solvable = solvable) return map(v -> v.label, vars)::Vector{Symbol} end # to be consolidated, see #612 -function listVariables( dfg::AbstractDFG, - typeFilter::Type{<:InferenceVariable}; - tags::Vector{Symbol}=Symbol[], - solvable::Int=0 ) +function listVariables( + dfg::AbstractDFG, + typeFilter::Type{<:InferenceVariable}; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) # retlist::Vector{Symbol} = ls(dfg, typeFilter) - 0 < length(tags) || solvable != 0 ? intersect(retlist, ls(dfg, tags=tags, solvable=solvable)) : retlist + if 0 < length(tags) || solvable != 0 + return intersect(retlist, ls(dfg; tags = tags, solvable = solvable)) + else + return retlist + end end """ @@ -531,8 +612,13 @@ end Get a list of the labels of the DFGFactors in the DFG. Optionally specify a label regular expression to retrieves a subset of the factors. """ -function listFactors(dfg::G, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0)::Vector{Symbol} where G <: AbstractDFG - return map(f -> f.label, getFactors(dfg, regexFilter, tags=tags, solvable=solvable)) +function listFactors( + dfg::G, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +)::Vector{Symbol} where {G <: AbstractDFG} + return map(f -> f.label, getFactors(dfg, regexFilter; tags = tags, solvable = solvable)) end """ @@ -543,32 +629,42 @@ Related [`listSupersolves`](@ref), [`getSolverDataDict`](@ref), [`listVariables`](@ref) """ -function listSolveKeys( variable::DFGVariable, - filterSolveKeys::Union{Regex,Nothing}=nothing, - skeys = Set{Symbol}() ) +function listSolveKeys( + variable::DFGVariable, + filterSolveKeys::Union{Regex, Nothing} = nothing, + skeys = Set{Symbol}(), +) # for ky in keys(getSolverDataDict(variable)) push!(skeys, ky) end #filter the solveKey set with filterSolveKeys regex - !isnothing(filterSolveKeys) && return filter!(k -> occursin(filterSolveKeys, string(k)), skeys) + !isnothing(filterSolveKeys) && + return filter!(k -> occursin(filterSolveKeys, string(k)), skeys) return skeys end -listSolveKeys( dfg::AbstractDFG, lbl::Symbol, - filterSolveKeys::Union{Regex,Nothing}=nothing, - skeys = Set{Symbol}() ) = listSolveKeys(getVariable(dfg, lbl), filterSolveKeys, skeys) +function listSolveKeys( + dfg::AbstractDFG, + lbl::Symbol, + filterSolveKeys::Union{Regex, Nothing} = nothing, + skeys = Set{Symbol}(), +) + return listSolveKeys(getVariable(dfg, lbl), filterSolveKeys, skeys) +end # -function listSolveKeys( dfg::AbstractDFG, - filterVariables::Union{Type{<:InferenceVariable},Regex, Nothing}=nothing; - filterSolveKeys::Union{Regex,Nothing}=nothing, - tags::Vector{Symbol}=Symbol[], - solvable::Int=0 ) +function listSolveKeys( + dfg::AbstractDFG, + filterVariables::Union{Type{<:InferenceVariable}, Regex, Nothing} = nothing; + filterSolveKeys::Union{Regex, Nothing} = nothing, + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) # skeys = Set{Symbol}() - varList = listVariables(dfg, filterVariables, tags=tags, solvable=solvable) + varList = listVariables(dfg, filterVariables; tags = tags, solvable = solvable) for vs in varList #, ky in keys(getSolverDataDict(getVariable(dfg, vs))) listSolveKeys(dfg, vs, filterSolveKeys, skeys) end @@ -581,12 +677,10 @@ function listSolveKeys( dfg::AbstractDFG, end const listSupersolves = listSolveKeys - ##------------------------------------------------------------------------------ ## Aliases and Other filtered lists ##------------------------------------------------------------------------------ - ## Aliases ##-------- """ @@ -598,8 +692,13 @@ Tags is a list of any tags that a node must have (at least one match). Notes: - Returns `Vector{Symbol}` """ -function ls(dfg::G, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0) where G <: AbstractDFG - return listVariables(dfg, regexFilter, tags=tags, solvable=solvable) +function ls( + dfg::G, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) where {G <: AbstractDFG} + return listVariables(dfg, regexFilter; tags = tags, solvable = solvable) end #TODO tags kwarg @@ -611,47 +710,53 @@ Optionally specify a label regular expression to retrieves a subset of the facto Notes - Return `Vector{Symbol}` """ -function lsf(dfg::G, regexFilter::Union{Nothing, Regex}=nothing; tags::Vector{Symbol}=Symbol[], solvable::Int=0) where G <: AbstractDFG - return listFactors(dfg, regexFilter, tags=tags, solvable=solvable) +function lsf( + dfg::G, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, +) where {G <: AbstractDFG} + return listFactors(dfg, regexFilter; tags = tags, solvable = solvable) end - """ $(SIGNATURES) Retrieve a list of labels of the immediate neighbors around a given variable or factor. """ -function ls(dfg::G, node::T; solvable::Int=0) where {G <: AbstractDFG, T <: DFGNode} - return listNeighbors(dfg, node, solvable=solvable) +function ls(dfg::G, node::T; solvable::Int = 0) where {G <: AbstractDFG, T <: DFGNode} + return listNeighbors(dfg, node; solvable = solvable) end -function ls(dfg::G, label::Symbol; solvable::Int=0) where G <: AbstractDFG - return listNeighbors(dfg, label, solvable=solvable) +function ls(dfg::G, label::Symbol; solvable::Int = 0) where {G <: AbstractDFG} + return listNeighbors(dfg, label; solvable = solvable) end -function lsf(dfg::G, label::Symbol; solvable::Int=0)::Vector{Symbol} where G <: AbstractDFG - return listNeighbors(dfg, label, solvable=solvable) +function lsf( + dfg::G, + label::Symbol; + solvable::Int = 0, +)::Vector{Symbol} where {G <: AbstractDFG} + return listNeighbors(dfg, label; solvable = solvable) end ## list by types ##-------------- function ls(dfg::G, ::Type{T}) where {G <: AbstractDFG, T <: InferenceVariable} - xx = getVariables(dfg) - mask = getVariableType.(xx) .|> typeof .== T - vxx = view(xx, mask) - map(x->x.label, vxx) + xx = getVariables(dfg) + mask = getVariableType.(xx) .|> typeof .== T + vxx = view(xx, mask) + return map(x -> x.label, vxx) end - function ls(dfg::G, ::Type{T}) where {G <: AbstractDFG, T <: AbstractFactor} - xx = getFactors(dfg) - names = typeof.(getFactorType.(xx)) .|> nameof - vxx = view(xx, names .== Symbol(T)) - map(x->x.label, vxx) + xx = getFactors(dfg) + names = typeof.(getFactorType.(xx)) .|> nameof + vxx = view(xx, names .== Symbol(T)) + return map(x -> x.label, vxx) end - function lsf(dfg::G, ::Type{T}) where {G <: AbstractDFG, T <: AbstractFactor} - ls(dfg, T) + return ls(dfg, T) end """ @@ -673,18 +778,17 @@ Return vector of prior factor symbol labels in factor graph `dfg`. Notes: - Returns `Vector{Symbol}` """ -function lsfPriors(dfg::G) where G <: AbstractDFG - priors = Symbol[] - fcts = lsf(dfg) - for fc in fcts - if isPrior(dfg, fc) - push!(priors, fc) +function lsfPriors(dfg::G) where {G <: AbstractDFG} + priors = Symbol[] + fcts = lsf(dfg) + for fc in fcts + if isPrior(dfg, fc) + push!(priors, fc) + end end - end - return priors + return priors end - #TODO is this repeated functionality? """ @@ -713,7 +817,6 @@ function lsWho(dfg::AbstractDFG, type::Symbol) return labels end - """ $(SIGNATURES) Gives back all factor labels that fit the bill: @@ -740,7 +843,6 @@ function lsfWho(dfg::AbstractDFG, type::Symbol) return labels end - ## list types ##----------- @@ -765,15 +867,14 @@ end Return `::Dict{Symbol, Vector{Symbol}}` of all unique variable types with labels in a factor graph. """ function lsTypesDict(dfg::AbstractDFG) - vars = getVariables(dfg) - alltypes = Dict{Symbol,Vector{Symbol}}() + alltypes = Dict{Symbol, Vector{Symbol}}() for v in vars varType = typeof(getVariableType(v)) |> nameof d = get!(alltypes, varType, Symbol[]) push!(d, v.label) end - return alltypes + return alltypes end """ @@ -798,16 +899,15 @@ Return `::Dict{Symbol, Vector{Symbol}}` of all unique factors types with labels """ function lsfTypesDict(dfg::AbstractDFG) facs = getFactors(dfg) - alltypes = Dict{Symbol,Vector{Symbol}}() + alltypes = Dict{Symbol, Vector{Symbol}}() for f in facs facType = typeof(getFactorType(f)) |> nameof d = get!(alltypes, facType, Symbol[]) push!(d, f.label) end - return alltypes + return alltypes end - ##------------------------------------------------------------------------------ ## tags ##------------------------------------------------------------------------------ @@ -816,65 +916,64 @@ end Determine if the variable or factor neighbors have the `tags:;Vector{Symbol}`, and `matchAll::Bool`. """ -function hasTags(dfg::AbstractDFG, - sym::Symbol, - tags::Vector{Symbol}; - matchAll::Bool=true ) - # - alltags = listTags(dfg, sym) - length(filter(x->x in alltags, tags)) >= (matchAll ? length(tags) : 1) +function hasTags(dfg::AbstractDFG, sym::Symbol, tags::Vector{Symbol}; matchAll::Bool = true) + # + alltags = listTags(dfg, sym) + return length(filter(x -> x in alltags, tags)) >= (matchAll ? length(tags) : 1) end - """ $SIGNATURES Determine if the variable or factor neighbors have the `tags:;Vector{Symbol}`, and `matchAll::Bool`. """ -function hasTagsNeighbors(dfg::AbstractDFG, - sym::Symbol, - tags::Vector{Symbol}; - matchAll::Bool=true ) - # - # assume only variables or factors are neighbors - getNeiFnc = isVariable(dfg, sym) ? getFactor : getVariable - alltags = union( (ls(dfg, sym) .|> x->getTags(getNeiFnc(dfg,x)))... ) - length(filter(x->x in alltags, tags)) >= (matchAll ? length(tags) : 1) +function hasTagsNeighbors( + dfg::AbstractDFG, + sym::Symbol, + tags::Vector{Symbol}; + matchAll::Bool = true, +) + # + # assume only variables or factors are neighbors + getNeiFnc = isVariable(dfg, sym) ? getFactor : getVariable + alltags = union((ls(dfg, sym) .|> x -> getTags(getNeiFnc(dfg, x)))...) + return length(filter(x -> x in alltags, tags)) >= (matchAll ? length(tags) : 1) end ##============================================================================== ## Finding ##============================================================================== # function findClosestTimestamp(setA::Vector{Tuple{DateTime,T}}, - # setB::Vector{Tuple{DateTime,S}}) where {S,T} +# setB::Vector{Tuple{DateTime,S}}) where {S,T} """ $SIGNATURES 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. """ -function findClosestTimestamp(setA::Vector{Tuple{ZonedDateTime,T}}, - setB::Vector{Tuple{ZonedDateTime,S}}) where {S,T} - # - # build matrix of delta times, ranges on rows x vars on columns - DT = Array{Millisecond, 2}(undef, length(setA), length(setB)) - for i in 1:length(setA), j in 1:length(setB) - DT[i,j] = setB[j][1] - setA[i][1] - end +function findClosestTimestamp( + setA::Vector{Tuple{ZonedDateTime, T}}, + setB::Vector{Tuple{ZonedDateTime, S}}, +) where {S, T} + # + # build matrix of delta times, ranges on rows x vars on columns + DT = Array{Millisecond, 2}(undef, length(setA), length(setB)) + for i = 1:length(setA), j = 1:length(setB) + DT[i, j] = setB[j][1] - setA[i][1] + end - DT .= abs.(DT) + DT .= abs.(DT) - # absolute time differences - # DTi = (x->x.value).(DT) .|> abs + # absolute time differences + # DTi = (x->x.value).(DT) .|> abs - # find the smallest element - mdt = minimum(DT) - corrs = findall(x->x==mdt, DT) + # find the smallest element + mdt = minimum(DT) + corrs = findall(x -> x == mdt, DT) - # return the closest timestamp, deltaT, number of correspondences - return corrs[1].I, mdt, length(corrs) + # return the closest timestamp, deltaT, number of correspondences + return corrs[1].I, mdt, length(corrs) end - """ $SIGNATURES @@ -892,50 +991,63 @@ Related ls, listVariables, findClosestTimestamp """ -function findVariableNearTimestamp(dfg::AbstractDFG, - timest::ZonedDateTime, - regexFilter::Union{Nothing, Regex}=nothing; - tags::Vector{Symbol}=Symbol[], - solvable::Int=0, - warnDuplicate::Bool=true, - number::Int=1 ) - # - # get the variable labels based on filters - # syms = listVariables(dfg, regexFilter, tags=tags, solvable=solvable) - syms = listVariables(dfg, regexFilter, tags=tags, solvable=solvable) - # compile timestamps with label - # vars = map( x->getVariable(dfg, x), syms ) - timeset = map(x->(getTimestamp(getVariable(dfg,x)), x), syms) - mask = BitArray{1}(undef, length(syms)) - fill!(mask, true) - - RET = Vector{Tuple{Vector{Symbol},Millisecond}}() - SYMS = Symbol[] - CORRS = 1 - NUMBER = number - while 0 < CORRS + NUMBER - # get closest - link, mdt, corrs = findClosestTimestamp([(timest,0)], timeset[mask]) - newsym = syms[link[2]] - union!(SYMS, !isa(newsym, Vector) ? [newsym] : newsym) - mask[link[2]] = false - CORRS = corrs-1 - # last match, done with this delta time - if corrs == 1 - NUMBER -= 1 - push!(RET, (deepcopy(SYMS),mdt)) - SYMS = Symbol[] +function findVariableNearTimestamp( + dfg::AbstractDFG, + timest::ZonedDateTime, + regexFilter::Union{Nothing, Regex} = nothing; + tags::Vector{Symbol} = Symbol[], + solvable::Int = 0, + warnDuplicate::Bool = true, + number::Int = 1, +) + # + # get the variable labels based on filters + # syms = listVariables(dfg, regexFilter, tags=tags, solvable=solvable) + syms = listVariables(dfg, regexFilter; tags = tags, solvable = solvable) + # compile timestamps with label + # vars = map( x->getVariable(dfg, x), syms ) + timeset = map(x -> (getTimestamp(getVariable(dfg, x)), x), syms) + mask = BitArray{1}(undef, length(syms)) + fill!(mask, true) + + RET = Vector{Tuple{Vector{Symbol}, Millisecond}}() + SYMS = Symbol[] + CORRS = 1 + NUMBER = number + while 0 < CORRS + NUMBER + # get closest + link, mdt, corrs = findClosestTimestamp([(timest, 0)], timeset[mask]) + newsym = syms[link[2]] + union!(SYMS, !isa(newsym, Vector) ? [newsym] : newsym) + mask[link[2]] = false + CORRS = corrs - 1 + # last match, done with this delta time + if corrs == 1 + NUMBER -= 1 + push!(RET, (deepcopy(SYMS), mdt)) + SYMS = Symbol[] + end end - end - # warn if duplicates found - # warnDuplicate && 1 < corrs ? @warn("getVariableNearTimestamp found more than one variable at $timestamp") : nothing + # warn if duplicates found + # warnDuplicate && 1 < corrs ? @warn("getVariableNearTimestamp found more than one variable at $timestamp") : nothing - return RET + return RET end -findVariableNearTimestamp(dfg::AbstractDFG, timest::DateTime, regexFilter::Union{Nothing, Regex}=nothing; - timezone=tz"UTC", kwargs...) = - findVariableNearTimestamp(dfg, ZonedDateTime(timest, timezone), regexFilter; kwargs...) +function findVariableNearTimestamp( + dfg::AbstractDFG, + timest::DateTime, + regexFilter::Union{Nothing, Regex} = nothing; + timezone = tz"UTC", + kwargs..., +) + return findVariableNearTimestamp( + dfg, + ZonedDateTime(timest, timezone), + regexFilter; + kwargs..., + ) +end ##============================================================================== ## Copy Functions @@ -958,16 +1070,16 @@ Related: function copyGraph!( destDFG::AbstractDFG, sourceDFG::AbstractDFG, - variableLabels::AbstractVector{Symbol}=listVariables(sourceDFG), - factorLabels::AbstractVector{Symbol}=listFactors(sourceDFG); - copyGraphMetadata::Bool=false, - overwriteDest::Bool=false, - deepcopyNodes::Bool=false, - verbose::Bool = false + variableLabels::AbstractVector{Symbol} = listVariables(sourceDFG), + factorLabels::AbstractVector{Symbol} = listFactors(sourceDFG); + copyGraphMetadata::Bool = false, + overwriteDest::Bool = false, + deepcopyNodes::Bool = false, + verbose::Bool = false, ) # Split into variables and factors - sourceVariables = map(vId->getVariable(sourceDFG, vId), variableLabels) - sourceFactors = map(fId->getFactor(sourceDFG, fId), factorLabels) + sourceVariables = map(vId -> getVariable(sourceDFG, vId), variableLabels) + sourceFactors = map(fId -> getFactor(sourceDFG, fId), factorLabels) # Now we have to add all variables first, @showprogress "copy variables" for variable in sourceVariables @@ -1024,12 +1136,21 @@ Related: - [`getNeighborhood`](@ref) - [`mergeGraph!`](@ref) """ -function deepcopyGraph!(destDFG::AbstractDFG, - sourceDFG::AbstractDFG, - variableLabels::Vector{Symbol} = ls(sourceDFG), - factorLabels::Vector{Symbol} = lsf(sourceDFG); - kwargs...) - copyGraph!(destDFG, sourceDFG, variableLabels, factorLabels; deepcopyNodes=true, kwargs...) +function deepcopyGraph!( + destDFG::AbstractDFG, + sourceDFG::AbstractDFG, + variableLabels::Vector{Symbol} = ls(sourceDFG), + factorLabels::Vector{Symbol} = lsf(sourceDFG); + kwargs..., +) + return copyGraph!( + destDFG, + sourceDFG, + variableLabels, + factorLabels; + deepcopyNodes = true, + kwargs..., + ) end """ @@ -1042,13 +1163,14 @@ Related: - [`getNeighborhood`](@ref) - [`mergeGraph!`](@ref) """ -function deepcopyGraph( ::Type{T}, - sourceDFG::AbstractDFG, - variableLabels::Vector{Symbol} = ls(sourceDFG), - factorLabels::Vector{Symbol} = lsf(sourceDFG); - sessionId::String = "", - kwargs...) where T <: AbstractDFG - +function deepcopyGraph( + ::Type{T}, + sourceDFG::AbstractDFG, + variableLabels::Vector{Symbol} = ls(sourceDFG), + factorLabels::Vector{Symbol} = lsf(sourceDFG); + sessionId::String = "", + kwargs..., +) where {T <: AbstractDFG} ginfo = [getDFGInfo(sourceDFG)...] if sessionId == "" ginfo[4] *= "_copy$(string(uuid4())[1:6])" @@ -1056,17 +1178,21 @@ function deepcopyGraph( ::Type{T}, ginfo[4] = sessionId end destDFG = T(ginfo...) - copyGraph!(destDFG, sourceDFG, variableLabels, factorLabels; deepcopyNodes=true, kwargs...) + copyGraph!( + destDFG, + sourceDFG, + variableLabels, + factorLabels; + deepcopyNodes = true, + kwargs..., + ) return destDFG end - - ##============================================================================== ## Automated Graph Searching ##============================================================================== - function findShortestPathDijkstra end """ @@ -1077,27 +1203,31 @@ Relatively naive function counting linearly from-to DevNotes - Convert to using Graphs shortest path methods instead. """ -function findFactorsBetweenNaive( dfg::AbstractDFG, - from::Symbol, - to::Symbol, - assertSingles::Bool=false) - # - @info "findFactorsBetweenNaive is naive linear number method -- improvements welcome" - SRT = getVariableLabelNumber(from) - STP = getVariableLabelNumber(to) - prefix = string(from)[1] - @assert prefix == string(to)[1] "from-to prefixes must match, one is $prefix, other $(string(to)[1])" - prev = from - fctlist = Symbol[] - for num in (SRT+1):STP - next = Symbol(prefix,num) - fct = intersect(ls(dfg, prev),ls(dfg,next)) - !assertSingles ? nothing : @assert length(fct) == 1 "assertSingles=true, won't return multiple factors joining variables at this time" - union!(fctlist, fct) - prev = next - end - - return fctlist +function findFactorsBetweenNaive( + dfg::AbstractDFG, + from::Symbol, + to::Symbol, + assertSingles::Bool = false, +) + # + @info "findFactorsBetweenNaive is naive linear number method -- improvements welcome" + SRT = getVariableLabelNumber(from) + STP = getVariableLabelNumber(to) + prefix = string(from)[1] + @assert prefix == string(to)[1] "from-to prefixes must match, one is $prefix, other $(string(to)[1])" + prev = from + fctlist = Symbol[] + for num = (SRT + 1):STP + next = Symbol(prefix, num) + fct = intersect(ls(dfg, prev), ls(dfg, next)) + if assertSingles + @assert length(fct) == 1 "assertSingles=true, won't return multiple factors joining variables at this time" + end + union!(fctlist, fct) + prev = next + end + + return fctlist end """ @@ -1114,13 +1244,18 @@ Related function isPathFactorsHomogeneous(dfg::AbstractDFG, from::Symbol, to::Symbol) # FIXME, must consider all paths, not just shortest... pth = intersect(findShortestPathDijkstra(dfg, from, to), lsf(dfg)) - types = getFactorType.(dfg, pth) .|> typeof .|> x->(x).name #TODO this might not be correct in julia 1.6 + types = getFactorType.(dfg, pth) .|> typeof .|> x -> (x).name #TODO this might not be correct in julia 1.6 utyp = unique(types) - (length(utyp) == 1), utyp + return (length(utyp) == 1), utyp end -function existsPathOfFactorsType(dfg::AbstractDFG, from::Symbol, to::Symbol, ftype::AbstractFactor) - error("WIP") +function existsPathOfFactorsType( + dfg::AbstractDFG, + from::Symbol, + to::Symbol, + ftype::AbstractFactor, +) + return error("WIP") end ##============================================================================== @@ -1144,7 +1279,7 @@ function getNeighborhood(dfg::AbstractDFG, label::Symbol, distance::Int) neighborList = Set{Symbol}([label]) curList = Set{Symbol}([label]) - for dist in 1:distance + for dist = 1:distance newNeighbors = Set{Symbol}() for node in curList neighbors = listNeighbors(dfg, node) @@ -1158,7 +1293,12 @@ function getNeighborhood(dfg::AbstractDFG, label::Symbol, distance::Int) return collect(neighborList) end -function getNeighborhood(dfg::AbstractDFG, variableFactorLabels::Vector{Symbol}, distance::Int; solvable::Int=0) +function getNeighborhood( + dfg::AbstractDFG, + variableFactorLabels::Vector{Symbol}, + distance::Int; + solvable::Int = 0, +) # find neighbors at distance to add neighbors = Symbol[] if distance > 0 @@ -1172,7 +1312,6 @@ function getNeighborhood(dfg::AbstractDFG, variableFactorLabels::Vector{Symbol}, solvable != 0 && filter!(nlbl -> (getSolvable(dfg, nlbl) >= solvable), allvarfacs) return allvarfacs - end """ @@ -1187,32 +1326,42 @@ Related: Dev Notes - Bulk vs node for node: a list of labels are compiled and the sugraph is copied in bulk. """ -function buildSubgraph(::Type{G}, - dfg::AbstractDFG, - variableFactorLabels::Vector{Symbol}, - distance::Int=0; - solvable::Int=0, - sessionId::String = "", - kwargs...) where G <: AbstractDFG - +function buildSubgraph( + ::Type{G}, + dfg::AbstractDFG, + variableFactorLabels::Vector{Symbol}, + distance::Int = 0; + solvable::Int = 0, + sessionId::String = "", + kwargs..., +) where {G <: AbstractDFG} if sessionId == "" sessionId = getSessionLabel(dfg) * "_sub_$(string(uuid4())[1:6])" end #build up the neighborhood from variableFactorLabels - allvarfacs = getNeighborhood(dfg, variableFactorLabels, distance; solvable=solvable) + allvarfacs = getNeighborhood(dfg, variableFactorLabels, distance; solvable = solvable) variableLabels = intersect(listVariables(dfg), allvarfacs) factorLabels = intersect(listFactors(dfg), allvarfacs) # Copy the section of graph we want - destDFG = deepcopyGraph(G, dfg, variableLabels, factorLabels; sessionId=sessionId, kwargs...) + destDFG = deepcopyGraph( + G, + dfg, + variableLabels, + factorLabels; + sessionId = sessionId, + kwargs..., + ) return destDFG end -function buildSubgraph(dfg::AbstractDFG, - variableFactorLabels::Vector{Symbol}, - distance::Int=0; - kwargs...) +function buildSubgraph( + dfg::AbstractDFG, + variableFactorLabels::Vector{Symbol}, + distance::Int = 0; + kwargs..., +) return buildSubgraph(LocalDFG, dfg, variableFactorLabels, distance; kwargs...) end @@ -1228,21 +1377,36 @@ Related: - [`getNeighborhood`](@ref) - [`deepcopyGraph`](@ref) """ -function mergeGraph!(destDFG::AbstractDFG, - sourceDFG::AbstractDFG, - variableLabels::Vector{Symbol} = ls(sourceDFG), - factorLabels::Vector{Symbol} = lsf(sourceDFG), - distance::Int = 0; - solvable::Int = 0, - kwargs...) +function mergeGraph!( + destDFG::AbstractDFG, + sourceDFG::AbstractDFG, + variableLabels::Vector{Symbol} = ls(sourceDFG), + factorLabels::Vector{Symbol} = lsf(sourceDFG), + distance::Int = 0; + solvable::Int = 0, + kwargs..., +) # find neighbors at distance to add - allvarfacs = getNeighborhood(sourceDFG, union(variableLabels, factorLabels), distance; solvable=solvable) + allvarfacs = getNeighborhood( + sourceDFG, + union(variableLabels, factorLabels), + distance; + solvable = solvable, + ) sourceVariables = intersect(listVariables(sourceDFG), allvarfacs) sourceFactors = intersect(listFactors(sourceDFG), allvarfacs) - copyGraph!(destDFG, sourceDFG, sourceVariables, sourceFactors; deepcopyNodes=true, overwriteDest=true, kwargs...) + copyGraph!( + destDFG, + sourceDFG, + sourceVariables, + sourceFactors; + deepcopyNodes = true, + overwriteDest = true, + kwargs..., + ) return destDFG end @@ -1258,12 +1422,12 @@ Merges and updates solver and estimate data for a variable (variable can be from Note: Makes a copy of the estimates and solver data so that there is no coupling between graphs. """ function mergeVariableData!(dfg::AbstractDFG, sourceVariable::AbstractDFGVariable) - var = getVariable(dfg, sourceVariable.label) mergePPEs!(var, sourceVariable) # If this variable has solverDataDict (summaries do not) - :solverDataDict in fieldnames(typeof(var)) && mergeVariableSolverData!(var, sourceVariable) + :solverDataDict in fieldnames(typeof(var)) && + mergeVariableSolverData!(var, sourceVariable) #update if its not a InMemoryDFGTypes, otherwise it was a reference # if satelite nodes are used it can be updated separately @@ -1281,7 +1445,11 @@ This should be used to push local solve data back into a cloud graph, for exampl Notes - Returns `::Nothing` """ -function mergeGraphVariableData!(destDFG::H, sourceDFG::G, varSyms::Vector{Symbol}) where {G <: AbstractDFG, H <: AbstractDFG} +function mergeGraphVariableData!( + destDFG::H, + sourceDFG::G, + varSyms::Vector{Symbol}, +) where {G <: AbstractDFG, H <: AbstractDFG} # Update all variables in the destination # (For now... we may change this soon) for variableId in varSyms @@ -1289,7 +1457,6 @@ function mergeGraphVariableData!(destDFG::H, sourceDFG::G, varSyms::Vector{Symbo end end - ##============================================================================== ## Graphs Structures (Abstract, overwrite for performance) ##============================================================================== @@ -1303,25 +1470,27 @@ Note: - rather use getBiadjacencyMatrix - Returns either of `::Matrix{Union{Nothing, Symbol}}` """ -function getAdjacencyMatrixSymbols(dfg::AbstractDFG; solvable::Int=0) +function getAdjacencyMatrixSymbols(dfg::AbstractDFG; solvable::Int = 0) # - varLabels = sort(map(v->v.label, getVariables(dfg, solvable=solvable))) - factLabels = sort(map(f->f.label, getFactors(dfg, solvable=solvable))) - vDict = Dict(varLabels .=> [1:length(varLabels)...].+1) - - adjMat = Matrix{Union{Nothing, Symbol}}(nothing, length(factLabels)+1, length(varLabels)+1) + varLabels = sort(map(v -> v.label, getVariables(dfg; solvable = solvable))) + factLabels = sort(map(f -> f.label, getFactors(dfg; solvable = solvable))) + vDict = Dict(varLabels .=> [1:length(varLabels)...] .+ 1) + + adjMat = Matrix{Union{Nothing, Symbol}}( + nothing, + length(factLabels) + 1, + length(varLabels) + 1, + ) # Set row/col headings adjMat[2:end, 1] = factLabels adjMat[1, 2:end] = varLabels for (fIndex, factLabel) in enumerate(factLabels) - factVars = listNeighbors(dfg, getFactor(dfg, factLabel), solvable=solvable) - map(vLabel -> adjMat[fIndex+1,vDict[vLabel]] = factLabel, factVars) + factVars = listNeighbors(dfg, getFactor(dfg, factLabel); solvable = solvable) + map(vLabel -> adjMat[fIndex + 1, vDict[vLabel]] = factLabel, factVars) end return adjMat end - - # TODO API name get seems wrong maybe just biadjacencyMatrix """ $(SIGNATURES) @@ -1333,22 +1502,21 @@ with the corresponding labels in varLabels,facLabels. Notes - Returns `::NamedTuple{(:B, :varLabels, :facLabels), Tuple{SparseMatrixCSC, Vector{Symbol}, Vector{Symbol}}}` """ -function getBiadjacencyMatrix(dfg::AbstractDFG; solvable::Int=0) - varLabels = map(v->v.label, getVariables(dfg, solvable=solvable)) - factLabels = map(f->f.label, getFactors(dfg, solvable=solvable)) +function getBiadjacencyMatrix(dfg::AbstractDFG; solvable::Int = 0) + varLabels = map(v -> v.label, getVariables(dfg; solvable = solvable)) + factLabels = map(f -> f.label, getFactors(dfg; solvable = solvable)) vDict = Dict(varLabels .=> [1:length(varLabels)...]) adjMat = spzeros(Int, length(factLabels), length(varLabels)) for (fIndex, factLabel) in enumerate(factLabels) - factVars = listNeighbors(dfg, getFactor(dfg, factLabel), solvable=solvable) - map(vLabel -> adjMat[fIndex,vDict[vLabel]] = 1, factVars) + factVars = listNeighbors(dfg, getFactor(dfg, factLabel); solvable = solvable) + map(vLabel -> adjMat[fIndex, vDict[vLabel]] = 1, factVars) end - return (B=adjMat, varLabels=varLabels, facLabels=factLabels) + return (B = adjMat, varLabels = varLabels, facLabels = factLabels) end - ##============================================================================== ## DOT Files, falls back to GraphsDFG dot functions ##============================================================================== @@ -1376,7 +1544,7 @@ Note - Can be viewed with the `xdot` system application. - Based on graphviz.org """ -function toDotFile(dfg::AbstractDFG, fileName::String="/tmp/dfg.dot") +function toDotFile(dfg::AbstractDFG, fileName::String = "/tmp/dfg.dot") #convert to GraphsDFG ldfg = GraphsDFG{NoSolverParams}() @@ -1401,11 +1569,12 @@ function getSummary(dfg::G) where {G <: AbstractDFG} vars = map(v -> DFGVariableSummary(v), getVariables(dfg)) facts = map(f -> DFGFactorSummary(f), getFactors(dfg)) return DFGSummary( - Dict(map(v->v.label, vars) .=> vars), - Dict(map(f->f.label, facts) .=> facts), + Dict(map(v -> v.label, vars) .=> vars), + Dict(map(f -> f.label, facts) .=> facts), dfg.userLabel, dfg.robotLabel, - dfg.sessionLabel) + dfg.sessionLabel, + ) end """ @@ -1417,11 +1586,12 @@ Notes - Returns `::GraphsDFG{NoSolverParams, DFGVariableSummary, DFGFactorSummary}` """ function getSummaryGraph(dfg::G) where {G <: AbstractDFG} - summaryDfg = GraphsDFG{NoSolverParams, DFGVariableSummary, DFGFactorSummary}( - description="Summary of $(getDescription(dfg))", - userLabel=dfg.userLabel, - robotLabel=dfg.robotLabel, - sessionLabel=dfg.sessionLabel) + summaryDfg = GraphsDFG{NoSolverParams, DFGVariableSummary, DFGFactorSummary}(; + description = "Summary of $(getDescription(dfg))", + userLabel = dfg.userLabel, + robotLabel = dfg.robotLabel, + sessionLabel = dfg.sessionLabel, + ) deepcopyGraph!(summaryDfg, dfg) # for v in getVariables(dfg) # newV = addVariable!(summaryDfg, DFGVariableSummary(v)) diff --git a/src/services/CommonAccessors.jl b/src/services/CommonAccessors.jl index 86f1484a..6faf90c1 100644 --- a/src/services/CommonAccessors.jl +++ b/src/services/CommonAccessors.jl @@ -37,9 +37,9 @@ $SIGNATURES Set the tags for a DFGNode. """ -function setTags!(f::DataLevel0, tags::Union{Vector{Symbol},Set{Symbol}}) - empty!(f.tags) - union!(f.tags, tags) +function setTags!(f::DataLevel0, tags::Union{Vector{Symbol}, Set{Symbol}}) + empty!(f.tags) + return union!(f.tags, tags) end ##------------------------------------------------------------------------------ @@ -53,7 +53,6 @@ Get the timestamp of a DFGNode. """ getTimestamp(v::DataLevel1) = v.timestamp - """ $SIGNATURES @@ -64,15 +63,18 @@ See also [`setTimestamp`](@ref) """ function setTimestamp!(dfg::AbstractDFG, lbl::Symbol, ts::ZonedDateTime) if isVariable(dfg, lbl) - return updateVariable!(dfg, setTimestamp(getVariable(dfg,lbl), ts; verbose=false)) + return updateVariable!( + dfg, + setTimestamp(getVariable(dfg, lbl), ts; verbose = false), + ) else - return updateFactor!(dfg, setTimestamp(getFactor(dfg,lbl), ts)) + return updateFactor!(dfg, setTimestamp(getFactor(dfg, lbl), ts)) end end -setTimestamp!(dfg::AbstractDFG, lbl::Symbol, ts::DateTime, timezone=localzone()) = setTimestamp!(dfg, lbl, ZonedDateTime(ts, timezone)) - - +function setTimestamp!(dfg::AbstractDFG, lbl::Symbol, ts::DateTime, timezone = localzone()) + return setTimestamp!(dfg, lbl, ZonedDateTime(ts, timezone)) +end ##------------------------------------------------------------------------------ ## solvable @@ -95,11 +97,11 @@ getSolvable(var::Union{DFGVariable, DFGFactor})::Int = var.solvable Get 'solvable' parameter for either a variable or factor. """ function getSolvable(dfg::AbstractDFG, sym::Symbol)::Int - if isVariable(dfg, sym) - return getVariable(dfg, sym).solvable - elseif isFactor(dfg, sym) - return getFactor(dfg, sym).solvable - end + if isVariable(dfg, sym) + return getVariable(dfg, sym).solvable + elseif isFactor(dfg, sym) + return getFactor(dfg, sym).solvable + end end #TODO data level2 for N @@ -108,28 +110,25 @@ end Set the `solvable` parameter for either a variable or factor. """ -function setSolvable!(node::N, solvable::Int)::Int where N <: DFGNode - node.solvable = solvable - return solvable +function setSolvable!(node::N, solvable::Int)::Int where {N <: DFGNode} + node.solvable = solvable + return solvable end - """ $SIGNATURES Set the `solvable` parameter for either a variable or factor. """ function setSolvable!(dfg::AbstractDFG, sym::Symbol, solvable::Int)::Int - if isVariable(dfg, sym) - getVariable(dfg, sym).solvable = solvable - elseif isFactor(dfg, sym) - getFactor(dfg, sym).solvable = solvable - end - return solvable + if isVariable(dfg, sym) + getVariable(dfg, sym).solvable = solvable + elseif isFactor(dfg, sym) + getFactor(dfg, sym).solvable = solvable + end + return solvable end - - """ $SIGNATURES @@ -140,7 +139,6 @@ Related: """ isSolvable(node::Union{DFGVariable, DFGFactor}) = getSolvable(node) > 0 - ##------------------------------------------------------------------------------ ## solveInProgress ##------------------------------------------------------------------------------ @@ -157,17 +155,27 @@ Related isSolvable """ -function getSolveInProgress(var::Union{DFGVariable, DFGFactor}, solveKey::Symbol=:default)::Int +function getSolveInProgress( + var::Union{DFGVariable, DFGFactor}, + solveKey::Symbol = :default, +)::Int # Variable - var isa DFGVariable && return haskey(getSolverDataDict(var), solveKey) ? getSolverDataDict(var)[solveKey].solveInProgress : 0 + if var isa DFGVariable + if haskey(getSolverDataDict(var), solveKey) + return getSolverDataDict(var)[solveKey].solveInProgress + else + return 0 + end + end # Factor return getSolverData(var).solveInProgress end #TODO missing set solveInProgress and graph level accessor -isSolveInProgress(node::Union{DFGVariable, DFGFactor}, solvekey::Symbol=:default) = getSolveInProgress(node, solvekey) > 0 - +function isSolveInProgress(node::Union{DFGVariable, DFGFactor}, solvekey::Symbol = :default) + return getSolveInProgress(node, solvekey) > 0 +end ##============================================================================== ## Common Layer 2 CRUD and SET @@ -182,8 +190,8 @@ $SIGNATURES Return the tags for a variable or factor. """ function listTags(dfg::AbstractDFG, sym::Symbol) - getFnc = isVariable(dfg,sym) ? getVariable : getFactor - getTags(getFnc(dfg, sym)) + getFnc = isVariable(dfg, sym) ? getVariable : getFactor + return getTags(getFnc(dfg, sym)) end #alias for completeness listTags(f::DataLevel0) = getTags(f) @@ -194,20 +202,19 @@ listTags(f::DataLevel0) = getTags(f) Merge add tags to a variable or factor (union) """ function mergeTags!(dfg::InMemoryDFGTypes, sym::Symbol, tags::Vector{Symbol}) - getFnc = isVariable(dfg,sym) ? getVariable : getFactor - union!(getTags(getFnc(dfg, sym)), tags) + getFnc = isVariable(dfg, sym) ? getVariable : getFactor + return union!(getTags(getFnc(dfg, sym)), tags) end mergeTags!(f::DataLevel0, tags::Vector{Symbol}) = union!(f.tags, tags) - """ $SIGNATURES Remove the tags from the node (setdiff) """ function removeTags!(dfg::InMemoryDFGTypes, sym::Symbol, tags::Vector{Symbol}) - getFnc = isVariable(dfg,sym) ? getVariable : getFactor - setdiff!(getTags(getFnc(dfg, sym)), tags) + getFnc = isVariable(dfg, sym) ? getVariable : getFactor + return setdiff!(getTags(getFnc(dfg, sym)), tags) end removeTags!(f::DataLevel0, tags::Vector{Symbol}) = setdiff!(f.tags, tags) @@ -217,7 +224,7 @@ $SIGNATURES Empty all tags from the node (empty) """ function emptyTags!(dfg::InMemoryDFGTypes, sym::Symbol) - getFnc = isVariable(dfg,sym) ? getVariable : getFactor - empty!(getTags(getFnc(dfg, sym))) + getFnc = isVariable(dfg, sym) ? getVariable : getFactor + return empty!(getTags(getFnc(dfg, sym))) end emptyTags!(f::DataLevel0) = empty!(f.tags) diff --git a/src/services/CompareUtils.jl b/src/services/CompareUtils.jl index 918a809f..85522e0d 100644 --- a/src/services/CompareUtils.jl +++ b/src/services/CompareUtils.jl @@ -16,19 +16,31 @@ implement compare if needed. ==(a::AbstractFactor, b::AbstractFactor) = typeof(a) == typeof(b) - # Generate compares automatically for all in this union -const GeneratedCompareUnion = Union{MeanMaxPPE, VariableNodeData, PackedVariableNodeData, - DFGVariable, Variable, DFGVariableSummary, SkeletonDFGVariable, - GenericFunctionNodeData, - DFGFactor, PackedFactor, DFGFactorSummary, SkeletonDFGFactor} - -@generated function ==(x::T, y::T) where T <: GeneratedCompareUnion +const GeneratedCompareUnion = Union{ + MeanMaxPPE, + VariableNodeData, + PackedVariableNodeData, + DFGVariable, + Variable, + DFGVariableSummary, + SkeletonDFGVariable, + GenericFunctionNodeData, + DFGFactor, + PackedFactor, + DFGFactorSummary, + SkeletonDFGFactor, +} + +@generated function ==(x::T, y::T) where {T <: GeneratedCompareUnion} ignored = [] - mapreduce(n -> :(x.$n == y.$n), (a,b)->:($a && $b), setdiff(fieldnames(x), ignored)) + return mapreduce( + n -> :(x.$n == y.$n), + (a, b) -> :($a && $b), + setdiff(fieldnames(x), ignored), + ) end - ##============================================================================== ## Compare ##============================================================================== @@ -39,11 +51,11 @@ function compareField(Allc, Bllc, syms) !isdefined(Bllc, syms) && return false a = getproperty(Allc, syms) b = getproperty(Bllc, syms) - @debug "Comparing field directly a vs b" syms a b + @debug "Comparing field directly a vs b" syms a b if a isa Base.RefValue - return a[] == b[] + return a[] == b[] else - return a == b + return a == b end end @@ -54,60 +66,71 @@ Compare the all fields of T that are not in `skip` for objects `Al` and `Bl` and TODO > add to func_ref.md """ -function compareFields( Al::T1, - Bl::T2; - show::Bool=true, - skip::Vector{Symbol}=Symbol[] ) where {T1,T2} - # - T1 == T2 ? nothing : @warn("different types in compareFields", T1, T2) - for field in fieldnames(T1) - (field in skip) && continue - tp = compareField(Al, Bl, field) - show && @debug(" $tp : $field") === nothing - show && !tp && (@debug " $field" a=getproperty(Al,field) b=getproperty(Bl,field)) - !tp && return false - end - return true +function compareFields( + Al::T1, + Bl::T2; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], +) where {T1, T2} + # + T1 == T2 ? nothing : @warn("different types in compareFields", T1, T2) + for field in fieldnames(T1) + (field in skip) && continue + tp = compareField(Al, Bl, field) + show && @debug(" $tp : $field") === nothing + show && + !tp && + (@debug " $field" a = getproperty(Al, field) b = getproperty(Bl, field)) + !tp && return false + end + return true end -function compareFields( Al::T, - Bl::T; - show::Bool=true, - skip::Vector{Symbol}=Symbol[] ) where {T <: Union{Number, AbstractString}} - # - return Al == Bl +function compareFields( + Al::T, + Bl::T; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], +) where {T <: Union{Number, AbstractString}} + # + return Al == Bl end -function compareAll(Al::T, - Bl::T; - show::Bool=true, - skip::Vector{Symbol}=Symbol[] ) where {T <: Union{AbstractString,Symbol}} - # - return Al == Bl +function compareAll( + Al::T, + Bl::T; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], +) where {T <: Union{AbstractString, Symbol}} + # + return Al == Bl end -function compareAll(Al::T, - Bl::T; - show::Bool=true, - skip::Vector{Symbol}=Symbol[] ) where {T <: Union{Array{<:Number}, Number}} - # - (length(Al) != length(Bl)) && return false - return norm(Al - Bl) < 1e-6 +function compareAll( + Al::T, + Bl::T; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], +) where {T <: Union{Array{<:Number}, Number}} + # + (length(Al) != length(Bl)) && return false + return norm(Al - Bl) < 1e-6 end -function compareAll(Al::T, - Bl::T; - show::Bool=true, - skip::Vector{Symbol}=Symbol[] ) where {T <: Array} - # - (length(Al) != length(Bl)) && return false - for i in 1:length(Al) - !compareAll(Al[i],Bl[i], show=false) && return false - end - return true +function compareAll( + Al::T, + Bl::T; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], +) where {T <: Array} + # + (length(Al) != length(Bl)) && return false + for i = 1:length(Al) + !compareAll(Al[i], Bl[i]; show = false) && return false + end + return true end - """ $(SIGNATURES) @@ -116,73 +139,95 @@ Recursively compare the all fields of T that are not in `skip` for objects `Al` TODO > add to func_ref.md """ function compareAll( - Al::Tuple, - Bl::Tuple; - show::Bool=true, - skip::Vector{Symbol}=Symbol[] + Al::Tuple, + Bl::Tuple; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], ) - # - length(Al) != length(Bl) && return false - for i in 1:length(Al) - !compareAll(Al[i], Bl[i], show=show, skip=skip) && return false - end - return true + # + length(Al) != length(Bl) && return false + for i = 1:length(Al) + !compareAll(Al[i], Bl[i]; show = show, skip = skip) && return false + end + return true end -function compareAll(Al::T, - Bl::T; - show::Bool=true, - skip::Vector{Symbol}=Symbol[] ) where {T <: Dict} - # - (length(Al) != length(Bl)) && return false - for (id, val) in Al - (Symbol(id) in skip) && continue - !compareAll(val, Bl[id], show=show, skip=skip) && return false - end - return true +function compareAll( + Al::T, + Bl::T; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], +) where {T <: Dict} + # + (length(Al) != length(Bl)) && return false + for (id, val) in Al + (Symbol(id) in skip) && continue + !compareAll(val, Bl[id]; show = show, skip = skip) && return false + end + return true end -function compareAll(Al::T1, Bl::T2; show::Bool=true, skip::Vector{Symbol}=Symbol[]) where {T1,T2} - @debug "Comparing types $T1, $T2" - if T1 != T2 - @warn "Types are different" T1 T2 - end - # @debug " Al = $Al" - # @debug " Bl = $Bl" - !compareFields(Al, Bl, show=show, skip=skip) && return false - for field in fieldnames(T1) - field in skip && continue - @debug(" Checking field: $field") - (!isdefined(Al, field) && !isdefined(Al, field)) && return true - !isdefined(Al, field) && return false - !isdefined(Bl, field) && return false - Ad = eval(:($Al.$field)) - Bd = eval(:($Bl.$field)) - !compareAll(Ad, Bd, show=show, skip=skip) && return false - end - return true +function compareAll( + Al::T1, + Bl::T2; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], +) where {T1, T2} + @debug "Comparing types $T1, $T2" + if T1 != T2 + @warn "Types are different" T1 T2 + end + # @debug " Al = $Al" + # @debug " Bl = $Bl" + !compareFields(Al, Bl; show = show, skip = skip) && return false + for field in fieldnames(T1) + field in skip && continue + @debug(" Checking field: $field") + (!isdefined(Al, field) && !isdefined(Al, field)) && return true + !isdefined(Al, field) && return false + !isdefined(Bl, field) && return false + Ad = eval(:($Al.$field)) + Bd = eval(:($Bl.$field)) + !compareAll(Ad, Bd; show = show, skip = skip) && return false + end + return true end #Compare VariableNodeData -function compare( - a::VariableNodeData, - b::VariableNodeData -) - a.val != b.val && @debug("val is not equal")==nothing && return false - a.bw != b.bw && @debug("bw is not equal")==nothing && return false - a.BayesNetOutVertIDs != b.BayesNetOutVertIDs && @debug("BayesNetOutVertIDs is not equal")==nothing && return false - a.dimIDs != b.dimIDs && @debug("dimIDs is not equal")==nothing && return false - a.dims != b.dims && @debug("dims is not equal")==nothing && return false - a.eliminated != b.eliminated && @debug("eliminated is not equal")==nothing && return false - a.BayesNetVertID != b.BayesNetVertID && @debug("BayesNetVertID is not equal")==nothing && return false - a.separator != b.separator && @debug("separator is not equal")==nothing && return false - a.initialized != b.initialized && @debug("initialized is not equal")==nothing && return false - !isapprox(a.infoPerCoord, b.infoPerCoord, atol=1e-13) && @debug("infoPerCoord is not equal")==nothing && return false - a.ismargin != b.ismargin && @debug("ismargin is not equal")==nothing && return false - a.dontmargin != b.dontmargin && @debug("dontmargin is not equal")==nothing && return false - a.solveInProgress != b.solveInProgress && @debug("solveInProgress is not equal")==nothing && return false - getVariableType(a) != getVariableType(b) && @debug("variableType is not equal")==nothing && return false - return true +function compare(a::VariableNodeData, b::VariableNodeData) + a.val != b.val && @debug("val is not equal") == nothing && return false + a.bw != b.bw && @debug("bw is not equal") == nothing && return false + a.BayesNetOutVertIDs != b.BayesNetOutVertIDs && + @debug("BayesNetOutVertIDs is not equal") == nothing && + return false + a.dimIDs != b.dimIDs && @debug("dimIDs is not equal") == nothing && return false + a.dims != b.dims && @debug("dims is not equal") == nothing && return false + a.eliminated != b.eliminated && + @debug("eliminated is not equal") == nothing && + return false + a.BayesNetVertID != b.BayesNetVertID && + @debug("BayesNetVertID is not equal") == nothing && + return false + a.separator != b.separator && + @debug("separator is not equal") == nothing && + return false + a.initialized != b.initialized && + @debug("initialized is not equal") == nothing && + return false + !isapprox(a.infoPerCoord, b.infoPerCoord; atol = 1e-13) && + @debug("infoPerCoord is not equal") == nothing && + return false + a.ismargin != b.ismargin && @debug("ismargin is not equal") == nothing && return false + a.dontmargin != b.dontmargin && + @debug("dontmargin is not equal") == nothing && + return false + a.solveInProgress != b.solveInProgress && + @debug("solveInProgress is not equal") == nothing && + return false + getVariableType(a) != getVariableType(b) && + @debug("variableType is not equal") == nothing && + return false + return true end """ @@ -191,60 +236,66 @@ end Compare that all fields are the same in a `::FactorGraph` variable. """ function compareVariable( - A::DFGVariable, - B::DFGVariable; - skip::Vector{Symbol}=Symbol[], - show::Bool=true, - skipsamples::Bool=true + A::DFGVariable, + B::DFGVariable; + skip::Vector{Symbol} = Symbol[], + show::Bool = true, + skipsamples::Bool = true, ) - # - skiplist = union([:attributes;:solverDataDict;:createdTimestamp;:lastUpdatedTimestamp],skip) - TP = compareAll(A, B, skip=skiplist, show=show) - varskiplist = skipsamples ? [:val; :bw] : Symbol[] - skiplist = union([:variableType;],varskiplist) - union!(skiplist, skip) - TP = TP && compareAll(A.solverDataDict, B.solverDataDict, skip=skiplist, show=show) - - Ad = getSolverData(A) - Bd = getSolverData(B) - - # TP = TP && compareAll(A.attributes, B.attributes, skip=[:variableType;], show=show) - varskiplist = union(varskiplist, [:variableType]) - union!(varskiplist, skip) - TP = TP && compareAll(Ad, Bd, skip=varskiplist, show=show) - TP = TP && typeof(getVariableType(Ad)) == typeof(getVariableType(Bd)) - TP = TP && compareAll(getVariableType(Ad), getVariableType(Bd), show=show, skip=skip) - return TP::Bool + # + skiplist = union( + [:attributes; :solverDataDict; :createdTimestamp; :lastUpdatedTimestamp], + skip, + ) + TP = compareAll(A, B; skip = skiplist, show = show) + varskiplist = skipsamples ? [:val; :bw] : Symbol[] + skiplist = union([:variableType;], varskiplist) + union!(skiplist, skip) + TP = TP && compareAll(A.solverDataDict, B.solverDataDict; skip = skiplist, show = show) + + Ad = getSolverData(A) + Bd = getSolverData(B) + + # TP = TP && compareAll(A.attributes, B.attributes, skip=[:variableType;], show=show) + varskiplist = union(varskiplist, [:variableType]) + union!(varskiplist, skip) + TP = TP && compareAll(Ad, Bd; skip = varskiplist, show = show) + TP = TP && typeof(getVariableType(Ad)) == typeof(getVariableType(Bd)) + TP = + TP && compareAll(getVariableType(Ad), getVariableType(Bd); show = show, skip = skip) + return TP::Bool end function compareAllSpecial( - A::T1, - B::T2; - skip=Symbol[], - show::Bool=true + A::T1, + B::T2; + skip = Symbol[], + show::Bool = true, ) where {T1 <: GenericFunctionNodeData, T2 <: GenericFunctionNodeData} - if T1 != T2 - @warn "compareAllSpecial is comparing different types" T1 T2 - # return false - # else - end - return compareAll(A, B, skip=skip, show=show) + if T1 != T2 + @warn "compareAllSpecial is comparing different types" T1 T2 + # return false + # else + end + return compareAll(A, B; skip = skip, show = show) end - # Compare FunctionNodeData -function compare(a::GenericFunctionNodeData{T1},b::GenericFunctionNodeData{T2}) where {T1, T2} - # TODO -- beef up this comparison to include the gwp - TP = true - TP = TP && a.eliminated == b.eliminated - TP = TP && a.potentialused == b.potentialused - TP = TP && a.edgeIDs == b.edgeIDs - # TP = TP && typeof(a.fnc) == typeof(b.fnc) - TP = TP && (a.multihypo - b.multihypo |> norm < 1e-10) - TP = TP && a.certainhypo == b.certainhypo - TP = TP && a.nullhypo == b.nullhypo - TP = TP && a.solveInProgress == b.solveInProgress - return TP +function compare( + a::GenericFunctionNodeData{T1}, + b::GenericFunctionNodeData{T2}, +) where {T1, T2} + # TODO -- beef up this comparison to include the gwp + TP = true + TP = TP && a.eliminated == b.eliminated + TP = TP && a.potentialused == b.potentialused + TP = TP && a.edgeIDs == b.edgeIDs + # TP = TP && typeof(a.fnc) == typeof(b.fnc) + TP = TP && (a.multihypo - b.multihypo |> norm < 1e-10) + TP = TP && a.certainhypo == b.certainhypo + TP = TP && a.nullhypo == b.nullhypo + TP = TP && a.solveInProgress == b.solveInProgress + return TP end """ @@ -256,45 +307,93 @@ DevNotes - TODO `getSolverData(A).fnc.varValsAll / varidx` are only defined downstream, so should should this function not be in IIF? """ function compareFactor( - A::DFGFactor, - B::DFGFactor; - show::Bool=true, - skip::Vector{Symbol}=Symbol[], - skipsamples::Bool=true, - skipcompute::Bool=true + A::DFGFactor, + B::DFGFactor; + show::Bool = true, + skip::Vector{Symbol} = Symbol[], + skipsamples::Bool = true, + skipcompute::Bool = true, ) - # - skip_ = union([:attributes;:solverData;:_variableOrderSymbols;:_gradients],skip) - TP = compareAll(A, B, skip=skip_, show=show) - @debug "compareFactor 1/5" TP - TP = TP & compareAllSpecial(getSolverData(A), getSolverData(B), skip=union([:fnc;:_gradients], skip), show=show) - @debug "compareFactor 2/5" TP - if !TP || :fnc in skip + # + skip_ = union([:attributes; :solverData; :_variableOrderSymbols; :_gradients], skip) + TP = compareAll(A, B; skip = skip_, show = show) + @debug "compareFactor 1/5" TP + TP = + TP & compareAllSpecial( + getSolverData(A), + getSolverData(B); + skip = union([:fnc; :_gradients], skip), + show = show, + ) + @debug "compareFactor 2/5" TP + if !TP || :fnc in skip + return TP + end + TP = + TP & compareAllSpecial( + getSolverData(A).fnc, + getSolverData(B).fnc; + skip = union( + [ + :cpt + :measurement + :params + :varValsAll + :varidx + :threadmodel + :_gradients + ], + skip, + ), + show = show, + ) + @debug "compareFactor 3/5" TP + if !(:measurement in skip) + TP = + TP & ( + skipsamples || compareAll( + getSolverData(A).fnc.measurement, + getSolverData(B).fnc.measurement; + show = show, + skip = skip, + ) + ) + end + @debug "compareFactor 4/5" TP + if !(:varValsAll in skip) && hasfield(typeof(getSolverData(A).fnc), :varValsAll) + TP = + TP & ( + skipcompute || compareAll( + getSolverData(A).fnc.varValsAll, + getSolverData(B).fnc.varValsAll; + show = show, + skip = skip, + ) + ) + end + @debug "compareFactor 5/5" TP + if !(:varidx in skip) && + hasfield(typeof(getSolverData(A).fnc), :varidx) && + getSolverData(A).fnc.varidx isa Base.RefValue + TP = + TP & ( + skipcompute || compareAll( + getSolverData(A).fnc.varidx[], + getSolverData(B).fnc.varidx[]; + show = show, + skip = skip, + ) + ) + end + return TP - end - TP = TP & compareAllSpecial(getSolverData(A).fnc, getSolverData(B).fnc, skip=union([:cpt;:measurement;:params;:varValsAll;:varidx;:threadmodel;:_gradients], skip), show=show) - @debug "compareFactor 3/5" TP - if !(:measurement in skip) - TP = TP & (skipsamples || compareAll(getSolverData(A).fnc.measurement, getSolverData(B).fnc.measurement, show=show, skip=skip)) - end - @debug "compareFactor 4/5" TP - if !(:varValsAll in skip) && hasfield(typeof(getSolverData(A).fnc), :varValsAll) - TP = TP & (skipcompute || compareAll(getSolverData(A).fnc.varValsAll, getSolverData(B).fnc.varValsAll, show=show, skip=skip)) - end - @debug "compareFactor 5/5" TP - if !(:varidx in skip) && hasfield(typeof(getSolverData(A).fnc), :varidx) && getSolverData(A).fnc.varidx isa Base.RefValue - TP = TP & (skipcompute || compareAll(getSolverData(A).fnc.varidx[], getSolverData(B).fnc.varidx[], show=show, skip=skip)) - end - - return TP end - # Ad = getSolverData(A) - # Bd = getSolverData(B) - # TP = compareAll(A, B, skip=[:attributes;:data], show=show) - # TP &= compareAll(A.attributes, B.attributes, skip=[:data;], show=show) - # TP &= compareAllSpecial(getSolverData(A).fnc, getSolverData(B).fnc, skip=[:cpt;], show=show) - # TP &= compareAll(getSolverData(A).fnc.cpt, getSolverData(B).fnc.cpt, show=show) - +# Ad = getSolverData(A) +# Bd = getSolverData(B) +# TP = compareAll(A, B, skip=[:attributes;:data], show=show) +# TP &= compareAll(A.attributes, B.attributes, skip=[:data;], show=show) +# TP &= compareAllSpecial(getSolverData(A).fnc, getSolverData(B).fnc, skip=[:cpt;], show=show) +# TP &= compareAll(getSolverData(A).fnc.cpt, getSolverData(B).fnc.cpt, show=show) """ $SIGNATURES @@ -309,34 +408,40 @@ Related: `compareFactorGraphs`, `compareSimilarVariables`, `compareVariable`, `ls` """ function compareAllVariables( - fgA::AbstractDFG, - fgB::AbstractDFG; - skip::Vector{Symbol}=Symbol[], - show::Bool=true, - skipsamples::Bool=true + fgA::AbstractDFG, + fgB::AbstractDFG; + skip::Vector{Symbol} = Symbol[], + show::Bool = true, + skipsamples::Bool = true, ) - # get all the variables in A or B - xlA = listVariables(fgA) - xlB = listVariables(fgB) - vars = union(xlA, xlB) - - # compare all variables exist in both A and B - TP = length(xlA) == length(xlB) - for xla in xlA - TP &= xla in xlB - end - # slightly redundant, but repeating opposite direction anyway - for xlb in xlB - TP &= xlb in xlA - end - - # compare each variable is the same in both A and B - for var in vars - TP = TP && compareVariable(getVariable(fgA, var), getVariable(fgB, var), skipsamples=skipsamples, skip=skip) - end - - # return comparison result - return TP::Bool + # get all the variables in A or B + xlA = listVariables(fgA) + xlB = listVariables(fgB) + vars = union(xlA, xlB) + + # compare all variables exist in both A and B + TP = length(xlA) == length(xlB) + for xla in xlA + TP &= xla in xlB + end + # slightly redundant, but repeating opposite direction anyway + for xlb in xlB + TP &= xlb in xlA + end + + # compare each variable is the same in both A and B + for var in vars + TP = + TP && compareVariable( + getVariable(fgA, var), + getVariable(fgB, var); + skipsamples = skipsamples, + skip = skip, + ) + end + + # return comparison result + return TP::Bool end """ @@ -352,28 +457,33 @@ Related: `compareFactorGraphs`, `compareAllVariables`, `compareSimilarFactors`, `compareVariable`, `ls`. """ function compareSimilarVariables( - fgA::AbstractDFG, - fgB::AbstractDFG; - skip::Vector{Symbol}=Symbol[], - show::Bool=true, - skipsamples::Bool=true + fgA::AbstractDFG, + fgB::AbstractDFG; + skip::Vector{Symbol} = Symbol[], + show::Bool = true, + skipsamples::Bool = true, ) - # - xlA = listVariables(fgA) - xlB = listVariables(fgB) - - # find common variables - xlAB = intersect(xlA, xlB) - TP = length(xlAB) > 0 - - # compare the common set - for var in xlAB - @info var - TP &= compareVariable(getVariable(fgA, var), getVariable(fgB, var), skipsamples=skipsamples, skip=skip) - end - - # return comparison result - return TP::Bool + # + xlA = listVariables(fgA) + xlB = listVariables(fgB) + + # find common variables + xlAB = intersect(xlA, xlB) + TP = length(xlAB) > 0 + + # compare the common set + for var in xlAB + @info var + TP &= compareVariable( + getVariable(fgA, var), + getVariable(fgB, var); + skipsamples = skipsamples, + skip = skip, + ) + end + + # return comparison result + return TP::Bool end """ @@ -385,30 +495,37 @@ Related: `compareFactorGraphs`, `compareSimilarVariables`, `compareAllVariables`, `ls`. """ -function compareSimilarFactors( - fgA::AbstractDFG, - fgB::AbstractDFG; - skipsamples::Bool=true, - skipcompute::Bool=true, - skip::AbstractVector{Symbol}=Symbol[], - show::Bool=true +function compareSimilarFactors( + fgA::AbstractDFG, + fgB::AbstractDFG; + skipsamples::Bool = true, + skipcompute::Bool = true, + skip::AbstractVector{Symbol} = Symbol[], + show::Bool = true, ) - # - xlA = listFactors(fgA) - xlB = listFactors(fgB) - - # find common variables - xlAB = intersect(xlA, xlB) - TP = length(xlAB) > 0 - - # compare the common set - for var in xlAB - TP = TP && compareFactor( getFactor(fgA, var), getFactor(fgB, var), - skipsamples=skipsamples, skipcompute=skipcompute, skip=skip, show=show) - end - - # return comparison result - return TP + # + xlA = listFactors(fgA) + xlB = listFactors(fgB) + + # find common variables + xlAB = intersect(xlA, xlB) + TP = length(xlAB) > 0 + + # compare the common set + for var in xlAB + TP = + TP && compareFactor( + getFactor(fgA, var), + getFactor(fgB, var); + skipsamples = skipsamples, + skipcompute = skipcompute, + skip = skip, + show = show, + ) + end + + # return comparison result + return TP end """ @@ -426,23 +543,49 @@ Related: `compareSimilarVariables`, `compareSimilarFactors`, `compareAllVariables`, `ls`. """ -function compareFactorGraphs( - fgA::AbstractDFG, - fgB::AbstractDFG; - skipsamples::Bool=true, - skipcompute::Bool=true, - skip::Vector{Symbol}=Symbol[], - show::Bool=true +function compareFactorGraphs( + fgA::AbstractDFG, + fgB::AbstractDFG; + skipsamples::Bool = true, + skipcompute::Bool = true, + skip::Vector{Symbol} = Symbol[], + show::Bool = true, ) - # - skiplist = Symbol[:g;:bn;:IDs;:fIDs;:id;:nodeIDs;:factorIDs;:fifo;:solverParams; :factorOperationalMemoryType] - skiplist = union(skiplist, skip) - @warn "compareFactorGraphs will skip comparisons on: $skiplist" + # + skiplist = Symbol[ + :g + :bn + :IDs + :fIDs + :id + :nodeIDs + :factorIDs + :fifo + :solverParams + :factorOperationalMemoryType + ] + skiplist = union(skiplist, skip) + @warn "compareFactorGraphs will skip comparisons on: $skiplist" + + TP = compareAll(fgA, fgB; skip = skiplist, show = show) + TP = + TP && compareSimilarVariables( + fgA, + fgB; + skipsamples = skipsamples, + show = show, + skip = skiplist, + ) + TP = + TP && compareSimilarFactors( + fgA, + fgB; + skipsamples = skipsamples, + skipcompute = skipcompute, + show = show, + skip = skiplist, + ) + TP = TP && compareAll(fgA.solverParams, fgB.solverParams; skip = skiplist) - TP = compareAll(fgA, fgB, skip=skiplist, show=show) - TP = TP && compareSimilarVariables(fgA, fgB, skipsamples=skipsamples, show=show, skip=skiplist ) - TP = TP && compareSimilarFactors(fgA, fgB, skipsamples=skipsamples, skipcompute=skipcompute, show=show, skip=skiplist ) - TP = TP && compareAll(fgA.solverParams, fgB.solverParams, skip=skiplist) - - return TP + return TP end diff --git a/src/services/CustomPrinting.jl b/src/services/CustomPrinting.jl index f5938ec5..5901b720 100644 --- a/src/services/CustomPrinting.jl +++ b/src/services/CustomPrinting.jl @@ -4,21 +4,23 @@ printVariable(vert::DFGVariable; kwargs...) = printVariable(stdout::IO, vert; kwargs...) -function printVariable( io::IO, vert::DFGVariable; - short::Bool=false, - compact::Bool=true, - limit::Bool=true, - skipfields::Vector{Symbol}=Symbol[], - solveKeys::Vector{Symbol}=Symbol[]) - - ioc = IOContext(io, :limit=>limit, :compact=>compact) +function printVariable( + io::IO, + vert::DFGVariable; + short::Bool = false, + compact::Bool = true, + limit::Bool = true, + skipfields::Vector{Symbol} = Symbol[], + solveKeys::Vector{Symbol} = Symbol[], +) + ioc = IOContext(io, :limit => limit, :compact => compact) if short # opmemt = (getVariableType(vert) |> typeof ).name vari = getVariableType(vert) |> typeof - printstyled(ioc, typeof(vert).name.name, "{",bold=true) - printstyled(ioc, vari.name.name, bold=true, color=:blue) - printstyled(ioc,"...}", bold=true) + printstyled(ioc, typeof(vert).name.name, "{"; bold = true) + printstyled(ioc, vari.name.name; bold = true, color = :blue) + printstyled(ioc, "...}"; bold = true) println(ioc, "") # printstyled(ioc, summary(vert),"\n", bold=true) @@ -28,43 +30,48 @@ function printVariable( io::IO, vert::DFGVariable; println(ioc, "") catch e end - vnd = haskey(vert.solverDataDict, :default) ? getSolverData(vert, :default) : nothing + vnd = + haskey(vert.solverDataDict, :default) ? getSolverData(vert, :default) : nothing println(ioc, " ID: ", vert.id) println(ioc, " timestamp: ", vert.timestamp) println(ioc, " nstime: ", vert.nstime) - print(ioc, " label: ") - printstyled(ioc, vert.label, bold=true) + print(ioc, " label: ") + printstyled(ioc, vert.label; bold = true) println(ioc) println(ioc, " solvable: ", getSolvable(vert)) println(ioc, " tags: ", getTags(vert)) solk = listSolveKeys(vert) |> collect lsolk = length(solk) - smsk = lsolk > 0 ? (rand(1:lsolk,100) |> unique)[1:minimum([4,lsolk])] : nothing + smsk = lsolk > 0 ? (rand(1:lsolk, 100) |> unique)[1:minimum([4, lsolk])] : nothing # list the marginalization status - ismarg = solk .|> x->isMarginalized(vert, x) - isinit = solk .|> x->isInitialized(vert, x) - printstyled(ioc, " # VND solveKeys= ($(lsolk))", bold=true) + ismarg = solk .|> x -> isMarginalized(vert, x) + isinit = solk .|> x -> isInitialized(vert, x) + printstyled(ioc, " # VND solveKeys= ($(lsolk))"; bold = true) println(ioc, "") - printstyled(ioc, " # initialized: ", bold=true) - println(ioc, "(true=", sum(isinit), ",false=", length(isinit) - sum(isinit), ")" ) - printstyled(ioc, " # marginalized: ", bold=true) - println(ioc, "(true=", sum(ismarg), ",false=", length(ismarg) - sum(ismarg), ")" ) - + printstyled(ioc, " # initialized: "; bold = true) + println(ioc, "(true=", sum(isinit), ",false=", length(isinit) - sum(isinit), ")") + printstyled(ioc, " # marginalized: "; bold = true) + println(ioc, "(true=", sum(ismarg), ",false=", length(ismarg) - sum(ismarg), ")") + if vnd !== nothing println(ioc, " :default <-- VariableNodeData") println(ioc, " initialized: ", isInitialized(vert, :default)) println(ioc, " marginalized: ", isMarginalized(vert, :default)) println(ioc, " size bel. samples: ", size(vnd.val)) print(ioc, " kde bandwidths: ") - 0 < length(vnd.bw) ? println(ioc, round.(vnd.bw[1], digits=4)) : nothing - printstyled(ioc, " VNDs: ",bold=true) - println(ioc, solk[smsk], 4limit, :compact=>compact) +function printFactor( + io::IO, + vert::DFGFactor; + short::Bool = false, + compact::Bool = true, + limit::Bool = true, + skipfields::Vector{Symbol} = Symbol[], +) + ioc = IOContext(io, :limit => limit, :compact => compact) if short opmemt = (getSolverData(vert).fnc |> typeof).name.name fct = getFactorType(vert) fctt = fct |> typeof - printstyled(ioc, typeof(vert).name.name, "{",opmemt,"{",bold=true) - printstyled(ioc, fctt.name.name,bold=true, color=:blue) - printstyled(ioc, "...}}", bold=true) + printstyled(ioc, typeof(vert).name.name, "{", opmemt, "{"; bold = true) + printstyled(ioc, fctt.name.name; bold = true, color = :blue) + printstyled(ioc, "...}}"; bold = true) println(ioc) println(ioc, " ID: ", vert.id) println(ioc, " timestamp: ", vert.timestamp) println(ioc, " nstime: ", vert.nstime) - print(ioc, " label: ") - printstyled(ioc, vert.label, bold=true) + print(ioc, " label: ") + printstyled(ioc, vert.label; bold = true) println(ioc) println(ioc, " solvable: ", vert.solvable) println(ioc, " VariableOrder: ", vert._variableOrderSymbols) println(ioc, " multihypo: ", getSolverData(vert).multihypo) # FIXME #477 println(ioc, " nullhypo: ", getSolverData(vert).nullhypo) println(ioc, " tags: ", vert.tags) - printstyled(ioc, " FactorType: ", bold=true, color=:blue) + printstyled(ioc, " FactorType: "; bold = true, color = :blue) println(ioc, fctt) # show(ioc, fctt) for f in setdiff(fieldnames(fctt), skipfields) - printstyled(ioc, f,":", color=:magenta) + printstyled(ioc, f, ":"; color = :magenta) println(ioc) show(ioc, getproperty(fct, f)) println(ioc) end else - - printstyled(ioc, summary(vert), bold=true, color=:blue) + printstyled(ioc, summary(vert); bold = true, color = :blue) println(ioc) :solver in skipfields && push!(skipfields, :solverData) @@ -150,22 +157,23 @@ function printFactor( io::IO, vert::DFGFactor; nf = nfields(vert) for f in fields - printstyled(ioc, f,":", color=:blue) + printstyled(ioc, f, ":"; color = :blue) println(ioc) show(ioc, getproperty(vert, f)) println(ioc) end end - nothing + return nothing end - """ $SIGNATURES Display and return to console the user factor identified by tag name. """ -printFactor(dfg::AbstractDFG, sym::Symbol; kwargs...) = printFactor(getFactor(dfg, sym); kwargs...) +function printFactor(dfg::AbstractDFG, sym::Symbol; kwargs...) + return printFactor(getFactor(dfg, sym); kwargs...) +end """ $SIGNATURES @@ -175,18 +183,29 @@ Display the content of `VariableNodeData` to console for a given factor graph an Dev Notes - TODO split as two show macros between AMP and DFG """ -printVariable(dfg::AbstractDFG, sym::Symbol; kwargs...) = printVariable(getVariable(dfg, sym); kwargs...) - -printNode(dfg::AbstractDFG, sym::Symbol; kwargs...) = isVariable(dfg,sym) ? printVariable(dfg, sym; kwargs...) : printFactor(dfg, sym; kwargs...) +function printVariable(dfg::AbstractDFG, sym::Symbol; kwargs...) + return printVariable(getVariable(dfg, sym); kwargs...) +end +function printNode(dfg::AbstractDFG, sym::Symbol; kwargs...) + if isVariable(dfg, sym) + return printVariable(dfg, sym; kwargs...) + else + return printFactor(dfg, sym; kwargs...) + end +end ##============================================================================== ## Overloading show ##============================================================================== # Base.show_default(io, v) -Base.show(io::IO, ::MIME"text/plain", v::DFGVariable) = printVariable(io, v, short=true, limit=false) +function Base.show(io::IO, ::MIME"text/plain", v::DFGVariable) + return printVariable(io, v; short = true, limit = false) +end -Base.show(io::IO, ::MIME"text/plain", f::DFGFactor) = printFactor(io, f, short=true, limit=false) +function Base.show(io::IO, ::MIME"text/plain", f::DFGFactor) + return printFactor(io, f; short = true, limit = false) +end function Base.show(io::IO, dfg::AbstractDFG) summary(io, dfg) @@ -195,13 +214,19 @@ function Base.show(io::IO, dfg::AbstractDFG) println(io, " SessionLabel: ", dfg.sessionLabel) println(io, " Description: ", dfg.description) println(io, " Nr variables: ", length(ls(dfg))) - println(io, " Nr factors: ",length(lsf(dfg))) + println(io, " Nr factors: ", length(lsf(dfg))) println(io, " User Data: ", keys(getUserData(dfg))) println(io, " Robot Data: ", keys(getRobotData(dfg))) - println(io, " Session Data: ", keys(getSessionData(dfg))) + return println(io, " Session Data: ", keys(getSessionData(dfg))) end Base.show(io::IO, ::MIME"text/plain", dfg::AbstractDFG) = show(io, dfg) #default for Atom/Juno -Base.show(io::IO, ::MIME"application/prs.juno.inline", x::Union{AbstractDFG, DFGVariable, DFGFactor}) = show(io, x) +function Base.show( + io::IO, + ::MIME"application/prs.juno.inline", + x::Union{AbstractDFG, DFGVariable, DFGFactor}, +) + return show(io, x) +end diff --git a/src/services/DFGFactor.jl b/src/services/DFGFactor.jl index 9bbe667d..7b4d010f 100644 --- a/src/services/DFGFactor.jl +++ b/src/services/DFGFactor.jl @@ -47,8 +47,9 @@ using RoME @assert RoME.PriorPose2 == DFG._getPriorType(Pose2) ``` """ -_getPriorType(_type::Type{<:InferenceVariable}) = getfield(_type.name.module, Symbol(:Prior, _type.name.name)) - +function _getPriorType(_type::Type{<:InferenceVariable}) + return getfield(_type.name.module, Symbol(:Prior, _type.name.name)) +end ##============================================================================== ## Factors @@ -81,13 +82,33 @@ _getPriorType(_type::Type{<:InferenceVariable}) = getfield(_type.name.module, Sy ## COMMON # getTimestamp -setTimestamp(f::AbstractDFGFactor, ts::DateTime, timezone=localzone()) = setTimestamp(f, ZonedDateTime(ts, timezone)) -setTimestamp(f::DFGFactor, ts::ZonedDateTime) = DFGFactor(f.label, ts, f.nstime, f.tags, f.solverData, f.solvable, getfield(f,:_variableOrderSymbols); id=f.id) -setTimestamp(f::DFGFactorSummary, ts::ZonedDateTime) = DFGFactorSummary(f.id, f.label, f.tags, f._variableOrderSymbols, ts) -setTimestamp(f::DFGFactorSummary, ts::DateTime) = DFGFactorSummary(f, ZonedDateTime(ts, localzone())) +function setTimestamp(f::AbstractDFGFactor, ts::DateTime, timezone = localzone()) + return setTimestamp(f, ZonedDateTime(ts, timezone)) +end +function setTimestamp(f::DFGFactor, ts::ZonedDateTime) + return DFGFactor( + f.label, + ts, + f.nstime, + f.tags, + f.solverData, + f.solvable, + getfield(f, :_variableOrderSymbols); + id = f.id, + ) +end +function setTimestamp(f::DFGFactorSummary, ts::ZonedDateTime) + return DFGFactorSummary(f.id, f.label, f.tags, f._variableOrderSymbols, ts) +end +function setTimestamp(f::DFGFactorSummary, ts::DateTime) + return DFGFactorSummary(f, ZonedDateTime(ts, localzone())) +end function setTimestamp(v::PackedFactor, timestamp::ZonedDateTime) - return PackedFactor(;(key => getproperty(v, key) for key in fieldnames(PackedFactor))..., timestamp) + return PackedFactor(; + (key => getproperty(v, key) for key in fieldnames(PackedFactor))..., + timestamp, + ) end ##------------------------------------------------------------------------------ @@ -105,7 +126,6 @@ end ## COMMON - ##------------------------------------------------------------------------------ ## _variableOrderSymbols ##------------------------------------------------------------------------------ @@ -130,34 +150,32 @@ getVariableOrder(dfg::AbstractDFG, fct::Symbol) = getVariableOrder(getFactor(dfg Retrieve solver data structure stored in a factor. """ -function getSolverData(f::F) where F <: DFGFactor - return f.solverData +function getSolverData(f::F) where {F <: DFGFactor} + return f.solverData end setSolverData!(f::DFGFactor, data::GenericFunctionNodeData) = f.solverData = data - ##------------------------------------------------------------------------------ ## utility ##------------------------------------------------------------------------------ - """ $SIGNATURES Return `::Bool` on whether given factor `fc::Symbol` is a prior in factor graph `dfg`. """ function isPrior(dfg::AbstractDFG, fc::Symbol) - fco = getFactor(dfg, fc) - isPrior(getFactorType(fco)) + fco = getFactor(dfg, fc) + return isPrior(getFactorType(fco)) end function isPrior(::AbstractPrior) - return true + return true end function isPrior(::AbstractRelative) - return false + return false end ##============================================================================== diff --git a/src/services/DFGVariable.jl b/src/services/DFGVariable.jl index f38faef4..0143ea8f 100644 --- a/src/services/DFGVariable.jl +++ b/src/services/DFGVariable.jl @@ -6,18 +6,24 @@ ##============================================================================== "$(SIGNATURES)" getPPEMax(est::AbstractPointParametricEst) = est.max -getPPEMax(fg::AbstractDFG, varlabel::Symbol, solveKey::Symbol=:default) = - getPPE(fg, varlabel, solveKey) |> getPPEMax +function getPPEMax(fg::AbstractDFG, varlabel::Symbol, solveKey::Symbol = :default) + return getPPE(fg, varlabel, solveKey) |> getPPEMax +end "$(SIGNATURES)" getPPEMean(est::AbstractPointParametricEst) = est.mean -getPPEMean(fg::AbstractDFG, varlabel::Symbol, solveKey::Symbol=:default) = - getPPE(fg, varlabel, solveKey) |> getPPEMean - +function getPPEMean(fg::AbstractDFG, varlabel::Symbol, solveKey::Symbol = :default) + return getPPE(fg, varlabel, solveKey) |> getPPEMean +end + "$(SIGNATURES)" getPPESuggested(est::AbstractPointParametricEst) = est.suggested -getPPESuggested(var::DFGVariable, solveKey::Symbol=:default) = getPPE(var, solveKey) |> getPPESuggested -getPPESuggested(dfg::AbstractDFG, varlabel::Symbol, solveKey::Symbol=:default) = getPPE(getVariable(dfg, varlabel), solveKey) |> getPPESuggested +function getPPESuggested(var::DFGVariable, solveKey::Symbol = :default) + return getPPE(var, solveKey) |> getPPESuggested +end +function getPPESuggested(dfg::AbstractDFG, varlabel::Symbol, solveKey::Symbol = :default) + return getPPE(getVariable(dfg, varlabel), solveKey) |> getPPESuggested +end "$(SIGNATURES)" getLastUpdatedTimestamp(est::AbstractPointParametricEst) = est.lastUpdatedTimestamp @@ -48,18 +54,15 @@ Related getVariableType """ -getVariableType(::DFGVariable{T}) where T = T() - -getVariableType(::VariableNodeData{T}) where T = T() - +getVariableType(::DFGVariable{T}) where {T} = T() +getVariableType(::VariableNodeData{T}) where {T} = T() # TODO: Confirm that we can switch this out, instead of retrieving the complete variable. # getVariableType(v::DFGVariable) = getVariableType(getSolverData(v)) # Optimized in CGDFG -getVariableType(dfg::AbstractDFG, lbl::Symbol) = getVariableType(getVariable(dfg,lbl)) - +getVariableType(dfg::AbstractDFG, lbl::Symbol) = getVariableType(getVariable(dfg, lbl)) ##------------------------------------------------------------------------------ ## InferenceVariable @@ -74,7 +77,6 @@ getVariableType(dfg::AbstractDFG, lbl::Symbol) = getVariableType(getVariable(dfg # getManifolds(::Type{<:T}) where {T <: ManifoldsBase.AbstractManifold} = convert(Tuple, T) # getManifolds(::T) where {T <: ManifoldsBase.AbstractManifold} = getManifolds(T) - """ @defVariable StructName manifolds<:ManifoldsBase.AbstractManifold @@ -88,24 +90,34 @@ DFG.@defVariable Pose2 SpecialEuclidean(2) ArrayPartition([0;0.0],[1 0; 0 1.0]) ``` """ macro defVariable(structname, manifold, point_identity) - return esc(quote - Base.@__doc__ struct $structname <: InferenceVariable end + return esc( + quote + Base.@__doc__ struct $structname <: InferenceVariable end - # user manifold must be a <:Manifold - @assert ($manifold isa AbstractManifold) "@defVariable of "*string($structname)*" requires that the "*string($manifold)*" be a subtype of `ManifoldsBase.AbstractManifold`" + # user manifold must be a <:Manifold + @assert ($manifold isa AbstractManifold) "@defVariable of " * + string($structname) * + " requires that the " * + string($manifold) * + " be a subtype of `ManifoldsBase.AbstractManifold`" - DFG.getManifold(::Type{$structname}) = $manifold + DFG.getManifold(::Type{$structname}) = $manifold - DFG.getPointType(::Type{$structname}) = typeof($point_identity) + DFG.getPointType(::Type{$structname}) = typeof($point_identity) - DFG.getPointIdentity(::Type{$structname}) = $point_identity + DFG.getPointIdentity(::Type{$structname}) = $point_identity - DFG.getVariableType(::typeof($manifold)) = $structname - - end) + DFG.getVariableType(::typeof($manifold)) = $structname + end, + ) end -Base.convert(::Type{<:AbstractManifold}, ::Union{<:T, Type{<:T}}) where {T <: InferenceVariable} = getManifold(T) +function Base.convert( + ::Type{<:AbstractManifold}, + ::Union{<:T, Type{<:T}}, +) where {T <: InferenceVariable} + return getManifold(T) +end """ $SIGNATURES @@ -145,7 +157,6 @@ Notes function getPointIdentity end getPointIdentity(::T) where {T <: InferenceVariable} = getPointIdentity(T) - """ $SIGNATURES @@ -160,11 +171,15 @@ Related [`getCoordinates`](@ref) """ -function getPoint(::Type{T}, v::AbstractVector, basis=ManifoldsBase.DefaultOrthogonalBasis()) where {T <: InferenceVariable} +function getPoint( + ::Type{T}, + v::AbstractVector, + basis = ManifoldsBase.DefaultOrthogonalBasis(), +) where {T <: InferenceVariable} M = getManifold(T) p0 = getPointIdentity(T) X = ManifoldsBase.get_vector(M, p0, v, basis) - ManifoldsBase.exp(M, p0, X) + return ManifoldsBase.exp(M, p0, X) end """ @@ -180,14 +195,17 @@ Related [`getPoint`](@ref) """ -function getCoordinates(::Type{T}, p, basis=ManifoldsBase.DefaultOrthogonalBasis()) where {T <: InferenceVariable} +function getCoordinates( + ::Type{T}, + p, + basis = ManifoldsBase.DefaultOrthogonalBasis(), +) where {T <: InferenceVariable} M = getManifold(T) p0 = getPointIdentity(T) X = ManifoldsBase.log(M, p0, p) - ManifoldsBase.get_coordinates(M, p0, X, basis) + return ManifoldsBase.get_coordinates(M, p0, X, basis) end - ##------------------------------------------------------------------------------ ## solvedCount ##------------------------------------------------------------------------------ @@ -202,9 +220,12 @@ Related isSolved, setSolvedCount! """ getSolvedCount(v::VariableNodeData) = v.solvedCount -getSolvedCount(v::VariableDataLevel2, solveKey::Symbol=:default) = getSolverData(v, solveKey) |> getSolvedCount -getSolvedCount(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol=:default) = getSolvedCount(getVariable(dfg, sym), solveKey) - +function getSolvedCount(v::VariableDataLevel2, solveKey::Symbol = :default) + return getSolverData(v, solveKey) |> getSolvedCount +end +function getSolvedCount(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol = :default) + return getSolvedCount(getVariable(dfg, sym), solveKey) +end """ $SIGNATURES @@ -216,9 +237,17 @@ Related getSolved, isSolved """ setSolvedCount!(v::VariableNodeData, val::Int) = v.solvedCount = val -setSolvedCount!(v::VariableDataLevel2, val::Int, solveKey::Symbol=:default) = setSolvedCount!(getSolverData(v, solveKey), val) -setSolvedCount!(dfg::AbstractDFG, sym::Symbol, val::Int, solveKey::Symbol=:default) = setSolvedCount!(getVariable(dfg, sym), val, solveKey) - +function setSolvedCount!(v::VariableDataLevel2, val::Int, solveKey::Symbol = :default) + return setSolvedCount!(getSolverData(v, solveKey), val) +end +function setSolvedCount!( + dfg::AbstractDFG, + sym::Symbol, + val::Int, + solveKey::Symbol = :default, +) + return setSolvedCount!(getVariable(dfg, sym), val, solveKey) +end """ $SIGNATURES @@ -230,8 +259,12 @@ Related getSolved, setSolved! """ isSolved(v::VariableNodeData) = 0 < v.solvedCount -isSolved(v::VariableDataLevel2, solveKey::Symbol=:default) = getSolverData(v, solveKey) |> isSolved -isSolved(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol=:default) = isSolved(getVariable(dfg, sym), solveKey) +function isSolved(v::VariableDataLevel2, solveKey::Symbol = :default) + return getSolverData(v, solveKey) |> isSolved +end +function isSolved(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol = :default) + return isSolved(getVariable(dfg, sym), solveKey) +end ##------------------------------------------------------------------------------ ## initialized @@ -244,22 +277,21 @@ Returns state of variable data `.initialized` flag. Notes: - used by both factor graph variable and Bayes tree clique logic. """ -function isInitialized(var::DFGVariable, key::Symbol=:default) - data = getSolverData(var, key) - if data === nothing - #TODO we still have a mixture of 2 error behaviours - # DF, not sure I follow the error here? - return false - else - return data.initialized - end +function isInitialized(var::DFGVariable, key::Symbol = :default) + data = getSolverData(var, key) + if data === nothing + #TODO we still have a mixture of 2 error behaviours + # DF, not sure I follow the error here? + return false + else + return data.initialized + end end -function isInitialized(dfg::AbstractDFG, label::Symbol, key::Symbol=:default) - return isInitialized(getVariable(dfg, label), key)::Bool +function isInitialized(dfg::AbstractDFG, label::Symbol, key::Symbol = :default) + return isInitialized(getVariable(dfg, label), key)::Bool end - """ $SIGNATURES @@ -268,8 +300,12 @@ Return `::Bool` on whether this variable has been marginalized. Notes: - VariableNodeData default `solveKey=:default` """ -isMarginalized(vert::DFGVariable, solveKey::Symbol=:default) = getSolverData(vert, solveKey).ismargin -isMarginalized(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol=:default) = isMarginalized(DFG.getVariable(dfg, sym), solveKey) +function isMarginalized(vert::DFGVariable, solveKey::Symbol = :default) + return getSolverData(vert, solveKey).ismargin +end +function isMarginalized(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol = :default) + return isMarginalized(DFG.getVariable(dfg, sym), solveKey) +end """ $SIGNATURES @@ -277,11 +313,19 @@ isMarginalized(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol=:default) = isMar Mark a variable as marginalized `true` or `false`. """ function setMarginalized!(vnd::VariableNodeData, val::Bool) - vnd.ismargin = val + return vnd.ismargin = val +end +function setMarginalized!(vari::DFGVariable, val::Bool, solveKey::Symbol = :default) + return setMarginalized!(getSolverData(vari, solveKey), val) +end +function setMarginalized!( + dfg::AbstractDFG, + sym::Symbol, + val::Bool, + solveKey::Symbol = :default, +) + return setMarginalized!(getVariable(dfg, sym), val, solveKey) end -setMarginalized!(vari::DFGVariable, val::Bool, solveKey::Symbol=:default) = setMarginalized!(getSolverData(vari, solveKey), val) -setMarginalized!(dfg::AbstractDFG, sym::Symbol, val::Bool, solveKey::Symbol=:default) = setMarginalized!(getVariable(dfg, sym), val, solveKey) - ##============================================================================== ## Variables @@ -326,24 +370,53 @@ Since the `timestamp` field is not mutable `setTimestamp` returns a new variable Use [`updateVariable!`](@ref) on the returened variable to update it in the factor graph if needed. Alternatively use [`setTimestamp!`](@ref). See issue #315. """ -function setTimestamp(v::DFGVariable, ts::ZonedDateTime; verbose::Bool=true) +function setTimestamp(v::DFGVariable, ts::ZonedDateTime; verbose::Bool = true) if verbose @warn "verbose=true: setTimestamp(::DFGVariable,...) creates a returns a new immutable DFGVariable object (and didn't change a distributed factor graph object), make sure you are using the right pointers: getVariable(...). See setTimestamp!(...) and note suggested use is at addVariable!(..., [timestamp=...]). See DFG #315 for explanation." end - return DFGVariable(v.id, v.label, ts, v.nstime, v.tags, v.ppeDict, v.solverDataDict, v.smallData, v.dataDict, Ref(v.solvable)) + return DFGVariable( + v.id, + v.label, + ts, + v.nstime, + v.tags, + v.ppeDict, + v.solverDataDict, + v.smallData, + v.dataDict, + Ref(v.solvable), + ) end -setTimestamp(v::AbstractDFGVariable, ts::DateTime, timezone=localzone(); verbose::Bool=true) = setTimestamp(v, ZonedDateTime(ts, timezone); verbose) +function setTimestamp( + v::AbstractDFGVariable, + ts::DateTime, + timezone = localzone(); + verbose::Bool = true, +) + return setTimestamp(v, ZonedDateTime(ts, timezone); verbose) +end -function setTimestamp(v::DFGVariableSummary, ts::ZonedDateTime; verbose::Bool=true) +function setTimestamp(v::DFGVariableSummary, ts::ZonedDateTime; verbose::Bool = true) if verbose @warn "verbose=true: setTimestamp(::DFGVariableSummary,...) creates and returns a new immutable DFGVariable object (and didn't change a distributed factor graph object), make sure you are using the right pointers: getVariable(...). See setTimestamp!(...) and note suggested use is at addVariable!(..., [timestamp=...]). See DFG #315 for explanation." end - return DFGVariableSummary(v.id, v.label, ts, v.tags, v.ppeDict, v.variableTypeName, v.dataDict) + return DFGVariableSummary( + v.id, + v.label, + ts, + v.tags, + v.ppeDict, + v.variableTypeName, + v.dataDict, + ) end -function setTimestamp(v::PackedVariable, timestamp::ZonedDateTime; verbose::Bool=true) - return PackedVariable(;(key => getproperty(v, key) for key in fieldnames(PackedVariable))..., timestamp) +function setTimestamp(v::PackedVariable, timestamp::ZonedDateTime; verbose::Bool = true) + return PackedVariable(; + (key => getproperty(v, key) for key in fieldnames(PackedVariable))..., + timestamp, + ) end ##------------------------------------------------------------------------------ @@ -368,7 +441,6 @@ Get the PPE dictionary for a variable. Recommended to use CRUD operations inste """ getPPEDict(v::VariableDataLevel1) = v.ppeDict - #TODO FIXME don't know if this should exist, should rather always update with fg object to simplify inmem vs cloud """ $SIGNATURES @@ -382,8 +454,8 @@ Related getMeanPPE, getMaxPPE, getKDEMean, getKDEFit, getPPEs, getVariablePPEs """ -function getPPE(vari::VariableDataLevel1, solveKey::Symbol=:default) - return getPPEDict(vari)[solveKey] +function getPPE(vari::VariableDataLevel1, solveKey::Symbol = :default) + return getPPEDict(vari)[solveKey] # return haskey(ppeDict, solveKey) ? ppeDict[solveKey] : nothing end @@ -416,16 +488,19 @@ Get solver data dictionary for a variable. Advised to use graph CRUD operations """ getSolverDataDict(v::DFGVariable) = v.solverDataDict - # TODO move to crud, don't know if this should exist, should rather always update with fg object to simplify inmem vs cloud """ $SIGNATURES Retrieve solver data structure stored in a variable. """ -function getSolverData(v::DFGVariable, key::Symbol=:default) +function getSolverData(v::DFGVariable, key::Symbol = :default) #TODO this does not fit in with some of the other error behaviour. but its used so added @error - vnd = haskey(getSolverDataDict(v), key) ? getSolverDataDict(v)[key] : (@error "Variable $(getLabel(v)) does not have solver data $(key)"; nothing) + vnd = if haskey(getSolverDataDict(v), key) + getSolverDataDict(v)[key] + else + (@error "Variable $(getLabel(v)) does not have solver data $(key)"; nothing) + end return vnd end @@ -434,9 +509,9 @@ end $SIGNATURES Set solver data structure stored in a variable. """ -function setSolverData!(v::DFGVariable, data::VariableNodeData, key::Symbol=:default) +function setSolverData!(v::DFGVariable, data::VariableNodeData, key::Symbol = :default) @assert key == data.solveKey "VariableNodeData.solveKey=:$(data.solveKey) does not match requested :$(key)" - v.solverDataDict[key] = data + return v.solverDataDict[key] = data end ##------------------------------------------------------------------------------ @@ -460,7 +535,7 @@ Note: Rather use SmallData CRUD """ function setSmallData!(v::DFGVariable, smallData::Dict{Symbol, SmallDataTypes}) empty!(v.smallData) - merge!(v.smallData, smallData) + return merge!(v.smallData, smallData) end # Generic SmallData CRUD @@ -470,15 +545,19 @@ end $(SIGNATURES) Get the small data entry at `key` for variable `label` in `dfg` """ -function getSmallData(dfg::AbstractDFG, label::Symbol, key::Symbol) - getVariable(dfg, label).smallData[key] +function getSmallData(dfg::AbstractDFG, label::Symbol, key::Symbol) + return getVariable(dfg, label).smallData[key] end """ $(SIGNATURES) Add a small data pair `key=>value` for variable `label` in `dfg` """ -function addSmallData!(dfg::AbstractDFG, label::Symbol, pair::Pair{Symbol, <:SmallDataTypes}) +function addSmallData!( + dfg::AbstractDFG, + label::Symbol, + pair::Pair{Symbol, <:SmallDataTypes}, +) v = getVariable(dfg, label) haskey(v.smallData, pair.first) && error("$(pair.first) already exists.") push!(v.smallData, pair) @@ -490,9 +569,16 @@ end $(SIGNATURES) Update a small data pair `key=>value` for variable `label` in `dfg` """ -function updateSmallData!(dfg::AbstractDFG, label::Symbol, pair::Pair{Symbol, <:SmallDataTypes}; warn_if_absent::Bool=true) +function updateSmallData!( + dfg::AbstractDFG, + label::Symbol, + pair::Pair{Symbol, <:SmallDataTypes}; + warn_if_absent::Bool = true, +) v = getVariable(dfg, label) - warn_if_absent && !haskey(v.smallData, pair.first) && @warn("$(pair.first) does not exist, adding.") + warn_if_absent && + !haskey(v.smallData, pair.first) && + @warn("$(pair.first) does not exist, adding.") push!(v.smallData, pair) updateVariable!(dfg, v) return v.smallData #or pair TODO @@ -529,7 +615,6 @@ function emptySmallData!(dfg::AbstractDFG, label::Symbol) return v.smallData #or pair TODO end - ##------------------------------------------------------------------------------ ## Data Entries and Blobs ##------------------------------------------------------------------------------ @@ -553,7 +638,6 @@ Retrieve the soft type name symbol for a DFGVariableSummary. ie :Point2, Pose2, """ getVariableTypeName(v::DFGVariableSummary) = v.variableTypeName::Symbol - function getVariableType(v::DFGVariableSummary)::InferenceVariable @warn "Looking for type in `Main`. Only use if `variableType` has only one implementation, ie. Pose2. Otherwise use the full variable." return getfield(Main, v.variableTypeName)() @@ -578,18 +662,26 @@ end $(SIGNATURES) Get variable solverdata for a given solve key. """ -function getVariableSolverData(dfg::AbstractDFG, variablekey::Symbol, solvekey::Symbol=:default) +function getVariableSolverData( + dfg::AbstractDFG, + variablekey::Symbol, + solvekey::Symbol = :default, +) v = getVariable(dfg, variablekey) - !haskey(v.solverDataDict, solvekey) && throw(KeyError("Solve key '$solvekey' not found in variable '$variablekey'")) + !haskey(v.solverDataDict, solvekey) && + throw(KeyError("Solve key '$solvekey' not found in variable '$variablekey'")) return v.solverDataDict[solvekey] end - """ $(SIGNATURES) Add variable solver data, errors if it already exists. """ -function addVariableSolverData!(dfg::AbstractDFG, variablekey::Symbol, vnd::VariableNodeData) +function addVariableSolverData!( + dfg::AbstractDFG, + variablekey::Symbol, + vnd::VariableNodeData, +) var = getVariable(dfg, variablekey) if haskey(var.solverDataDict, vnd.solveKey) error("VariableNodeData '$(vnd.solveKey)' already exists") @@ -603,9 +695,17 @@ end Add a new solver data entry from a deepcopy of the source variable solver data. NOTE: Copies the solver data. """ -addVariableSolverData!(dfg::AbstractDFG, sourceVariable::DFGVariable, solveKey::Symbol=:default) = - addVariableSolverData!(dfg, sourceVariable.label, deepcopy(getSolverData(sourceVariable, solveKey))) - +function addVariableSolverData!( + dfg::AbstractDFG, + sourceVariable::DFGVariable, + solveKey::Symbol = :default, +) + return addVariableSolverData!( + dfg, + sourceVariable.label, + deepcopy(getSolverData(sourceVariable, solveKey)), + ) +end """ $(SIGNATURES) @@ -623,18 +723,23 @@ function updateVariableSolverData!( dfg::AbstractDFG, variablekey::Symbol, vnd::VariableNodeData, - useCopy::Bool=false, - fields::Vector{Symbol}=Symbol[]; - warn_if_absent::Bool=true + useCopy::Bool = false, + fields::Vector{Symbol} = Symbol[]; + warn_if_absent::Bool = true, ) #This is basically just setSolverData var = getVariable(dfg, variablekey) - warn_if_absent && !haskey(var.solverDataDict, vnd.solveKey) && @warn "VariableNodeData '$(vnd.solveKey)' does not exist, adding" + warn_if_absent && + !haskey(var.solverDataDict, vnd.solveKey) && + @warn "VariableNodeData '$(vnd.solveKey)' does not exist, adding" # for InMemoryDFGTypes do memory copy or repointing, for cloud this would be an different kind of update. usevnd = vnd # useCopy ? deepcopy(vnd) : vnd # should just one, or many pointers be updated? - useExisting = haskey(var.solverDataDict, vnd.solveKey) && isa(var.solverDataDict[vnd.solveKey], VariableNodeData) && length(fields) != 0 + useExisting = + haskey(var.solverDataDict, vnd.solveKey) && + isa(var.solverDataDict[vnd.solveKey], VariableNodeData) && + length(fields) != 0 # @error useExisting vnd.solveKey if useExisting # change multiple pointers inside the VND var.solverDataDict[solvekey] @@ -642,11 +747,11 @@ function updateVariableSolverData!( destField = getfield(var.solverDataDict[vnd.solveKey], field) srcField = getfield(usevnd, field) if isa(destField, Array) && size(destField) == size(srcField) - # use broadcast (in-place operation) - destField .= srcField + # use broadcast (in-place operation) + destField .= srcField else - # change pointer of destination VND object member - setfield!(var.solverDataDict[vnd.solveKey], field, srcField) + # change pointer of destination VND object member + setfield!(var.solverDataDict[vnd.solveKey], field, srcField) end end else @@ -662,29 +767,45 @@ function updateVariableSolverData!( variablekey::Symbol, vnd::VariableNodeData, solveKey::Symbol, - useCopy::Bool=false, - fields::Vector{Symbol}=Symbol[]; - warn_if_absent::Bool=true + useCopy::Bool = false, + fields::Vector{Symbol} = Symbol[]; + warn_if_absent::Bool = true, ) # TODO not very clean if vnd.solveKey != solveKey - @warn("updateVariableSolverData with solveKey parameter might change in the future, see DFG #565. Future warnings are suppressed", maxlog=1) + @warn( + "updateVariableSolverData with solveKey parameter might change in the future, see DFG #565. Future warnings are suppressed", + maxlog = 1 + ) usevnd = useCopy ? deepcopy(vnd) : vnd usevnd.solveKey = solveKey - return updateVariableSolverData!(dfg, variablekey, usevnd, useCopy, fields; warn_if_absent=warn_if_absent) + return updateVariableSolverData!( + dfg, + variablekey, + usevnd, + useCopy, + fields; + warn_if_absent = warn_if_absent, + ) else - return updateVariableSolverData!(dfg, variablekey, vnd, useCopy, fields; warn_if_absent=warn_if_absent) + return updateVariableSolverData!( + dfg, + variablekey, + vnd, + useCopy, + fields; + warn_if_absent = warn_if_absent, + ) end end - -function updateVariableSolverData!( +function updateVariableSolverData!( dfg::AbstractDFG, sourceVariable::DFGVariable, - solveKey::Symbol=:default, - useCopy::Bool=false, - fields::Vector{Symbol}=Symbol[]; - warn_if_absent::Bool=true + solveKey::Symbol = :default, + useCopy::Bool = false, + fields::Vector{Symbol} = Symbol[]; + warn_if_absent::Bool = true, ) # vnd = getSolverData(sourceVariable, solveKey) @@ -692,20 +813,34 @@ function updateVariableSolverData!( # @info "update DFGVar solveKey" solveKey vnd.solveKey # @show toshow @assert solveKey == vnd.solveKey "VariableNodeData's solveKey=:$(vnd.solveKey) does not match requested :$solveKey" - updateVariableSolverData!(dfg, sourceVariable.label, vnd, useCopy, fields; warn_if_absent=warn_if_absent) + return updateVariableSolverData!( + dfg, + sourceVariable.label, + vnd, + useCopy, + fields; + warn_if_absent = warn_if_absent, + ) end -function updateVariableSolverData!( +function updateVariableSolverData!( dfg::AbstractDFG, sourceVariables::Vector{<:DFGVariable}, - solveKey::Symbol=:default, - useCopy::Bool=false, - fields::Vector{Symbol}=Symbol[]; - warn_if_absent::Bool=true + solveKey::Symbol = :default, + useCopy::Bool = false, + fields::Vector{Symbol} = Symbol[]; + warn_if_absent::Bool = true, ) #I think cloud would do this in bulk for speed for var in sourceVariables - updateVariableSolverData!(dfg, var.label, getSolverData(var, solveKey), useCopy, fields; warn_if_absent=warn_if_absent) + updateVariableSolverData!( + dfg, + var.label, + getSolverData(var, solveKey), + useCopy, + fields; + warn_if_absent = warn_if_absent, + ) end end @@ -721,29 +856,24 @@ function cloneSolveKey!( dest::Symbol, src_dfg::AbstractDFG, src::Symbol; - solvable::Int=0, - labels=intersect(ls(dest_dfg, solvable=solvable), ls(src_dfg, solvable=solvable)), - verbose::Bool=false + solvable::Int = 0, + labels = intersect(ls(dest_dfg; solvable = solvable), ls(src_dfg; solvable = solvable)), + verbose::Bool = false, ) # for x in labels sd = deepcopy(getSolverData(getVariable(src_dfg, x), src)) sd.solveKey = dest - updateVariableSolverData!(dest_dfg, x, sd, true, Symbol[]; warn_if_absent=verbose ) + updateVariableSolverData!(dest_dfg, x, sd, true, Symbol[]; warn_if_absent = verbose) end - - nothing + + return nothing end -function cloneSolveKey!( - dfg::AbstractDFG, - dest::Symbol, - src::Symbol; - kw... -) +function cloneSolveKey!(dfg::AbstractDFG, dest::Symbol, src::Symbol; kw...) # @assert dest != src "Must copy to a different solveKey within the same graph, $dest." - cloneSolveKey!(dfg, dest, dfg, src; kw...) + return cloneSolveKey!(dfg, dest, dfg, src; kw...) end # @@ -752,7 +882,11 @@ end $(SIGNATURES) Delete variable solver data, returns the deleted element. """ -function deleteVariableSolverData!(dfg::AbstractDFG, variablekey::Symbol, solveKey::Symbol=:default) +function deleteVariableSolverData!( + dfg::AbstractDFG, + variablekey::Symbol, + solveKey::Symbol = :default, +) var = getVariable(dfg, variablekey) if !haskey(var.solverDataDict, solveKey) @@ -766,8 +900,13 @@ end $(SIGNATURES) Delete variable solver data, returns the deleted element. """ -deleteVariableSolverData!(dfg::AbstractDFG, sourceVariable::DFGVariable, solveKey::Symbol=:default) = - deleteVariableSolverData!(dfg, sourceVariable.label, solveKey) +function deleteVariableSolverData!( + dfg::AbstractDFG, + sourceVariable::DFGVariable, + solveKey::Symbol = :default, +) + return deleteVariableSolverData!(dfg, sourceVariable.label, solveKey) +end ##------------------------------------------------------------------------------ ## SET: list, merge @@ -794,8 +933,12 @@ function mergeVariableSolverData!(destVariable::DFGVariable, sourceVariable::DFG return destVariable end -mergeVariableSolverData!(dfg::AbstractDFG, sourceVariable::DFGVariable) = mergeVariableSolverData!(getVariable(dfg,getLabel(sourceVariable)), sourceVariable) - +function mergeVariableSolverData!(dfg::AbstractDFG, sourceVariable::DFGVariable) + return mergeVariableSolverData!( + getVariable(dfg, getLabel(sourceVariable)), + sourceVariable, + ) +end ##============================================================================== ## Point Parametric Estimates @@ -815,19 +958,32 @@ Notes Related [`getMeanPPE`](@ref), [`getMaxPPE`](@ref), [`updatePPE!`](@ref), getKDEMean, getKDEFit, getPPEs, getVariablePPEs """ -function getPPE(v::DFGVariable, ppekey::Symbol=:default) - !haskey(v.ppeDict, ppekey) && throw(KeyError("PPE key '$ppekey' not found in variable '$(getLabel(v))'")) +function getPPE(v::DFGVariable, ppekey::Symbol = :default) + !haskey(v.ppeDict, ppekey) && + throw(KeyError("PPE key '$ppekey' not found in variable '$(getLabel(v))'")) return v.ppeDict[ppekey] end -getPPE(dfg::AbstractDFG, variablekey::Symbol, ppekey::Symbol=:default) = getPPE(getVariable(dfg, variablekey), ppekey) +function getPPE(dfg::AbstractDFG, variablekey::Symbol, ppekey::Symbol = :default) + return getPPE(getVariable(dfg, variablekey), ppekey) +end # Not the most efficient call but it at least reuses above (in memory it's probably ok) -getPPE(dfg::AbstractDFG, sourceVariable::VariableDataLevel1, ppekey::Symbol=:default) = getPPE(dfg, sourceVariable.label, ppekey) +function getPPE( + dfg::AbstractDFG, + sourceVariable::VariableDataLevel1, + ppekey::Symbol = :default, +) + return getPPE(dfg, sourceVariable.label, ppekey) +end """ $(SIGNATURES) Add variable PPE, errors if it already exists. """ -function addPPE!(dfg::AbstractDFG, variablekey::Symbol, ppe::P) where {P <: AbstractPointParametricEst} +function addPPE!( + dfg::AbstractDFG, + variablekey::Symbol, + ppe::P, +) where {P <: AbstractPointParametricEst} var = getVariable(dfg, variablekey) if haskey(var.ppeDict, ppe.solveKey) error("PPE '$(ppe.solveKey)' already exists") @@ -841,9 +997,9 @@ end Add a new PPE entry from a deepcopy of the source variable PPE. NOTE: Copies the PPE. """ -addPPE!(dfg::AbstractDFG, sourceVariable::DFGVariable, ppekey::Symbol=:default) = - addPPE!(dfg, sourceVariable.label, deepcopy(getPPE(sourceVariable, ppekey))) - +function addPPE!(dfg::AbstractDFG, sourceVariable::DFGVariable, ppekey::Symbol = :default) + return addPPE!(dfg, sourceVariable.label, deepcopy(getPPE(sourceVariable, ppekey))) +end """ $(SIGNATURES) @@ -852,7 +1008,12 @@ Update PPE data if it exists, otherwise add it -- one call per `key::Symbol=:def Notes - uses `ppe.solveKey` as solveKey. """ -function updatePPE!(dfg::AbstractDFG, variablekey::Symbol, ppe::AbstractPointParametricEst; warn_if_absent::Bool=true) +function updatePPE!( + dfg::AbstractDFG, + variablekey::Symbol, + ppe::AbstractPointParametricEst; + warn_if_absent::Bool = true, +) var = getVariable(dfg, variablekey) if warn_if_absent && !haskey(var.ppeDict, ppe.solveKey) @warn "PPE '$(ppe.solveKey)' does not exist, adding" @@ -867,17 +1028,38 @@ end Update PPE data if it exists, otherwise add it. NOTE: Copies the PPE data. """ -updatePPE!(dfg::AbstractDFG, sourceVariable::VariableDataLevel1, ppekey::Symbol=:default; warn_if_absent::Bool=true) = - updatePPE!(dfg, sourceVariable.label, deepcopy(getPPE(sourceVariable, ppekey)); warn_if_absent=warn_if_absent) +function updatePPE!( + dfg::AbstractDFG, + sourceVariable::VariableDataLevel1, + ppekey::Symbol = :default; + warn_if_absent::Bool = true, +) + return updatePPE!( + dfg, + sourceVariable.label, + deepcopy(getPPE(sourceVariable, ppekey)); + warn_if_absent = warn_if_absent, + ) +end """ $(SIGNATURES) Update PPE data if it exists, otherwise add it. """ -function updatePPE!(dfg::AbstractDFG, sourceVariables::Vector{<:VariableDataLevel1}, ppekey::Symbol=:default; warn_if_absent::Bool=true) +function updatePPE!( + dfg::AbstractDFG, + sourceVariables::Vector{<:VariableDataLevel1}, + ppekey::Symbol = :default; + warn_if_absent::Bool = true, +) #I think cloud would do this in bulk for speed for var in sourceVariables - updatePPE!(dfg, var.label, getPPE(dfg, var, ppekey); warn_if_absent=warn_if_absent) + updatePPE!( + dfg, + var.label, + getPPE(dfg, var, ppekey); + warn_if_absent = warn_if_absent, + ) end end @@ -885,7 +1067,7 @@ end $(SIGNATURES) Delete PPE data, returns the deleted element. """ -function deletePPE!(dfg::AbstractDFG, variablekey::Symbol, ppekey::Symbol=:default) +function deletePPE!(dfg::AbstractDFG, variablekey::Symbol, ppekey::Symbol = :default) var = getVariable(dfg, variablekey) if !haskey(var.ppeDict, ppekey) @@ -899,8 +1081,13 @@ end $(SIGNATURES) Delete PPE data, returns the deleted element. """ -deletePPE!(dfg::AbstractDFG, sourceVariable::DFGVariable, ppekey::Symbol=:default) = - deletePPE!(dfg, sourceVariable.label, ppekey) +function deletePPE!( + dfg::AbstractDFG, + sourceVariable::DFGVariable, + ppekey::Symbol = :default, +) + return deletePPE!(dfg, sourceVariable.label, ppekey) +end ##------------------------------------------------------------------------------ ## SET: list, merge diff --git a/src/services/Serialization.jl b/src/services/Serialization.jl index d3c2abd1..23a685b0 100644 --- a/src/services/Serialization.jl +++ b/src/services/Serialization.jl @@ -8,27 +8,30 @@ const TYPEKEY = "_type" ## Version checking #NOTE fixed really bad function but kept similar as fallback #TODO upgrade to use pkgversion(m::Module) function _getDFGVersion() - if VERSION >= v"1.9" return pkgversion(DistributedFactorGraphs) end #TODO when we drop jl<1.9 remove the rest here - pkgorigin = get(Base.pkgorigins, Base.PkgId(DistributedFactorGraphs), nothing) - if !isnothing(pkgorigin) && !isnothing(pkgorigin.version) + pkgorigin = get(Base.pkgorigins, Base.PkgId(DistributedFactorGraphs), nothing) + if !isnothing(pkgorigin) && !isnothing(pkgorigin.version) return pkgorigin.version end - dep = get(Pkg.dependencies(), Base.UUID("b5cc3c7e-6572-11e9-2517-99fb8daf2f04"), nothing) + dep = + get(Pkg.dependencies(), Base.UUID("b5cc3c7e-6572-11e9-2517-99fb8daf2f04"), nothing) if !isnothing(dep) return dep.version else # This is arguably slower, but needed for Travis. - return Pkg.TOML.parse(read(joinpath(dirname(pathof(@__MODULE__)), "..", "Project.toml"), String))["version"] |> VersionNumber + return Pkg.TOML.parse( + read(joinpath(dirname(pathof(@__MODULE__)), "..", "Project.toml"), String), + )["version"] |> VersionNumber end end function _versionCheck(node::Union{<:PackedVariable, <:PackedFactor}) if VersionNumber(node._version) < _getDFGVersion() - @warn "This data was serialized using DFG $(node._version) but you have $(_getDFGVersion()) installed, there may be deserialization issues." maxlog=10 + @warn "This data was serialized using DFG $(node._version) but you have $(_getDFGVersion()) installed, there may be deserialization issues." maxlog = + 10 end end @@ -37,7 +40,7 @@ end # variableType module.type string functions function typeModuleName(variableType::InferenceVariable) io = IOBuffer() - ioc = IOContext(io, :module=>DistributedFactorGraphs) + ioc = IOContext(io, :module => DistributedFactorGraphs) show(ioc, typeof(variableType)) return String(take!(io)) end @@ -59,7 +62,7 @@ function getTypeFromSerializationModule(_typeString::AbstractString) else m = Main end - noparams = split(split_st[end], r"{") + noparams = split(split_st[end], r"{") ret = if 1 < length(noparams) # fix #671, but does not work with specific module yet bidx = findfirst(r"{", split_st[end])[1] @@ -69,7 +72,7 @@ function getTypeFromSerializationModule(_typeString::AbstractString) getfield(m, Symbol(split_st[end])) end - return ret + return ret catch ex @error "Unable to deserialize type $(_typeString)" @@ -78,38 +81,48 @@ function getTypeFromSerializationModule(_typeString::AbstractString) err = String(take!(io)) @error(err) end - nothing + return nothing end # returns a PackedVariableNodeData function packVariableNodeData(d::VariableNodeData{T}) where {T <: InferenceVariable} - @debug "Dispatching conversion variable -> packed variable for type $(string(getVariableType(d)))" - castval = if 0 < length(d.val) - precast = getCoordinates.(T, d.val) - @cast castval[i,j] := precast[j][i] - castval - else - zeros(1,0) - end - _val = castval[:] - - length(d.covar) > 1 && @warn("Packing of more than one parametric covariance is NOT supported yet, only packing first.") - - return PackedVariableNodeData(d.id, _val, size(castval,1), - d.bw[:], size(d.bw,1), - d.BayesNetOutVertIDs, - d.dimIDs, d.dims, d.eliminated, - d.BayesNetVertID, d.separator, - typeModuleName(getVariableType(d)), - d.initialized, - d.infoPerCoord, - d.ismargin, - d.dontmargin, - d.solveInProgress, - d.solvedCount, - d.solveKey, - isempty(d.covar) ? Float64[] : vec(d.covar[1]), - string(_getDFGVersion())) + @debug "Dispatching conversion variable -> packed variable for type $(string(getVariableType(d)))" + castval = if 0 < length(d.val) + precast = getCoordinates.(T, d.val) + @cast castval[i, j] := precast[j][i] + castval + else + zeros(1, 0) + end + _val = castval[:] + + length(d.covar) > 1 && @warn( + "Packing of more than one parametric covariance is NOT supported yet, only packing first." + ) + + return PackedVariableNodeData( + d.id, + _val, + size(castval, 1), + d.bw[:], + size(d.bw, 1), + d.BayesNetOutVertIDs, + d.dimIDs, + d.dims, + d.eliminated, + d.BayesNetVertID, + d.separator, + typeModuleName(getVariableType(d)), + d.initialized, + d.infoPerCoord, + d.ismargin, + d.dontmargin, + d.solveInProgress, + d.solvedCount, + d.solveKey, + isempty(d.covar) ? Float64[] : vec(d.covar[1]), + string(_getDFGVersion()), + ) end function unpackVariableNodeData(d::PackedVariableNodeData) @@ -118,53 +131,61 @@ function unpackVariableNodeData(d::PackedVariableNodeData) # TODO deprecated remove in v0.11 - for backward compatibility for saved variableTypes. ststring = string(split(d.variableType, "(")[1]) T = getTypeFromSerializationModule(ststring) - isnothing(T) && error("The variable doesn't seem to have a variableType. It needs to set up with an InferenceVariable from IIF. This will happen if you use DFG to add serialized variables directly and try use them. Please use IncrementalInference.addVariable().") - + isnothing(T) && error( + "The variable doesn't seem to have a variableType. It needs to set up with an InferenceVariable from IIF. This will happen if you use DFG to add serialized variables directly and try use them. Please use IncrementalInference.addVariable().", + ) + r3 = d.dimval - c3 = r3 > 0 ? floor(Int,length(d.vecval)/r3) : 0 - M3 = reshape(d.vecval,r3,c3) - @cast val_[j][i] := M3[i,j] + c3 = r3 > 0 ? floor(Int, length(d.vecval) / r3) : 0 + M3 = reshape(d.vecval, r3, c3) + @cast val_[j][i] := M3[i, j] vals = Vector{getPointType(T)}(undef, length(val_)) # vals = getPoint.(T, val_) - for (i,v) in enumerate(val_) + for (i, v) in enumerate(val_) vals[i] = getPoint(T, v) end - + r4 = d.dimbw - c4 = r4 > 0 ? floor(Int,length(d.vecbw)/r4) : 0 - BW = reshape(d.vecbw,r4,c4) + c4 = r4 > 0 ? floor(Int, length(d.vecbw) / r4) : 0 + BW = reshape(d.vecbw, r4, c4) # N = getDimension(T) return VariableNodeData{T, getPointType(T), N}(; id = d.id, - val = vals, - bw = BW, + val = vals, + bw = BW, #TODO only one covar is currently supported in packed VND covar = isempty(d.covar) ? SMatrix{N, N, Float64}[] : [d.covar], BayesNetOutVertIDs = Symbol.(d.BayesNetOutVertIDs), - dimIDs = d.dimIDs, - dims = d.dims, - eliminated = d.eliminated, - BayesNetVertID = Symbol(d.BayesNetVertID), + dimIDs = d.dimIDs, + dims = d.dims, + eliminated = d.eliminated, + BayesNetVertID = Symbol(d.BayesNetVertID), separator = Symbol.(d.separator), - initialized = d.initialized, - infoPerCoord = d.infoPerCoord, - ismargin = d.ismargin, - dontmargin = d.dontmargin, - solveInProgress = d.solveInProgress, - solvedCount = d.solvedCount, + initialized = d.initialized, + infoPerCoord = d.infoPerCoord, + ismargin = d.ismargin, + dontmargin = d.dontmargin, + solveInProgress = d.solveInProgress, + solvedCount = d.solvedCount, solveKey = Symbol(d.solveKey), - events = Dict{Symbol,Threads.Condition}() ) + events = Dict{Symbol, Threads.Condition}(), + ) end ##============================================================================== ## Variable Packing and unpacking ##============================================================================== -function packVariable(v::DFGVariable; includePPEs::Bool=true, includeSolveData::Bool=true, includeDataEntries::Bool=true) +function packVariable( + v::DFGVariable; + includePPEs::Bool = true, + includeSolveData::Bool = true, + includeDataEntries::Bool = true, +) return PackedVariable(; - id=v.id, + id = v.id, label = v.label, timestamp = v.timestamp, nstime = string(v.nstime.value), @@ -175,40 +196,53 @@ function packVariable(v::DFGVariable; includePPEs::Bool=true, includeSolveData:: solvable = v.solvable, variableType = DFG.typeModuleName(DFG.getVariableType(v)), blobEntries = collect(values(v.dataDict)), - _version = string(DFG._getDFGVersion())) + _version = string(DFG._getDFGVersion()), + ) end -function packVariable(v::Variable; includePPEs::Bool=true, includeSolveData::Bool=true, includeDataEntries::Bool=true) +function packVariable( + v::Variable; + includePPEs::Bool = true, + includeSolveData::Bool = true, + includeDataEntries::Bool = true, +) return v end -function unpackVariable(variable::PackedVariable; skipVersionCheck::Bool=false) +function unpackVariable(variable::PackedVariable; skipVersionCheck::Bool = false) !skipVersionCheck && _versionCheck(variable) # Variable and point type variableType = DFG.getTypeFromSerializationModule(variable.variableType) - isnothing(variableType) && error("Cannot deserialize variableType '$(variable.variableType)' in variable '$(variable.label)'") + isnothing(variableType) && error( + "Cannot deserialize variableType '$(variable.variableType)' in variable '$(variable.label)'", + ) pointType = DFG.getPointType(variableType) - ppeDict = Dict{Symbol, MeanMaxPPE}(map(p->p.solveKey, variable.ppes) .=> variable.ppes) + ppeDict = + Dict{Symbol, MeanMaxPPE}(map(p -> p.solveKey, variable.ppes) .=> variable.ppes) solverDict = Dict{Symbol, VariableNodeData{variableType, pointType}}( - map(sd -> sd.solveKey, variable.solverData) .=> - map(sd -> DFG.unpackVariableNodeData(sd), variable.solverData)) - dataDict = Dict{Symbol, BlobEntry}(map(de -> de.label, variable.blobEntries) .=> variable.blobEntries) + map(sd -> sd.solveKey, variable.solverData) .=> + map(sd -> DFG.unpackVariableNodeData(sd), variable.solverData), + ) + dataDict = Dict{Symbol, BlobEntry}( + map(de -> de.label, variable.blobEntries) .=> variable.blobEntries, + ) metadata = JSON3.read(base64decode(variable.metadata), Dict{Symbol, DFG.SmallDataTypes}) return DFGVariable( - variable.label, + variable.label, variableType; id = variable.id, - timestamp=variable.timestamp, - nstime=Nanosecond(variable.nstime), - tags=Set(variable.tags), - ppeDict=ppeDict, - solverDataDict=solverDict, - smallData=metadata, - dataDict=dataDict, - solvable=variable.solvable ) + timestamp = variable.timestamp, + nstime = Nanosecond(variable.nstime), + tags = Set(variable.tags), + ppeDict = ppeDict, + solverDataDict = solverDict, + smallData = metadata, + dataDict = dataDict, + solvable = variable.solvable, + ) end DFGVariable(v::Variable) = unpackVariable(v) @@ -217,14 +251,11 @@ DFGVariable(v::Variable) = unpackVariable(v) ## Factor Packing and unpacking ##============================================================================== - -function _packSolverData( - f::DFGFactor, - fnctype::AbstractFactor) +function _packSolverData(f::DFGFactor, fnctype::AbstractFactor) # packtype = convertPackedType(fnctype) try - packed = convert( PackedFunctionNodeData{packtype}, getSolverData(f) ) + packed = convert(PackedFunctionNodeData{packtype}, getSolverData(f)) packedJson = packed return packedJson catch ex @@ -239,7 +270,7 @@ end # returns PackedFactor function packFactor(f::DFGFactor) fnctype = getSolverData(f).fnc.usrfnc! - return PackedFactor(; + return PackedFactor(; id = f.id, label = f.label, tags = collect(f.tags), @@ -251,7 +282,8 @@ function packFactor(f::DFGFactor) metadata = base64encode(JSON3.write(f.smallData)), # Pack the node data data = JSON3.write(_packSolverData(f, fnctype)), - _version = string(_getDFGVersion())) + _version = string(_getDFGVersion()), + ) return props end @@ -259,7 +291,12 @@ packFactor(f::PackedFactor) = f function reconstFactorData end -function decodePackedType(dfg::AbstractDFG, varOrder::AbstractVector{Symbol}, ::Type{T}, packeddata::GenericFunctionNodeData{PT}) where {T<:FactorOperationalMemory, PT} +function decodePackedType( + dfg::AbstractDFG, + varOrder::AbstractVector{Symbol}, + ::Type{T}, + packeddata::GenericFunctionNodeData{PT}, +) where {T <: FactorOperationalMemory, PT} # # TODO, to solve IIF 1424 # variables = map(lb->getVariable(dfg, lb), varOrder) @@ -274,14 +311,12 @@ end function fncStringToData(packtype::Type{<:AbstractPackedFactor}, data::String) # Read string as JSON object to use as kwargs - fncData = JSON3.read( - if data[1] == '{' - data - else - String(base64decode(data)) - end - ) - packT = packtype(;fncData.fnc...) + fncData = JSON3.read(if data[1] == '{' + data + else + String(base64decode(data)) + end) + packT = packtype(; fncData.fnc...) packed = GenericFunctionNodeData{packtype}( fncData["eliminated"], @@ -297,20 +332,35 @@ function fncStringToData(packtype::Type{<:AbstractPackedFactor}, data::String) ) return packed end -fncStringToData(packtype::Type{<:AbstractPackedFactor}, data::NamedTuple) = error("Who is calling deserialize factor with NamedTuple, likely JSON3 somewhere") -fncStringToData(::Type{T}, data::PackedFunctionNodeData{T}) where {T <: AbstractPackedFactor} = data -function fncStringToData(fncType::String, data::PackedFunctionNodeData{T}) where {T <: AbstractPackedFactor} - packtype = DFG.getTypeFromSerializationModule("Packed"*fncType) +function fncStringToData(packtype::Type{<:AbstractPackedFactor}, data::NamedTuple) + return error( + "Who is calling deserialize factor with NamedTuple, likely JSON3 somewhere", + ) +end + +function fncStringToData( + ::Type{T}, + data::PackedFunctionNodeData{T}, +) where {T <: AbstractPackedFactor} + return data +end +function fncStringToData( + fncType::String, + data::PackedFunctionNodeData{T}, +) where {T <: AbstractPackedFactor} + packtype = DFG.getTypeFromSerializationModule("Packed" * fncType) if packtype == T data else - error("Unknown type conversion\n$(fncType)\n$packtype\n$(PackedFunctionNodeData{T})") + error( + "Unknown type conversion\n$(fncType)\n$packtype\n$(PackedFunctionNodeData{T})", + ) end end function fncStringToData(fncType::String, data::T) where {T <: AbstractPackedFactor} - packtype = DFG.getTypeFromSerializationModule("Packed"*fncType) + packtype = DFG.getTypeFromSerializationModule("Packed" * fncType) if packtype == T # || T <: packtype data else @@ -319,20 +369,19 @@ function fncStringToData(fncType::String, data::T) where {T <: AbstractPackedFac end function fncStringToData(fncType::String, data::Union{String, <:NamedTuple}) # FIXME, should rather just store the data as `PackedFactorX` rather than hard code the type change here??? - packtype = DFG.getTypeFromSerializationModule("Packed"*fncType) - fncStringToData(packtype, data) + packtype = DFG.getTypeFromSerializationModule("Packed" * fncType) + return fncStringToData(packtype, data) end - function unpackFactor( - dfg::AbstractDFG, + dfg::AbstractDFG, factor::PackedFactor; - skipVersionCheck::Bool=false + skipVersionCheck::Bool = false, ) # @debug "DECODING factor type = '$(factor.fnctype)' for factor '$(factor.label)'" !skipVersionCheck && _versionCheck(factor) - + fullFactorData = nothing try if factor.data[1] == '{' @@ -341,14 +390,15 @@ function unpackFactor( packedFnc = fncStringToData(factor.fnctype, String(base64decode(factor.data))) end decodeType = getFactorOperationalMemoryType(dfg) - fullFactorData = decodePackedType(dfg, factor._variableOrderSymbols, decodeType, packedFnc) + fullFactorData = + decodePackedType(dfg, factor._variableOrderSymbols, decodeType, packedFnc) catch ex io = IOBuffer() showerror(io, ex, catch_backtrace()) err = String(take!(io)) msg = "Error while unpacking '$(factor.label)' as '$(factor.fnctype)', please check the unpacking/packing converters for this factor - \r\n$err" error(msg) - end + end metadata = JSON3.read(base64decode(factor.metadata), Dict{Symbol, DFG.SmallDataTypes}) @@ -359,10 +409,10 @@ function unpackFactor( Set(factor.tags), fullFactorData, factor.solvable, - Tuple(factor._variableOrderSymbols), - id=factor.id, - smallData = metadata + Tuple(factor._variableOrderSymbols); + id = factor.id, + smallData = metadata, ) end -# \ No newline at end of file +# diff --git a/test/FactorGraphsTests.jl b/test/FactorGraphsTests.jl index e201cf48..c177a29a 100644 --- a/test/FactorGraphsTests.jl +++ b/test/FactorGraphsTests.jl @@ -3,9 +3,7 @@ using DistributedFactorGraphs using DistributedFactorGraphs.GraphsDFGs.FactorGraphs - @testset "GraphsDFGs.FactorGraphs BiMaps" begin - @test isa(FactorGraphs.BiDictMap(), FactorGraphs.BiDictMap{Int64}) bi = FactorGraphs.BiDictMap{Int}() @@ -15,17 +13,17 @@ using DistributedFactorGraphs.GraphsDFGs.FactorGraphs @test bi[:x1] == 2 @test_throws KeyError bi[1] - @test haskey(bi,2) - @test !haskey(bi,1) - @test haskey(bi,:x1) - @test !haskey(bi,:x10) + @test haskey(bi, 2) + @test !haskey(bi, 1) + @test haskey(bi, :x1) + @test !haskey(bi, :x10) @test (bi[:x10] = 10) == 10 @test bi[10] == :x10 @test (bi[:x11] = 10) == 10 - @test !haskey(bi,:x10) + @test !haskey(bi, :x10) bi[1] = :x1 bi[:x1] = 2 @@ -37,29 +35,42 @@ using DistributedFactorGraphs.GraphsDFGs.FactorGraphs @test length(bi.int_sym) == 3 @test length(bi) == 3 @test !(isempty(bi)) - end @testset "GraphsDFGs.FactorGraphs" begin - - - @test isa(FactorGraphs.FactorGraph(), FactorGraph{Int64,AbstractDFGVariable,AbstractDFGFactor}) + @test isa( + FactorGraphs.FactorGraph(), + FactorGraph{Int64, AbstractDFGVariable, AbstractDFGFactor}, + ) fg = FactorGraphs.FactorGraph{Int, SkeletonDFGVariable, SkeletonDFGFactor}() @test !FactorGraphs.is_directed(fg) - @test !FactorGraphs.is_directed(FactorGraph{Int, SkeletonDFGVariable, SkeletonDFGFactor}) + @test !FactorGraphs.is_directed( + FactorGraph{Int, SkeletonDFGVariable, SkeletonDFGFactor}, + ) @test isa(zero(fg), FactorGraph{Int64, SkeletonDFGVariable, SkeletonDFGFactor}) # @test @test FactorGraphs.addVariable!(fg, SkeletonDFGVariable(:a)) - @test @test_logs (:error, r"already") !FactorGraphs.addVariable!(fg, SkeletonDFGVariable(:a)) + @test @test_logs (:error, r"already") !FactorGraphs.addVariable!( + fg, + SkeletonDFGVariable(:a), + ) @test FactorGraphs.addVariable!(fg, SkeletonDFGVariable(:b)) - @test FactorGraphs.addFactor!(fg, [:a,:b], SkeletonDFGFactor(:abf1, [:a,:b])) - @test @test_logs (:error, r"already") !FactorGraphs.addFactor!(fg, [:a,:b], SkeletonDFGFactor(:abf1, [:a,:b])) - @test @test_logs (:error, r"not found") !FactorGraphs.addFactor!(fg, [:a,:c], SkeletonDFGFactor(:acf1, [:a,:c])) + @test FactorGraphs.addFactor!(fg, [:a, :b], SkeletonDFGFactor(:abf1, [:a, :b])) + @test @test_logs (:error, r"already") !FactorGraphs.addFactor!( + fg, + [:a, :b], + SkeletonDFGFactor(:abf1, [:a, :b]), + ) + @test @test_logs (:error, r"not found") !FactorGraphs.addFactor!( + fg, + [:a, :c], + SkeletonDFGFactor(:acf1, [:a, :c]), + ) @test eltype(fg) == Int @@ -68,10 +79,8 @@ end @test FactorGraphs.has_vertex(fg, 1) @test !FactorGraphs.has_vertex(fg, 4) - @test FactorGraphs.has_edge(fg, FactorGraphs.Graphs.SimpleGraphs.SimpleEdge(1,3)) - - @test FactorGraphs.rem_edge!(fg, FactorGraphs.Graphs.SimpleGraphs.SimpleEdge(2,3)) - @test !FactorGraphs.has_edge(fg, FactorGraphs.Graphs.SimpleGraphs.SimpleEdge(2,3)) - + @test FactorGraphs.has_edge(fg, FactorGraphs.Graphs.SimpleGraphs.SimpleEdge(1, 3)) + @test FactorGraphs.rem_edge!(fg, FactorGraphs.Graphs.SimpleGraphs.SimpleEdge(2, 3)) + @test !FactorGraphs.has_edge(fg, FactorGraphs.Graphs.SimpleGraphs.SimpleEdge(2, 3)) end diff --git a/test/GraphsDFGSummaryTypes.jl b/test/GraphsDFGSummaryTypes.jl index 7216cb24..72472b68 100644 --- a/test/GraphsDFGSummaryTypes.jl +++ b/test/GraphsDFGSummaryTypes.jl @@ -3,13 +3,52 @@ # FACTYPE = DFGFactorSummary dfg = GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}() -DistributedFactorGraphs.DFGVariableSummary(label::Symbol) = DFGVariableSummary(nothing, label, DistributedFactorGraphs.now(localzone()), Set{Symbol}(), Dict{Symbol, MeanMaxPPE}(), :Pose2, Dict{Symbol,BlobEntry}()) -DistributedFactorGraphs.DFGFactorSummary(label::Symbol) = DFGFactorSummary(nothing, label, Set{Symbol}(), Symbol[], DistributedFactorGraphs.now(localzone())) +function DistributedFactorGraphs.DFGVariableSummary(label::Symbol) + return DFGVariableSummary( + nothing, + label, + DistributedFactorGraphs.now(localzone()), + Set{Symbol}(), + Dict{Symbol, MeanMaxPPE}(), + :Pose2, + Dict{Symbol, BlobEntry}(), + ) +end +function DistributedFactorGraphs.DFGFactorSummary(label::Symbol) + return DFGFactorSummary( + nothing, + label, + Set{Symbol}(), + Symbol[], + DistributedFactorGraphs.now(localzone()), + ) +end -DistributedFactorGraphs.DFGVariableSummary(label::Symbol, ::VariableNodeData{T}) where T = DFGVariableSummary(nothing, label, DistributedFactorGraphs.now(localzone()), Set{Symbol}(), Dict{Symbol, MeanMaxPPE}(), Symbol(T), Dict{Symbol,BlobEntry}()) -DistributedFactorGraphs.SkeletonDFGVariable(label::Symbol, args...) = SkeletonDFGVariable(label) -DistributedFactorGraphs.SkeletonDFGVariable(label::Symbol, ::VariableNodeData{T}) where T = SkeletonDFGVariable(nothing, label, Set{Symbol}()) +function DistributedFactorGraphs.DFGVariableSummary( + label::Symbol, + ::VariableNodeData{T}, +) where {T} + return DFGVariableSummary( + nothing, + label, + DistributedFactorGraphs.now(localzone()), + Set{Symbol}(), + Dict{Symbol, MeanMaxPPE}(), + Symbol(T), + Dict{Symbol, BlobEntry}(), + ) +end + +function DistributedFactorGraphs.SkeletonDFGVariable(label::Symbol, args...) + return SkeletonDFGVariable(label) +end +function DistributedFactorGraphs.SkeletonDFGVariable( + label::Symbol, + ::VariableNodeData{T}, +) where {T} + return SkeletonDFGVariable(nothing, label, Set{Symbol}()) +end dfg = GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}() v1 = VARTYPE(:a) @@ -18,65 +57,63 @@ v3 = VARTYPE(:c) f0 = FACTYPE(:af1) f1 = FACTYPE(:abf1) f2 = FACTYPE(:bcf1) -append!(f2._variableOrderSymbols, [:b,:c]) +append!(f2._variableOrderSymbols, [:b, :c]) union!(v1.tags, [:VARIABLE, :POSE]) union!(v2.tags, [:VARIABLE, :LANDMARK]) union!(f1.tags, [:FACTOR]) -if false -#TODO add to tests -VARTYPE = PackedVariable -FACTYPE = PackedFactor -dfg = GraphsDFG{NoSolverParams, PackedVariable, PackedFactor}() -v1 = PackedVariable(;label=:a, variableType="Pose2", tags=[:VARIABLE, :POSE]) -v2 = PackedVariable(;label=:b, variableType="Pose2", tags=[:VARIABLE, :LANDMARK]) -v3 = PackedVariable(;label=:c, variableType="Pose2") -orphan = PackedVariable(;label=:orphan, variableType="Pose2") -f0 = PackedFactor(; - label=:af1, - tags = [:FACTOR], - _variableOrderSymbols=[:a], - timestamp=DFG.Dates.now(DFG.tz"Z"), - nstime=0, - fnctype="PriorPose2", - solvable=1, - data = "", - metadata = "", -) -f1 = PackedFactor(; - label=:abf1, - tags = [:FACTOR], - _variableOrderSymbols=[:a, :b], - timestamp=DFG.Dates.now(DFG.tz"Z"), - nstime=0, - fnctype="Pose2Pose2", - solvable=1, - data = "", - metadata = "", -) -f2 = PackedFactor(; - label=:bcf1, - tags = [:FACTOR], - _variableOrderSymbols=[:b, :c], - timestamp=DFG.Dates.now(DFG.tz"Z"), - nstime=0, - fnctype="Pose2Pose2", - solvable=1, - data = "", - metadata = "", -) +if false + #TODO add to tests + VARTYPE = PackedVariable + FACTYPE = PackedFactor + dfg = GraphsDFG{NoSolverParams, PackedVariable, PackedFactor}() + v1 = PackedVariable(; label = :a, variableType = "Pose2", tags = [:VARIABLE, :POSE]) + v2 = PackedVariable(; label = :b, variableType = "Pose2", tags = [:VARIABLE, :LANDMARK]) + v3 = PackedVariable(; label = :c, variableType = "Pose2") + orphan = PackedVariable(; label = :orphan, variableType = "Pose2") + f0 = PackedFactor(; + label = :af1, + tags = [:FACTOR], + _variableOrderSymbols = [:a], + timestamp = DFG.Dates.now(DFG.tz"Z"), + nstime = 0, + fnctype = "PriorPose2", + solvable = 1, + data = "", + metadata = "", + ) + f1 = PackedFactor(; + label = :abf1, + tags = [:FACTOR], + _variableOrderSymbols = [:a, :b], + timestamp = DFG.Dates.now(DFG.tz"Z"), + nstime = 0, + fnctype = "Pose2Pose2", + solvable = 1, + data = "", + metadata = "", + ) + f2 = PackedFactor(; + label = :bcf1, + tags = [:FACTOR], + _variableOrderSymbols = [:b, :c], + timestamp = DFG.Dates.now(DFG.tz"Z"), + nstime = 0, + fnctype = "Pose2Pose2", + solvable = 1, + data = "", + metadata = "", + ) end - @testset "Variables and Factors CRUD and SET" begin - VariablesandFactorsCRUD_SET!(dfg,v1,v2,v3,f0,f1,f2) + VariablesandFactorsCRUD_SET!(dfg, v1, v2, v3, f0, f1, f2) end - # Gets @testset "Gets, Sets, and Accessors" begin - global dfg,v1,v2,f1 + global dfg, v1, v2, f1 @test getLabel(v1) == v1.label @test getTags(v1) == v1.tags @@ -103,36 +140,50 @@ end @test getTimestamp(f1ts) == testTimestamp @test_throws MethodError setTimestamp!(v1, testTimestamp) end - end @testset "Updating Nodes" begin VARTYPE == DFGVariableSummary && PPETestBlock!(dfg, v1) end - @testset "Adjacency Matrices" begin fg = GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}() addVariable!(fg, VARTYPE(:a)) addVariable!(fg, VARTYPE(:b)) - addFactor!(fg, [:a,:b], FACTYPE(:abf1)) + addFactor!(fg, [:a, :b], FACTYPE(:abf1)) addVariable!(fg, VARTYPE(:orphan)) AdjacencyMatricesTestBlock(fg) end @testset "Getting Neighbors" begin - GettingNeighbors(GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}, VARTYPE=VARTYPE, FACTYPE=FACTYPE) + GettingNeighbors( + GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}; + VARTYPE = VARTYPE, + FACTYPE = FACTYPE, + ) end @testset "Building Subgraphs" begin - BuildingSubgraphs(GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}, VARTYPE=VARTYPE, FACTYPE=FACTYPE) + BuildingSubgraphs( + GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}; + VARTYPE = VARTYPE, + FACTYPE = FACTYPE, + ) end @testset "Producing Dot Files" begin - ProducingDotFiles(GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}, VARTYPE=VARTYPE, FACTYPE=FACTYPE) + ProducingDotFiles( + GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}; + VARTYPE = VARTYPE, + FACTYPE = FACTYPE, + ) end @testset "Connectivity Test" begin - ConnectivityTest(GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}, VARTYPE=VARTYPE, FACTYPE=FACTYPE) + ConnectivityTest( + GraphsDFG{NoSolverParams, VARTYPE, FACTYPE}; + VARTYPE = VARTYPE, + FACTYPE = FACTYPE, + ) end diff --git a/test/compareTests.jl b/test/compareTests.jl index 1ef5782f..822566b4 100644 --- a/test/compareTests.jl +++ b/test/compareTests.jl @@ -21,16 +21,15 @@ vnd2.val[1] = [0.1;] @test !(vnd1 == vnd3) # MeanMaxPPE -ppe1 = MeanMaxPPE(:default, [1.], [2.], [3.]) +ppe1 = MeanMaxPPE(:default, [1.0], [2.0], [3.0]) ppe2 = deepcopy(ppe1) -ppe3 = MeanMaxPPE(:default, [2.], [3.], [4.]) +ppe3 = MeanMaxPPE(:default, [2.0], [3.0], [4.0]) @test ppe1 == ppe2 ppe2.max[1] = 0.1 @test !(ppe1 == ppe2) @test !(ppe1 == ppe3) - # DFGVariable v1 = DFGVariable(:x1, TestVariableType1()) v2 = deepcopy(v1) @@ -43,9 +42,19 @@ v2.solvable = 0 @test !(DFGVariable(:x1, TestVariableType1()) == DFGVariable(:x1, TestVariableType2())) # GenericFunctionNodeData -gfnd1 = GenericFunctionNodeData(; eliminated=true, potentialused=true, edgeIDs=[1,2], fnc=TestFunctorInferenceType1()) +gfnd1 = GenericFunctionNodeData(; + eliminated = true, + potentialused = true, + edgeIDs = [1, 2], + fnc = TestFunctorInferenceType1(), +) gfnd2 = deepcopy(gfnd1) -gfnd3 = GenericFunctionNodeData(;eliminated=true, potentialused=true, edgeIDs=[1,2], fnc=TestFunctorInferenceType2()) +gfnd3 = GenericFunctionNodeData(; + eliminated = true, + potentialused = true, + edgeIDs = [1, 2], + fnc = TestFunctorInferenceType2(), +) @test gfnd1 == gfnd2 @test !(gfnd1 == gfnd3) @@ -58,7 +67,6 @@ f3 = DFGFactor(:f1, [:b, :a], gfnd1) @test f1 == f2 @test !(f1 == f3) - ## Compare functions vnd1 = VariableNodeData(TestVariableType1()) vnd2 = deepcopy(vnd1) @@ -74,9 +82,19 @@ vnd2.val[1][1] = 0.1 @test !compare(vnd1, vnd2) @test !compare(vnd1, vnd3) -gfnd1 = GenericFunctionNodeData(eliminated=true, potentialused=true, edgeIDs=[1,2], fnc=TestFunctorInferenceType1()) +gfnd1 = GenericFunctionNodeData(; + eliminated = true, + potentialused = true, + edgeIDs = [1, 2], + fnc = TestFunctorInferenceType1(), +) gfnd2 = deepcopy(gfnd1) -gfnd3 = GenericFunctionNodeData(eliminated=true, potentialused=true, edgeIDs=[1,2], fnc=PackedTestFunctorInferenceType1()) +gfnd3 = GenericFunctionNodeData(; + eliminated = true, + potentialused = true, + edgeIDs = [1, 2], + fnc = PackedTestFunctorInferenceType1(), +) @test compare(gfnd1, gfnd2) @test_broken !(compare(gfnd1, gfnd3)) diff --git a/test/consol_DataEntryBlobTests.jl b/test/consol_DataEntryBlobTests.jl index f48eb75f..858d322e 100644 --- a/test/consol_DataEntryBlobTests.jl +++ b/test/consol_DataEntryBlobTests.jl @@ -1,16 +1,16 @@ if false -using Test -using GraphPlot -using DistributedFactorGraphs -using Pkg -using Dates -using UUIDs -using TimeZones -using SHA + using Test + using GraphPlot + using DistributedFactorGraphs + using Pkg + using Dates + using UUIDs + using TimeZones + using SHA -include("testBlocks.jl") + include("testBlocks.jl") -# import DistributedFactorGraphs: addData!, updateData!, getData, deleteData! + # import DistributedFactorGraphs: addData!, updateData!, getData, deleteData! end @@ -45,7 +45,6 @@ dataset2 = rand(UInt8, 1000) # @test ade == ade2 == ade3 # @test adb == adb2 == adb3 - # @test :random in listBlobEntries(dfg, :x2) # @test length(listBlobEntries(dfg, :x1)) === 0 # @test length(listBlobEntries(dfg, :x2)) === 1 @@ -72,7 +71,6 @@ dataset2 = rand(UInt8, 1000) # @test ade == gde == dde # @test adb == gdb == ddb - # @test_throws ErrorException addBlob!(dfg, :x2, deepcopy(ade), dataset2) # ade2,adb2 = addBlob!(dfg, :x2, deepcopy(ade), dataset1) @@ -92,22 +90,22 @@ ds = FolderStore{Vector{UInt8}}(:filestore, "/tmp/dfgFolderStore") addBlobStore!(dfg, ds) ade = addData!(dfg, :filestore, :x1, :random, dataset1) -_ = addData!(dfg, :filestore, :x1, :another_1, dataset1) -_,_ = getData(dfg, :x1, "random") -_,_ = getData(dfg, :x1, r"rando") -gde,gdb = getData(dfg, :x1, :random) +_ = addData!(dfg, :filestore, :x1, :another_1, dataset1) +_, _ = getData(dfg, :x1, "random") +_, _ = getData(dfg, :x1, r"rando") +gde, gdb = getData(dfg, :x1, :random) @test hasBlob(dfg, ade) @show gde -@test incrDataLabelSuffix(dfg,:x1,:random) == :random_1 -@test incrDataLabelSuffix(dfg,:x1,:another_1) == :another_2 +@test incrDataLabelSuffix(dfg, :x1, :random) == :random_1 +@test incrDataLabelSuffix(dfg, :x1, :another_1) == :another_2 # @test incrDataLabelSuffix(dfg,:x1,:another) == :another_2 # TODO exand support for Regex likely search on labels # @test incrDataLabelSuffix(dfg,:x1,"random") == "random_1" # TODO expand support for label::String -dde,ddb = deleteData!(dfg, :x1, :random) -_,_ = deleteData!(dfg, :x1, :another_1) +dde, ddb = deleteData!(dfg, :x1, :random) +_, _ = deleteData!(dfg, :x1, :another_1) @test ade == gde == dde @test dataset1 == gdb == ddb @@ -135,8 +133,8 @@ ds = InMemoryBlobStore() addBlobStore!(dfg, ds) ade = addData!(dfg, :default_inmemory_store, :x1, :random, dataset1) -gde,gdb = getData(dfg, :x1, :random) -dde,ddb = deleteData!(dfg, :x1, :random) +gde, gdb = getData(dfg, :x1, :random) +dde, ddb = deleteData!(dfg, :x1, :random) @test ade == gde == dde @test dataset1 == gdb == ddb @@ -163,9 +161,7 @@ store = TestStore{Int}() @test_throws ErrorException getBlob(store, ade) @test_throws ErrorException addBlob!(store, ade, 1) -@test_throws ErrorException updateBlob!(store, ade, 1) +@test_throws ErrorException updateBlob!(store, ade, 1) @test_throws ErrorException deleteBlob!(store, ade) @test_throws ErrorException listBlobs(store) @test_throws ErrorException hasBlob(store, uuid4()) - - diff --git a/test/fileDFGTests.jl b/test/fileDFGTests.jl index 3aca5499..5ad0f7cc 100644 --- a/test/fileDFGTests.jl +++ b/test/fileDFGTests.jl @@ -14,53 +14,111 @@ using UUIDs numNodes = 5 # Arranging some random data - verts = map(n -> addVariable!(dfg, Symbol("x$n"), ContinuousScalar, tags = [:POSE]), 1:numNodes) + verts = map( + n -> addVariable!(dfg, Symbol("x$n"), ContinuousScalar; tags = [:POSE]), + 1:numNodes, + ) map(v -> setSolvable!(v, Int(round(rand()))), verts) - map(v -> getSolverData(verts[4]).solveInProgress=Int(round(rand())), verts) - map(v -> setSolvedCount!(v, Int(round(10*rand()))), verts) + map(v -> getSolverData(verts[4]).solveInProgress = Int(round(rand())), verts) + map(v -> setSolvedCount!(v, Int(round(10 * rand()))), verts) # Add some data entries - map(v -> addBlobEntry!(v, BlobEntry(nothing, nothing, uuid4(), :testing, :store, "", "", "", "", "", now(localzone()), "BlobEntry", string(DFG._getDFGVersion()))), verts) - map(v -> addBlobEntry!(v, BlobEntry(nothing, nothing, uuid4(), :testing2, :store, "", "", "", "", "", ZonedDateTime(2014, 5, 30, 21, tz"UTC-4"), "BlobEntry", string(DFG._getDFGVersion()))), verts) + map( + v -> addBlobEntry!( + v, + BlobEntry( + nothing, + nothing, + uuid4(), + :testing, + :store, + "", + "", + "", + "", + "", + now(localzone()), + "BlobEntry", + string(DFG._getDFGVersion()), + ), + ), + verts, + ) + map( + v -> addBlobEntry!( + v, + BlobEntry( + nothing, + nothing, + uuid4(), + :testing2, + :store, + "", + "", + "", + "", + "", + ZonedDateTime(2014, 5, 30, 21, tz"UTC-4"), + "BlobEntry", + string(DFG._getDFGVersion()), + ), + ), + verts, + ) # Add some PPEs ppe1 = MeanMaxPPE(:default, [1.0], [0.2], [3.456]) - ppe2 = MeanMaxPPE(;solveKey=:other, suggested=[1.0], mean=[0.2], max=[3.456], createdTimestamp=ZonedDateTime(2014, 5, 30, 21, tz"UTC-4")) + ppe2 = MeanMaxPPE(; + solveKey = :other, + suggested = [1.0], + mean = [0.2], + max = [3.456], + createdTimestamp = ZonedDateTime(2014, 5, 30, 21, tz"UTC-4"), + ) map(v -> addPPE!(dfg, getLabel(v), deepcopy(ppe1)), verts) map(v -> addPPE!(dfg, getLabel(v), deepcopy(ppe2)), verts) #call update to set it on cloud updateVariable!.(dfg, verts) - - facts = map(n -> addFactor!(dfg, [verts[n], verts[n+1]], LinearRelative(Normal(50.0,2.0))), 1:(numNodes-1)) + facts = map( + n -> addFactor!( + dfg, + [verts[n], verts[n + 1]], + LinearRelative(Normal(50.0, 2.0)), + ), + 1:(numNodes - 1), + ) map(f -> setSolvable!(f, Int(round(rand()))), facts) map(f -> f.solverData.eliminated = rand() > 0.5, facts) map(f -> f.solverData.potentialused = rand() > 0.5, facts) updateFactor!.(dfg, facts) - - #test multihypo - addFactor!(dfg, [:x1, :x2, :x3], LinearRelative(Normal(50.0,2.0)), multihypo = [1, 0.3, 0.7]) + #test multihypo + addFactor!( + dfg, + [:x1, :x2, :x3], + LinearRelative(Normal(50.0, 2.0)); + multihypo = [1, 0.3, 0.7], + ) #test user/robot/session metadata - #test user/robot/session blob entries be = BlobEntry( - nothing, - nothing, - uuid4(), - :testing2, - :store, - "", - "", - "", - "", - "", - ZonedDateTime(2023, 2, 3, 20, tz"UTC+1"), - "BlobEntry", - string(DFG._getDFGVersion()) + nothing, + nothing, + uuid4(), + :testing2, + :store, + "", + "", + "", + "", + "", + ZonedDateTime(2023, 2, 3, 20, tz"UTC+1"), + "BlobEntry", + string(DFG._getDFGVersion()), ) addSessionBlobEntry!(dfg, be) @@ -73,14 +131,16 @@ using UUIDs setUserData!(dfg, smallUserData) setRobotData!(dfg, smallRobotData) setSessionData!(dfg, smallSessionData) - # Save and load the graph to test. saveDFG(filename, dfg) @info "Going to load $filename" copyDfg = DistributedFactorGraphs._getDuplicatedEmptyDFG(dfg) - @test_throws AssertionError loadDFG!(DistributedFactorGraphs._getDuplicatedEmptyDFG(dfg),"badfilename") + @test_throws AssertionError loadDFG!( + DistributedFactorGraphs._getDuplicatedEmptyDFG(dfg), + "badfilename", + ) retDFG = loadDFG!(copyDfg, filename) @@ -90,23 +150,26 @@ using UUIDs @test getVariable(dfg, var) == getVariable(retDFG, var) end for fact in lsf(dfg) - @test compareFactor(getFactor(dfg, fact), + @test compareFactor( + getFactor(dfg, fact), getFactor(retDFG, fact), - skip=[:timezone, :zone]) # Timezones - # :hypotheses, :certainhypo, :multihypo, # Multihypo - # :eliminated, - # :potentialused]) + skip = [:timezone, :zone], + ) # Timezones + # :hypotheses, :certainhypo, :multihypo, # Multihypo + # :eliminated, + # :potentialused]) end - + # Check data entries for v in ls(dfg) - @test getBlobEntries(getVariable(dfg, v)) == getBlobEntries(getVariable(retDFG, v)) + @test getBlobEntries(getVariable(dfg, v)) == + getBlobEntries(getVariable(retDFG, v)) @test issetequal(listPPEs(dfg, v), listPPEs(retDFG, v)) for ppe in listPPEs(dfg, v) @test getPPE(dfg, v, ppe) == getPPE(retDFG, v, ppe) end end - + # test the duplicate order #581 saveDFG(dfg, filename) end @@ -128,4 +191,4 @@ end end end -## \ No newline at end of file +## diff --git a/test/iifCompareTests.jl b/test/iifCompareTests.jl index 39c122cf..dfaac6b2 100644 --- a/test/iifCompareTests.jl +++ b/test/iifCompareTests.jl @@ -5,21 +5,20 @@ using IncrementalInference using Test @testset "testing compare functions for variables and factors..." begin - fg = initfg() v1 = addVariable!(fg, :x0, ContinuousScalar) f1 = addFactor!(fg, [:x0;], Prior(Normal())) - @test compareVariable(v1,v1) - @test compareFactor(f1,f1) + @test compareVariable(v1, v1) + @test compareFactor(f1, f1) v2 = addVariable!(fg, :x1, ContinuousScalar) - f2 = addFactor!(fg, [:x0;:x1], LinearRelative(Normal(2.0, 0.1))) + f2 = addFactor!(fg, [:x0; :x1], LinearRelative(Normal(2.0, 0.1))) fg2 = deepcopy(fg) - @test !compareVariable(v1,v2) + @test !compareVariable(v1, v2) # not testing different factors in this way # @test !compareFactor(f1,f2) @@ -42,53 +41,77 @@ using Test x1a = getVariable(fg, :x0) x1b = getVariable(fg2, :x0) - @test !compareVariable(x1a, x1b, skipsamples=false) + @test !compareVariable(x1a, x1b; skipsamples = false) - @test !compareSimilarVariables(fg, fg2, skipsamples=false) - @test !compareSimilarFactors(fg, fg2, skipsamples=false) + @test !compareSimilarVariables(fg, fg2; skipsamples = false) + @test !compareSimilarFactors(fg, fg2; skipsamples = false) @test compareFactorGraphs(fg, fg) - @test !compareFactorGraphs(fg, fg2, skipsamples=false) + @test !compareFactorGraphs(fg, fg2; skipsamples = false) initAll!(fg2) - @test compareSimilarVariables(fg, fg2, skipsamples=true, skip=Symbol[:infoPerCoord;:initialized;:inferdim;:ppeDict;:solvedCount]) + @test compareSimilarVariables( + fg, + fg2, + skipsamples = true, + skip = Symbol[:infoPerCoord; :initialized; :inferdim; :ppeDict; :solvedCount], + ) # fg2 has been solved, so it should fail on the estimate dictionary - @test !compareSimilarVariables(fg, fg2, skipsamples=true, skip=Symbol[:initialized;:inferdim]) + @test !compareSimilarVariables( + fg, + fg2; + skipsamples = true, + skip = Symbol[:initialized; :inferdim], + ) tree = buildTreeReset!(fg2) - @test compareSimilarFactors(fg, fg2, skipsamples=true, skipcompute=true, skip=[:fullvariables]) - - @test !compareSimilarFactors(fg, fg2, skipsamples=true, skipcompute=false) - - @test compareFactorGraphs(fg, fg2, skipsamples=true, skipcompute=true, skip=[:fullvariables; :infoPerCoord; :initialized; :inferdim; :ppeDict; :solvedCount]) - + @test compareSimilarFactors( + fg, + fg2, + skipsamples = true, + skipcompute = true, + skip = [:fullvariables], + ) + + @test !compareSimilarFactors(fg, fg2; skipsamples = true, skipcompute = false) + + @test compareFactorGraphs( + fg, + fg2, + skipsamples = true, + skipcompute = true, + skip = [ + :fullvariables + :infoPerCoord + :initialized + :inferdim + :ppeDict + :solvedCount + ], + ) end - - - @testset "test subgraph functions..." begin - fg = initfg() addVariable!(fg, :x0, ContinuousScalar) addFactor!(fg, [:x0;], Prior(Normal())) addVariable!(fg, :x1, ContinuousScalar) - addFactor!(fg, [:x0;:x1], LinearRelative(Normal(2.0, 0.1))) + addFactor!(fg, [:x0; :x1], LinearRelative(Normal(2.0, 0.1))) addVariable!(fg, :x2, ContinuousScalar) - addFactor!(fg, [:x1;:x2], LinearRelative(Normal(4.0, 0.1))) + addFactor!(fg, [:x1; :x2], LinearRelative(Normal(4.0, 0.1))) addVariable!(fg, :l1, ContinuousScalar) - addFactor!(fg, [:x1;:l1], LinearRelative(Rayleigh())) + addFactor!(fg, [:x1; :l1], LinearRelative(Rayleigh())) - sfg = buildSubgraph(GraphsDFG, fg, [:x0;:x1]) + sfg = buildSubgraph(GraphsDFG, fg, [:x0; :x1]) @warn "FIXME This is NOT supposed to pass" - @test_skip compareFactorGraphs(fg, sfg, skip=[:labelDict;:addHistory;:logpath]) + @test_skip compareFactorGraphs(fg, sfg, skip = [:labelDict; :addHistory; :logpath]) # drawGraph(sfg) end diff --git a/test/iifInterfaceTests.jl b/test/iifInterfaceTests.jl index ae741b04..ed7b7518 100644 --- a/test/iifInterfaceTests.jl +++ b/test/iifInterfaceTests.jl @@ -1,12 +1,12 @@ -global dfg,v1,v2,f1 +global dfg, v1, v2, f1 # Building simple graph... @testset "Building a simple Graph" begin - global dfg,v1,v2,f1 + global dfg, v1, v2, f1 # Use IIF to add the variables and factors - v1 = addVariable!(dfg, :a, Position{1}, tags = [:POSE], solvable=0) - v2 = addVariable!(dfg, :b, Position{1}, tags = [:LANDMARK], solvable=1) - f1 = addFactor!(dfg, [:a; :b], LinearRelative(Normal(50.0,2.0)), solvable=0) + v1 = addVariable!(dfg, :a, Position{1}; tags = [:POSE], solvable = 0) + v2 = addVariable!(dfg, :b, Position{1}; tags = [:LANDMARK], solvable = 1) + f1 = addFactor!(dfg, [:a; :b], LinearRelative(Normal(50.0, 2.0)); solvable = 0) end println() @@ -17,12 +17,36 @@ println() global dfg todotstr = toDot(dfg) #TODO consider using a regex, but for now test all orders - todota = cmp(todotstr, "graph graphname {\n2 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n") |> abs - todotb = cmp(todotstr, "graph graphname {\n2 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n") |> abs - todotc = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box];\na -- abf1\nb -- abf1\n}\n") |> abs - todotd = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box];\nb -- abf1\na -- abf1\n}\n") |> abs - todote = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\na -- abf1\nb -- abf1\n}\n") |> abs - todotf = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\nb -- abf1\na -- abf1\n}\n") |> abs + todota = + cmp( + todotstr, + "graph graphname {\n2 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n", + ) |> abs + todotb = + cmp( + todotstr, + "graph graphname {\n2 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n", + ) |> abs + todotc = + cmp( + todotstr, + "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box];\na -- abf1\nb -- abf1\n}\n", + ) |> abs + todotd = + cmp( + todotstr, + "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box];\nb -- abf1\na -- abf1\n}\n", + ) |> abs + todote = + cmp( + todotstr, + "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\na -- abf1\nb -- abf1\n}\n", + ) |> abs + todotf = + cmp( + todotstr, + "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\nb -- abf1\na -- abf1\n}\n", + ) |> abs # @show todota, todotb, todotc, todotd, todote, todotf @test (todota < 1 || todotb < 1 || todotc < 1 || todotd < 1 || todote < 1 || todotf < 1) @test toDotFile(dfg, "something.dot") === nothing @@ -34,20 +58,20 @@ end # dfg to copy to # creating a whole new graph with the same labels T = typeof(dfg) - dfg2 = T(solverParams=SolverParams(), userLabel="test@navability.io") + dfg2 = T(; solverParams = SolverParams(), userLabel = "test@navability.io") # Build a new in-memory IIF graph to transfer into the new graph. iiffg = initfg() v1 = deepcopy(addVariable!(iiffg, :a, Position{1})) v2 = deepcopy(addVariable!(iiffg, :b, Position{1})) v3 = deepcopy(addVariable!(iiffg, :c, Position{1})) - f1 = deepcopy(addFactor!(iiffg, [:a; :b], LinearRelative(Normal(50.0,2.0)) )) - f2 = deepcopy(addFactor!(iiffg, [:b; :c], LinearRelative(Normal(10.0,1.0)) )) + f1 = deepcopy(addFactor!(iiffg, [:a; :b], LinearRelative(Normal(50.0, 2.0)))) + f2 = deepcopy(addFactor!(iiffg, [:b; :c], LinearRelative(Normal(10.0, 1.0)))) # Add it to the new graph. @test addVariable!(dfg2, v1) == v1 @test addVariable!(dfg2, v2) == v2 - @test @test_logs (:warn, r"exist") match_mode=:any updateVariable!(dfg2, v3) == v3 + @test @test_logs (:warn, r"exist") match_mode = :any updateVariable!(dfg2, v3) == v3 @test_throws ErrorException addVariable!(dfg2, v3) @test addFactor!(dfg2, [v1, v2], f1) == f1 @test_throws ErrorException addFactor!(dfg2, [v1, v2], f1) @@ -61,7 +85,7 @@ end @test dv3.label == v3.label @test_throws ErrorException deleteVariable!(dfg2, v3) - @test issetequal(ls(dfg2),[:a,:b]) + @test issetequal(ls(dfg2), [:a, :b]) df2 = dv3facs[1] #TODO write compare if we want to compare complete one, for now just label # @test df2 == f2 @@ -69,29 +93,28 @@ end @test_throws ErrorException deleteFactor!(dfg2, f2) @test lsf(dfg2) == [:abf1] - end @testset "Listing Nodes" begin - global dfg,v1,v2,f1 + global dfg, v1, v2, f1 @test length(ls(dfg)) == 2 @test length(lsf(dfg)) == 1 # Unless we add the prior! @test symdiff([:a, :b], listVariables(dfg)) == [] @test listFactors(dfg) == [:abf1] # Unless we add the prior! # Additional testing for https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/201 - @test symdiff([:a, :b], listVariables(dfg, solvable=0)) == [] - @test listVariables(dfg, solvable=1) == [:b] - @test map(v->v.label, getVariables(dfg, solvable=1)) == [:b] + @test symdiff([:a, :b], listVariables(dfg; solvable = 0)) == [] + @test listVariables(dfg; solvable = 1) == [:b] + @test map(v -> v.label, getVariables(dfg; solvable = 1)) == [:b] @test listFactors(dfg) == [:abf1] - @test listFactors(dfg, solvable=1) == [] - @test listFactors(dfg, solvable=0) == [:abf1] - @test map(f->f.label, getFactors(dfg, solvable=0)) == [:abf1] - @test map(f->f.label, getFactors(dfg, solvable=1)) == [] + @test listFactors(dfg; solvable = 1) == [] + @test listFactors(dfg; solvable = 0) == [:abf1] + @test map(f -> f.label, getFactors(dfg; solvable = 0)) == [:abf1] + @test map(f -> f.label, getFactors(dfg; solvable = 1)) == [] # @test lsf(dfg, :a) == [f1.label] # Tags - @test ls(dfg, tags=[:POSE]) == [:a] - @test symdiff(ls(dfg, tags=[:POSE, :LANDMARK]), ls(dfg, tags=[:VARIABLE])) == [] + @test ls(dfg; tags = [:POSE]) == [:a] + @test symdiff(ls(dfg; tags = [:POSE, :LANDMARK]), ls(dfg; tags = [:VARIABLE])) == [] # Regexes @test ls(dfg, r"a") == [v1.label] # TODO: Check that this regular expression works on everything else! @@ -115,13 +138,12 @@ end @test !isVariable(dfg, :doesntexist) @test !isFactor(dfg, :doesntexist) - @test issetequal([:a,:b], listVariables(dfg)) + @test issetequal([:a, :b], listVariables(dfg)) @test issetequal([:abf1], listFactors(dfg)) # @test @test_deprecated getVariableIds(dfg) == listVariables(dfg) # @test @test_deprecated getFactorIds(dfg) == listFactors(dfg) - @test getFactorType(f1.solverData) === f1.solverData.fnc.usrfnc! @test getFactorType(f1) === f1.solverData.fnc.usrfnc! @test getFactorType(dfg, :abf1) === f1.solverData.fnc.usrfnc! @@ -136,22 +158,21 @@ end @test lsfWho(dfg, :LinearRelative) == [:abf1] @test getVariableType(v1) isa Position{1} - @test getVariableType(dfg,:a) isa Position{1} + @test getVariableType(dfg, :a) isa Position{1} #TODO what is lsTypes supposed to return? @test_broken lsTypes(dfg) @test issetequal(ls(dfg, Position{1}), [:a, :b]) - @test issetequal(lsWho(dfg, :Position),[:a, :b]) + @test issetequal(lsWho(dfg, :Position), [:a, :b]) varNearTs = findVariableNearTimestamp(dfg, now()) - @test_skip varNearTs[1][1] == [:b] - + @test_skip varNearTs[1][1] == [:b] end # Gets @testset "Gets, Sets, and Accessors" begin - global dfg,v1,v2,f1 + global dfg, v1, v2, f1 @test getVariable(dfg, v1.label) == v1 @test getFactor(dfg, f1.label) == f1 @test_throws Exception getVariable(dfg, :nope) @@ -180,7 +201,6 @@ end # legacy compat test @test getVariablePPEDict(v1) == v1.ppeDict # changed to .ppeDict -- delete by DFG v0.7 - @test typeof(getVariableType(v1)) == Position{1} @test typeof(getVariableType(v2)) == Position{1} @test typeof(getVariableType(v1)) == Position{1} @@ -208,39 +228,37 @@ end @test getUserData(dfg) == smallUserData @test getRobotData(dfg) == smallRobotData @test getSessionData(dfg) == smallSessionData - end @testset "Data Entries" begin - - de1 = BlobEntry( + de1 = BlobEntry(; originId = uuid4(), label = :key1, blobstore = :test, hash = "", origin = "", description = "", - mimeType = "" + mimeType = "", ) - de2 = BlobEntry( + de2 = BlobEntry(; originId = uuid4(), label = :key2, blobstore = :test, hash = "", origin = "", description = "", - mimeType = "" + mimeType = "", ) - de2_update = BlobEntry( + de2_update = BlobEntry(; originId = uuid4(), label = :key2, blobstore = :test, hash = "", origin = "", description = "", - mimeType = "image/jpg" + mimeType = "image/jpg", ) #add @@ -259,12 +277,16 @@ end #update @test updateBlobEntry!(dfg, :a, de2_update) == de2_update @test deepcopy(de2_update) == getBlobEntry(dfg, :a, :key2) - @test @test_logs (:warn, r"does not exist") match_mode=:any updateBlobEntry!(dfg, :b, de2_update) == de2_update + @test @test_logs (:warn, r"does not exist") match_mode = :any updateBlobEntry!( + dfg, + :b, + de2_update, + ) == de2_update #list entries = getBlobEntries(dfg, :a) @test length(entries) == 2 - @test issetequal(map(e->e.label, entries), [:key1, :key2]) + @test issetequal(map(e -> e.label, entries), [:key1, :key2]) @test length(getBlobEntries(dfg, :b)) == 1 @test issetequal(listBlobEntries(dfg, :a), [:key1, :key2]) @@ -305,7 +327,6 @@ end #Check if variable is updated @test getVariablePPEDict(newvar) == getVariablePPEDict(var1) - # Delete :default and replace to see if new ones can be added delete!(getVariablePPEDict(newvar), :default) #confirm delete @@ -318,37 +339,37 @@ end # TODO issue #166 @test getVariablePPEDict(newvar) != getVariablePPEDict(var1) - @test collect(keys(getVariablePPEDict(var1))) == [:default, :second] + @test collect(keys(getVariablePPEDict(var1))) == [:default, :second] # @test symdiff(collect(keys(getVariablePPE(getVariable(dfg, :a)))), [:default, :second]) == Symbol[] end # Connectivity test @testset "Connectivity Test" begin - global dfg,v1,v2,f1 + global dfg, v1, v2, f1 @test isConnected(dfg) == true # @test @test_deprecated isFullyConnected(dfg) == true # @test @test_deprecated hasOrphans(dfg) == false - addVariable!(dfg, :orphan, Position{1}, tags = [:POSE], solvable=0) + addVariable!(dfg, :orphan, Position{1}; tags = [:POSE], solvable = 0) @test isConnected(dfg) == false end # Adjacency matrices @testset "Adjacency Matrices" begin - global dfg,v1,v2,f1 + global dfg, v1, v2, f1 # Normal adjMat = DistributedFactorGraphs.getAdjacencyMatrixSymbols(dfg) - @test size(adjMat) == (2,4) + @test size(adjMat) == (2, 4) @test symdiff(adjMat[1, :], [nothing, :a, :b, :orphan]) == Symbol[] @test symdiff(adjMat[2, :], [:abf1, :abf1, :abf1, nothing]) == Symbol[] #sparse adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg) - @test size(adjMat) == (1,3) + @test size(adjMat) == (1, 3) # Checking the elements of adjacency, its not sorted so need indexing function - indexOf = (arr, el1) -> findfirst(el2->el2==el1, arr) + indexOf = (arr, el1) -> findfirst(el2 -> el2 == el1, arr) @test adjMat[1, indexOf(v_ll, :orphan)] == 0 @test adjMat[1, indexOf(v_ll, :a)] == 1 @test adjMat[1, indexOf(v_ll, :b)] == 1 @@ -356,12 +377,12 @@ end @test symdiff(f_ll, [:abf1, :abf1, :abf1]) == Symbol[] # Filtered - REF DFG #201 - adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg, solvable=1) - @test size(adjMat) == (0,1) + adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg; solvable = 1) + @test size(adjMat) == (0, 1) # sparse - adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg, solvable=1) - @test size(adjMat) == (0,1) + adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg; solvable = 1) + @test size(adjMat) == (0, 1) @test issetequal(v_ll, [:b]) @test f_ll == [] end @@ -379,12 +400,11 @@ end @test listVariables(dfg) == [] end - # Now make a complex graph for connectivity tests numNodes = 10 #change solvable and solveInProgress for x7,x8 for improved tests on x7x8f1 -verts = map(n -> addVariable!(dfg, Symbol("x$n"), Position{1}, tags = [:POSE]), 1:numNodes) +verts = map(n -> addVariable!(dfg, Symbol("x$n"), Position{1}; tags = [:POSE]), 1:numNodes) #TODO fix this to use accessors setSolvable!(verts[7], 1) setSolvable!(verts[8], 0) @@ -393,11 +413,18 @@ getSolverData(verts[8]).solveInProgress = 1 updateVariable!(dfg, verts[7]) updateVariable!(dfg, verts[8]) -facts = map(n -> - addFactor!(dfg, [verts[n], verts[n+1]], LinearRelative(Normal(50.0,2.0)),solvable=0), 1:(numNodes-1)) +facts = map( + n -> addFactor!( + dfg, + [verts[n], verts[n + 1]], + LinearRelative(Normal(50.0, 2.0)); + solvable = 0, + ), + 1:(numNodes - 1), +) @testset "Getting Neighbors" begin - global dfg,verts + global dfg, verts # Trivial test to validate that intersect([], []) returns order of first parameter @test intersect([:x3, :x2, :x1], [:x1, :x2]) == [:x2, :x1] # Get neighbors tests @@ -409,15 +436,14 @@ facts = map(n -> @test listNeighbors(dfg, :x1x2f1) == ls(dfg, :x1x2f1) # solvable checks - @test listNeighbors(dfg, :x5, solvable=1) == Symbol[] - @test symdiff(listNeighbors(dfg, :x5, solvable=0), [:x4x5f1,:x5x6f1]) == [] - @test symdiff(listNeighbors(dfg, :x5),[:x4x5f1,:x5x6f1]) == [] - @test listNeighbors(dfg, :x7x8f1, solvable=0) == [:x7, :x8] - @test listNeighbors(dfg, :x7x8f1, solvable=1) == [:x7] - @test listNeighbors(dfg, verts[1], solvable=0) == [:x1x2f1] - @test listNeighbors(dfg, verts[1], solvable=1) == Symbol[] + @test listNeighbors(dfg, :x5; solvable = 1) == Symbol[] + @test symdiff(listNeighbors(dfg, :x5; solvable = 0), [:x4x5f1, :x5x6f1]) == [] + @test symdiff(listNeighbors(dfg, :x5), [:x4x5f1, :x5x6f1]) == [] + @test listNeighbors(dfg, :x7x8f1; solvable = 0) == [:x7, :x8] + @test listNeighbors(dfg, :x7x8f1; solvable = 1) == [:x7] + @test listNeighbors(dfg, verts[1]; solvable = 0) == [:x1x2f1] + @test listNeighbors(dfg, verts[1]; solvable = 1) == Symbol[] @test listNeighbors(dfg, verts[1]) == [:x1x2f1] - end #TODO make sure similar testing exists then delete @@ -473,17 +499,19 @@ end for v in ls(summaryGraph) for field in variableFields if field != :variableTypeName - @test getproperty(getVariable(dfg, v), field) == getfield(getVariable(summaryGraph, v), field) + @test getproperty(getVariable(dfg, v), field) == + getfield(getVariable(summaryGraph, v), field) else # Special case to check the symbol variableType is equal to the full variableType. - @test Symbol(typeof(getVariableType(getVariable(dfg, v)))) == getVariableTypeName(getVariable(summaryGraph, v)) + @test Symbol(typeof(getVariableType(getVariable(dfg, v)))) == + getVariableTypeName(getVariable(summaryGraph, v)) end end end for f in lsf(summaryGraph) for field in factorFields - @test getproperty(getFactor(dfg, f), field) == getfield(getFactor(summaryGraph, f), field) + @test getproperty(getFactor(dfg, f), field) == + getfield(getFactor(summaryGraph, f), field) end end - end diff --git a/test/interfaceTests.jl b/test/interfaceTests.jl index c1a0ea0c..7a268f07 100644 --- a/test/interfaceTests.jl +++ b/test/interfaceTests.jl @@ -1,25 +1,24 @@ if false -using Test -using GraphPlot -using DistributedFactorGraphs -using Pkg -using Dates -using UUIDs -using TimeZones + using Test + using GraphPlot + using DistributedFactorGraphs + using Pkg + using Dates + using UUIDs + using TimeZones -include("testBlocks.jl") + include("testBlocks.jl") -testDFGAPI = GraphsDFG + testDFGAPI = GraphsDFG -# Enable debug logging -using Logging -logger = SimpleLogger(stdout, Logging.Debug) -global_logger(logger) - -# or -logger = ConsoleLogger(stdout, Logging.Debug) -global_logger(logger) + # Enable debug logging + using Logging + logger = SimpleLogger(stdout, Logging.Debug) + global_logger(logger) + # or + logger = ConsoleLogger(stdout, Logging.Debug) + global_logger(logger) end # DFG Accessors @@ -49,12 +48,10 @@ end global fac0, fac1, fac2 = DFGFactorSCA() end - @testset "Variables and Factors CRUD and SET" begin VariablesandFactorsCRUD_SET!(fg1, var1, var2, var3, fac0, fac1, fac2) end - @testset "Custom Printing" begin global var1, var2, var3, v1_tags, vorphan @@ -63,16 +60,19 @@ end @test printVariable(var1) === nothing @test printFactor(fac1) === nothing - @test printVariable(iobuf, var1, skipfields=[:timestamp, :solver, :ppe, :nstime]) === nothing - + @test printVariable(iobuf, var1; skipfields = [:timestamp, :solver, :ppe, :nstime]) === + nothing + # for julia v1.6 if DistributedFactorGraphs._getDFGVersion() < v"0.19" - @test String(take!(iobuf)) == "DFGVariable{TestVariableType1}\nid:\nnothing\nlabel:\n:a\ntags:\nSet([:VARIABLE, :POSE])\nsmallData:\nDict{Symbol, Union{Bool, Float64, Int64, Vector{Bool}, Vector{Float64}, Vector{Int64}, Vector{String}, String}}(:small=>\"data\")\ndataDict:\nDict{Symbol, DistributedFactorGraphs.BlobEntry}()\nsolvable:\n0\n" + @test String(take!(iobuf)) == + "DFGVariable{TestVariableType1}\nid:\nnothing\nlabel:\n:a\ntags:\nSet([:VARIABLE, :POSE])\nsmallData:\nDict{Symbol, Union{Bool, Float64, Int64, Vector{Bool}, Vector{Float64}, Vector{Int64}, Vector{String}, String}}(:small=>\"data\")\ndataDict:\nDict{Symbol, DistributedFactorGraphs.BlobEntry}()\nsolvable:\n0\n" else - @test String(take!(iobuf)) == "DFGVariable{TestVariableType1, Vector{Float64}, 1}\nid:\nnothing\nlabel:\n:a\ntags:\nSet([:VARIABLE, :POSE])\nsmallData:\nDict{Symbol, Union{Bool, Float64, Int64, Vector{Bool}, Vector{Float64}, Vector{Int64}, Vector{String}, String}}(:small=>\"data\")\ndataDict:\nDict{Symbol, BlobEntry}()\nsolvable:\n0\n" + @test String(take!(iobuf)) == + "DFGVariable{TestVariableType1, Vector{Float64}, 1}\nid:\nnothing\nlabel:\n:a\ntags:\nSet([:VARIABLE, :POSE])\nsmallData:\nDict{Symbol, Union{Bool, Float64, Int64, Vector{Bool}, Vector{Float64}, Vector{Int64}, Vector{String}, String}}(:small=>\"data\")\ndataDict:\nDict{Symbol, BlobEntry}()\nsolvable:\n0\n" end - @test printVariable(iobuf, var1, short=true) === nothing + @test printVariable(iobuf, var1; short = true) === nothing varstr = String(take!(iobuf)) @test occursin(r"DFGVariable", varstr) @test occursin(r"timestamp", varstr) @@ -80,13 +80,13 @@ end @test occursin(r"bandwidths", varstr) # == "DFGVariable{TestVariableType1}\nlabel: a\ntags: Set([:VARIABLE, :POSE])\nsize marginal samples: (1, 1)\nkde bandwidths: [0.0]\nNo PPEs\n" - - @test printFactor(iobuf, fac1, skipfields=[:timestamp, :solver, :nstime]) === nothing + @test printFactor(iobuf, fac1; skipfields = [:timestamp, :solver, :nstime]) === nothing @test occursin(r"DFGFactor.*\nid:\nnothing\nlabel:\n:abf1", String(take!(iobuf))) - String(take!(iobuf)) == "DFGFactor{TestCCW{TestFunctorInferenceType1}}\nid:\nnothing\nlabel:\n:abf1\ntags:\nSet([:tag1, :tag2])\nsolvable:\n0\nsolvable:\n1\n_variableOrderSymbols:\n[:a, :b]\n" + String(take!(iobuf)) == + "DFGFactor{TestCCW{TestFunctorInferenceType1}}\nid:\nnothing\nlabel:\n:abf1\ntags:\nSet([:tag1, :tag2])\nsolvable:\n0\nsolvable:\n1\n_variableOrderSymbols:\n[:a, :b]\n" - @test printFactor(iobuf, fac1, short=true) === nothing + @test printFactor(iobuf, fac1; short = true) === nothing @show teststr = String(take!(iobuf)) @test occursin(r"DFGFactor", teststr) @test occursin(r"label", teststr) @@ -100,9 +100,9 @@ end @test show(fac1) === nothing @test show(iobuf, MIME("text/plain"), var1) === nothing - isapprox(length(take!(iobuf)), 452, atol=10) + isapprox(length(take!(iobuf)), 452; atol = 10) @test show(iobuf, MIME("text/plain"), fac1) === nothing - isapprox(length(take!(iobuf)), 301, atol=10) + isapprox(length(take!(iobuf)), 301; atol = 10) @test printVariable(fg1, :a) === nothing @test printFactor(fg1, :abf1) === nothing @@ -118,7 +118,6 @@ end tagsTestBlock!(fg1, var1, v1_tags) end - @testset "Parametric Point Estimates" begin PPETestBlock!(fg1, var1) end @@ -141,7 +140,7 @@ end end @testset "TODO Sorteer groep" begin - if typeof(fg1) <: InMemoryDFGTypes + if typeof(fg1) <: InMemoryDFGTypes testGroup!(fg1, var1, var2, fac0, fac1) else @test_skip testGroup!(fg1, var1, var2, fac0, fac1) @@ -151,8 +150,7 @@ end # order up to here is important, TODO maybe make independant ## @testset "Adjacency Matrices" begin - - fg = testDFGAPI(userLabel="test@navability.io") + fg = testDFGAPI(; userLabel = "test@navability.io") addVariable!(fg, var1) setSolvable!(fg, :a, 1) addVariable!(fg, var2) @@ -160,7 +158,6 @@ end addVariable!(fg, vorphan) AdjacencyMatricesTestBlock(fg) - end @testset "Getting Neighbors" begin @@ -193,10 +190,9 @@ end ConnectivityTest(testDFGAPI) end - @testset "Copy Functions" begin rand(6) - fg = testDFGAPI(userLabel="test@navability.io") + fg = testDFGAPI(; userLabel = "test@navability.io") addVariable!(fg, var1) addVariable!(fg, var2) addVariable!(fg, var3) @@ -207,12 +203,11 @@ end # @test getVariableOrder(fg,:f1) == getVariableOrder(fgcopy,:f1) #test copyGraph, deepcopyGraph[!] - fgcopy = testDFGAPI(userLabel="test@navability.io") + fgcopy = testDFGAPI(; userLabel = "test@navability.io") DFG.deepcopyGraph!(fgcopy, fg) - @test getVariableOrder(fg,:abf1) == getVariableOrder(fgcopy,:abf1) + @test getVariableOrder(fg, :abf1) == getVariableOrder(fgcopy, :abf1) CopyFunctionsTest(testDFGAPI) - end @testset "File Save Functions" begin diff --git a/test/plottingTest.jl b/test/plottingTest.jl index 12c5b039..e8da1858 100644 --- a/test/plottingTest.jl +++ b/test/plottingTest.jl @@ -14,7 +14,16 @@ numNodes = 10 dfg = GraphsDFG{NoSolverParams}() verts = map(n -> DFGVariable(Symbol("x$n"), TestInferenceVariable1()), 1:numNodes) map(v -> addVariable!(dfg, v), verts) -map(n -> addFactor!(dfg, DFGFactor{TestFunctorInferenceType1}(Symbol("x$(n)x$(n+1)f1"), [verts[n].label, verts[n+1].label])), 1:(numNodes-1)) +map( + n -> addFactor!( + dfg, + DFGFactor{TestFunctorInferenceType1}( + Symbol("x$(n)x$(n+1)f1"), + [verts[n].label, verts[n + 1].label], + ), + ), + 1:(numNodes - 1), +) ## @@ -30,4 +39,4 @@ iobuf = IOBuffer() plotDFG(iobuf, MIME("application/prs.juno.plotpane+html"), dfg) @test length(take!(iobuf)) > 1e3 -## \ No newline at end of file +## diff --git a/test/runtests.jl b/test/runtests.jl index bf58157a..2e3ae496 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,10 +24,7 @@ end include("FactorGraphsTests.jl") end - -apis = [ - GraphsDFG, - ] +apis = [GraphsDFG] for api in apis @testset "Testing Driver: $(api)" begin @@ -38,7 +35,7 @@ for api in apis end # Test special cases - @testset "Plotting Tests" begin +@testset "Plotting Tests" begin include("plottingTest.jl") end @@ -47,7 +44,10 @@ end end @testset "GraphsDFG subtype tests" begin - for type in [(var=DFGVariableSummary, fac=DFGFactorSummary), (var=SkeletonDFGVariable,fac=SkeletonDFGFactor)] + for type in [ + (var = DFGVariableSummary, fac = DFGFactorSummary), + (var = SkeletonDFGVariable, fac = SkeletonDFGFactor), + ] @testset "$(type.var) and $(type.fac) tests" begin @info "Testing $(type.var) and $(type.fac)" global VARTYPE = type.var @@ -57,11 +57,12 @@ end end end - if get(ENV, "IIF_TEST", "true") == "true" # Switch to our upstream test branch. - Pkg.add(PackageSpec(name="IncrementalInference", rev="upstream/dfg_integration_test")) + Pkg.add( + PackageSpec(; name = "IncrementalInference", rev = "upstream/dfg_integration_test"), + ) @info "------------------------------------------------------------------------" @info "These tests are using IncrementalInference to do additional driver tests" @info "------------------------------------------------------------------------" @@ -69,7 +70,10 @@ if get(ENV, "IIF_TEST", "true") == "true" using IncrementalInference apis = Vector{AbstractDFG}() - push!(apis, GraphsDFG(solverParams=SolverParams(), userLabel="test@navability.io")) + push!( + apis, + GraphsDFG(; solverParams = SolverParams(), userLabel = "test@navability.io"), + ) for api in apis @testset "Testing Driver: $(typeof(api))" begin @@ -95,8 +99,8 @@ if get(ENV, "IIF_TEST", "true") == "true" # This is just to validate we're not going to blow up downstream. apis = [ # GraphsDFG{SolverParams}(), - GraphsDFG(solverParams=SolverParams(), userLabel="test@navability.io"), - ] + GraphsDFG(; solverParams = SolverParams(), userLabel = "test@navability.io"), + ] for api in apis @info "Running simple solver test: $(typeof(api))" global dfg = deepcopy(api) @@ -107,7 +111,6 @@ else @warn "Skipping IncrementalInference driver tests" end - struct NotImplementedDFG{T} <: AbstractDFG{T} end @testset "No Interface tests" begin @@ -138,5 +141,4 @@ struct NotImplementedDFG{T} <: AbstractDFG{T} end @test_throws ErrorException isVariable(dfg, :a) @test_throws ErrorException isFactor(dfg, :a) - end diff --git a/test/sandbox.jl b/test/sandbox.jl index 57490974..48a01c48 100644 --- a/test/sandbox.jl +++ b/test/sandbox.jl @@ -4,23 +4,26 @@ using Profile using BenchmarkTools using IncrementalInference -neo4jConnection = Neo4j.Connection("localhost", port=7474, user="neo4j",password= "test") +neo4jConnection = + Neo4j.Connection("localhost"; port = 7474, user = "neo4j", password = "test") graph = Neo4j.getgraph(neo4jConnection) neo4jInstance = Neo4jInstance(neo4jConnection, graph) -dfg = Neo4jDFG{SolverParams}(neo4jInstance, - "test@navability.io", - "DefaultRobot", - "Session_a892c5", - "Description of test session", - Symbol[], - SolverParams(), - createSessionNodes=false, - blobStores=Dict{Symbol, AbstractBlobStore}()) +dfg = Neo4jDFG{SolverParams}( + neo4jInstance, + "test@navability.io", + "DefaultRobot", + "Session_a892c5", + "Description of test session", + Symbol[], + SolverParams(); + createSessionNodes = false, + blobStores = Dict{Symbol, AbstractBlobStore}(), +) createDfgSessionIfNotExist(dfg) -v1 = addVariable!(dfg, :a, Position{1}, tags = [:POSE], solvable=0) -v2 = addVariable!(dfg, :b, ContinuousScalar, tags = [:LANDMARK], solvable=1) -f1 = addFactor!(dfg, [:a; :b], LinearRelative(Normal(50.0,2.0)), solvable=0) +v1 = addVariable!(dfg, :a, Position{1}; tags = [:POSE], solvable = 0) +v2 = addVariable!(dfg, :b, ContinuousScalar; tags = [:LANDMARK], solvable = 1) +f1 = addFactor!(dfg, [:a; :b], LinearRelative(Normal(50.0, 2.0)); solvable = 0) -lsWho(dfg, :Position) \ No newline at end of file +lsWho(dfg, :Position) diff --git a/test/solveTest.jl b/test/solveTest.jl index 56c57c8c..200eec7e 100644 --- a/test/solveTest.jl +++ b/test/solveTest.jl @@ -1,11 +1,11 @@ #TODO Test with standard generated graphs from IIF # Add some nodes. -v1 = addVariable!(dfg, :a, ContinuousScalar, tags = [:POSE]) -addFactor!(dfg, [:a], Prior(Normal(0,1))) -v2 = addVariable!(dfg, :b, ContinuousScalar, tags = [:POSE]) -v3 = addVariable!(dfg, :c, ContinuousScalar, tags = [:LANDMARK]) -f1 = addFactor!(dfg, [:a; :b], LinearRelative(Normal(50.0,2.0)) ) -f2 = addFactor!(dfg, [:b; :c], LinearRelative(Normal(50.0,2.0)) ) +v1 = addVariable!(dfg, :a, ContinuousScalar; tags = [:POSE]) +addFactor!(dfg, [:a], Prior(Normal(0, 1))) +v2 = addVariable!(dfg, :b, ContinuousScalar; tags = [:POSE]) +v3 = addVariable!(dfg, :c, ContinuousScalar; tags = [:LANDMARK]) +f1 = addFactor!(dfg, [:a; :b], LinearRelative(Normal(50.0, 2.0))) +f2 = addFactor!(dfg, [:b; :c], LinearRelative(Normal(50.0, 2.0))) # Solve it tree = solveTree!(dfg) diff --git a/test/testBlocks.jl b/test/testBlocks.jl index 248dd210..0be23655 100644 --- a/test/testBlocks.jl +++ b/test/testBlocks.jl @@ -14,12 +14,11 @@ import DistributedFactorGraphs: reconstFactorData # TestVariableType1() = new(1,(:Euclid,)) # end - Base.convert(::Type{<:Tuple}, ::typeof(Euclidean(1))) = (:Euclid,) Base.convert(::Type{<:Tuple}, ::typeof(Euclidean(2))) = (:Euclid, :Euclid) @defVariable TestVariableType1 Euclidean(1) [0.0;] -@defVariable TestVariableType2 Euclidean(2) [0;0.0] +@defVariable TestVariableType2 Euclidean(2) [0; 0.0] # struct TestVariableType2 <: InferenceVariable # dims::Int @@ -27,7 +26,6 @@ Base.convert(::Type{<:Tuple}, ::typeof(Euclidean(2))) = (:Euclid, :Euclid) # TestVariableType2() = new(2,(:Euclid,:Circular,)) # end - struct TestFunctorInferenceType1 <: AbstractRelative end struct TestFunctorInferenceType2 <: AbstractRelative end @@ -42,20 +40,25 @@ end function Base.convert(::Type{PackedTestFunctorInferenceType1}, d::TestFunctorInferenceType1) # @info "convert(::Type{PackedTestFunctorInferenceType1}, d::TestFunctorInferenceType1)" - PackedTestFunctorInferenceType1() + return PackedTestFunctorInferenceType1() end -function reconstFactorData(dfg::AbstractDFG, vo::AbstractVector, ::Type{TestFunctorInferenceType1}, d::PackedTestFunctorInferenceType1, ::String) - TestFunctorInferenceType1() +function reconstFactorData( + dfg::AbstractDFG, + vo::AbstractVector, + ::Type{TestFunctorInferenceType1}, + d::PackedTestFunctorInferenceType1, + ::String, +) + return TestFunctorInferenceType1() end # overly simplified test requires both reconstitute and convert -function Base.convert(::Type{TestFunctorInferenceType1}, d::PackedTestFunctorInferenceType1 ) +function Base.convert(::Type{TestFunctorInferenceType1}, d::PackedTestFunctorInferenceType1) # @info "convert(::Type{TestFunctorInferenceType1}, d::PackedTestFunctorInferenceType1)" - TestFunctorInferenceType1() + return TestFunctorInferenceType1() end - Base.@kwdef struct PackedTestAbstractPrior <: AbstractPackedFactor s::String = "" end @@ -63,55 +66,62 @@ end function Base.convert(::Type{PackedTestAbstractPrior}, d::TestAbstractPrior) # @info "convert(::Type{PackedTestAbstractPrior}, d::TestAbstractPrior)" - PackedTestAbstractPrior() + return PackedTestAbstractPrior() end function Base.convert(::Type{TestAbstractPrior}, d::PackedTestAbstractPrior) # @info "onvert(::Type{TestAbstractPrior}, d::PackedTestAbstractPrior)" - TestAbstractPrior() + return TestAbstractPrior() end struct TestCCW{T <: AbstractFactor} <: FactorOperationalMemory usrfnc!::T end -TestCCW{T}() where T = TestCCW(T()) +TestCCW{T}() where {T} = TestCCW(T()) Base.:(==)(a::TestCCW, b::TestCCW) = a.usrfnc! == b.usrfnc! DFG.getFactorOperationalMemoryType(par::NoSolverParams) = TestCCW DFG.rebuildFactorMetadata!(dfg::AbstractDFG{NoSolverParams}, fac::DFGFactor) = fac -function reconstFactorData(dfg::AbstractDFG, - vo::AbstractVector, - ::Type{<:DFG.FunctionNodeData{TestCCW{F}}}, - d::DFG.PackedFunctionNodeData{<:AbstractPackedFactor} ) where {F <: DFG.AbstractFactor} +function reconstFactorData( + dfg::AbstractDFG, + vo::AbstractVector, + ::Type{<:DFG.FunctionNodeData{TestCCW{F}}}, + d::DFG.PackedFunctionNodeData{<:AbstractPackedFactor}, +) where {F <: DFG.AbstractFactor} nF = convert(F, d.fnc) - return DFG.FunctionNodeData(d.eliminated, - d.potentialused, - d.edgeIDs, - TestCCW(nF), - d.multihypo, - d.certainhypo, - d.nullhypo, - d.solveInProgress, - d.inflation) + return DFG.FunctionNodeData( + d.eliminated, + d.potentialused, + d.edgeIDs, + TestCCW(nF), + d.multihypo, + d.certainhypo, + d.nullhypo, + d.solveInProgress, + d.inflation, + ) end -function Base.convert(::Type{DFG.PackedFunctionNodeData{P}}, d::DFG.FunctionNodeData{<:FactorOperationalMemory}) where P <: AbstractPackedFactor - return DFG.PackedFunctionNodeData(d.eliminated, - d.potentialused, - d.edgeIDs, - convert(P, d.fnc.usrfnc!), - d.multihypo, - d.certainhypo, - d.nullhypo, - d.solveInProgress, - d.inflation) +function Base.convert( + ::Type{DFG.PackedFunctionNodeData{P}}, + d::DFG.FunctionNodeData{<:FactorOperationalMemory}, +) where {P <: AbstractPackedFactor} + return DFG.PackedFunctionNodeData( + d.eliminated, + d.potentialused, + d.edgeIDs, + convert(P, d.fnc.usrfnc!), + d.multihypo, + d.certainhypo, + d.nullhypo, + d.solveInProgress, + d.inflation, + ) end - - ## # global testDFGAPI = GraphsDFG # T = testDFGAPI @@ -122,40 +132,54 @@ end # struct TestFunctorInferenceType1 <: AbstractFactor end # NOTE see note in AbstractDFG.jl setSolverParams! -struct GeenSolverParams <: AbstractParams -end +struct GeenSolverParams <: AbstractParams end -solparams=NoSolverParams() +solparams = NoSolverParams() # DFG Accessors -function DFGStructureAndAccessors(::Type{T}, solparams::AbstractParams=NoSolverParams()) where T <: AbstractDFG +function DFGStructureAndAccessors( + ::Type{T}, + solparams::AbstractParams = NoSolverParams(), +) where {T <: AbstractDFG} # "DFG Structure and Accessors" # Constructors # Constructors to be implemented - fg = T(solverParams=solparams, userLabel="test@navability.io") + fg = T(; solverParams = solparams, userLabel = "test@navability.io") #TODO test something better @test isa(fg, T) - @test getUserLabel(fg)=="test@navability.io" - @test getRobotLabel(fg)=="DefaultRobot" + @test getUserLabel(fg) == "test@navability.io" + @test getRobotLabel(fg) == "DefaultRobot" @test getSessionLabel(fg)[1:8] == "Session_" # Test the validation of the robot, session, and user IDs. - notAllowedList = ["!notValid", "1notValid", "_notValid", "USER", "ROBOT", "SESSION", - "VARIABLE", "FACTOR", "ENVIRONMENT", "PPE", "DATA_ENTRY", "FACTORGRAPH"] + notAllowedList = [ + "!notValid", + "1notValid", + "_notValid", + "USER", + "ROBOT", + "SESSION", + "VARIABLE", + "FACTOR", + "ENVIRONMENT", + "PPE", + "DATA_ENTRY", + "FACTORGRAPH", + ] for s in notAllowedList - @test_throws ErrorException T(solverParams=solparams, sessionLabel=s) - @test_throws ErrorException T(solverParams=solparams, robotLabel=s) - @test_throws ErrorException T(solverParams=solparams, userLabel=s) + @test_throws ErrorException T(solverParams = solparams, sessionLabel = s) + @test_throws ErrorException T(solverParams = solparams, robotLabel = s) + @test_throws ErrorException T(solverParams = solparams, userLabel = s) end des = "description for runtest" uId = "test@navability.io" rId = "testRobotId" sId = "testSessionId" - ud = Dict{Symbol,SmallDataTypes}(:ud=>"udEntry") - rd = Dict{Symbol,SmallDataTypes}(:rd=>"rdEntry") - sd = Dict{Symbol,SmallDataTypes}(:sd=>"sdEntry") - fg = T(des, uId, rId, sId, ud, rd, sd, solparams) + ud = Dict{Symbol, SmallDataTypes}(:ud => "udEntry") + rd = Dict{Symbol, SmallDataTypes}(:rd => "rdEntry") + sd = Dict{Symbol, SmallDataTypes}(:sd => "sdEntry") + fg = T(des, uId, rId, sId, ud, rd, sd, solparams) # accesssors # get @@ -187,15 +211,12 @@ function DFGStructureAndAccessors(::Type{T}, solparams::AbstractParams=NoSolverP @test getRobotData(fg) == smallRobotData @test getSessionData(fg) == smallSessionData - # NOTE see note in AbstractDFG.jl setSolverParams! @test_throws MethodError setSolverParams!(fg, GeenSolverParams()) == GeenSolverParams() - @test setSolverParams!(fg, typeof(solparams)()) == typeof(solparams)() - @test setDescription!(fg, des*"_1") == des*"_1" - + @test setDescription!(fg, des * "_1") == des * "_1" #TODO # duplicateEmptyDFG @@ -206,35 +227,34 @@ function DFGStructureAndAccessors(::Type{T}, solparams::AbstractParams=NoSolverP # copyEmptyDFG(sourceDFG::T) where T <: AbstractDFG = copyEmptyDFG(T, sourceDFG) return fg - end # User, Robot, Session Data -function UserRobotSessionData!(fg::AbstractDFG) +function UserRobotSessionData!(fg::AbstractDFG) # "User, Robot, Session Data" # User Data @test getUserData(fg, :a) == "42" #TODO @test_broken addUserData! - @test updateUserData!(fg, :b=>"1") == getUserData(fg) + @test updateUserData!(fg, :b => "1") == getUserData(fg) @test getUserData(fg, :b) == deleteUserData!(fg, :b) - @test emptyUserData!(fg) == Dict{Symbol,String}() + @test emptyUserData!(fg) == Dict{Symbol, String}() # Robot Data @test getRobotData(fg, :a) == "43" #TODO @test_broken addRobotData! - @test updateRobotData!(fg, :b=>"2") == getRobotData(fg) + @test updateRobotData!(fg, :b => "2") == getRobotData(fg) @test getRobotData(fg, :b) == deleteRobotData!(fg, :b) - @test emptyRobotData!(fg) == Dict{Symbol,String}() + @test emptyRobotData!(fg) == Dict{Symbol, String}() # SessionData @test getSessionData(fg, :a) == "44" #TODO @test_broken addSessionData! - @test updateSessionData!(fg, :b=>"3") == getSessionData(fg) + @test updateSessionData!(fg, :b => "3") == getSessionData(fg) @test getSessionData(fg, :b) == deleteSessionData!(fg, :b) - @test emptySessionData!(fg) == Dict{Symbol,String}() + @test emptySessionData!(fg) == Dict{Symbol, String}() # TODO Set-like if we want eg. list, merge, etc # listUserData @@ -247,19 +267,18 @@ function UserRobotSessionData!(fg::AbstractDFG) end # User, Robot, Session Data Blob Entries -function UserRobotSessionBlobEntries!(fg::AbstractDFG) - - be = BlobEntry( - id = uuid4(), +function UserRobotSessionBlobEntries!(fg::AbstractDFG) + be = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :key1, - blobstore = :b, + label = :key1, + blobstore = :b, hash = "", origin = "", description = "", - mimeType = "", - metadata = "" + mimeType = "", + metadata = "", ) # User Blob Entries @@ -273,9 +292,8 @@ function UserRobotSessionBlobEntries!(fg::AbstractDFG) @test ae == be ge = getSessionBlobEntry(fg, :key1) @test ge == be - - #TODO + #TODO end @@ -284,14 +302,34 @@ function DFGVariableSCA() v1_lbl = :a v1_tags = Set([:VARIABLE, :POSE]) - small = Dict{Symbol, SmallDataTypes}(:small=>"data") + small = Dict{Symbol, SmallDataTypes}(:small => "data") testTimestamp = now(localzone()) # Constructors - v1 = DFGVariable(v1_lbl, TestVariableType1(), tags=v1_tags, solvable=0, solverDataDict=Dict(:default=>VariableNodeData{TestVariableType1}())) - v2 = DFGVariable(:b, VariableNodeData{TestVariableType2}(), tags=Set([:VARIABLE, :LANDMARK])) - v3 = DFGVariable(:c, VariableNodeData{TestVariableType2}(), timestamp=ZonedDateTime("2020-08-11T00:12:03.000-05:00")) + v1 = DFGVariable( + v1_lbl, + TestVariableType1(); + tags = v1_tags, + solvable = 0, + solverDataDict = Dict(:default => VariableNodeData{TestVariableType1}()), + ) + v2 = DFGVariable( + :b, + VariableNodeData{TestVariableType2}(); + tags = Set([:VARIABLE, :LANDMARK]), + ) + v3 = DFGVariable( + :c, + VariableNodeData{TestVariableType2}(); + timestamp = ZonedDateTime("2020-08-11T00:12:03.000-05:00"), + ) - vorphan = DFGVariable(:orphan, TestVariableType1(), tags=v1_tags, solvable=0, solverDataDict=Dict(:default=>VariableNodeData{TestVariableType1}())) + vorphan = DFGVariable( + :orphan, + TestVariableType1(); + tags = v1_tags, + solvable = 0, + solverDataDict = Dict(:default => VariableNodeData{TestVariableType1}()), + ) # v1.solverDataDict[:default].val[1] = [0.0;] # v1.solverDataDict[:default].bw[1] = [1.0;] @@ -300,7 +338,6 @@ function DFGVariableSCA() # v3.solverDataDict[:default].val[1] = [0.0;0.0] # v3.solverDataDict[:default].bw[1] = [1.0;1.0] - getSolverData(v1).solveInProgress = 1 @test getLabel(v1) == v1_lbl @@ -316,11 +353,10 @@ function DFGVariableSCA() @test getPPEDict(v1) == v1.ppeDict - @test getSmallData(v1) == Dict{Symbol,SmallDataTypes}() + @test getSmallData(v1) == Dict{Symbol, SmallDataTypes}() @test getVariableType(v1) == TestVariableType1() - #TODO here for now, don't reccomend usage. testTags = [:tag1, :tag2] @test setTags!(v3, testTags) == Set(testTags) @@ -357,13 +393,10 @@ function DFGVariableSCA() # isSolved # setSolvedCount - return (v1=v1, v2=v2, v3=v3, vorphan = vorphan, v1_tags=v1_tags) - + return (v1 = v1, v2 = v2, v3 = v3, vorphan = vorphan, v1_tags = v1_tags) end - - -function DFGFactorSCA() +function DFGFactorSCA() # "DFG Factor" # Constructors @@ -372,18 +405,21 @@ function DFGFactorSCA() f1_tags = Set([:FACTOR]) testTimestamp = now(localzone()) - gfnd_prior = GenericFunctionNodeData(fnc=TestCCW(TestAbstractPrior())) + gfnd_prior = GenericFunctionNodeData(; fnc = TestCCW(TestAbstractPrior())) - gfnd = GenericFunctionNodeData(fnc=TestCCW(TestFunctorInferenceType1())) + gfnd = GenericFunctionNodeData(; fnc = TestCCW(TestFunctorInferenceType1())) - f1 = DFGFactor{TestCCW{TestFunctorInferenceType1}}(f1_lbl, [:a,:b]) - f1 = DFGFactor(f1_lbl, [:a,:b], gfnd, tags = f1_tags, solvable=0) + f1 = DFGFactor{TestCCW{TestFunctorInferenceType1}}(f1_lbl, [:a, :b]) + f1 = DFGFactor(f1_lbl, [:a, :b], gfnd; tags = f1_tags, solvable = 0) - f2 = DFGFactor{TestCCW{TestFunctorInferenceType1}}(:bcf1, [:b, :c], ZonedDateTime("2020-08-11T00:12:03.000-05:00")) + f2 = DFGFactor{TestCCW{TestFunctorInferenceType1}}( + :bcf1, + [:b, :c], + ZonedDateTime("2020-08-11T00:12:03.000-05:00"), + ) #TODO add tests for mutating vos in updateFactor and orphan related checks. # we should perhaps prevent an empty vos - @test getLabel(f1) == f1_lbl @test getTags(f1) == f1_tags @@ -391,10 +427,9 @@ function DFGFactorSCA() @test getSolvable(f1) == 0 - @test getSolverData(f1) === f1.solverData - @test getVariableOrder(f1) == [:a,:b] + @test getVariableOrder(f1) == [:a, :b] getSolverData(f1).solveInProgress = 1 @test setSolvable!(f1, 1) == 1 @@ -403,7 +438,6 @@ function DFGFactorSCA() @test typeof(getFactorType(f1)) == TestFunctorInferenceType1 @test typeof(getFactorFunction(f1)) == TestFunctorInferenceType1 - #TODO here for now, don't recommend usage. testTags = [:tag1, :tag2] @test setTags!(f1, testTags) == Set(testTags) @@ -427,17 +461,17 @@ function DFGFactorSCA() @test setSolverData!(f1, deepcopy(gfnd)) == gfnd # create f0 here for a later timestamp - f0 = DFGFactor(:af1, [:a], gfnd_prior, tags = Set([:PRIOR])) + f0 = DFGFactor(:af1, [:a], gfnd_prior; tags = Set([:PRIOR])) #fill in undefined fields # f2.solverData.certainhypo = Int[] # f2.solverData.multihypo = Float64[] # f2.solverData.edgeIDs = Int64[] - return (f0=f0, f1=f1, f2=f2) + return (f0 = f0, f1 = f1, f2 = f2) end -function VariablesandFactorsCRUD_SET!(fg, v1, v2, v3, f0, f1, f2) +function VariablesandFactorsCRUD_SET!(fg, v1, v2, v3, f0, f1, f2) # "Variables and Factors CRUD an SET" #TODO dont throw ErrorException @@ -446,145 +480,164 @@ function VariablesandFactorsCRUD_SET!(fg, v1, v2, v3, f0, f1, f2) # fg = GraphsDFG(solverParams=NoSolverParams()) # fg = GraphsDFG(solverParams=NoSolverParams()) # add update delete -@test addVariable!(fg, v1) == v1 -@test addVariable!(fg, v2) == v2 - -# test getindex -@test getLabel(fg[getLabel(v1)]) == getLabel(v1) - -#TODO standardize this error and res also for that matter -@test_throws Exception addFactor!(fg, [:a, :nope], f1) -@test_throws Exception addFactor!(fg, [v1, v2, v3], f1) - -@test addFactor!(fg, [v1, v2], f1) == f1 -@test_throws ErrorException addFactor!(fg, [v1, v2], f1) - -@test getLabel(fg[getLabel(f1)]) == getLabel(f1) - -@test @test_logs (:warn, Regex("'$(v3.label)' does not exist")) match_mode=:any updateVariable!(fg, v3) == v3 -@test updateVariable!(fg, v3) == v3 -@test_throws ErrorException addVariable!(fg, v3) - -@test @test_logs (:warn, Regex("'$(f2.label)' does not exist")) match_mode=:any updateFactor!(fg, f2) === f2 -@test updateFactor!(fg, f2) === f2 -@test_throws ErrorException addFactor!(fg, [:b, :c], f2) -#TODO Graphs.jl, but look at refactoring absract @test_throws ErrorException addFactor!(fg, f2) - - -if f2 isa DFGFactor - f2_mod = DFGFactor(f2.label, f2.timestamp, f2.nstime, f2.tags, f2.solverData, f2.solvable, (:a,)) -else - f2_mod = deepcopy(f2) - pop!(f2_mod._variableOrderSymbols) -end + @test addVariable!(fg, v1) == v1 + @test addVariable!(fg, v2) == v2 + + # test getindex + @test getLabel(fg[getLabel(v1)]) == getLabel(v1) + + #TODO standardize this error and res also for that matter + @test_throws Exception addFactor!(fg, [:a, :nope], f1) + @test_throws Exception addFactor!(fg, [v1, v2, v3], f1) + + @test addFactor!(fg, [v1, v2], f1) == f1 + @test_throws ErrorException addFactor!(fg, [v1, v2], f1) + + @test getLabel(fg[getLabel(f1)]) == getLabel(f1) + + @test @test_logs (:warn, Regex("'$(v3.label)' does not exist")) match_mode = :any updateVariable!( + fg, + v3, + ) == v3 + @test updateVariable!(fg, v3) == v3 + @test_throws ErrorException addVariable!(fg, v3) + + @test @test_logs (:warn, Regex("'$(f2.label)' does not exist")) match_mode = :any updateFactor!( + fg, + f2, + ) === f2 + @test updateFactor!(fg, f2) === f2 + @test_throws ErrorException addFactor!(fg, [:b, :c], f2) + #TODO Graphs.jl, but look at refactoring absract @test_throws ErrorException addFactor!(fg, f2) + + if f2 isa DFGFactor + f2_mod = DFGFactor( + f2.label, + f2.timestamp, + f2.nstime, + f2.tags, + f2.solverData, + f2.solvable, + (:a,), + ) + else + f2_mod = deepcopy(f2) + pop!(f2_mod._variableOrderSymbols) + end -@test_throws ErrorException updateFactor!(fg, f2_mod) -@test issetequal(lsf(fg), [:bcf1, :abf1]) + @test_throws ErrorException updateFactor!(fg, f2_mod) + @test issetequal(lsf(fg), [:bcf1, :abf1]) -@test getAddHistory(fg) == [:a, :b, :c] + @test getAddHistory(fg) == [:a, :b, :c] -# Extra timestamp functions https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/315 -if !(v1 isa SkeletonDFGVariable) - newtimestamp = now(localzone()) - @test !(setTimestamp!(fg, :c, newtimestamp) === v3) - @test getVariable(fg, :c) |> getTimestamp == newtimestamp + # Extra timestamp functions https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/315 + if !(v1 isa SkeletonDFGVariable) + newtimestamp = now(localzone()) + @test !(setTimestamp!(fg, :c, newtimestamp) === v3) + @test getVariable(fg, :c) |> getTimestamp == newtimestamp - @test !(setTimestamp!(fg, :bcf1, newtimestamp) === f2) - @test getFactor(fg, :bcf1) |> getTimestamp == newtimestamp -end -#deletions -delvarCompare = getVariable(fg, :c) -delfacCompare = getFactor(fg, :bcf1) -delvar, delfacs = deleteVariable!(fg, v3) -@test delvarCompare == delvar -@test delfacCompare == delfacs[1] -@test_throws ErrorException deleteVariable!(fg, v3) -@test setdiff(ls(fg),[:a,:b]) == [] - -@test addVariable!(fg, v3) === v3 -@test addFactor!(fg, f2) === f2 - -@test getFactor(fg, :bcf1) == deleteFactor!(fg, f2) -@test_throws ErrorException deleteFactor!(fg, f2) -@test lsf(fg) == [:abf1] - -delvarCompare = getVariable(fg, :c) -delfacCompare = [] -delvar, delfacs = deleteVariable!(fg, v3) -@test delvarCompare == delvar -@test delfacCompare == [] - -@test getVariable(fg, :a) == v1 -@test getVariable(fg, :a, :default) == v1 - -@test addFactor!(fg, f0) == f0 - -if isa(v1, DFGVariable) - #TODO decide if this should be @error or other type - @test_throws ErrorException getVariable(fg, :a, :missingfoo) -else - @test_logs (:warn, r"supported for type DFGVariable") getVariable(fg, :a, :missingfoo) -end + @test !(setTimestamp!(fg, :bcf1, newtimestamp) === f2) + @test getFactor(fg, :bcf1) |> getTimestamp == newtimestamp + end + #deletions + delvarCompare = getVariable(fg, :c) + delfacCompare = getFactor(fg, :bcf1) + delvar, delfacs = deleteVariable!(fg, v3) + @test delvarCompare == delvar + @test delfacCompare == delfacs[1] + @test_throws ErrorException deleteVariable!(fg, v3) + @test setdiff(ls(fg), [:a, :b]) == [] + + @test addVariable!(fg, v3) === v3 + @test addFactor!(fg, f2) === f2 + + @test getFactor(fg, :bcf1) == deleteFactor!(fg, f2) + @test_throws ErrorException deleteFactor!(fg, f2) + @test lsf(fg) == [:abf1] + + delvarCompare = getVariable(fg, :c) + delfacCompare = [] + delvar, delfacs = deleteVariable!(fg, v3) + @test delvarCompare == delvar + @test delfacCompare == [] + + @test getVariable(fg, :a) == v1 + @test getVariable(fg, :a, :default) == v1 + + @test addFactor!(fg, f0) == f0 + + if isa(v1, DFGVariable) + #TODO decide if this should be @error or other type + @test_throws ErrorException getVariable(fg, :a, :missingfoo) + else + @test_logs (:warn, r"supported for type DFGVariable") getVariable( + fg, + :a, + :missingfoo, + ) + end -@test getFactor(fg, :abf1) == f1 + @test getFactor(fg, :abf1) == f1 -@test_throws ErrorException getVariable(fg, :c) -@test_throws ErrorException getFactor(fg, :bcf1) + @test_throws ErrorException getVariable(fg, :c) + @test_throws ErrorException getFactor(fg, :bcf1) -#test issue #375 -@test_throws ErrorException getVariable(fg, :abf1) -@test_throws ErrorException getFactor(fg, :a) + #test issue #375 + @test_throws ErrorException getVariable(fg, :abf1) + @test_throws ErrorException getFactor(fg, :a) -# Existence -@test exists(fg, :a) -@test !exists(fg, :c) -@test exists(fg, :abf1) -@test !exists(fg, :bcf1) + # Existence + @test exists(fg, :a) + @test !exists(fg, :c) + @test exists(fg, :abf1) + @test !exists(fg, :bcf1) -@test exists(fg, v1) -@test !exists(fg, v3) -@test exists(fg, f1) -@test !exists(fg, f2) + @test exists(fg, v1) + @test !exists(fg, v3) + @test exists(fg, f1) + @test !exists(fg, f2) -# check types -@test isVariable(fg, :a) -@test !isVariable(fg, :abf1) + # check types + @test isVariable(fg, :a) + @test !isVariable(fg, :abf1) -@test isFactor(fg, :abf1) -@test !isFactor(fg, :a) + @test isFactor(fg, :abf1) + @test !isFactor(fg, :a) -if f0 isa DFGFactor - @test isPrior(fg, :af1) - @test !isPrior(fg, :abf1) -end + if f0 isa DFGFactor + @test isPrior(fg, :af1) + @test !isPrior(fg, :abf1) + end -#list -@test length(getVariables(fg)) == 2 -@test issetequal(getLabel.(getFactors(fg)), [:af1, :abf1]) + #list + @test length(getVariables(fg)) == 2 + @test issetequal(getLabel.(getFactors(fg)), [:af1, :abf1]) -@test issetequal([:a,:b], listVariables(fg)) -@test issetequal([:af1,:abf1], listFactors(fg)) + @test issetequal([:a, :b], listVariables(fg)) + @test issetequal([:af1, :abf1], listFactors(fg)) -@test ls(fg) == listVariables(fg) -@test lsf(fg) == listFactors(fg) + @test ls(fg) == listVariables(fg) + @test lsf(fg) == listFactors(fg) -if getVariable(fg, ls(fg)[1]) isa DFGVariable - @test :default in listSolveKeys(fg) - @test :default in listSolveKeys(fg, r"a"; filterSolveKeys=r"default") - @test :default in listSupersolves(fg) -end + if getVariable(fg, ls(fg)[1]) isa DFGVariable + @test :default in listSolveKeys(fg) + @test :default in listSolveKeys(fg, r"a"; filterSolveKeys = r"default") + @test :default in listSupersolves(fg) + end -# simple broadcast test -if f0 isa DFGFactor - @test issetequal(getFactorType.(fg, lsf(fg)), [TestFunctorInferenceType1(), TestAbstractPrior()]) -end -@test getVariable.(fg, [:a]) == [getVariable(fg, :a)] + # simple broadcast test + if f0 isa DFGFactor + @test issetequal( + getFactorType.(fg, lsf(fg)), + [TestFunctorInferenceType1(), TestAbstractPrior()], + ) + end + @test getVariable.(fg, [:a]) == [getVariable(fg, :a)] end - -function tagsTestBlock!(fg, v1, v1_tags) -# "tags" -# +function tagsTestBlock!(fg, v1, v1_tags) + # "tags" + # v1Tags = deepcopy(getTags(v1)) @test issetequal(v1Tags, v1_tags) @test issetequal(listTags(fg, :a), v1Tags) @@ -592,18 +645,15 @@ function tagsTestBlock!(fg, v1, v1_tags) @test issetequal(removeTags!(fg, :a, [:TAG]), v1Tags) @test emptyTags!(fg, :a) == Set{Symbol}() - v2Tags = [listTags(fg, :b)...] @test hasTags(fg, :b, [v2Tags...]) - @test hasTags(fg, :b, [:LANDMARK, :TAG], matchAll=false) + @test hasTags(fg, :b, [:LANDMARK, :TAG], matchAll = false) @test hasTagsNeighbors(fg, :abf1, [:LANDMARK]) @test !hasTagsNeighbors(fg, :abf1, [:LANDMARK, :TAG]) - end - -function PPETestBlock!(fg, v1) +function PPETestBlock!(fg, v1) # "Parametric Point Estimates" # - `getPPEs` @@ -636,7 +686,11 @@ function PPETestBlock!(fg, v1) @test_throws KeyError getPPE(fg, :a, :default) # Update add it - @test @test_logs (:warn, Regex("'$(ppe.solveKey)' does not exist")) match_mode=:any updatePPE!(fg, :a, ppe) == ppe + @test @test_logs (:warn, Regex("'$(ppe.solveKey)' does not exist")) match_mode = :any updatePPE!( + fg, + :a, + ppe, + ) == ppe # Update update it @test updatePPE!(fg, :a, ppe) == ppe @test deletePPE!(fg, :a, :default) == ppe @@ -698,35 +752,34 @@ function PPETestBlock!(fg, v1) # @test symdiff(collect(keys(getVariablePPEs(getVariable(dfg, :a)))), [:default, :second]) == Symbol[] #update - ## TODO make sure these are covered - # global dfg - # #get the variable - # var1 = getVariable(dfg, :a) - # #make a copy and simulate external changes - # newvar = deepcopy(var1) - # getVariablePPEs(newvar)[:default] = MeanMaxPPE(:default, [150.0], [100.0], [50.0]) - # #update - # mergeUpdateVariableSolverData!(dfg, newvar) - # #For now spot check - # # @test solverDataDict(newvar) == solverDataDict(var1) - # @test getVariablePPEs(newvar) == getVariablePPEs(var1) - # - # # Delete :default and replace to see if new ones can be added - # delete!(getVariablePPEs(newvar), :default) - # getVariablePPEs(newvar)[:second] = MeanMaxPPE(:second, [15.0], [10.0], [5.0]) - # - # # Persist to the original variable. - # mergeUpdateVariableSolverData!(dfg, newvar) - # # At this point newvar will have only :second, and var1 should have both (it is the reference) - # @test symdiff(collect(keys(getVariablePPEs(var1))), [:default, :second]) == Symbol[] - # @test symdiff(collect(keys(getVariablePPEs(newvar))), [:second]) == Symbol[] - # # Get the source too. - # @test symdiff(collect(keys(getVariablePPEs(getVariable(dfg, :a)))), [:default, :second]) == Symbol[] + # global dfg + # #get the variable + # var1 = getVariable(dfg, :a) + # #make a copy and simulate external changes + # newvar = deepcopy(var1) + # getVariablePPEs(newvar)[:default] = MeanMaxPPE(:default, [150.0], [100.0], [50.0]) + # #update + # mergeUpdateVariableSolverData!(dfg, newvar) + # #For now spot check + # # @test solverDataDict(newvar) == solverDataDict(var1) + # @test getVariablePPEs(newvar) == getVariablePPEs(var1) + # + # # Delete :default and replace to see if new ones can be added + # delete!(getVariablePPEs(newvar), :default) + # getVariablePPEs(newvar)[:second] = MeanMaxPPE(:second, [15.0], [10.0], [5.0]) + # + # # Persist to the original variable. + # mergeUpdateVariableSolverData!(dfg, newvar) + # # At this point newvar will have only :second, and var1 should have both (it is the reference) + # @test symdiff(collect(keys(getVariablePPEs(var1))), [:default, :second]) == Symbol[] + # @test symdiff(collect(keys(getVariablePPEs(newvar))), [:second]) == Symbol[] + # # Get the source too. + # @test symdiff(collect(keys(getVariablePPEs(getVariable(dfg, :a)))), [:default, :second]) == Symbol[] ## end -function VSDTestBlock!(fg, v1) +function VSDTestBlock!(fg, v1) # "Variable Solver Data" # #### Variable Solver Data # **CRUD** @@ -747,7 +800,7 @@ function VSDTestBlock!(fg, v1) # **VariableNodeData** # - `getSolveInProgress` - vnd = VariableNodeData{TestVariableType1}(solveKey=:parametric) + vnd = VariableNodeData{TestVariableType1}(; solveKey = :parametric) # vnd.val[1] = [0.0;] # vnd.bw[1] = [1.0;] @test addVariableSolverData!(fg, :a, vnd) == vnd @@ -760,11 +813,11 @@ function VSDTestBlock!(fg, v1) vndBack = getVariableSolverData(fg, :a, :parametric) @test vndBack == vnd - # Delete it @test deleteVariableSolverData!(fg, :a, :parametric) == vndBack # Update add it - @test @test_logs (:warn, r"does not exist") updateVariableSolverData!(fg, :a, vnd) == vnd + @test @test_logs (:warn, r"does not exist") updateVariableSolverData!(fg, :a, vnd) == + vnd # Update update it @test updateVariableSolverData!(fg, :a, vnd) == vnd @@ -779,7 +832,7 @@ function VSDTestBlock!(fg, v1) retVnd = updateVariableSolverData!(fg, :a, altVnd, false, [:infoPerCoord;]) @test retVnd == altVnd - altVnd.bw = -ones(1,1) + altVnd.bw = -ones(1, 1) retVnd = updateVariableSolverData!(fg, :a, altVnd, false, [:bw;]) @test retVnd == altVnd @@ -787,9 +840,10 @@ function VSDTestBlock!(fg, v1) @test retVnd != altVnd # restore without copy - @test updateVariableSolverData!(fg, :a, keepVnd, false, [:infoPerCoord;:bw]) == vnd - @test getSolverData(getVariable(fg, :a), :parametric).infoPerCoord[1] != altVnd.infoPerCoord[1] - @test getSolverData(getVariable(fg, :a), :parametric).bw != altVnd.bw + @test updateVariableSolverData!(fg, :a, keepVnd, false, [:infoPerCoord; :bw]) == vnd + @test getSolverData(getVariable(fg, :a), :parametric).infoPerCoord[1] != + altVnd.infoPerCoord[1] + @test getSolverData(getVariable(fg, :a), :parametric).bw != altVnd.bw # Delete parametric from v1 @test deleteVariableSolverData!(fg, :a, :parametric) == vnd @@ -802,10 +856,10 @@ function VSDTestBlock!(fg, v1) # Add new VND of type ContinuousScalar to :x0 # Could also do VariableNodeData(ContinuousScalar()) - vnd = VariableNodeData{TestVariableType1}(solveKey=:parametric) + vnd = VariableNodeData{TestVariableType1}(; solveKey = :parametric) # vnd.val[1] = [0.0;] # vnd.bw[1] = [1.0;] - + addVariableSolverData!(fg, :a, vnd) @test setdiff(listVariableSolverData(fg, :a), [:default, :parametric]) == [] # Get the data back - note that this is a reference to above. @@ -820,7 +874,7 @@ function VSDTestBlock!(fg, v1) # Bulk copy update x0 updateVariableSolverData!(fg, [v1], :default) # Delete parametric from v1 - deleteVariableSolverData!(fg, :a, :parametric) + return deleteVariableSolverData!(fg, :a, :parametric) #TODO # mergeVariableSolverData!(...) @@ -838,42 +892,37 @@ function VSDTestBlock!(fg, v1) end function smallDataTestBlock!(fg) - @test listSmallData(fg, :a) == Symbol[:small] @test listSmallData(fg, :b) == Symbol[] @test small = getSmallData(fg, :a, :small) == "data" - @test addSmallData!(fg, :a, :a=>5) == getVariable(fg, :a).smallData - @test addSmallData!(fg, :a, :b=>10.0) == getVariable(fg, :a).smallData - @test addSmallData!(fg, :a, :c=>true) == getVariable(fg, :a).smallData - @test addSmallData!(fg, :a, :d=>"yes") == getVariable(fg, :a).smallData - @test addSmallData!(fg, :a, :e=>[1, 2, 3]) == getVariable(fg, :a).smallData - @test addSmallData!(fg, :a, :f=>[1.4, 2.5, 3.6]) == getVariable(fg, :a).smallData - @test addSmallData!(fg, :a, :g=>["yes", "maybe"]) == getVariable(fg, :a).smallData - @test addSmallData!(fg, :a, :h=>[true, false]) == getVariable(fg, :a).smallData - - @test_throws ErrorException addSmallData!(fg, :a, :a=>3) - @test updateSmallData!(fg, :a, :a=>3) == getVariable(fg, :a).smallData - - @test_throws MethodError addSmallData!(fg, :a, :no=>0x01) - @test_throws MethodError addSmallData!(fg, :a, :no=>1f0) - @test_throws MethodError addSmallData!(fg, :a, :no=>Nanosecond(3)) - @test_throws MethodError addSmallData!(fg, :a, :no=>[0x01]) - @test_throws MethodError addSmallData!(fg, :a, :no=>[1f0]) - @test_throws MethodError addSmallData!(fg, :a, :no=>[Nanosecond(3)]) - + @test addSmallData!(fg, :a, :a => 5) == getVariable(fg, :a).smallData + @test addSmallData!(fg, :a, :b => 10.0) == getVariable(fg, :a).smallData + @test addSmallData!(fg, :a, :c => true) == getVariable(fg, :a).smallData + @test addSmallData!(fg, :a, :d => "yes") == getVariable(fg, :a).smallData + @test addSmallData!(fg, :a, :e => [1, 2, 3]) == getVariable(fg, :a).smallData + @test addSmallData!(fg, :a, :f => [1.4, 2.5, 3.6]) == getVariable(fg, :a).smallData + @test addSmallData!(fg, :a, :g => ["yes", "maybe"]) == getVariable(fg, :a).smallData + @test addSmallData!(fg, :a, :h => [true, false]) == getVariable(fg, :a).smallData + + @test_throws ErrorException addSmallData!(fg, :a, :a => 3) + @test updateSmallData!(fg, :a, :a => 3) == getVariable(fg, :a).smallData + + @test_throws MethodError addSmallData!(fg, :a, :no => 0x01) + @test_throws MethodError addSmallData!(fg, :a, :no => 1.0f0) + @test_throws MethodError addSmallData!(fg, :a, :no => Nanosecond(3)) + @test_throws MethodError addSmallData!(fg, :a, :no => [0x01]) + @test_throws MethodError addSmallData!(fg, :a, :no => [1.0f0]) + @test_throws MethodError addSmallData!(fg, :a, :no => [Nanosecond(3)]) + @test deleteSmallData!(fg, :a, :a) == 3 - @test updateSmallData!(fg, :a, :a=>3) == getVariable(fg, :a).smallData + @test updateSmallData!(fg, :a, :a => 3) == getVariable(fg, :a).smallData @test length(listSmallData(fg, :a)) == 9 emptySmallData!(fg, :a) @test length(listSmallData(fg, :a)) == 0 - end - - - -function DataEntriesTestBlock!(fg, v2) +function DataEntriesTestBlock!(fg, v2) # "Data Entries" # getBlobEntry @@ -884,17 +933,18 @@ function DataEntriesTestBlock!(fg, v2) # listBlobEntries # emptyDataEntries # mergeDataEntries - storeEntry = BlobEntry( - id = uuid4(), + storeEntry = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :a, - blobstore = :b, + label = :a, + blobstore = :b, hash = "", origin = "", description = "", - mimeType = "", - metadata = "") + mimeType = "", + metadata = "", + ) @test getLabel(storeEntry) == storeEntry.label @test getId(storeEntry) == storeEntry.id @test getHash(storeEntry) == hex2bytes(storeEntry.hash) @@ -902,45 +952,48 @@ function DataEntriesTestBlock!(fg, v2) # oid = zeros(UInt8,12); oid[12] = 0x01 # de1 = MongodbDataEntry(:key1, uuid4(), NTuple{12,UInt8}(oid), "", now(localzone())) - de1 = BlobEntry( - id = uuid4(), + de1 = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :key1, - blobstore = :b, + label = :key1, + blobstore = :b, hash = "", origin = "", description = "", - mimeType = "", - metadata = "") + mimeType = "", + metadata = "", + ) # oid = zeros(UInt8,12); oid[12] = 0x02 # de2 = MongodbDataEntry(:key2, uuid4(), NTuple{12,UInt8}(oid), "", now(localzone())) - de2 = BlobEntry( - id = uuid4(), + de2 = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :key2, - blobstore = :b, + label = :key2, + blobstore = :b, hash = "", origin = "", description = "", - mimeType = "", - metadata = "") + mimeType = "", + metadata = "", + ) # oid = zeros(UInt8,12); oid[12] = 0x03 # de2_update = MongodbDataEntry(:key2, uuid4(), NTuple{12,UInt8}(oid), "", now(localzone())) - de2_update = BlobEntry( - id = uuid4(), + de2_update = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :key2, - blobstore = :b, + label = :key2, + blobstore = :b, hash = "", origin = "", description = "Yay", - mimeType = "", - metadata = "") + mimeType = "", + metadata = "", + ) #add v1 = getVariable(fg, :a) @@ -958,12 +1011,13 @@ function DataEntriesTestBlock!(fg, v2) #update @test updateBlobEntry!(fg, :a, de2_update) == de2_update @test deepcopy(de2_update) == getBlobEntry(fg, :a, :key2) - @test @test_logs (:warn, r"does not exist") updateBlobEntry!(fg, :b, de2_update) == de2_update + @test @test_logs (:warn, r"does not exist") updateBlobEntry!(fg, :b, de2_update) == + de2_update #list entries = getBlobEntries(fg, :a) @test length(entries) == 2 - @test issetequal(map(e->e.label, entries), [:key1, :key2]) + @test issetequal(map(e -> e.label, entries), [:key1, :key2]) @test length(getBlobEntries(fg, :b)) == 1 @test issetequal(listBlobEntries(fg, :a), [:key1, :key2]) @@ -989,41 +1043,44 @@ function DataEntriesTestBlock!(fg, v2) end function blobsStoresTestBlock!(fg) - de1 = BlobEntry( - id = uuid4(), + de1 = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :label1, - blobstore = :store1, + label = :label1, + blobstore = :store1, hash = "AAAA", origin = "origin1", description = "description1", - mimeType = "mimetype1", - metadata = "") - de2 = BlobEntry( - id = uuid4(), + mimeType = "mimetype1", + metadata = "", + ) + de2 = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :label2, - blobstore = :store2, + label = :label2, + blobstore = :store2, hash = "FFFF", origin = "origin2", description = "description2", - mimeType = "mimetype2", + mimeType = "mimetype2", metadata = "", - timestamp = ZonedDateTime("2020-08-12T12:00:00.000+00:00")) - de2_update = BlobEntry( - id = uuid4(), + timestamp = ZonedDateTime("2020-08-12T12:00:00.000+00:00"), + ) + de2_update = BlobEntry(; + id = uuid4(), blobId = uuid4(), originId = uuid4(), - label = :label2, - blobstore = :store2, + label = :label2, + blobstore = :store2, hash = "0123", origin = "origin2", description = "description2", - mimeType = "mimetype2", + mimeType = "mimetype2", metadata = "", - timestamp = ZonedDateTime("2020-08-12T12:00:00.000+00:00")) + timestamp = ZonedDateTime("2020-08-12T12:00:00.000+00:00"), + ) @test getLabel(de1) == de1.label @test getId(de1) == de1.id @test getHash(de1) == hex2bytes(de1.hash) @@ -1047,12 +1104,13 @@ function blobsStoresTestBlock!(fg) #update @test updateBlobEntry!(fg, :a, de2_update) == de2_update @test deepcopy(de2_update) == getBlobEntry(fg, :a, :label2) - @test @test_logs (:warn, r"does not exist") updateBlobEntry!(fg, :b, de2_update) == de2_update + @test @test_logs (:warn, r"does not exist") updateBlobEntry!(fg, :b, de2_update) == + de2_update #list entries = getBlobEntries(fg, :a) @test length(entries) == 2 - @test issetequal(map(e->e.label, entries), [:label1, :label2]) + @test issetequal(map(e -> e.label, entries), [:label1, :label2]) @test length(getBlobEntries(fg, :b)) == 1 @test issetequal(listBlobEntries(fg, :a), [:label1, :label2]) @@ -1100,18 +1158,15 @@ function blobsStoresTestBlock!(fg) @test updateData[1].hash != data[1].hash @test updateData[2] != data[2] # Deleting - retData = deleteData!(fg, :a, :testing) # convenience wrapper around deleteBlob! - + return retData = deleteData!(fg, :a, :testing) # convenience wrapper around deleteBlob! end - function testGroup!(fg, v1, v2, f0, f1) # "TODO Sorteer groep" @testset "Listing Variables and Factors with filters" begin - - @test issetequal([:a,:b], listVariables(fg)) - @test issetequal([:af1,:abf1], listFactors(fg)) + @test issetequal([:a, :b], listVariables(fg)) + @test issetequal([:af1, :abf1], listFactors(fg)) # @test @test_deprecated getVariableIds(fg) == listVariables(fg) # @test @test_deprecated getFactorIds(fg) == listFactors(fg) @@ -1137,10 +1192,10 @@ function testGroup!(fg, v1, v2, f0, f1) @test lsfWho(fg, :TestFunctorInferenceType1) == [:abf1] @test getVariableType(v1) == TestVariableType1() - @test getVariableType(fg,:a) == TestVariableType1() + @test getVariableType(fg, :a) == TestVariableType1() @test getVariableType(v1) == TestVariableType1() - @test getVariableType(fg,:a) == TestVariableType1() + @test getVariableType(fg, :a) == TestVariableType1() @test ls2(fg, :a) == [:b] @@ -1160,41 +1215,40 @@ function testGroup!(fg, v1, v2, f0, f1) @test_skip varNearTs[1][1] == [:b] ## SORT copied from CRUD - @test all(getVariables(fg, r"a") .== [getVariable(fg,v1.label)]) - @test all(getVariables(fg, solvable=1) .== [getVariable(fg,v2.label)]) - @test getVariables(fg, r"a", solvable=1) == [] - @test getVariables(fg, tags=[:LANDMARK])[1] == getVariable(fg, v2.label) + @test all(getVariables(fg, r"a") .== [getVariable(fg, v1.label)]) + @test all(getVariables(fg; solvable = 1) .== [getVariable(fg, v2.label)]) + @test getVariables(fg, r"a"; solvable = 1) == [] + @test getVariables(fg; tags = [:LANDMARK])[1] == getVariable(fg, v2.label) @test getFactors(fg, r"nope") == [] - @test issetequal(getLabel.(getFactors(fg, solvable=1)), [:af1, :abf1]) - @test getFactors(fg, solvable=2) == [] - @test getFactors(fg, tags=[:tag1])[1] == f1 - @test getFactors(fg, tags=[:PRIOR])[1] == f0 + @test issetequal(getLabel.(getFactors(fg; solvable = 1)), [:af1, :abf1]) + @test getFactors(fg; solvable = 2) == [] + @test getFactors(fg; tags = [:tag1])[1] == f1 + @test getFactors(fg; tags = [:PRIOR])[1] == f0 ##/SORT # Additional testing for https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/201 # list solvable - @test symdiff([:a, :b], listVariables(fg, solvable=0)) == [] - @test listVariables(fg, solvable=1) == [:b] + @test symdiff([:a, :b], listVariables(fg; solvable = 0)) == [] + @test listVariables(fg; solvable = 1) == [:b] - @test issetequal(listFactors(fg, solvable=1), [:af1, :abf1]) - @test issetequal(listFactors(fg, solvable=0), [:af1, :abf1]) - @test all([f in [f0, f1] for f in getFactors(fg, solvable=1)]) + @test issetequal(listFactors(fg; solvable = 1), [:af1, :abf1]) + @test issetequal(listFactors(fg; solvable = 0), [:af1, :abf1]) + @test all([f in [f0, f1] for f in getFactors(fg; solvable = 1)]) @test lsf(fg, :b) == [f1.label] # Tags - @test ls(fg, tags=[:POSE]) == [] - @test issetequal(ls(fg, tags=[:POSE, :LANDMARK]), ls(fg, tags=[:VARIABLE])) + @test ls(fg; tags = [:POSE]) == [] + @test issetequal(ls(fg; tags = [:POSE, :LANDMARK]), ls(fg; tags = [:VARIABLE])) - @test lsf(fg, tags=[:NONE]) == [] - @test lsf(fg, tags=[:PRIOR]) == [:af1] + @test lsf(fg; tags = [:NONE]) == [] + @test lsf(fg; tags = [:PRIOR]) == [:af1] # Regexes @test ls(fg, r"a") == [v1.label] @test lsf(fg, r"abf*") == [f1.label] - #TODO test filters and options # regexFilter::Union{Nothing, Regex}=nothing; # tags::Vector{Symbol}=Symbol[], @@ -1205,21 +1259,78 @@ function testGroup!(fg, v1, v2, f0, f1) end @testset "Sorting" begin - unsorted = [:x1_3;:x1_6;:l1;:april1] #this will not work for :x1x2f1 - @test sort([:x1x2f1, :x1l1f1], lt=natural_lt) == [:x1l1f1, :x1x2f1] + unsorted = [:x1_3; :x1_6; :l1; :april1] #this will not work for :x1x2f1 + @test sort([:x1x2f1, :x1l1f1]; lt = natural_lt) == [:x1l1f1, :x1x2f1] # NOTE Some of what is possible with sort and the wrappers - l = [:a1, :X1, :b1c2, :x2_2, :c, :x1, :x10, :x1_1, :x10_10,:a, :x2_1, :xy3, :l1, :x1_2, :x1l1f1, Symbol("1a1"), :x1x2f1] - @test sortDFG(l) == [Symbol("1a1"), :X1, :a, :a1, :b1c2, :c, :l1, :x1, :x1_1, :x1_2, :x1l1f1, :x1x2f1, :x2_1, :x2_2, :x10, :x10_10, :xy3] - @test sort(l, lt=natural_lt) == [Symbol("1a1"), :X1, :a, :a1, :b1c2, :c, :l1, :x1, :x1_1, :x1_2, :x1l1f1, :x1x2f1, :x2_1, :x2_2, :x10, :x10_10, :xy3] - - @test getLabel.(sortDFG(getVariables(fg), lt=natural_lt, by=getLabel)) == [:a, :b] - @test getLabel.(sort(getVariables(fg), lt=natural_lt, by=getLabel)) == [:a, :b] + l = [ + :a1, + :X1, + :b1c2, + :x2_2, + :c, + :x1, + :x10, + :x1_1, + :x10_10, + :a, + :x2_1, + :xy3, + :l1, + :x1_2, + :x1l1f1, + Symbol("1a1"), + :x1x2f1, + ] + @test sortDFG(l) == [ + Symbol("1a1"), + :X1, + :a, + :a1, + :b1c2, + :c, + :l1, + :x1, + :x1_1, + :x1_2, + :x1l1f1, + :x1x2f1, + :x2_1, + :x2_2, + :x10, + :x10_10, + :xy3, + ] + @test sort(l; lt = natural_lt) == [ + Symbol("1a1"), + :X1, + :a, + :a1, + :b1c2, + :c, + :l1, + :x1, + :x1_1, + :x1_2, + :x1l1f1, + :x1x2f1, + :x2_1, + :x2_2, + :x10, + :x10_10, + :xy3, + ] + + @test getLabel.(sortDFG(getVariables(fg); lt = natural_lt, by = getLabel)) == + [:a, :b] + @test getLabel.(sort(getVariables(fg); lt = natural_lt, by = getLabel)) == [:a, :b] @test getLabel.(sortDFG(getFactors(fg))) == [:abf1, :af1] - @test getLabel.(sort(getFactors(fg), by=getTimestamp)) == [:abf1, :af1] + @test getLabel.(sort(getFactors(fg); by = getTimestamp)) == [:abf1, :af1] - @test getLabel.(sortDFG(vcat(getVariables(fg),getFactors(fg)), lt=natural_lt, by=getLabel)) == [:a,:abf1, :af1, :b] + @test getLabel.( + sortDFG(vcat(getVariables(fg), getFactors(fg)); lt = natural_lt, by = getLabel) + ) == [:a, :abf1, :af1, :b] end @testset "Some more helpers to sort out" begin @@ -1255,7 +1366,6 @@ function testGroup!(fg, v1, v2, f0, f1) #TODO follow up on why f1 is no longer referenced, and remove next line @test_broken getSolvable(f1) == 0 - # isFactor and isVariable @test isFactor(fg, f1.label) @test !isFactor(fg, v1.label) @@ -1275,7 +1385,6 @@ function testGroup!(fg, v1, v2, f0, f1) end end - # Feed with graph a b solvable orphan not factor on a b # fg = testDFGAPI() # addVariable!(fg, DFGVariable(:a, TestVariableType1())) @@ -1287,16 +1396,16 @@ function AdjacencyMatricesTestBlock(fg) #deprecated # @test_throws ErrorException getAdjacencyMatrix(fg) adjMat = DistributedFactorGraphs.getAdjacencyMatrixSymbols(fg) - @test size(adjMat) == (2,4) + @test size(adjMat) == (2, 4) @test issetequal(adjMat[1, :], [nothing, :a, :b, :orphan]) @test issetequal(adjMat[2, :], [:abf1, :abf1, :abf1, nothing]) # #sparse adjMat, v_ll, f_ll = getBiadjacencyMatrix(fg) - @test size(adjMat) == (1,3) + @test size(adjMat) == (1, 3) # Checking the elements of adjacency, its not sorted so need indexing function - indexOf = (arr, el1) -> findfirst(el2->el2==el1, arr) + indexOf = (arr, el1) -> findfirst(el2 -> el2 == el1, arr) @test adjMat[1, indexOf(v_ll, :orphan)] == 0 @test adjMat[1, indexOf(v_ll, :a)] == 1 @test adjMat[1, indexOf(v_ll, :b)] == 1 @@ -1306,63 +1415,95 @@ function AdjacencyMatricesTestBlock(fg) # Only do solvable tests on DFGVariable if isa(getVariable(fg, :a), DFGVariable) # Filtered - REF DFG #201 - adjMat, v_ll, f_ll = getBiadjacencyMatrix(fg, solvable=0) - @test size(adjMat) == (1,3) + adjMat, v_ll, f_ll = getBiadjacencyMatrix(fg; solvable = 0) + @test size(adjMat) == (1, 3) @test symdiff(v_ll, [:a, :b, :orphan]) == Symbol[] @test symdiff(f_ll, [:abf1]) == Symbol[] # sparse - adjMat, v_ll, f_ll = getBiadjacencyMatrix(fg, solvable=1) - @test size(adjMat) == (1,2) + adjMat, v_ll, f_ll = getBiadjacencyMatrix(fg; solvable = 1) + @test size(adjMat) == (1, 2) @test issetequal(v_ll, [:a, :b]) @test f_ll == [:abf1] end end # Now make a complex graph for connectivity tests -function connectivityTestGraph(::Type{T}; VARTYPE=DFGVariable, FACTYPE=DFGFactor) where T <: AbstractDFG#InMemoryDFGTypes +function connectivityTestGraph( + ::Type{T}; + VARTYPE = DFGVariable, + FACTYPE = DFGFactor, +) where {T <: AbstractDFG}#InMemoryDFGTypes #settings numNodesType1 = 5 numNodesType2 = 5 - dfg = T(userLabel="test@navability.io") - - vars = vcat(map(n -> VARTYPE(Symbol("x$n"), VariableNodeData{TestVariableType1}()), 1:numNodesType1), - map(n -> VARTYPE(Symbol("x$(numNodesType1+n)"), VariableNodeData{TestVariableType2}()), 1:numNodesType2)) + dfg = T(; userLabel = "test@navability.io") + + vars = vcat( + map( + n -> VARTYPE(Symbol("x$n"), VariableNodeData{TestVariableType1}()), + 1:numNodesType1, + ), + map( + n -> VARTYPE( + Symbol("x$(numNodesType1+n)"), + VariableNodeData{TestVariableType2}(), + ), + 1:numNodesType2, + ), + ) foreach(v -> addVariable!(dfg, v), vars) - if FACTYPE == DFGFactor #change ready and solveInProgress for x7,x8 for improved tests on x7x8f1 #NOTE because defaults changed setSolvable!(dfg, :x8, 0) setSolvable!(dfg, :x9, 0) - gfnd = GenericFunctionNodeData(eliminated=true, potentialused=true, fnc=TestCCW(TestFunctorInferenceType1()), multihypo=Float64[], certainhypo=Int[], solveInProgress=0, inflation=1.0) + gfnd = GenericFunctionNodeData(; + eliminated = true, + potentialused = true, + fnc = TestCCW(TestFunctorInferenceType1()), + multihypo = Float64[], + certainhypo = Int[], + solveInProgress = 0, + inflation = 1.0, + ) f_tags = Set([:FACTOR]) # f1 = DFGFactor(f1_lbl, [:a,:b], gfnd, tags = f_tags) - facs = map(n -> addFactor!(dfg, DFGFactor(Symbol("x$(n)x$(n+1)f1"), - [vars[n].label, vars[n+1].label], - deepcopy(gfnd), - tags=deepcopy(f_tags))), - 1:length(vars)-1) + facs = map( + n -> addFactor!( + dfg, + DFGFactor( + Symbol("x$(n)x$(n+1)f1"), + [vars[n].label, vars[n + 1].label], + deepcopy(gfnd); + tags = deepcopy(f_tags), + ), + ), + 1:(length(vars) - 1), + ) setSolvable!(dfg, :x7x8f1, 0) else - facs = map(n -> addFactor!(dfg, [vars[n], vars[n+1]], FACTYPE(Symbol("x$(n)x$(n+1)f1"))), 1:length(vars)-1) + facs = map( + n -> addFactor!(dfg, [vars[n], vars[n + 1]], FACTYPE(Symbol("x$(n)x$(n+1)f1"))), + 1:(length(vars) - 1), + ) end - return (dfg=dfg, variables=vars, factors=facs) - + return (dfg = dfg, variables = vars, factors = facs) end # dfg, verts, facs = connectivityTestGraph(testDFGAPI) -function GettingNeighbors(testDFGAPI; VARTYPE=DFGVariable, FACTYPE=DFGFactor) +function GettingNeighbors(testDFGAPI; VARTYPE = DFGVariable, FACTYPE = DFGFactor) # "Getting Neighbors" - dfg, verts, facs = connectivityTestGraph(testDFGAPI, VARTYPE=VARTYPE, FACTYPE=FACTYPE) + dfg, verts, facs = + connectivityTestGraph(testDFGAPI; VARTYPE = VARTYPE, FACTYPE = FACTYPE) # Trivial test to validate that intersect([], []) returns order of first parameter @test intersect([:x3, :x2, :x1], [:x1, :x2]) == [:x2, :x1] # Get neighbors tests @@ -1376,16 +1517,15 @@ function GettingNeighbors(testDFGAPI; VARTYPE=DFGVariable, FACTYPE=DFGFactor) # Solvable #TODO if not a GraphsDFG with and summary or skeleton if VARTYPE == DFGVariable - @test listNeighbors(dfg, :x5, solvable=2) == Symbol[] - @test issetequal(listNeighbors(dfg, :x5, solvable=0), [:x4x5f1,:x5x6f1]) - @test issetequal(listNeighbors(dfg, :x5), [:x4x5f1,:x5x6f1]) - @test listNeighbors(dfg, :x7x8f1, solvable=0) == [:x7, :x8] - @test listNeighbors(dfg, :x7x8f1, solvable=1) == [:x7] - @test listNeighbors(dfg, verts[1], solvable=0) == [:x1x2f1] - @test listNeighbors(dfg, verts[1], solvable=2) == Symbol[] + @test listNeighbors(dfg, :x5; solvable = 2) == Symbol[] + @test issetequal(listNeighbors(dfg, :x5; solvable = 0), [:x4x5f1, :x5x6f1]) + @test issetequal(listNeighbors(dfg, :x5), [:x4x5f1, :x5x6f1]) + @test listNeighbors(dfg, :x7x8f1; solvable = 0) == [:x7, :x8] + @test listNeighbors(dfg, :x7x8f1; solvable = 1) == [:x7] + @test listNeighbors(dfg, verts[1]; solvable = 0) == [:x1x2f1] + @test listNeighbors(dfg, verts[1]; solvable = 2) == Symbol[] @test listNeighbors(dfg, verts[1]) == [:x1x2f1] end - end #TODO confirm these tests are covered somewhere then delete @@ -1439,11 +1579,11 @@ end # # end +function BuildingSubgraphs(testDFGAPI; VARTYPE = DFGVariable, FACTYPE = DFGFactor) -function BuildingSubgraphs(testDFGAPI; VARTYPE=DFGVariable, FACTYPE=DFGFactor) - - # "Getting Subgraphs" - dfg, verts, facs = connectivityTestGraph(testDFGAPI, VARTYPE=VARTYPE, FACTYPE=FACTYPE) + # "Getting Subgraphs" + dfg, verts, facs = + connectivityTestGraph(testDFGAPI; VARTYPE = VARTYPE, FACTYPE = FACTYPE) # Subgraphs dfgSubgraph = buildSubgraph(testDFGAPI, dfg, [verts[1].label], 2) # Only returns x1 and x2 @@ -1459,7 +1599,7 @@ function BuildingSubgraphs(testDFGAPI; VARTYPE=DFGVariable, FACTYPE=DFGFactor) #TODO if not a GraphsDFG with and summary or skeleton if VARTYPE == DFGVariable - dfgSubgraph = buildSubgraph(testDFGAPI, dfg, [:x8], 2, solvable=1) + dfgSubgraph = buildSubgraph(testDFGAPI, dfg, [:x8], 2; solvable = 1) @test issetequal([:x7], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) #end if not a GraphsDFG with and summary or skeleton end @@ -1470,7 +1610,8 @@ function BuildingSubgraphs(testDFGAPI; VARTYPE=DFGVariable, FACTYPE=DFGFactor) dfgSubgraph = buildSubgraph(testDFGAPI, dfg, [fId], 2) # For each factor check that the order the copied graph == original for fact in getFactors(dfgSubgraph) - @test fact._variableOrderSymbols == getFactor(dfg, fact.label)._variableOrderSymbols + @test fact._variableOrderSymbols == + getFactor(dfg, fact.label)._variableOrderSymbols end end @@ -1480,22 +1621,24 @@ function BuildingSubgraphs(testDFGAPI; VARTYPE=DFGVariable, FACTYPE=DFGFactor) @test issetequal([:x1, :x1x2f1, :x2], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) dfgSubgraph = buildSubgraph(dfg, [:x2, :x3], 2) - @test issetequal([:x2, :x3, :x1, :x4, :x3x4f1, :x1x2f1, :x2x3f1], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) + @test issetequal( + [:x2, :x3, :x1, :x4, :x3x4f1, :x1x2f1, :x2x3f1], + [ls(dfgSubgraph)..., lsf(dfgSubgraph)...], + ) dfgSubgraph = buildSubgraph(dfg, [:x1x2f1], 1) @test issetequal([:x1, :x1x2f1, :x2], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) end - end #TODO Summaries and Summary Graphs -function Summaries(testDFGAPI) +function Summaries(testDFGAPI) # "Summaries and Summary Graphs" dfg, verts, facs = connectivityTestGraph(testDFGAPI) #TODO for summary # if VARTYPE == DFGVariableSummary - # factorFields = fieldnames(FACTYPE) - # variableFields = fieldnames(VARTYPE) + # factorFields = fieldnames(FACTYPE) + # variableFields = fieldnames(VARTYPE) factorFields = fieldnames(DFGFactorSummary) variableFields = fieldnames(DFGVariableSummary) @@ -1510,30 +1653,36 @@ function Summaries(testDFGAPI) for v in ls(summaryGraph) for field in variableFields if field != :variableTypeName - @test getproperty(getVariable(dfg, v), field) == getproperty(getVariable(summaryGraph, v), field) + @test getproperty(getVariable(dfg, v), field) == + getproperty(getVariable(summaryGraph, v), field) else # Special case to check the symbol variableType is equal to the full variableType. - @test Symbol(typeof(getVariableType(getVariable(dfg, v)))) == getVariableTypeName(getVariable(summaryGraph, v)) - @test getVariableType(getVariable(dfg, v)) == getVariableType(getVariable(summaryGraph, v)) + @test Symbol(typeof(getVariableType(getVariable(dfg, v)))) == + getVariableTypeName(getVariable(summaryGraph, v)) + @test getVariableType(getVariable(dfg, v)) == + getVariableType(getVariable(summaryGraph, v)) end end end for f in lsf(summaryGraph) for field in factorFields - @test getproperty(getFactor(dfg, f), field) == getproperty(getFactor(summaryGraph, f), field) + @test getproperty(getFactor(dfg, f), field) == + getproperty(getFactor(summaryGraph, f), field) end end end -function ProducingDotFiles(testDFGAPI, - v1 = nothing, - v2 = nothing, - f1 = nothing; - VARTYPE=DFGVariable, - FACTYPE=DFGFactor) +function ProducingDotFiles( + testDFGAPI, + v1 = nothing, + v2 = nothing, + f1 = nothing; + VARTYPE = DFGVariable, + FACTYPE = DFGFactor, +) # "Producing Dot Files" # create a simpler graph for dot testing - dotdfg = testDFGAPI(userLabel="test@navability.io") + dotdfg = testDFGAPI(; userLabel = "test@navability.io") if v1 === nothing v1 = VARTYPE(:a, VariableNodeData{TestVariableType1}()) @@ -1542,7 +1691,11 @@ function ProducingDotFiles(testDFGAPI, v2 = VARTYPE(:b, VariableNodeData{TestVariableType1}()) end if f1 === nothing - f1 = (FACTYPE==DFGFactor) ? DFGFactor{TestFunctorInferenceType1}(:abf1, [:a, :b]) : FACTYPE(:abf1) + if (FACTYPE == DFGFactor) + f1 = DFGFactor{TestFunctorInferenceType1}(:abf1, [:a, :b]) + else + f1 = FACTYPE(:abf1) + end end addVariable!(dotdfg, v1) @@ -1555,15 +1708,19 @@ function ProducingDotFiles(testDFGAPI, #NOTE hardcoded toDot will have different results so test Graphs seperately if testDFGAPI <: GraphsDFG || testDFGAPI <: GraphsDFG todotstr = toDot(dotdfg) - todota = todotstr == "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\na -- abf1\nb -- abf1\n}\n" - todotb = todotstr == "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\nb -- abf1\na -- abf1\n}\n" + todota = + todotstr == + "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\na -- abf1\nb -- abf1\n}\n" + todotb = + todotstr == + "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\nb -- abf1\na -- abf1\n}\n" @test (todota || todotb) else - @test toDot(dotdfg) == "graph graphname {\n2 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n" + @test toDot(dotdfg) == + "graph graphname {\n2 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n" end @test toDotFile(dotdfg, "something.dot") == nothing - Base.rm("something.dot") - + return Base.rm("something.dot") end function ConnectivityTest(testDFGAPI; kwargs...) @@ -1577,10 +1734,8 @@ function ConnectivityTest(testDFGAPI; kwargs...) deleteVariable!(dfg, :x5) @test isConnected(dfg) == false - end - function CopyFunctionsTest(testDFGAPI; kwargs...) # testDFGAPI = GraphsDFG @@ -1618,9 +1773,8 @@ function CopyFunctionsTest(testDFGAPI; kwargs...) @test !isConnected(dcdfg_part) # plotDFG(dcdfg_part) - vlbls = [:x2, :x3] - dcdfg_part = deepcopyGraph(GraphsDFG, dfg, vlbls; verbose=false) + dcdfg_part = deepcopyGraph(GraphsDFG, dfg, vlbls; verbose = false) @test issetequal(ls(dcdfg_part), vlbls) @test issetequal(lsf(dcdfg_part), [:x2x3f1]) @@ -1630,20 +1784,31 @@ function CopyFunctionsTest(testDFGAPI; kwargs...) # already exists errors dcdfg_part = deepcopyGraph(GraphsDFG, dfg, [:x1, :x2, :x3], [:x1x2f1, :x2x3f1]) - @test_throws ErrorException deepcopyGraph!(dcdfg_part, dfg, [:x4, :x2, :x3], [:x1x2f1, :x2x3f1]) + @test_throws ErrorException deepcopyGraph!( + dcdfg_part, + dfg, + [:x4, :x2, :x3], + [:x1x2f1, :x2x3f1], + ) @test_throws ErrorException deepcopyGraph!(dcdfg_part, dfg, [:x1x2f1]) # same but overwrite destination - deepcopyGraph!(dcdfg_part, dfg, [:x4, :x2, :x3], [:x1x2f1, :x2x3f1]; overwriteDest = true) + deepcopyGraph!( + dcdfg_part, + dfg, + [:x4, :x2, :x3], + [:x1x2f1, :x2x3f1]; + overwriteDest = true, + ) - deepcopyGraph!(dcdfg_part, dfg, Symbol[], [:x1x2f1]; overwriteDest=true) + deepcopyGraph!(dcdfg_part, dfg, Symbol[], [:x1x2f1]; overwriteDest = true) vlbls1 = [:x1, :x2, :x3] vlbls2 = [:x4, :x5, :x6] dcdfg_part1 = deepcopyGraph(GraphsDFG, dfg, vlbls1) dcdfg_part2 = deepcopyGraph(GraphsDFG, dfg, vlbls2) - mergedGraph = testDFGAPI(userLabel="test@navability.io") + mergedGraph = testDFGAPI(; userLabel = "test@navability.io") mergeGraph!(mergedGraph, dcdfg_part1) mergeGraph!(mergedGraph, dcdfg_part2) @@ -1673,7 +1838,6 @@ function FileDFGTestBlock(testDFGAPI; kwargs...) dfg, verts, facs = connectivityTestGraph(testDFGAPI; kwargs...) for filename in ["/tmp/fileDFG", "/tmp/FileDFGExtension.tar.gz"] - v4 = getVariable(dfg, :x4) vnd = getSolverData(v4) # set everything @@ -1710,10 +1874,10 @@ function FileDFGTestBlock(testDFGAPI; kwargs...) # Save and load the graph to test. saveDFG(dfg, filename) - retDFG = testDFGAPI(userLabel="test@navability.io") + retDFG = testDFGAPI(; userLabel = "test@navability.io") @info "Going to load $filename" - @test_throws AssertionError loadDFG!(retDFG,"badfilename") + @test_throws AssertionError loadDFG!(retDFG, "badfilename") loadDFG!(retDFG, filename) @@ -1731,5 +1895,4 @@ function FileDFGTestBlock(testDFGAPI; kwargs...) # @test length(getBlobEntries(getVariable(retDFG, :x2))) == 1 # @test typeof(getBlobEntry(getVariable(retDFG, :x2),:testing2)) == FileDataEntry end - end diff --git a/test/test_defVariable.jl b/test/test_defVariable.jl index 5ad20ad7..668a5f67 100644 --- a/test/test_defVariable.jl +++ b/test/test_defVariable.jl @@ -3,47 +3,54 @@ using Test using LinearAlgebra @testset "Testing @defVariable" begin -## + ## -struct NotAManifold end + struct NotAManifold end -@test_throws AssertionError @defVariable(MyVar, NotAManifold(), zeros(3,3)) + @test_throws AssertionError @defVariable(MyVar, NotAManifold(), zeros(3, 3)) -## + ## -@defVariable(TestVarType1, Euclidean(3), zeros(3)) -@defVariable(TestVarType2, SpecialEuclidean(3), ArrayPartition(zeros(3), diagm(ones(3)))) + @defVariable(TestVarType1, Euclidean(3), zeros(3)) + @defVariable( + TestVarType2, + SpecialEuclidean(3), + ArrayPartition(zeros(3), diagm(ones(3))) + ) + ## -## + @test getManifold(TestVarType1) == Euclidean(3) + @test getManifold(TestVarType2) == SpecialEuclidean(3) -@test getManifold( TestVarType1) == Euclidean(3) -@test getManifold( TestVarType2) == SpecialEuclidean(3) + @test getDimension(TestVarType1) === 3 + @test getDimension(TestVarType2) === 6 -@test getDimension(TestVarType1) === 3 -@test getDimension(TestVarType2) === 6 + @test getPointType(TestVarType1) == Vector{Float64} + @test getPointType(TestVarType2) == + ArrayPartition{Float64, Tuple{Vector{Float64}, Matrix{Float64}}} -@test getPointType(TestVarType1) == Vector{Float64} -@test getPointType(TestVarType2) == ArrayPartition{Float64, Tuple{Vector{Float64}, Matrix{Float64}}} + @test getPointIdentity(TestVarType1) == zeros(3) + @test getPointIdentity(TestVarType2).x[1] == + ArrayPartition(zeros(3), diagm(ones(3))).x[1] + @test getPointIdentity(TestVarType2).x[2] == + ArrayPartition(zeros(3), diagm(ones(3))).x[2] -@test getPointIdentity(TestVarType1) == zeros(3) -@test getPointIdentity(TestVarType2).x[1] == ArrayPartition(zeros(3), diagm(ones(3))).x[1] -@test getPointIdentity(TestVarType2).x[2] == ArrayPartition(zeros(3), diagm(ones(3))).x[2] + ## -## + @test getManifold(TestVarType1()) == Euclidean(3) + @test getManifold(TestVarType2()) == SpecialEuclidean(3) + @test getDimension(TestVarType1()) === 3 + @test getDimension(TestVarType2()) === 6 -@test getManifold( TestVarType1()) == Euclidean(3) -@test getManifold( TestVarType2()) == SpecialEuclidean(3) - -@test getDimension(TestVarType1()) === 3 -@test getDimension(TestVarType2()) === 6 - -@test getPointType(TestVarType1()) == Vector{Float64} -@test getPointType(TestVarType2()) == ArrayPartition{Float64, Tuple{Vector{Float64}, Matrix{Float64}}} - -@test getPointIdentity(TestVarType1()) == zeros(3) -@test getPointIdentity(TestVarType2()).x[1] == ArrayPartition(zeros(3), diagm(ones(3))).x[1] -@test getPointIdentity(TestVarType2()).x[2] == ArrayPartition(zeros(3), diagm(ones(3))).x[2] + @test getPointType(TestVarType1()) == Vector{Float64} + @test getPointType(TestVarType2()) == + ArrayPartition{Float64, Tuple{Vector{Float64}, Matrix{Float64}}} + @test getPointIdentity(TestVarType1()) == zeros(3) + @test getPointIdentity(TestVarType2()).x[1] == + ArrayPartition(zeros(3), diagm(ones(3))).x[1] + @test getPointIdentity(TestVarType2()).x[2] == + ArrayPartition(zeros(3), diagm(ones(3))).x[2] end