diff --git a/.gitignore b/.gitignore index 0e82faa3..e3de6832 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ docs/build Manifest.toml dev test/sandbox.jl +lcov.info \ No newline at end of file diff --git a/NEWS.md b/NEWS.md index 7eae746d..0ddfa300 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,13 +2,19 @@ Listing news on any major breaking changes in DFG. For regular changes, see int # v0.28 - Reading or deserialzing of factor graphs created prior to v0.25 are no longer suppoted with the complete removal of User/Robot/Session - Deprecated AbstractRelativeMinimize and AbstractManifoldsMinimize - -#TODO pending: -- AbstractPrior -> AbstractPriorObservation/PriorObservation -- AbstractRelative -> RelativeObservation/RelativeObservation -- InferenceType -> AbstractPackedFactorObservation -- InferenceVariable -> [Abstract]VariableStateType/AbstractVarstateType -- PackedSamplableBelief -> [Abstract]PackedBelief +- Rename `VariableState` -> `State` + +Abstract Types Standardized, see #1153: +- AbstractParams -> [Abstract]DFGParams +- DFGNode -> [Abstract]GraphNode +- AbstractDFGVariable -> [Abstract]GraphVariable +- AbstractDFGFactor -> [Abstract]GraphFactor +- AbstractPackedFactorObservation -> [Abstract]PackedObservation +- AbstractFactorObservation -> [Abstract]Observation +- AbstractPrior -> [Abstract]PriorObservation +- AbstractRelative -> [Abstract]RelativeObservation +- FactorSolverCache -> [Abstract]FactorCache +- VariableStateType -> [Abstract]StateType # v0.27 - `delete` returns number of nodes deleted and no longer the object that was deleted. diff --git a/docs/src/DrawingGraphs.md b/docs/src/DrawingGraphs.md index 99490c94..c15c23f1 100644 --- a/docs/src/DrawingGraphs.md +++ b/docs/src/DrawingGraphs.md @@ -64,8 +64,8 @@ More information at [GraphMakie.jl](https://github.com/MakieOrg/GraphMakie.jl) Dot files are a standard format for visualizing graphs and applications such as xdot are available to view the files. Dot plotting does not require `GraphMakie` and can be drawn by either: -- Calling [`toDot`](@ref) on any graph to produce a string of the graph -- Calling [`toDotFile`](@ref) on any graph to save it directly to a dotfile +- Calling [`DFG.toDot`](@ref) on any graph to produce a string of the graph +- Calling [`DFG.toDotFile`](@ref) on any graph to save it directly to a dotfile ```julia using DistributedFactorGraphs diff --git a/docs/src/GraphData.md b/docs/src/GraphData.md index 8afbb017..7b438588 100644 --- a/docs/src/GraphData.md +++ b/docs/src/GraphData.md @@ -15,7 +15,7 @@ The following is a guideline to using these parameters. **NOTE**: Adds in general throw an error if the element already exists. Update will update the element if it exists, otherwise it will add it. -**NOTE**: In general these functions will return an error if the respective element is not found. This is to avoid returning, say, nothing, which will be horribly confusing if you tried `getVariableState(dfg, :a, :b)` and it returned nothing - which was missing, :a or :b, or was there a communication issue? We recommend coding defensively and trapping errors in critical portions of your user code. +**NOTE**: In general these functions will return an error if the respective element is not found. This is to avoid returning, say, nothing, which will be horribly confusing if you tried `getState(dfg, :a, :b)` and it returned nothing - which was missing, :a or :b, or was there a communication issue? We recommend coding defensively and trapping errors in critical portions of your user code. **NOTE**: All data is passed by reference, so if you update the returned structure it will update in the graph. The database driver is an exception, and once the variable or factor is updated you need to call update* to persist the changes to the graph. @@ -53,7 +53,7 @@ Each variable or factor can have a timestamp associated with it. Tags are a set of symbols that contain identifiers for the variable or factor. -- [`listTags`](@ref) +- [`getTags`](@ref) - [`mergeTags!`](@ref) - [`removeTags!`](@ref) - [`emptyTags!`](@ref) @@ -118,41 +118,41 @@ updatePPE!(dfg, :x0, ppe, :default) updatePPE!(dfg, [x0], :default) ``` -#### Solver Data +#### Variable States (Solver Data) -Solver data is used by IncrementalInference/RoME/Caesar solver to produce the above PPEs. +Variable `State`s are used by the IncrementalInference/RoME/Caesar solver. Related functions: -- [`listVariableStates`](@ref) -- [`getVariableState`](@ref) -- [`addVariableState!`](@ref) -- [`mergeVariableState!`](@ref) -- [`deleteVariableState!`](@ref) -- [`mergeVariableState!`](@ref) +- [`listStates`](@ref) +- [`getState`](@ref) +- [`addState!`](@ref) +- [`mergeState!`](@ref) +- [`deleteState!`](@ref) +- [`mergeState!`](@ref) -Example of solver data operations: +Example of variable `State` operations: ```julia # Add new VND of type ContinuousScalar to :x0 -# Could also do VariableState(ContinuousScalar()) -vnd = VariableState{ContinuousScalar}() -addVariableState!(dfg, :x0, vnd, :parametric) -@show listVariableStates(dfg, :x0) +# Could also do State(ContinuousScalar()) +state = State{ContinuousScalar}() +addState!(dfg, :x0, state, :parametric) +@show listStates(dfg, :x0) # Get the data back - note that this is a reference to above. -vndBack = getVariableState(dfg, :x0, :parametric) +stateBack = getState(dfg, :x0, :parametric) # Delete it -deleteVariableState!(dfg, :x0, :parametric) +deleteState!(dfg, :x0, :parametric) ``` -#### Small Data +#### Metadata -Small data allows you to assign a dictionary to variables. It is a useful way to -keep small amounts of string data in a variable. As it is stored in the graph +Metadata (small data) allows you to assign a dictionary to variables. It is a useful way to +keep small amounts of primative (Strings, Integers, Floats, Bool) data in a variable. As it is stored in the graph itself, large entries will slow the graph down, so if data should exceed a -few bytes/kb, it should rather be saved in bigData. +few bytes/kb, it should rather be saved in Blobs. - [`getMetadata`](@ref) diff --git a/src/Common.jl b/src/Common.jl index 25c667b8..754c93eb 100644 --- a/src/Common.jl +++ b/src/Common.jl @@ -3,10 +3,10 @@ _getmodule(t::T) where {T} = T.name.module _getname(t::T) where {T} = T.name.name -function convertPackedType(t::Union{T, Type{T}}) where {T <: AbstractFactorObservation} +function convertPackedType(t::Union{T, Type{T}}) where {T <: AbstractObservation} return getfield(_getmodule(t), Symbol("Packed$(_getname(t))")) end -function convertStructType(::Type{PT}) where {PT <: AbstractPackedFactorObservation} +function convertStructType(::Type{PT}) where {PT <: AbstractPackedObservation} # 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 @@ -64,11 +64,68 @@ Related ls, lsf """ -function sortDFG(vars::Vector{<:DFGNode}; by = getTimestamp, kwargs...) +function sortDFG(vars::Vector{<:AbstractGraphNode}; by = getTimestamp, kwargs...) return sort(vars; by = by, kwargs...) end sortDFG(vars::Vector{Symbol}; lt = natural_lt, kwargs...) = sort(vars; lt = lt, kwargs...) +##============================================================================== +## Filtering +##============================================================================== + +# std_numeric_predicates = [==, <, <=, >, >=, in] +# std_string_predicates = [==, in, contains, startswith, endswith] + +# # full list +# tags_includes(tag::Symbol) = Base.Fix1(in, tag) +# solvable_eq(x::Int) = ==(x) +# solvable_in(x::Vector{Int}) = in(x) +# solvable_lt(x::Int) = <(x) +# solvable_lte(x::Int) = <=(x) +# solvable_gt(x::Int) = >(x) +# solvable_gte(x::Int) = >=(x) +# label_in(x::Vector{Symbol}) = in(x) +# label_contains(x::String) = contains(x) +# label_startswith(x::String) = startswith(x) +# label_endswith(x::String) = endswith(x) +# type_eq(x::AbstractStateType) = ==(x) +# type_in(x::Vector{<:AbstractStateType}) = in(x) +# type_contains(x::String) = contains(x) +# type_startswith(x::String) = startswith(x) +# type_endswith(x::String) = endswith(x) + +# Set predicates +# collection_includes(item) = Base.Fix1(in, item) # collection includes item (item in collection) + +# not supported helper +# collection_overlap(collection) = !isdisjoint(collection) # collection overlaps with another collection + +""" + $SIGNATURES +Filter nodes in a DFG based on a predicate function. +This function modifies the input `nodes` vector in place, removing nodes that do not satisfy the predicate. + +- **For cross-backend compatibility:** + Use only the standard predicates (`==`, `<`, `<=`, `>`, `>=`, `in`, `contains`, `startswith`, `endswith`) + when you need your code to work with both in-memory and database-backed DFGs. + These are likely to be supported by database query languages and are defined in `std_numeric_predicates` and `std_string_predicates`. + +- **For in-memory only operations:** + You can use any Julia predicate, since you have full access to the data and Julia's capabilities. + This is more flexible but will not work if you later switch to a database backend or another programming language. + +Standard predicates +- Numeric predicates: `==`, `<`, `<=`, `>`, `>=`, `in` +- String predicates: `==`, `contains`, `startswith`, `endswith`, `in` +""" +function filterDFG! end + +filterDFG!(nodes, predicate::Nothing, by::Function = identity) = nodes +# function filterDFG!(nodes, predicate::Base.Fix2, by=identity) +function filterDFG!(nodes, predicate::Function, by::Function = identity) + return filter!(predicate ∘ by, nodes) +end + ##============================================================================== ## Validation of session, robot, and user labels. ##============================================================================== @@ -83,10 +140,8 @@ $(SIGNATURES) Returns true if the label is valid for node. """ function isValidLabel(id::Union{Symbol, String}) - if typeof(id) == Symbol - id = String(id) - end - return !in(uppercase(id), _invalidIds) && !isnothing(match(_validLabelRegex, id)) + _id = string(id) + return occursin(_validLabelRegex, _id) && !in(uppercase(_id), _invalidIds) end """ diff --git a/src/DataBlobs/services/BlobEntry.jl b/src/DataBlobs/services/BlobEntry.jl index 6874cb47..21e10c20 100644 --- a/src/DataBlobs/services/BlobEntry.jl +++ b/src/DataBlobs/services/BlobEntry.jl @@ -65,7 +65,7 @@ Get data entry Also see: [`addBlobentry!`](@ref), [`getBlob`](@ref), [`listBlobentries`](@ref) """ -function getBlobentry(var::AbstractDFGVariable, key::Symbol) +function getBlobentry(var::AbstractGraphVariable, key::Symbol) if !hasBlobentry(var, key) throw(LabelNotFoundError("Blobentry", key, collect(keys(var.dataDict)))) end @@ -85,7 +85,7 @@ Finds and returns the first blob entry that matches the filter. Also see: [`getBlobentry`](@ref) """ -function getfirstBlobentry(var::AbstractDFGVariable, blobId::UUID) +function getfirstBlobentry(var::AbstractGraphVariable, blobId::UUID) for (k, v) in var.dataDict if blobId == v.blobId return v @@ -98,7 +98,7 @@ function getfirstBlobentry(dfg::AbstractDFG, label::Symbol, blobId::UUID) return getfirstBlobentry(getVariable(dfg, label), blobId) end -function getfirstBlobentry(var::AbstractDFGVariable, key::Regex) +function getfirstBlobentry(var::AbstractGraphVariable, key::Regex) for (k, v) in var.dataDict if occursin(key, string(v.label)) return v @@ -152,7 +152,7 @@ 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::AbstractGraphVariable, 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) @@ -182,7 +182,7 @@ Update a Blobentry in the factor graph. If the Blobentry does not exist, it will be added. Notes: """ -function mergeBlobentry!(var::AbstractDFGVariable, bde::Blobentry) +function mergeBlobentry!(var::AbstractGraphVariable, bde::Blobentry) if !haskey(var.dataDict, bde.label) addBlobentry!(var, bde) else @@ -203,7 +203,7 @@ Note this doesn't remove it from any data stores. Notes: - users responsibility to delete data in db before deleting entry """ -function deleteBlobentry!(var::AbstractDFGVariable, key::Symbol) +function deleteBlobentry!(var::AbstractGraphVariable, key::Symbol) pop!(var.dataDict, key) return 1 end @@ -226,7 +226,7 @@ function deleteBlobentry!(dfg::AbstractDFG, label::Symbol, key::Symbol) return deleteBlobentry!(getVariable(dfg, label), key) end -function deleteBlobentry!(var::AbstractDFGVariable, entry::Blobentry) +function deleteBlobentry!(var::AbstractGraphVariable, entry::Blobentry) #users responsibility to delete data in db before deleting entry return deleteBlobentry!(var, entry.label) end @@ -240,7 +240,8 @@ end Does a blob entry exist with `blobLabel`. """ -hasBlobentry(var::AbstractDFGVariable, blobLabel::Symbol) = haskey(var.dataDict, blobLabel) +hasBlobentry(var::AbstractGraphVariable, blobLabel::Symbol) = + haskey(var.dataDict, blobLabel) function hasBlobentry(var::VariableDFG, label::Symbol) return label in getproperty.(var.blobEntries, :label) @@ -251,7 +252,7 @@ end Get blob entries, Vector{Blobentry} """ -function getBlobentries(var::AbstractDFGVariable) +function getBlobentries(var::AbstractGraphVariable) #or should we return the iterator, Base.ValueIterator{Dict{Symbol,Blobentry}}? return collect(values(var.dataDict)) end @@ -311,7 +312,7 @@ end $(SIGNATURES) List the blob entries associated with a particular variable. """ -function listBlobentries(var::AbstractDFGVariable) +function listBlobentries(var::AbstractGraphVariable) return collect(keys(var.dataDict)) end diff --git a/src/DataBlobs/services/BlobStores.jl b/src/DataBlobs/services/BlobStores.jl index 42eee96f..078cda66 100644 --- a/src/DataBlobs/services/BlobStores.jl +++ b/src/DataBlobs/services/BlobStores.jl @@ -7,6 +7,8 @@ Get the data blob for the specified blobstore or dfg. Related [`getBlobentry`](@ref) +Implement +`getBlob(store::AbstractBlobstore, blobId::UUID)` $(METHODLIST) """ @@ -17,67 +19,31 @@ Adds a blob to the blob store or dfg with the blobId. Related [`addBlobentry!`](@ref) - +Implement +`addBlob!(store::AbstractBlobstore, blobId::UUID, data)` $(METHODLIST) """ function addBlob! end -""" -Update a blob to the blob store or dfg with the given entry. -Related -[`mergeBlobentry!`](@ref) - -$(METHODLIST) - -DevNotes -- TODO TBD update verb on data since data blobs and entries are restricted to immutable only. -""" -function updateBlob! end - """ Delete a blob from the blob store or dfg with the given entry. Related [`deleteBlobentry!`](@ref) - +Implement +`deleteBlob!(store::AbstractBlobstore, blobId::UUID)` $(METHODLIST) """ function deleteBlob! end """ $(SIGNATURES) -List all ids in the blob store. +List all `blobId`s in the blob store. +Implement +`listBlobs(store::AbstractBlobstore)` """ function listBlobs end -##============================================================================== -## AbstractBlobstore CRUD Interface -##============================================================================== - -function getBlob(store::AbstractBlobstore, ::UUID) - return error("$(typeof(store)) doesn't override 'getBlob'.") -end - -function addBlob!(store::AbstractBlobstore{T}, ::UUID, ::T) where {T} - return error("$(typeof(store)) doesn't override 'addBlob!'.") -end - -function updateBlob!(store::AbstractBlobstore{T}, ::UUID, ::T) where {T} - return error("$(typeof(store)) doesn't override 'updateBlob!'.") -end - -function deleteBlob!(store::AbstractBlobstore, ::UUID) - return error("$(typeof(store)) doesn't override 'deleteBlob!'.") -end - -function listBlobs(store::AbstractBlobstore) - return error("$(typeof(store)) doesn't override 'listBlobs'.") -end - -function hasBlob(store::AbstractBlobstore, ::UUID) - return error("$(typeof(store)) doesn't override 'hasBlob'.") -end - ##============================================================================== ## AbstractBlobstore derived CRUD for Blob ##============================================================================== diff --git a/src/Deprecated.jl b/src/Deprecated.jl index 28901498..1f5e78bf 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -9,115 +9,95 @@ export AbstractRelativeMinimize, InferenceType, PackedSamplableBelief +#TODO: maybe just remove these +export NoSolverParams + const AbstractPrior = PriorObservation const AbstractRelative = RelativeObservation +const AbstractParams = AbstractDFGParams abstract type AbstractRelativeMinimize <: RelativeObservation end abstract type AbstractManifoldMinimize <: RelativeObservation end -const InferenceVariable = VariableStateType{Any} -const InferenceType = AbstractPackedFactorObservation +const InferenceVariable = StateType{Any} +const InferenceType = AbstractPackedObservation const PackedSamplableBelief = PackedBelief +export getVariableState +export addVariableState! +export mergeVariableState! +export deleteVariableState! +export listVariableStates +export VariableState +export VariableStateType +export copytoVariableState! +const getVariableState = getState +const addVariableState! = addState! +const mergeVariableState! = mergeState! +const deleteVariableState! = deleteState! +const listVariableStates = listStates +const VariableState = State +const VariableStateType = StateType +const copytoVariableState! = copytoState! + export setSolverData! # """ # $SIGNATURES # Set solver data structure stored in a variable. # """ -function setSolverData!(v::VariableCompute, data::VariableState, key::Symbol = :default) +function setSolverData!(v::VariableCompute, data::State, key::Symbol = :default) Base.depwarn( - "setSolverData!(v::VariableCompute, data::VariableState, key::Symbol = :default) is deprecated, use mergeVariableState! instead.", + "setSolverData!(v::VariableCompute, data::State, key::Symbol = :default) is deprecated, use mergeState! instead.", :setSolverData!, ) - @assert key == data.solveKey "VariableState.solveKey=:$(data.solveKey) does not match requested :$(key)" + @assert key == data.solveKey "State.solveKey=:$(data.solveKey) does not match requested :$(key)" return v.solverDataDict[key] = data end -@deprecate mergeVariableSolverData!(args...; kwargs...) mergeVariableState!( - args...; - kwargs..., -) +@deprecate mergeVariableSolverData!(args...; kwargs...) mergeState!(args...; kwargs...) export mergeVariableData!, mergeGraphVariableData! function mergeVariableData!(args...) return error( - "mergeVariableData! is obsolete, use mergeVariableState! for state, PPEs are obsolete", + "mergeVariableData! is obsolete, use mergeState! for state, PPEs are obsolete", ) end function mergeGraphVariableData!(args...) return error( - "mergeGraphVariableData! is obsolete, use mergeVariableState! for state, PPEs are obsolete", + "mergeGraphVariableData! is obsolete, use mergeState! for state, PPEs are obsolete", ) end -#NOTE List types funcction do not fit verb noun and will be deprecated. -# should return types - # """ -# $SIGNATURES +# $(SIGNATURES) +# Gives back all factor labels that fit the bill: +# lsWho(dfg, :Pose3) -# Return `Vector{Symbol}` of all unique variable types in factor graph. -# """ -function lsTypes(dfg::AbstractDFG) - vars = getVariables(dfg) - alltypes = Set{Symbol}() - for v in vars - varType = Symbol(typeof(getVariableType(v))) - push!(alltypes, varType) - end - return collect(alltypes) -end +# Notes +# - Returns `Vector{Symbol}` -# """ -# $SIGNATURES +# Dev Notes +# - Cloud versions will benefit from less data transfer +# - `ls(dfg::C, ::T) where {C <: CloudDFG, T <: ..}` + +# Related -# Return `::Dict{Symbol, Vector{Symbol}}` of all unique variable types with labels in a factor graph. +# ls, lsf, lsfPriors # """ -function lsTypesDict(dfg::AbstractDFG) +function lsWho(dfg::AbstractDFG, type::Symbol) + Base.depwarn("lsWho(dfg, type) is deprecated, use ls(dfg, type) instead.", :lsWho) vars = getVariables(dfg) - alltypes = Dict{Symbol, Vector{Symbol}}() + labels = Symbol[] for v in vars - varType = Symbol(typeof(getVariableType(v))) - d = get!(alltypes, varType, Symbol[]) - push!(d, v.label) + varType = typeof(getVariableType(v)) |> nameof + varType == type && push!(labels, v.label) end - return alltypes -end - -# """ -# $SIGNATURES - -# Return `Vector{Symbol}` of all unique factor types in factor graph. -# """ -function lsfTypes(dfg::AbstractDFG) - facs = getFactors(dfg) - alltypes = Set{Symbol}() - for f in facs - facType = typeof(getFactorType(f)) |> nameof - push!(alltypes, facType) - end - return collect(alltypes) -end - -# """ -# $SIGNATURES - -# Return `::Dict{Symbol, Vector{Symbol}}` of all unique factors types with labels in a factor graph. -# """ -function lsfTypesDict(dfg::AbstractDFG) - facs = getFactors(dfg) - 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 labels end # solvekey is deprecated and sync!/copyto! is the better verb. -#TODO replace with syncVariableStates! or similar +#TODO replace with syncStates! or similar # """ # $SIGNATURES # Duplicate a `solveKey`` into a destination from a source. @@ -136,8 +116,8 @@ function cloneSolveKey!( ) # for x in labels - sd = deepcopy(getVariableState(getVariable(src_dfg, x), src)) - copytoVariableState!(dest_dfg, x, dest, sd) + sd = deepcopy(getState(getVariable(src_dfg, x), src)) + copytoState!(dest_dfg, x, dest, sd) end return nothing @@ -149,20 +129,100 @@ function cloneSolveKey!(dfg::AbstractDFG, dest::Symbol, src::Symbol; kw...) return cloneSolveKey!(dfg, dest, dfg, src; kw...) end +export getData, addData!, updateData!, deleteData! + +#TODO not a good function, as it's not complete. +# """ +# $(SIGNATURES) +# Convenience function to get all the metadata of a DFG +# """ +# export getDFGInfo +function getDFGInfo(dfg::AbstractDFG) + return ( + description = getDescription(dfg), + agentLabel = getAgentLabel(dfg), + graphLabel = getGraphLabel(dfg), + agentMetadata = getAgentMetadata(dfg), + graphMetadata = getGraphMetadata(dfg), + solverParams = getSolverParams(dfg), + ) +end + +export DFGVariable +const DFGVariable = VariableCompute + +export listSolveKeys, listSupersolves +# """ +# $TYPEDSIGNATURES +# List all the solvekeys used amongst all variables in the distributed factor graph object. + +# Related + +# [`listSolveKeys`](@ref), [`getSolverDataDict`](@ref), [`listVariables`](@ref) +# """ +function listSolveKeys( + variable::VariableCompute, + filterSolveKeys::Union{Regex, Nothing} = nothing, + skeys = Set{Symbol}(), +) + Base.depwarn("listSolveKeys is deprecated, use listStates instead.", :listSolveKeys) + # + 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) + return skeys +end + +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{<:StateType}, 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) + for vs in varList #, ky in keys(getSolverDataDict(getVariable(dfg, vs))) + listSolveKeys(dfg, vs, filterSolveKeys, skeys) + end + + # done inside the loop + # #filter the solveKey set with filterSolveKeys regex + # !isnothing(filterSolveKeys) && return filter!(k -> occursin(filterSolveKeys, string(k)), skeys) + + return skeys +end +const listSupersolves = listSolveKeys + ## ================================================================================ ## Deprecated in v0.27 ##================================================================================= export AbstractFactor -const AbstractFactor = AbstractFactorObservation +const AbstractFactor = AbstractObservation export AbstractPackedFactor -const AbstractPackedFactor = AbstractPackedFactorObservation +const AbstractPackedFactor = AbstractPackedObservation export FactorOperationalMemory -const FactorOperationalMemory = FactorSolverCache +const FactorOperationalMemory = FactorCache export VariableNodeData -const VariableNodeData = VariableState +const VariableNodeData = State @deprecate getNeighborhood(args...; kwargs...) listNeighborhood(args...; kwargs...) @deprecate addBlob!(store::AbstractBlobstore, blobId::UUID, data, ::String) addBlob!( @@ -214,8 +274,8 @@ const VariableNodeData = VariableState @deprecate hasBlobEntry(args...; kwargs...) hasBlobentry(args...; kwargs...) @deprecate getBlobEntry(args...; kwargs...) getBlobentry(args...; kwargs...) @deprecate getBlobEntryFirst(args...; kwargs...) getfirstBlobentry(args...; kwargs...) -@deprecate getBlobentry(var::AbstractDFGVariable, blobId::UUID) getfirstBlobentry( - var::AbstractDFGVariable, +@deprecate getBlobentry(var::AbstractGraphVariable, blobId::UUID) getfirstBlobentry( + var::AbstractGraphVariable, blobId::UUID, ) @deprecate addBlobEntry!(args...; kwargs...) addBlobentry!(args...; kwargs...) @@ -228,28 +288,19 @@ const VariableNodeData = VariableState ) @deprecate mergeBlobEntries!(args...; kwargs...) mergeBlobentries!(args...; kwargs...) -@deprecate getVariableSolverData(args...; kwargs...) getVariableState(args...; kwargs...) -@deprecate addVariableSolverData!(args...; kwargs...) addVariableState!(args...; kwargs...) -@deprecate deleteVariableSolverData!(args...; kwargs...) deleteVariableState!( - args...; - kwargs..., -) -@deprecate listVariableSolverData(args...; kwargs...) listVariableStates(args...; kwargs...) -@deprecate getVariableSolverDataAll(args...; kwargs...) getVariableStates( - args...; - kwargs..., -) +@deprecate getVariableSolverData(args...; kwargs...) getState(args...; kwargs...) +@deprecate addVariableSolverData!(args...; kwargs...) addState!(args...; kwargs...) +@deprecate deleteVariableSolverData!(args...; kwargs...) deleteState!(args...; kwargs...) +@deprecate listVariableSolverData(args...; kwargs...) listStates(args...; kwargs...) +@deprecate getVariableSolverDataAll(args...; kwargs...) getStates(args...; kwargs...) -@deprecate getSolverData(v::VariableCompute, solveKey::Symbol = :default) getVariableState( +@deprecate getSolverData(v::VariableCompute, solveKey::Symbol = :default) getState( v, solveKey, ) -@deprecate packVariableNodeData(args...; kwargs...) packVariableState(args...; kwargs...) -@deprecate unpackVariableNodeData(args...; kwargs...) unpackVariableState( - args...; - kwargs..., -) +@deprecate packVariableNodeData(args...; kwargs...) packState(args...; kwargs...) +@deprecate unpackVariableNodeData(args...; kwargs...) unpackState(args...; kwargs...) export updateVariableSolverData! @@ -257,27 +308,27 @@ export updateVariableSolverData! function updateVariableSolverData!( dfg::AbstractDFG, variablekey::Symbol, - vnd::VariableState, + vnd::State, useCopy::Bool = false, fields::Vector{Symbol} = Symbol[]; warn_if_absent::Bool = true, ) Base.depwarn( - "updateVariableSolverData! is deprecated, use mergeVariableState! or copytoVariableState! instead", + "updateVariableSolverData! is deprecated, use mergeState! or copytoState! instead", :updateVariableSolverData!, ) #This is basically just setSolverData var = getVariable(dfg, variablekey) warn_if_absent && !haskey(var.solverDataDict, vnd.solveKey) && - @warn "VariableState '$(vnd.solveKey)' does not exist, adding" + @warn "State '$(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], VariableState) && + isa(var.solverDataDict[vnd.solveKey], State) && length(fields) != 0 # @error useExisting vnd.solveKey if useExisting @@ -304,7 +355,7 @@ end function updateVariableSolverData!( dfg::AbstractDFG, variablekey::Symbol, - vnd::VariableState, + vnd::State, solveKey::Symbol, useCopy::Bool = false, fields::Vector{Symbol} = Symbol[]; @@ -313,7 +364,7 @@ function updateVariableSolverData!( # TODO not very clean if vnd.solveKey != solveKey Base.depwarn( - "updateVariableSolverData with solveKey is deprecated use copytoVariableState! instead.", + "updateVariableSolverData with solveKey is deprecated use copytoState! instead.", :updateVariableSolverData!, ) usevnd = useCopy ? deepcopy(vnd) : vnd @@ -351,7 +402,7 @@ function updateVariableSolverData!( # toshow = listSolveKeys(sourceVariable) |> collect # @info "update DFGVar solveKey" solveKey vnd.solveKey # @show toshow - @assert solveKey == vnd.solveKey "VariableState's solveKey=:$(vnd.solveKey) does not match requested :$solveKey" + @assert solveKey == vnd.solveKey "State's solveKey=:$(vnd.solveKey) does not match requested :$solveKey" return updateVariableSolverData!( dfg, sourceVariable.label, @@ -385,11 +436,7 @@ end ## factor refactor deprecations Base.@kwdef mutable struct GenericFunctionNodeData{ - T <: Union{ - <:AbstractPackedFactorObservation, - <:AbstractFactorObservation, - <:FactorSolverCache, - }, + T <: Union{<:AbstractPackedObservation, <:AbstractObservation, <:FactorCache}, } eliminated::Bool = false potentialused::Bool = false @@ -412,7 +459,7 @@ function FactorCompute( variableOrder::Union{Vector{Symbol}, Tuple}; observation = getFactorType(solverData), state::FactorState = FactorState(), - solvercache::Base.RefValue{<:FactorSolverCache} = Ref{FactorSolverCache}(), + solvercache::Base.RefValue{<:FactorCache} = Ref{FactorCache}(), id::Union{UUID, Nothing} = nothing, smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}(), ) @@ -467,7 +514,7 @@ function decodePackedType( varOrder::AbstractVector{Symbol}, ::Type{T}, packeddata::GenericFunctionNodeData{PT}, -) where {T <: FactorSolverCache, PT} +) where {T <: FactorCache, PT} error("decodePackedType is obsolete") # # TODO, to solve IIF 1424 @@ -481,7 +528,7 @@ function decodePackedType( end export _packSolverData -function _packSolverData(f::FactorCompute, fnctype::AbstractFactorObservation) +function _packSolverData(f::FactorCompute, fnctype::AbstractObservation) # error("_packSolverData is deprecated, use seperate packing of observation #TODO") packtype = convertPackedType(fnctype) @@ -501,20 +548,19 @@ end export GenericFunctionNodeData, PackedFunctionNodeData, FunctionNodeData const PackedFunctionNodeData{T} = - GenericFunctionNodeData{T} where {T <: AbstractPackedFactorObservation} + GenericFunctionNodeData{T} where {T <: AbstractPackedObservation} function PackedFunctionNodeData(args...; kw...) error("PackedFunctionNodeData is obsolete") return PackedFunctionNodeData{typeof(args[4])}(args...; kw...) end -const FunctionNodeData{T} = GenericFunctionNodeData{ - T, -} where {T <: Union{<:AbstractFactorObservation, <:FactorSolverCache}} +const FunctionNodeData{T} = + GenericFunctionNodeData{T} where {T <: Union{<:AbstractObservation, <:FactorCache}} FunctionNodeData(args...; kw...) = FunctionNodeData{typeof(args[4])}(args...; kw...) # this is the GenericFunctionNodeData for packed types #TODO deprecate FactorData in favor of FactorState (with no more distinction between packed and compute) -const FactorData = PackedFunctionNodeData{AbstractPackedFactorObservation} +const FactorData = PackedFunctionNodeData{AbstractPackedObservation} function FactorCompute( label::Symbol, @@ -542,7 +588,7 @@ function FactorCompute( solverData.inflation, ) - if solverData.fnc isa FactorSolverCache + if solverData.fnc isa FactorCache solvercache = solverData.fnc else solvercache = nothing @@ -574,14 +620,14 @@ end #TODO make sure getFactorOperationalMemoryType is obsolete function getFactorOperationalMemoryType(dummy) return error( - "Please extend your workspace with function getFactorOperationalMemoryType(<:AbstractParams) for your usecase, e.g. IncrementalInference uses `CommonConvWrapper <: FactorSolverCache`", + "Please extend your workspace with function getFactorOperationalMemoryType(<:AbstractParams) for your usecase, e.g. IncrementalInference uses `CommonConvWrapper <: FactorCache`", ) end function getFactorOperationalMemoryType(dfg::AbstractDFG) return getFactorOperationalMemoryType(getSolverParams(dfg)) end -function typeModuleName(variableType::VariableStateType) +function typeModuleName(variableType::StateType) Base.depwarn("typeModuleName is obsolete", :typeModuleName) io = IOBuffer() ioc = IOContext(io, :module => DistributedFactorGraphs) @@ -589,7 +635,7 @@ function typeModuleName(variableType::VariableStateType) return String(take!(io)) end -typeModuleName(varT::Type{<:VariableStateType}) = typeModuleName(varT()) +typeModuleName(varT::Type{<:StateType}) = typeModuleName(varT()) ## ================================================================================ ## Deprecated in v0.25 diff --git a/src/DistributedFactorGraphs.jl b/src/DistributedFactorGraphs.jl index cd16cee2..b73e8699 100644 --- a/src/DistributedFactorGraphs.jl +++ b/src/DistributedFactorGraphs.jl @@ -49,8 +49,6 @@ using RecursiveArrayTools: ArrayPartition export ArrayPartition using StaticArrays -import Base: getindex - using InteractiveUtils: subtypes ##============================================================================== @@ -89,17 +87,69 @@ export DFG export GraphsDFGs, GraphsDFG ## -export getVariableState, getFactorState # FIXME these were questioned and being reviewed again for name, other than that they are checked. +export getState, getFactorState # FIXME these were questioned and being reviewed again for name, other than that they are checked. + +## CRUD Matrix +# export addVariable!, getVariable, mergeVariable!, deleteVariable! +# export addVariables!, getVariables, mergeVariables!, deleteVariables! +# export addFactor!, getFactor, mergeFactor!, deleteFactor! +# export addFactors!, getFactors, mergeFactors!, deleteFactors! + +# export addState!, getState, mergeState!, deleteState! +# export addStates!, getStates, mergeStates!, deleteStates! + +# export addBlobentry!, getBlobentry, mergeBlobentry!, deleteBlobentry! # historic for VariableBlobentry +# export addBlobentries!, getBlobentries, mergeBlobentries!, deleteBlobentries! +# export addGraphBlobentry!, getGraphBlobentry, mergeGraphBlobentry!, deleteGraphBlobentry! +# export addGraphBlobentries!, getGraphBlobentries, mergeGraphBlobentries!, deleteGraphBlobentries! +# export addAgentBlobentry!, getAgentBlobentry, mergeAgentBlobentry!, deleteAgentBlobentry! +# export addAgentBlobentries!, getAgentBlobentries, mergeAgentBlobentries!, deleteAgentBlobentries! +# export addFactorBlobentry!, getFactorBlobentry, mergeFactorBlobentry!, deleteFactorBlobentry! +# export addFactorBlobentries!, getFactorBlobentries, mergeFactorBlobentries!, deleteFactorBlobentries! + +# export addVariableMetadata!, getVariableMetadata, mergeVariableMetadata!, deleteVariableMetadata! +# export addFactorMetadata!, getFactorMetadata, mergeFactorMetadata!, deleteFactorMetadata! +# export addAgentMetadata!, getAgentMetadata, mergeAgentMetadata!, deleteAgentMetadata! +# export addGraphMetadata!, getGraphMetadata, mergeGraphMetadata!, deleteGraphMetadata! + +# export addVariableBlobentryMetadata!, getVariableBlobentryMetadata, mergeVariableBlobentryMetadata!, deleteVariableBlobentryMetadata! +# export addFactorBlobentryMetadata!, getFactorBlobentryMetadata, mergeFactorBlobentryMetadata!, deleteFactorBlobentryMetadata! +# export addAgentBlobentryMetadata!, getAgentBlobentryMetadata, mergeAgentBlobentryMetadata!, deleteAgentBlobentryMetadata! +# export addGraphBlobentryMetadata!, getGraphBlobentryMetadata, mergeGraphBlobentryMetadata!, deleteGraphBlobentryMetadata! + +## list +# export listVariables, listFactors, listStates, listBlobentries, listFactorBlobEntries, listGraphBlobentries, listAgentBlobentries +# export listVariableMetadata, listFactorMetadata, listAgentMetadata, listGraphMetadata +# export listVariableBlobentryMetadata, listFactorBlobentryMetadata, listAgentBlobentryMetadata, listGraphBlobentryMetadata + +##------------------------------------------------------------------------------ +## Abstract types +##------------------------------------------------------------------------------ + +export AbstractObservation, AbstractPackedObservation +export PriorObservation, RelativeObservation +export FactorCache + +#TODO +export PackedBelief + +# public AbstractGraphVariable, AbstractGraphFactor + +##============================================================================== +## Internal or not yet ready +##============================================================================== ##------------------------------------------------------------------------------ ## DFG ##------------------------------------------------------------------------------ +export AbstractDFGParams, DFGParams + +# Abstract Nodes +export AbstractGraphNode export AbstractDFG -export AbstractParams, NoSolverParams export AbstractBlobstore # accessors & crud -export getDFGInfo export getDescription, setDescription!, getSolverParams, @@ -146,8 +196,6 @@ export exists, deleteFactor!, listVariables, listFactors, - listSolveKeys, - listSupersolves, getVariables, getFactors, isVariable, @@ -161,9 +209,6 @@ export getBiadjacencyMatrix export getSummaryGraph -# Abstract Nodes -export DFGNode, AbstractDFGVariable, AbstractDFGFactor - # Variables export VariableCompute, VariableSummary, VariableSkeleton, VariableDFG @@ -179,17 +224,18 @@ export getLabel, getTimestamp, setTimestamp, getTags, setTags! export getAgentLabel, getGraphLabel -# Node Data +#TODO these are currently unused, do we deprecate? export isSolveInProgress, getSolveInProgress # CRUD & SET -export listTags, mergeTags!, removeTags!, emptyTags! +export listTags, mergeTags!, emptyTags! +export removeTags! #TODO do we want this one ##------------------------------------------------------------------------------ # Variable ##------------------------------------------------------------------------------ # Abstract Variable Data -export VariableStateType +export StateType # accessors export getSolverDataDict @@ -214,8 +260,7 @@ export getMetadata, emptyMetadata! # CRUD & SET -export getVariableStates, - addVariableState!, mergeVariableState!, deleteVariableState!, listVariableStates +export getStates, addState!, mergeState!, deleteState!, listStates # PPE ##------------------------------------------------------------------------------ @@ -234,9 +279,9 @@ export getPPE, # Variable Node Data ##------------------------------------------------------------------------------ -export VariableState, PackedVariableState +export State, PackedState -export packVariableState, unpackVariableState +export packState, unpackState export getSolvedCount, isSolved, setSolvedCount!, isInitialized, isMarginalized, setMarginalized! @@ -269,9 +314,6 @@ export @format_str # exported from FileIO # Factors ##------------------------------------------------------------------------------ # Factor Data -export AbstractFactorObservation, AbstractPackedFactorObservation -export PriorObservation, RelativeObservation -export FactorSolverCache # accessors export getVariableOrder @@ -290,11 +332,10 @@ export pack, unpack, packDistribution, unpackDistribution export natural_lt, sortDFG # Validation -export isValidLabel +# export isValidLabel ## List export ls, lsf, ls2 -export lsWho export isPrior, lsfPriors export hasTags, hasTagsNeighbors @@ -308,7 +349,8 @@ export @defVariable # File import and export export saveDFG, loadDFG!, loadDFG -export toDot, toDotFile + +# export toDot, toDotFile # shortest path export findShortestPathDijkstra @@ -341,7 +383,6 @@ export Blobentry # export copyStore export getId, getHash, getTimestamp # convenience wrappers -export getData, addData!, updateData!, deleteData! export plotDFG @@ -375,7 +416,7 @@ include("entities/DFGFactor.jl") include("entities/DFGVariable.jl") -include("entities/Agent.jl") +include("entities/Agent_and_Graph.jl") include("services/AbstractDFG.jl") @@ -385,6 +426,9 @@ include("DataBlobs/services/BlobStores.jl") include("DataBlobs/services/BlobPacking.jl") include("DataBlobs/services/HelpersDataWrapEntryBlob.jl") +# To be moved as necessary. +include("Common.jl") + # In Memory Types include("GraphsDFG/GraphsDFG.jl") using .GraphsDFGs @@ -407,9 +451,6 @@ include("FileDFG/FileDFG.jl") # Custom show and printing for variable factor etc. include("services/CustomPrinting.jl") -# To be moved as necessary. -include("Common.jl") - include("weakdeps_prototypes.jl") #TODO start off as just an alias before deprecating @@ -420,9 +461,6 @@ const SkeletonDFGVariable = VariableSkeleton export DFGVariableSummary const DFGVariableSummary = VariableSummary -export DFGVariable -const DFGVariable = VariableCompute - export PackedVariable const PackedVariable = VariableDFG export Variable diff --git a/src/FileDFG/services/FileDFG.jl b/src/FileDFG/services/FileDFG.jl index 3eac17cf..fbffbfaa 100644 --- a/src/FileDFG/services/FileDFG.jl +++ b/src/FileDFG/services/FileDFG.jl @@ -1,4 +1,3 @@ - """ $(SIGNATURES) Save a DFG to a folder. Will create/overwrite folder if it exists. @@ -228,7 +227,21 @@ function loadDFG(file::AbstractString) #Only GraphsDFG metadata supported jstr = read("$loaddir/dfg.json", String) - fgPacked = JSON3.read(jstr, GraphsDFGs.PackedGraphsDFG) + # --------------------------------- + #TODO deprecate old format, v0.28 + local fgPacked + try + fgPacked = JSON3.read(jstr, GraphsDFGs.PackedGraphsDFG) + catch e + if e isa MethodError + @warn "Deprecated serialization: Failed to read DFG metadata. Attempting to load using the old format. Error:" e + fgPacked = + GraphsDFGs.PackedGraphsDFG(JSON3.read(jstr, GraphsDFGs._OldPackedGraphsDFG)) + else + rethrow(e) + end + end + # ---------------------------------- dfg = GraphsDFGs.unpackDFGMetadata(fgPacked) @debug "DFG.loadDFG is deleting a temp folder created during unzip, $loaddir" diff --git a/src/GraphsDFG/FactorGraphs/BiMaps.jl b/src/GraphsDFG/FactorGraphs/BiMaps.jl index 0fbfa1b4..14134786 100644 --- a/src/GraphsDFG/FactorGraphs/BiMaps.jl +++ b/src/GraphsDFG/FactorGraphs/BiMaps.jl @@ -1,4 +1,3 @@ -# import Base: getindex, setindex!, firstindex, lastindex, iterate, keys, isempty struct BiDictMap{T <: Integer} int_sym::Dict{T, Symbol} sym_int::Dict{Symbol, T} diff --git a/src/GraphsDFG/FactorGraphs/FactorGraphs.jl b/src/GraphsDFG/FactorGraphs/FactorGraphs.jl index 28dc4641..567de3dc 100644 --- a/src/GraphsDFG/FactorGraphs/FactorGraphs.jl +++ b/src/GraphsDFG/FactorGraphs/FactorGraphs.jl @@ -3,9 +3,7 @@ using Graphs using OrderedCollections -import Base: eltype, show, ==, Pair, Tuple, copy, length, size, issubset, zero, getindex -# import Random: -# randstring, seed! +import Base import Graphs: AbstractGraph, @@ -39,18 +37,11 @@ import Graphs.SimpleGraphs: AbstractSimpleGraph, SimpleGraph, SimpleDiGraph, SimpleEdge, fadj, badj export FactorGraph -# addVariable!, -# addFactor!, -# GraphsBayesGraph, -# filter_edges, -# filter_vertices, -# reverse - -# import DistributedFactorGraphs: DFGNode -# const AbstractNodeType = DFGNode -import DistributedFactorGraphs: AbstractDFGVariable, AbstractDFGFactor -const AbstractVariableType = AbstractDFGVariable -const AbstractFactorType = AbstractDFGFactor + +using DistributedFactorGraphs: AbstractGraphNode +import DistributedFactorGraphs: AbstractGraphVariable, AbstractGraphFactor +const AbstractVariableType = AbstractGraphVariable +const AbstractFactorType = AbstractGraphFactor include("BiMaps.jl") @@ -82,7 +73,7 @@ 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) +function Base.show(io::IO, ::MIME"text/plain", g::FactorGraph) dir = is_directed(g) ? "directed" : "undirected" return print(io, "{$(nv(g)), $(ne(g))} $dir $(eltype(g)) $(typeof(g))") end @@ -90,7 +81,7 @@ 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) +Base.eltype(g::FactorGraph) = eltype(g.graph) edgetype(g::FactorGraph) = edgetype(g.graph) nv(g::FactorGraph) = nv(g.graph) vertices(g::FactorGraph) = vertices(g.graph) @@ -108,7 +99,7 @@ is_directed(::Type{FactorGraph}) = 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) +Base.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) diff --git a/src/GraphsDFG/GraphsDFG.jl b/src/GraphsDFG/GraphsDFG.jl index 0898a5f7..61a75647 100644 --- a/src/GraphsDFG/GraphsDFG.jl +++ b/src/GraphsDFG/GraphsDFG.jl @@ -8,7 +8,15 @@ using OrderedCollections using StructTypes using ...DistributedFactorGraphs -using ...DistributedFactorGraphs: Agent, LabelNotFoundError, LabelExistsError +using ...DistributedFactorGraphs: + Agent, + LabelNotFoundError, + LabelExistsError, + FactorgraphRoot, + AbstractGraphVariable, + AbstractGraphFactor, + NoSolverParams, + filterDFG! # import DFG functions to extend import ...DistributedFactorGraphs: diff --git a/src/GraphsDFG/entities/GraphsDFG.jl b/src/GraphsDFG/entities/GraphsDFG.jl index 9463a5b0..2064f933 100644 --- a/src/GraphsDFG/entities/GraphsDFG.jl +++ b/src/GraphsDFG/entities/GraphsDFG.jl @@ -7,31 +7,31 @@ An in-memory DistributedFactorGraph based on Graphs.jl with parameters: - F: Factor type """ mutable struct GraphsDFG{ - T <: AbstractParams, - V <: AbstractDFGVariable, - F <: AbstractDFGFactor, -} <: AbstractDFG{T} + T <: AbstractDFGParams, + V <: AbstractGraphVariable, + F <: AbstractGraphFactor, +} <: AbstractDFG{V, F} g::FactorGraph{Int, V, F} - description::String addHistory::Vector{Symbol} #TODO: Discuss more - is this an audit trail? solverParams::T # Solver parameters blobStores::Dict{Symbol, AbstractBlobstore} - # new structure to replace URS - graphLabel::Symbol # graph (session) label - graphTags::Vector{Symbol} - graphMetadata::Dict{Symbol, SmallDataTypes} # graph (session) metadata - graphBlobEntries::OrderedDict{Symbol, Blobentry} #graph (session) blob entries - agent::Agent # (robot) + graph::FactorgraphRoot + agent::Agent end DFG.getAgent(dfg::GraphsDFG) = dfg.agent +DFG.getGraphLabel(dfg::GraphsDFG) = dfg.graph.label +DFG.getMetadata(dfg::GraphsDFG) = dfg.graph.metadata +DFG.getDescription(dfg::GraphsDFG) = dfg.graph.description -DFG.getGraphLabel(dfg::GraphsDFG) = dfg.graphLabel -DFG.getMetadata(dfg::GraphsDFG) = dfg.graphMetadata function DFG.setMetadata!(dfg::GraphsDFG, metadata::Dict{Symbol, SmallDataTypes}) # with set old data should be removed, but care is taken to make sure its not the same object - dfg.graphMetadata !== metadata && empty!(dfg.graphMetadata) - return merge!(dfg.graphMetadata, metadata) + dfg.graph.metadata !== metadata && empty!(dfg.graph.metadata) + return merge!(dfg.graph.metadata, metadata) +end + +function DFG.setDescription!(dfg::GraphsDFG, description::String) + return dfg.graph.description = description end """ @@ -54,6 +54,13 @@ function GraphsDFG{T, V, F}( graphBlobEntries = OrderedDict{Symbol, Blobentry}(), description::String = "", graphDescription::String = description, + graph::FactorgraphRoot = FactorgraphRoot( + graphLabel, + graphDescription, + graphTags, + graphMetadata, + graphBlobEntries, + ), # agent agentLabel::Symbol = :DefaultAgent, agentDescription::String = "", @@ -67,28 +74,24 @@ function GraphsDFG{T, V, F}( agentMetadata, agentBlobEntries, ), -) where {T <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} +) where {T <: AbstractDFGParams, V <: AbstractGraphVariable, F <: AbstractGraphFactor} # Validate the graphLabel and agentLabel - !isValidLabel(graphLabel) && error("'$graphLabel' is not a valid label") - !isValidLabel(agentLabel) && error("'$agentLabel' is not a valid label") + !DFG.isValidLabel(graphLabel) && error("'$graphLabel' is not a valid label") + !DFG.isValidLabel(agentLabel) && error("'$agentLabel' is not a valid label") return GraphsDFG{T, V, F}( g, - graphDescription, addHistory, solverParams, blobStores, # new fields - graphLabel, - graphTags, - graphMetadata, - graphBlobEntries, + graph, agent, ) end -# GraphsDFG{T}(; kwargs...) where T <: AbstractParams = GraphsDFG{T,VariableCompute,FactorCompute}(;kwargs...) +# GraphsDFG{T}(; kwargs...) where T <: AbstractDFGParams = GraphsDFG{T,VariableCompute,FactorCompute}(;kwargs...) function GraphsDFG{T}( g::FactorGraph{Int, VariableCompute, FactorCompute} = FactorGraph{ Int, @@ -96,7 +99,7 @@ function GraphsDFG{T}( FactorCompute, }(); kwargs..., -) where {T <: AbstractParams} +) where {T <: AbstractDFGParams} return GraphsDFG{T, VariableCompute, FactorCompute}(g; kwargs...) end diff --git a/src/GraphsDFG/services/GraphsDFG.jl b/src/GraphsDFG/services/GraphsDFG.jl index 62dc58af..6d01ab1b 100644 --- a/src/GraphsDFG/services/GraphsDFG.jl +++ b/src/GraphsDFG/services/GraphsDFG.jl @@ -9,21 +9,21 @@ end function isVariable( dfg::GraphsDFG{P, V, F}, sym::Symbol, -) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} +) where {P <: AbstractDFGParams, V <: AbstractGraphVariable, F <: AbstractGraphFactor} return haskey(dfg.g.variables, sym) end function isFactor( dfg::GraphsDFG{P, V, F}, sym::Symbol, -) where {P <: AbstractParams, V <: AbstractDFGVariable, F <: AbstractDFGFactor} +) where {P <: AbstractDFGParams, V <: AbstractGraphVariable, F <: AbstractGraphFactor} return haskey(dfg.g.factors, sym) end function addVariable!( - dfg::GraphsDFG{<:AbstractParams, V, <:AbstractDFGFactor}, + dfg::GraphsDFG{<:AbstractDFGParams, V, <:AbstractGraphFactor}, variable::V, -) where {V <: AbstractDFGVariable} +) where {V <: AbstractGraphVariable} if haskey(dfg.g.variables, variable.label) throw(LabelExistsError("Variable", variable.label)) end @@ -37,16 +37,16 @@ function addVariable!( end function addVariable!( - dfg::GraphsDFG{<:AbstractParams, VD, <:AbstractDFGFactor}, - variable::AbstractDFGVariable, -) where {VD <: AbstractDFGVariable} + dfg::GraphsDFG{<:AbstractDFGParams, VD, <:AbstractGraphFactor}, + variable::AbstractGraphVariable, +) where {VD <: AbstractGraphVariable} return addVariable!(dfg, VD(variable)) end function addFactor!( - dfg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, F}, + dfg::GraphsDFG{<:AbstractDFGParams, <:AbstractGraphVariable, F}, factor::F, -) where {F <: AbstractDFGFactor} +) where {F <: AbstractGraphFactor} if haskey(dfg.g.factors, factor.label) throw(LabelExistsError("Factor", factor.label)) end @@ -61,9 +61,9 @@ function addFactor!( end function addFactor!( - dfg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, F}, - factor::AbstractDFGFactor, -) where {F <: AbstractDFGFactor} + dfg::GraphsDFG{<:AbstractDFGParams, <:AbstractGraphVariable, F}, + factor::AbstractGraphFactor, +) where {F <: AbstractGraphFactor} return addFactor!(dfg, F(factor)) end @@ -82,7 +82,7 @@ function getFactor(dfg::GraphsDFG, label::Symbol) return dfg.g.factors[label] end -function mergeVariable!(dfg::GraphsDFG, variable::AbstractDFGVariable) +function mergeVariable!(dfg::GraphsDFG, variable::AbstractGraphVariable) if !haskey(dfg.g.variables, variable.label) addVariable!(dfg, variable) else @@ -91,7 +91,7 @@ function mergeVariable!(dfg::GraphsDFG, variable::AbstractDFGVariable) return 1 end -function mergeFactor!(dfg::GraphsDFG, factor::AbstractDFGFactor;) +function mergeFactor!(dfg::GraphsDFG, factor::AbstractGraphFactor;) if !haskey(dfg.g.factors, factor.label) addFactor!(dfg, factor) elseif dfg.g.factors[factor.label]._variableOrderSymbols != factor._variableOrderSymbols @@ -107,7 +107,7 @@ function mergeFactor!(dfg::GraphsDFG, factor::AbstractDFGFactor;) return 1 end -function deleteVariable!(dfg::GraphsDFG, label::Symbol)#::Tuple{AbstractDFGVariable, Vector{<:AbstractDFGFactor}} +function deleteVariable!(dfg::GraphsDFG, label::Symbol)#::Tuple{AbstractGraphVariable, Vector{<:AbstractGraphFactor}} if !haskey(dfg.g.variables, label) throw(LabelNotFoundError("Variable", label)) end @@ -128,25 +128,56 @@ function deleteFactor!(dfg::GraphsDFG, label::Symbol; suppressGetFactor::Bool = return 1 end +# """ +# tagsFilter = ⊇([:x1]) +# tagsFilter([:x1, :x2]) +# true +# tagsFilter = Base.Fix1(in, :x1) +# tagsFilter([:x1, :x2]) +# true +# """ + function getVariables( dfg::GraphsDFG, - regexFilter::Union{Nothing, Regex} = nothing; + regex::Union{Nothing, Regex} = nothing; tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, - solvableFilter::Union{Nothing, Base.Fix2} = nothing, + solvable::Union{Nothing, Int} = nothing, + solvableFilter::Union{Nothing, Function} = nothing, + labelFilter::Union{Nothing, Function} = nothing, + tagsFilter::Union{Nothing, Function} = nothing, + typeFilter::Union{Nothing, Function} = nothing, ) - - # variables = map(v -> v.dfgNode, filter(n -> n.dfgNode isa VariableCompute, vertices(dfg.g))) variables = collect(values(dfg.g.variables)) - !isnothing(regexFilter) && - filter!(v -> occursin(regexFilter, String(v.label)), variables) - - solvable != 0 && filter!(v -> _isSolvable(dfg, v.label, solvable), variables) - - !isempty(tags) && filter!(v -> !isempty(intersect(v.tags, tags)), variables) + if !isnothing(regex) + # NOTE that contains(regex::Regex) is not supported by the NvaDFG. + Base.depwarn( + "The regex filter argument is deprecated, use kwarg `labelFilter=contains(regex)` instead", #v0.28 + :getVariables, + ) + filterDFG!(variables, contains(regex), (String ∘ getLabel)) + end + if !isempty(tags) + # NOTE that !isdisjoint is not supported by NvaDFG. + Base.depwarn( + "tags kwarg is deprecated, use kwarg `tagsFilter = !isdisjoint(tags)` instead", #v0.28 + :getVariables, + ) + filterDFG!(variables, x -> !isdisjoint(x, tags), getTags) + end + if !isnothing(solvable) + #TODO review. just one solvableFilter or keep solvable as well. + Base.depwarn( + "solvable kwarg is deprecated, use kwarg `solvableFilter = (>=solvable)` instead", #v0.28 + :getVariables, + ) + filterDFG!(variables, >=(solvable), getSolvable) + end - !isnothing(solvableFilter) && filter!(v -> solvableFilter(getSolvable(v)), variables) + filterDFG!(variables, labelFilter, (String ∘ getLabel)) + filterDFG!(variables, solvableFilter, getSolvable) + filterDFG!(variables, tagsFilter, getTags) + filterDFG!(variables, typeFilter, getVariableType) return variables end @@ -155,44 +186,79 @@ function listVariables( dfg::GraphsDFG, regexFilter::Union{Nothing, Regex} = nothing; tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, - solvableFilter::Union{Nothing, Base.Fix2} = nothing, + solvable::Union{Nothing, Int} = nothing, + solvableFilter::Union{Nothing, Function} = nothing, + tagsFilter::Union{Nothing, Function} = nothing, + typeFilter::Union{Nothing, Function} = nothing, + labelFilter::Union{Nothing, Function} = nothing, ) - - # variables = map(v -> v.dfgNode, filter(n -> n.dfgNode isa VariableCompute, vertices(dfg.g))) - if length(tags) > 0 + if !isnothing(solvableFilter) || + !isnothing(tagsFilter) || + !isnothing(typeFilter) || + !isnothing(regexFilter) || #TODO deprecated + !isempty(tags) || #TODO deprecated + !isnothing(solvable) #TODO Maybe deprecated? return map( - v -> v.label, - getVariables(dfg, regexFilter; tags = tags, solvable = solvable), - )::Vector{Symbol} + getLabel, + getVariables( + dfg, + regexFilter; + tags, + solvable, + solvableFilter, + tagsFilter, + typeFilter, + labelFilter, + ), + ) else - variables = copy(dfg.g.variables.keys) - !isnothing(regexFilter) && filter!(v -> occursin(regexFilter, String(v)), variables) - solvable != 0 && filter!(vId -> _isSolvable(dfg, vId, solvable), variables) - !isnothing(solvableFilter) && - filter!(v -> solvableFilter(getSolvable(dfg, v)), variables) - return variables::Vector{Symbol} + # Is it ok to continue using the internal keys property? collect(keys(dfg.g.variables)) allowcates a lot. + labels = copy(dfg.g.variables.keys) + filterDFG!(labels, labelFilter, string) + return labels end end function getFactors( dfg::GraphsDFG, - regexFilter::Union{Nothing, Regex} = nothing; + regex::Union{Nothing, Regex} = nothing; tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, + solvable::Union{Nothing, Int} = nothing, + solvableFilter::Union{Nothing, Function} = nothing, + tagsFilter::Union{Nothing, Function} = nothing, + typeFilter::Union{Nothing, Function} = nothing, + labelFilter::Union{Nothing, Function} = nothing, ) - # factors = map(v -> v.dfgNode, filter(n -> n.dfgNode isa FactorCompute, vertices(dfg.g))) factors = collect(values(dfg.g.factors)) - if !isnothing(regexFilter) - factors = filter(f -> occursin(regexFilter, String(f.label)), factors) + if !isnothing(regex) + # NOTE that contains(regex::Regex) is not supported by the NvaDFG. + Base.depwarn( + "The regex filter argument is deprecated, use kwarg `labelFilter=contains(regex)` instead", #v0.28 + :getFactors, + ) + filterDFG!(factors, contains(regex), (String ∘ getLabel)) end - if solvable != 0 - factors = filter(f -> _isSolvable(dfg, f.label, solvable), factors) + if !isempty(tags) + # NOTE that !isdisjoint is not supported by NvaDFG. + Base.depwarn( + "tags kwarg is deprecated, use kwarg `tagsFilter = !isdisjoint(tags)` instead", #v0.28 + :getFactors, + ) + filterDFG!(factors, x -> !isdisjoint(x, tags), getTags) end - if length(tags) > 0 - mask = map(v -> length(intersect(v.tags, tags)) > 0, factors) - return factors[mask] + if !isnothing(solvable) + #TODO review. just one solvableFilter or keep solvable as well. + Base.depwarn( + "solvable kwarg is deprecated, use kwarg `solvableFilter = (>=solvable)` instead", #v0.28 + :getFactors, + ) + filterDFG!(factors, >=(solvable), getSolvable) end + + filterDFG!(factors, labelFilter, (String ∘ getLabel)) + filterDFG!(factors, solvableFilter, getSolvable) + filterDFG!(factors, tagsFilter, getTags) + filterDFG!(factors, typeFilter, typeof ∘ getFactorType) return factors end @@ -200,23 +266,37 @@ function listFactors( dfg::GraphsDFG, regexFilter::Union{Nothing, Regex} = nothing; tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, + solvable::Union{Nothing, Int} = nothing, + solvableFilter::Union{Nothing, Function} = nothing, + tagsFilter::Union{Nothing, Function} = nothing, + typeFilter::Union{Nothing, Function} = nothing, + labelFilter::Union{Nothing, Function} = nothing, ) - # factors = map(v -> v.dfgNode, filter(n -> n.dfgNode isa FactorCompute, vertices(dfg.g))) - if length(tags) > 0 + if !isnothing(solvableFilter) || + !isnothing(tagsFilter) || + !isnothing(typeFilter) || + !isnothing(regexFilter) || #TODO deprecated + !isempty(tags) || #TODO deprecated + !isnothing(solvable) #TODO Maybe deprecated? return map( - v -> v.label, - getFactors(dfg, regexFilter; tags = tags, solvable = solvable), + getLabel, + getFactors( + dfg, + regexFilter; + tags, + solvable, + solvableFilter, + tagsFilter, + typeFilter, + labelFilter, + ), ) + else + # Is it ok to continue using the internal keys property? collect(keys(dfg.g.factors)) allowcates a lot. + labels = copy(dfg.g.factors.keys) + filterDFG!(labels, labelFilter, string) + return labels end - factors = copy(dfg.g.factors.keys) - if !isnothing(regexFilter) - factors = filter(f -> occursin(regexFilter, String(f)), factors) - end - if solvable != 0 - factors = filter(fId -> _isSolvable(dfg, fId, solvable), factors) - end - return factors::Vector{Symbol} end function isConnected(dfg::GraphsDFG) @@ -224,17 +304,27 @@ function isConnected(dfg::GraphsDFG) # return length(Graphs.connected_components(dfg.g)) == 1 end +_isSolvable(dfg::GraphsDFG, label::Symbol, ready::Nothing) = true + function _isSolvable(dfg::GraphsDFG, label::Symbol, ready::Int) haskey(dfg.g.variables, label) && (return dfg.g.variables[label].solvable >= ready) haskey(dfg.g.factors, label) && (return dfg.g.factors[label].solvable >= ready) throw(LabelNotFoundError(label)) end -function listNeighbors(dfg::GraphsDFG, node::DFGNode; solvable::Int = 0) +function listNeighbors( + dfg::GraphsDFG, + node::AbstractGraphNode; + solvable::Union{Nothing, Int} = nothing, +) return listNeighbors(dfg, node.label; solvable) end -function listNeighbors(dfg::GraphsDFG, label::Symbol; solvable::Int = 0) +function listNeighbors( + dfg::GraphsDFG, + label::Symbol; + solvable::Union{Nothing, Int} = nothing, +) if !(hasVariable(dfg, label) || hasFactor(dfg, label)) throw(LabelNotFoundError(label)) end @@ -257,7 +347,7 @@ function listNeighborhood( dfg::GraphsDFG, variableFactorLabels::Vector{Symbol}, distance::Int; - solvable::Int = 0, + solvable::Union{Nothing, Int} = nothing, ) # find neighbors at distance to add nbhood = Int[] @@ -268,7 +358,8 @@ function listNeighborhood( allvarfacs = [dfg.g.labels[id] for id in nbhood] - solvable != 0 && filter!(nlbl -> (getSolvable(dfg, nlbl) >= solvable), allvarfacs) + !isnothing(solvable) && + filter!(nlbl -> (getSolvable(dfg, nlbl) >= solvable), allvarfacs) return allvarfacs end @@ -285,9 +376,9 @@ end # Biadjacency Matrix https://en.wikipedia.org/wiki/Adjacency_matrix#Of_a_bipartite_graph function getBiadjacencyMatrix( dfg::GraphsDFG; - solvable::Int = 0, - varLabels = listVariables(dfg; solvable = solvable), - factLabels = listFactors(dfg; solvable = solvable), + solvable::Union{Nothing, Int} = nothing, + varLabels = listVariables(dfg; solvable), + factLabels = listFactors(dfg; solvable), ) varIndex = [dfg.g.labels[s] for s in varLabels] factIndex = [dfg.g.labels[s] for s in factLabels] @@ -304,13 +395,13 @@ 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} +) where {P <: AbstractDFGParams, V <: AbstractGraphVariable, F <: AbstractGraphFactor} newDfg = GraphsDFG{P, V, F}(; agentLabel = getAgentLabel(dfg), graphLabel = getGraphLabel(dfg), solverParams = deepcopy(dfg.solverParams), ) - newDfg.description = "(Copy of) $(dfg.description)" + DFG.setDescription!(newDfg, "(Copy of) $(DFG.getDescription(dfg))") return newDfg end @@ -363,7 +454,7 @@ function findShortestPathDijkstra( tagsFactors::Vector{Symbol} = Symbol[], typeVariables::Union{Nothing, <:AbstractVector} = nothing, typeFactors::Union{Nothing, <:AbstractVector} = nothing, - solvable::Int = 0, + solvable::Union{Nothing, Int} = nothing, initialized::Union{Nothing, Bool} = nothing, ) # @@ -378,14 +469,14 @@ function findShortestPathDijkstra( # duplicate = - regexVariables !== nothing || - regexFactors !== nothing || - 0 < length(tagsVariables) || - 0 < length(tagsFactors) || - typeVariables !== nothing || - typeFactors !== nothing || - initialized !== nothing || - solvable != 0 + !isnothing(regexVariables) || + !isnothing(regexFactors) || + !isempty(tagsVariables) || + !isempty(tagsFactors) || + !isnothing(typeVariables) || + !isnothing(typeFactors) || + !isnothing(initialized) || + !isnothing(solvable) # dfg_ = if duplicate # use copy if filter is being applied @@ -458,10 +549,10 @@ end # FG blob entries function getGraphBlobentry(fg::GraphsDFG, label::Symbol) - if !haskey(fg.graphBlobEntries, label) + if !haskey(fg.graph.blobEntries, label) throw(LabelNotFoundError("GraphBlobentry", label)) end - return fg.graphBlobEntries[label] + return fg.graph.blobEntries[label] end function getGraphBlobentries( @@ -487,10 +578,10 @@ function listAgentBlobentries(fg::GraphsDFG) end function addGraphBlobentry!(fg::GraphsDFG, entry::Blobentry) - if haskey(fg.graphBlobEntries, entry.label) + if haskey(fg.graph.blobEntries, entry.label) throw(LabelExistsError("Blobentry", entry.label)) end - push!(fg.graphBlobEntries, entry.label => entry) + push!(fg.graph.blobEntries, entry.label => entry) return entry end diff --git a/src/GraphsDFG/services/GraphsDFGSerialization.jl b/src/GraphsDFG/services/GraphsDFGSerialization.jl index 1cd210f6..b26a850c 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 _OldPackedGraphsDFG{T <: AbstractDFGParams} description::String addHistory::Vector{Symbol} solverParams::T @@ -14,18 +14,73 @@ using InteractiveUtils graphBlobEntries::OrderedDict{Symbol, Blobentry} agent::Agent end +StructTypes.StructType(::Type{_OldPackedGraphsDFG}) = StructTypes.AbstractType() +function StructTypes.StructType( + ::Type{_OldPackedGraphsDFG{T}}, +) where {T <: AbstractDFGParams} + return StructTypes.Struct() +end +StructTypes.subtypekey(::Type{_OldPackedGraphsDFG}) = :solverParams_type +#TODO look at StructTypes.@register_struct_subtype when new StructTypes.jl is tagged (for type field) + +function StructTypes.subtypes(::Type{_OldPackedGraphsDFG}) + subs = subtypes(AbstractDFGParams) + return NamedTuple(map(s -> nameof(s) => _OldPackedGraphsDFG{s}, subs)) +end + +@kwdef struct PackedGraphsDFG{T <: AbstractDFGParams} + addHistory::Vector{Symbol} + solverParams::T + solverParams_type::String = string(nameof(typeof(solverParams))) + typePackedVariable::Bool = false # Are variables packed or full + typePackedFactor::Bool = false # Are factors packed or full + blobStores::Union{Nothing, Dict{Symbol, FolderStore{Vector{UInt8}}}} #FIXME allow more types of blobstores + graph::FactorgraphRoot + agent::Agent +end + +# TODO deprecate, constructor serialization backwards compatibility, v0.28 +function PackedGraphsDFG(old::_OldPackedGraphsDFG) + return PackedGraphsDFG{typeof(old.solverParams)}( + old.addHistory, + old.solverParams, + old.solverParams_type, + old.typePackedVariable, + old.typePackedFactor, + old.blobStores, + FactorgraphRoot( + old.graphLabel, + old.description, + old.graphTags, + old.graphMetadata, + old.graphBlobEntries, + ), + old.agent, + ) +end StructTypes.StructType(::Type{PackedGraphsDFG}) = StructTypes.AbstractType() +function StructTypes.StructType(::Type{PackedGraphsDFG{T}}) where {T <: AbstractDFGParams} + return StructTypes.Struct() +end 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}) - subs = subtypes(AbstractParams) + subs = subtypes(AbstractDFGParams) return NamedTuple(map(s -> nameof(s) => PackedGraphsDFG{s}, subs)) end -getTypeDFGVariables(fg::GraphsDFG{<:AbstractParams, T, <:AbstractDFGFactor}) where {T} = T -getTypeDFGFactors(fg::GraphsDFG{<:AbstractParams, <:AbstractDFGVariable, T}) where {T} = T +function getTypeDFGVariables( + fg::GraphsDFG{<:AbstractDFGParams, T, <:AbstractGraphFactor}, +) where {T} + return T +end +function getTypeDFGFactors( + fg::GraphsDFG{<:AbstractDFGParams, <:AbstractGraphVariable, T}, +) where {T} + return T +end ## """ diff --git a/src/entities/AbstractDFG.jl b/src/entities/AbstractDFG.jl index 9daaf38b..01256f36 100644 --- a/src/entities/AbstractDFG.jl +++ b/src/entities/AbstractDFG.jl @@ -1,39 +1,54 @@ +# TODO consider enforcing the full structure. +# This is not explicitly inforced, but surves as extra information of how the structure is put together. +# AbstractDFGNode are all nodes that make up a DFG, including Agent, Graph, Variable, Factor, Blobstore, etc. +# abstract type AbstractDFGNode end +# any DFGNode shall have a label. +# abstract type AbstractGraphNode end <: AbstractDFGNode +# the rest of the nodes are also AbstractDFGNodes, eg. +# Agent <: AbstractGraphNode +# FactorgraphRoot <: AbstractGraphNode + """ $(TYPEDEF) Abstract parent struct for DFG variables and factors. """ -abstract type DFGNode end +abstract type AbstractGraphNode end #✅ +const GraphNode = AbstractGraphNode """ $(TYPEDEF) An abstract DFG variable. """ -abstract type AbstractDFGVariable <: DFGNode end +abstract type AbstractGraphVariable <: AbstractGraphNode end #✅ +const GraphVariable = AbstractGraphVariable """ $(TYPEDEF) An abstract DFG factor. """ -abstract type AbstractDFGFactor <: DFGNode end +abstract type AbstractGraphFactor <: AbstractGraphNode end #✅ +const GraphFactor = AbstractGraphFactor """ $(TYPEDEF) -Abstract parent struct for solver parameters. +Abstract parent struct for a DFG graph. """ -abstract type AbstractParams end +abstract type AbstractDFG{V <: AbstractGraphVariable, F <: AbstractGraphFactor} end #✅ +#const DFG clashes with module DFG. """ $(TYPEDEF) -Abstract parent struct for a DFG graph. - """ -abstract type AbstractDFG{T <: AbstractParams} end +Abstract parent struct for solver parameters. +""" +abstract type AbstractDFGParams end #✅ +const DFGParams = AbstractDFGParams """ $(TYPEDEF) Empty structure for solver parameters. """ -@kwdef struct NoSolverParams <: AbstractParams +@kwdef struct NoSolverParams <: AbstractDFGParams d::Int = 0#FIXME JSON3.jl error MethodError: no method matching read(::StructTypes.SingletonType, ... end diff --git a/src/entities/Agent.jl b/src/entities/Agent.jl deleted file mode 100644 index d304384c..00000000 --- a/src/entities/Agent.jl +++ /dev/null @@ -1,7 +0,0 @@ -@kwdef struct Agent - label::Symbol = :DefaultAgent - description::String = "" - tags::Vector{Symbol} = Symbol[] - metadata::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}() - blobEntries::OrderedDict{Symbol, Blobentry} = OrderedDict{Symbol, Blobentry}() -end diff --git a/src/entities/Agent_and_Graph.jl b/src/entities/Agent_and_Graph.jl new file mode 100644 index 00000000..93561dd2 --- /dev/null +++ b/src/entities/Agent_and_Graph.jl @@ -0,0 +1,16 @@ +#TODO maybe mutable +@kwdef mutable struct Agent + label::Symbol = :DefaultAgent + description::String = "" + tags::Vector{Symbol} = Symbol[] + metadata::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}() + blobEntries::OrderedDict{Symbol, Blobentry} = OrderedDict{Symbol, Blobentry}() +end + +@kwdef mutable struct FactorgraphRoot + label::Symbol = :DefaultFactorgraph + description::String = "" + tags::Vector{Symbol} = Symbol[] + metadata::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}() + blobEntries::OrderedDict{Symbol, Blobentry} = OrderedDict{Symbol, Blobentry}() +end diff --git a/src/entities/DFGFactor.jl b/src/entities/DFGFactor.jl index 618c3808..857b6465 100644 --- a/src/entities/DFGFactor.jl +++ b/src/entities/DFGFactor.jl @@ -2,19 +2,27 @@ ## Abstract Types ##============================================================================== -abstract type AbstractPackedFactorObservation end -abstract type AbstractFactorObservation end - -abstract type PriorObservation <: AbstractFactorObservation end -abstract type RelativeObservation <: AbstractFactorObservation end -abstract type PackedObservation <: AbstractFactorObservation end -# NOTE DF, Convolution is IIF idea, but DFG should know about "FactorSolverCache" -# DF, IIF.CommonConvWrapper <: FactorSolverCache # -# NOTE was `<: Function` as unnecessary -abstract type FactorSolverCache end -# TODO to be removed from DFG, -# we can add to IIF or have IIF.CommonConvWrapper <: FactorSolverCache directly -# abstract type ConvolutionObject <: FactorSolverCache end +abstract type AbstractPackedObservation end #✅ +const PackedObservation = AbstractPackedObservation + +abstract type AbstractObservation end #✅ +const Observation = AbstractObservation + +abstract type AbstractPriorObservation <: AbstractObservation end #✅ +const PriorObservation = AbstractPriorObservation + +abstract type AbstractRelativeObservation <: AbstractObservation end #✅ +const RelativeObservation = AbstractRelativeObservation + +abstract type AbstractPackedBelief end #✅ +const PackedBelief = AbstractPackedBelief + +# TODO https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/pull/1127#discussion_r2154672975 +# and #1138 +abstract type AbstractFactorCache end #✅ +const FactorCache = AbstractFactorCache # + +##============================================================================== #TODO is this mutable @kwdef mutable struct FactorState @@ -27,11 +35,6 @@ abstract type FactorSolverCache end inflation::Float64 = 0.0 end -# TODO should we move non FactorSolverCache to FactorCompute: -# fnc, multihypo, nullhypo, inflation ? -# that way we split solverData <: FactorSolverCache and constants -# TODO see if above ever changes? - ## Constructors ##============================================================================== @@ -53,7 +56,7 @@ end The Factor information packed in a way that accomdates multi-lang using json. """ -Base.@kwdef struct FactorDFG <: AbstractDFGFactor +Base.@kwdef struct FactorDFG <: AbstractGraphFactor id::Union{UUID, Nothing} = nothing label::Symbol tags::Set{Symbol} @@ -125,18 +128,16 @@ function FactorDFG( ) end -FactorDFG(f::FactorDFG) = f - # Packed Factor constructor function assembleFactorName(xisyms::Union{Vector{String}, Vector{Symbol}}) return Symbol(xisyms..., "_f", randstring(4)) end -getFncTypeName(fnc::AbstractPackedFactorObservation) = split(string(typeof(fnc)), ".")[end] +getFncTypeName(fnc::AbstractPackedObservation) = split(string(typeof(fnc)), ".")[end] function FactorDFG( xisyms::Vector{Symbol}, - fnc::AbstractPackedFactorObservation; + fnc::AbstractPackedObservation; multihypo::Vector{Float64} = Float64[], nullhypo::Float64 = 0.0, solvable::Int = 1, @@ -185,7 +186,7 @@ DevNotes Fields: $(TYPEDFIELDS) """ -Base.@kwdef struct FactorCompute{FT <: AbstractFactorObservation, N} <: AbstractDFGFactor +Base.@kwdef struct FactorCompute{FT <: AbstractObservation, N} <: AbstractGraphFactor """The ID for the factor""" id::Union{UUID, Nothing} = nothing #TODO deprecate id """Factor label, e.g. :x1f1. @@ -219,7 +220,7 @@ Base.@kwdef struct FactorCompute{FT <: AbstractFactorObservation, N} <: Abstract """Temporary, non-persistent memory used internally by the solver for intermediate numerical computations and buffers. `solvercache` is lazily allocated and only used during factor operations; it is not serialized or retained after solving. Accessors: [`getCache`](@ref), [`setCache!`](@ref)""" - solvercache::Base.RefValue{<:FactorSolverCache} #TODO easy of use vs. performance as container is abstract in any case. + solvercache::Base.RefValue{<:FactorCache} #TODO easy of use vs. performance as container is abstract in any case. end ##------------------------------------------------------------------------------ @@ -229,7 +230,7 @@ end function FactorCompute( label::Symbol, variableOrder::Union{Vector{Symbol}, Tuple}, - observation::AbstractFactorObservation, + observation::AbstractObservation, state::FactorState = FactorState(), cache = nothing; tags::Set{Symbol} = Set{Symbol}(), @@ -245,7 +246,7 @@ function FactorCompute( end if isnothing(cache) - solvercache = Ref{FactorSolverCache}() + solvercache = Ref{FactorCache}() else solvercache = Ref(cache) end @@ -303,7 +304,7 @@ Read-only summary factor structure for a DistributedFactorGraph factor. Fields: $(TYPEDFIELDS) """ -Base.@kwdef struct FactorSummary <: AbstractDFGFactor +Base.@kwdef struct FactorSummary <: AbstractGraphFactor """The ID for the factor""" id::Union{UUID, Nothing} """Factor label, e.g. :x1f1. @@ -342,7 +343,7 @@ Skeleton factor structure for a DistributedFactorGraph factor. Fields: $(TYPEDFIELDS) """ -Base.@kwdef struct FactorSkeleton <: AbstractDFGFactor +Base.@kwdef struct FactorSkeleton <: AbstractGraphFactor """The ID for the factor""" id::Union{UUID, Nothing} """Factor label, e.g. :x1f1. @@ -368,13 +369,6 @@ function FactorSkeleton( return FactorSkeleton(id, label, tags, variableOrderSymbols) end -##============================================================================== -## Define factor levels -##============================================================================== -const FactorDataLevel0 = Union{FactorCompute, FactorSummary, FactorDFG, FactorSkeleton} -const FactorDataLevel1 = Union{FactorCompute, FactorSummary, FactorDFG} -const FactorDataLevel2 = Union{FactorCompute} - ##============================================================================== ## Conversion constructors ##============================================================================== @@ -389,7 +383,7 @@ function FactorSummary(f::FactorCompute) ) end -function FactorSkeleton(f::FactorDataLevel1) +function FactorSkeleton(f::AbstractGraphFactor) return FactorSkeleton( f.id, f.label, diff --git a/src/entities/DFGVariable.jl b/src/entities/DFGVariable.jl index ebc1247d..ba316bfb 100644 --- a/src/entities/DFGVariable.jl +++ b/src/entities/DFGVariable.jl @@ -2,10 +2,11 @@ ## Abstract Types ##============================================================================== -abstract type VariableStateType{N} end +abstract type AbstractStateType{N} end +const StateType = AbstractStateType ##============================================================================== -## VariableState +## State ##============================================================================== """ @@ -19,7 +20,7 @@ N: Manifold dimension. Fields: $(TYPEDFIELDS) """ -Base.@kwdef mutable struct VariableState{T <: VariableStateType, P, N} +Base.@kwdef mutable struct State{T <: StateType, P, N} """ Globally unique identifier. """ @@ -70,7 +71,7 @@ Base.@kwdef mutable struct VariableState{T <: VariableStateType, P, N} """ solvedCount::Int = 0 """ - solveKey identifier associated with this VariableState object. + solveKey identifier associated with this State object. """ solveKey::Symbol = :default """ @@ -82,32 +83,32 @@ end ##------------------------------------------------------------------------------ ## Constructors -function VariableState{T}(; kwargs...) where {T <: VariableStateType} - return VariableState{T, getPointType(T), getDimension(T)}(; kwargs...) +function State{T}(; kwargs...) where {T <: StateType} + return State{T, getPointType(T), getDimension(T)}(; kwargs...) end -function VariableState(variableType::VariableStateType; kwargs...) - return VariableState{typeof(variableType)}(; kwargs...) +function State(variableType::StateType; kwargs...) + return State{typeof(variableType)}(; kwargs...) end -function VariableState(state::VariableState; kwargs...) - return VariableState{typeof(getVariableType(state))}(; - (key => deepcopy(getproperty(state, key)) for key in fieldnames(VariableState))..., +function State(state::State; kwargs...) + return State{typeof(getVariableType(state))}(; + (key => deepcopy(getproperty(state, key)) for key in fieldnames(State))..., kwargs..., ) end ##============================================================================== -## PackedVariableState.jl +## PackedState.jl ##============================================================================== """ $(TYPEDEF) -Packed VariableState structure for serializing DFGVariables. +Packed State structure for serializing DFGVariables. --- Fields: $(TYPEDFIELDS) """ -Base.@kwdef mutable struct PackedVariableState +Base.@kwdef mutable struct PackedState id::Union{UUID, Nothing} # If it's blank it doesn't exist in the DB. vecval::Vector{Float64} dimval::Int @@ -134,9 +135,9 @@ end # createdTimestamp::DateTime#! # lastUpdatedTimestamp::DateTime#! -StructTypes.StructType(::Type{PackedVariableState}) = StructTypes.UnorderedStruct() -StructTypes.idproperty(::Type{PackedVariableState}) = :id -StructTypes.omitempties(::Type{PackedVariableState}) = (:id,) +StructTypes.StructType(::Type{PackedState}) = StructTypes.UnorderedStruct() +StructTypes.idproperty(::Type{PackedState}) = :id +StructTypes.omitempties(::Type{PackedState}) = (:id,) ##============================================================================== ## PointParametricEst @@ -220,7 +221,7 @@ Notes: - nstime can be used as mission time, with the convention that the timestamp millis coincide with the mission start nstime - e.g. timestamp is `2020-01-01 06:30:01.250 UTC` and first nstime is `250_000_000`. """ -Base.@kwdef struct VariableDFG <: AbstractDFGVariable +Base.@kwdef struct VariableDFG <: AbstractGraphVariable id::Union{UUID, Nothing} = nothing label::Symbol tags::Vector{Symbol} = Symbol[] @@ -232,7 +233,7 @@ Base.@kwdef struct VariableDFG <: AbstractDFGVariable _version::VersionNumber = _getDFGVersion() metadata::String = "e30=" solvable::Int = 1 - solverData::Vector{PackedVariableState} = PackedVariableState[] + solverData::Vector{PackedState} = PackedState[] end # maybe add to variable # createdTimestamp::DateTime @@ -289,7 +290,7 @@ Complete variable structure for a DistributedFactorGraph variable. Fields: $(TYPEDFIELDS) """ -Base.@kwdef struct VariableCompute{T <: VariableStateType, P, N} <: AbstractDFGVariable +Base.@kwdef struct VariableCompute{T <: StateType, P, N} <: AbstractGraphVariable """The ID for the variable""" id::Union{UUID, Nothing} = nothing """Variable label, e.g. :x1. @@ -308,9 +309,8 @@ Base.@kwdef struct VariableCompute{T <: VariableStateType, P, N} <: AbstractDFGV ppeDict::Dict{Symbol, AbstractPointParametricEst} = Dict{Symbol, AbstractPointParametricEst}() """Dictionary of solver data. May be a subset of all solutions if a solver label was specified in the get call. - Accessors: [`addVariableState!`](@ref), [`mergeVariableState!`](@ref), and [`deleteVariableState!`](@ref)""" - solverDataDict::Dict{Symbol, VariableState{T, P, N}} = - Dict{Symbol, VariableState{T, P, N}}() + Accessors: [`addState!`](@ref), [`mergeState!`](@ref), and [`deleteState!`](@ref)""" + solverDataDict::Dict{Symbol, State{T, P, N}} = Dict{Symbol, State{T, P, N}}() """Dictionary of small data associated with this variable. Accessors: [`getMetadata`](@ref), [`setMetadata!`](@ref)""" smallData::Dict{Symbol, SmallDataTypes} = Dict{Symbol, SmallDataTypes}() @@ -331,7 +331,7 @@ The default VariableCompute constructor. """ function VariableCompute( label::Symbol, - T::Type{<:VariableStateType}; + T::Type{<:StateType}; timestamp::ZonedDateTime = now(localzone()), solvable::Union{Int, Base.RefValue{Int}} = Ref(1), kwargs..., @@ -343,11 +343,11 @@ function VariableCompute( return VariableCompute{T, P, N}(; label, timestamp, solvable, kwargs...) end -function VariableCompute(label::Symbol, variableType::VariableStateType; kwargs...) +function VariableCompute(label::Symbol, variableType::StateType; kwargs...) return VariableCompute(label, typeof(variableType); kwargs...) end -function VariableCompute(label::Symbol, solverData::VariableState; kwargs...) +function VariableCompute(label::Symbol, solverData::State; kwargs...) return VariableCompute(; label, solverDataDict = Dict(:default => solverData), @@ -390,7 +390,7 @@ Summary variable structure for a DistributedFactorGraph variable. Fields: $(TYPEDFIELDS) """ -Base.@kwdef struct VariableSummary <: AbstractDFGVariable +Base.@kwdef struct VariableSummary <: AbstractGraphVariable """The ID for the variable""" id::Union{UUID, Nothing} """Variable label, e.g. :x1. @@ -439,7 +439,7 @@ Skeleton variable structure for a DistributedFactorGraph variable. Fields: $(TYPEDFIELDS) """ -Base.@kwdef struct VariableSkeleton <: AbstractDFGVariable +Base.@kwdef struct VariableSkeleton <: AbstractGraphVariable """The ID for the variable""" id::Union{UUID, Nothing} = nothing """Variable label, e.g. :x1. @@ -458,14 +458,6 @@ function VariableSkeleton( return VariableSkeleton(id, label, tags) end -##============================================================================== -# Define variable levels -##============================================================================== -const VariableDataLevel0 = - Union{VariableCompute, VariableSummary, VariableDFG, VariableSkeleton} -const VariableDataLevel1 = Union{VariableCompute, VariableSummary, VariableDFG} -const VariableDataLevel2 = Union{VariableCompute} - ##============================================================================== ## Conversion constructors ##============================================================================== @@ -482,6 +474,6 @@ function VariableSummary(v::VariableCompute) ) end -function VariableSkeleton(v::VariableDataLevel1) +function VariableSkeleton(v::AbstractGraphVariable) return VariableSkeleton(v.id, v.label, copy(v.tags)) end diff --git a/src/services/AbstractDFG.jl b/src/services/AbstractDFG.jl index a3bb3377..0715f0e1 100644 --- a/src/services/AbstractDFG.jl +++ b/src/services/AbstractDFG.jl @@ -14,7 +14,7 @@ Base.Broadcast.broadcastable(dfg::AbstractDFG) = Ref(dfg) # TODO update to include graph and agent extras. # Standard recommended fields to implement for AbstractDFG # - `description::String` -# - `solverParams::T<:AbstractParams` +# - `solverParams::T<:AbstractDFGParams` # - `addHistory::Vector{Symbol}` # - `blobStores::Dict{Symbol, AbstractBlobstore}` # AbstractDFG Accessors @@ -41,25 +41,10 @@ Get the metadata of the node. """ getMetadata(node) = node.metadata -""" - $(SIGNATURES) -Convenience function to get all the metadata of a DFG -""" -function getDFGInfo(dfg::AbstractDFG) - return ( - description = getDescription(dfg), - agentLabel = getAgentLabel(dfg), - graphLabel = getGraphLabel(dfg), - agentMetadata = getAgentMetadata(dfg), - graphMetadata = getGraphMetadata(dfg), - solverParams = getSolverParams(dfg), - ) -end - """ $(SIGNATURES) """ -getAgent(dfg::AbstractDFG) = dfg.agent +function getAgent end """ $(SIGNATURES) @@ -96,11 +81,7 @@ getSolverParams(dfg::AbstractDFG) = dfg.solverParams Method must be overloaded by the user for Serialization to work. """ -function rebuildFactorCache!( - dfg::AbstractDFG{<:AbstractParams}, - factor::AbstractDFGFactor, - neighbors = [], -) +function rebuildFactorCache!(dfg::AbstractDFG, factor::AbstractGraphFactor, neighbors = []) @warn( "FactorCache not build, rebuildFactorCache! is not implemented for $(typeof(dfg)). Make sure to load IncrementalInference.", maxlog = 1 @@ -143,7 +124,7 @@ 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 -function setSolverParams!(dfg::AbstractDFG, solverParams::AbstractParams) +function setSolverParams!(dfg::AbstractDFG, solverParams::AbstractDFGParams) return dfg.solverParams = solverParams end @@ -194,7 +175,7 @@ function updateAgentMetadata!(dfg::AbstractDFG, pair::Pair{Symbol, String}) return push!(dfg.agent.metadata, pair) end function updateGraphMetadata!(dfg::AbstractDFG, pair::Pair{Symbol, String}) - return push!(dfg.graphMetadata, pair) + return push!(dfg.graph.metadata, pair) end function deleteAgentMetadata!(dfg::AbstractDFG, key::Symbol) @@ -203,12 +184,12 @@ function deleteAgentMetadata!(dfg::AbstractDFG, key::Symbol) end function deleteGraphMetadata!(dfg::AbstractDFG, key::Symbol) - pop!(dfg.graphMetadata, key) + pop!(dfg.graph.metadata, key) return 1 end emptyAgentMetadata!(dfg::AbstractDFG) = empty!(dfg.agent.metadata) -emptyGraphMetadata!(dfg::AbstractDFG) = empty!(dfg.graphMetadata) +emptyGraphMetadata!(dfg::AbstractDFG) = empty!(dfg.graph.metadata) #TODO add__Data!? @@ -281,32 +262,30 @@ listBlobstores(dfg::AbstractDFG) = collect(keys(dfg.blobStores)) """ $(SIGNATURES) True if the variable exists in the graph. +Implement `hasVariable(dfg::AbstractDFG, label::Symbol)` """ -function hasVariable(dfg::AbstractDFG, label::Symbol) - return error("hasVariable not implemented for $(typeof(dfg))") -end +function hasVariable end """ $(SIGNATURES) True if the factor exists in the graph. +Implement `hasFactor(dfg::AbstractDFG, label::Symbol)` """ -function hasFactor(dfg::AbstractDFG, label::Symbol) - return error("hasFactor not implemented for $(typeof(dfg))") -end +function hasFactor end """ $(SIGNATURES) Add a VariableCompute to a DFG. +Implement `addVariable!(dfg::AbstractDFG, variable::AbstractGraphVariable)` """ -function addVariable!(dfg::AbstractDFG, ::AbstractDFGVariable) - return error("addVariable! not implemented for $(typeof(dfg))") -end +function addVariable! end """ $(SIGNATURES) Add a Vector{VariableCompute} to a DFG. +Implement `addVariables!(dfg::AbstractDFG, variables::Vector{<:AbstractGraphVariable})` """ -function addVariables!(dfg::AbstractDFG, variables::Vector{<:AbstractDFGVariable}) +function addVariables!(dfg::AbstractDFG, variables::Vector{<:AbstractGraphVariable}) return asyncmap(variables) do v return addVariable!(dfg, v) end @@ -315,16 +294,15 @@ end """ $(SIGNATURES) Add a FactorCompute to a DFG. +Implement `addFactor!(dfg::AbstractDFG, factor::AbstractGraphFactor)` """ -function addFactor!(dfg::AbstractDFG, ::AbstractDFGFactor) - return error("addFactor! not implemented for $(typeof(dfg))(dfg, factor)") -end +function addFactor! end """ $(SIGNATURES) Add a Vector{FactorCompute} to a DFG. """ -function addFactors!(dfg::AbstractDFG, factors::Vector{<:AbstractDFGFactor}) +function addFactors!(dfg::AbstractDFG, factors::Vector{<:AbstractGraphFactor}) return asyncmap(factors) do f return addFactor!(dfg, f) end @@ -333,10 +311,9 @@ end """ $(SIGNATURES) Get a VariableCompute from a DFG using its label. +Implement `getVariable(dfg::AbstractDFG, label::Symbol)` """ -function getVariable(dfg::G, label::Symbol) where {G <: AbstractDFG} - return error("getVariable not implemented for $(typeof(dfg))") -end +function getVariable end """ $(SIGNATURES) @@ -365,10 +342,9 @@ function getVariablesSkeleton end """ $(SIGNATURES) Get a FactorCompute from a DFG using its label. +Implement `getFactor(dfg::AbstractDFG, label::Symbol)` """ -function getFactor(dfg::AbstractDFG, label::Symbol) - return error("getFactor not implemented for $(typeof(dfg))") -end +function getFactor end """ $(SIGNATURES) @@ -376,13 +352,13 @@ Get the skeleton factors from a DFG as a Vector{FactorSkeleton}. """ function getFactorsSkeleton end -function Base.getindex(dfg::AbstractDFG, lbl::Union{Symbol, String}) +function Base.getindex(dfg::AbstractDFG, lbl::Symbol) if isVariable(dfg, lbl) getVariable(dfg, lbl) elseif isFactor(dfg, lbl) getFactor(dfg, lbl) else - error("Cannot find $lbl in this $(typeof(dfg))") + throw(LabelNotFoundError("GraphNode", lbl)) end end @@ -390,49 +366,51 @@ end $(SIGNATURES) Merge a variable into the DFG. If a variable with the same label exists, it will be overwritten; otherwise, the variable will be added to the graph. +Implement `mergeVariable!(dfg::AbstractDFG, variable::AbstractGraphVariable)` """ -function mergeVariable!(dfg::AbstractDFG, variable::AbstractDFGVariable) - return error("mergeVariable! not implemented for $(typeof(dfg))") -end +function mergeVariable! end """ $(SIGNATURES) Merge a factor into the DFG. If a factor with the same label exists, it will be overwritten; otherwise, the factor will be added to the graph. +Implement `mergeFactor!(dfg::AbstractDFG, factor::AbstractGraphFactor)` """ -function mergeFactor!(dfg::AbstractDFG, factor::AbstractDFGFactor) - return error("mergeFactor! not implemented for $(typeof(dfg))") -end +function mergeFactor! end """ $(SIGNATURES) Delete a VariableCompute from the DFG using its label. +Implement `deleteVariable!(dfg::AbstractDFG, label::Symbol)` """ -function deleteVariable!(dfg::AbstractDFG, label::Symbol) - return error("deleteVariable! not implemented for $(typeof(dfg))") -end +function deleteVariable! end """ $(SIGNATURES) Delete a FactorCompute from the DFG using its label. +Implement `deleteFactor!(dfg::AbstractDFG, label::Symbol)` """ -function deleteFactor!(dfg::AbstractDFG, label::Symbol) - return error("deleteFactor not implemented for $(typeof(dfg))") -end +function deleteFactor! end """ $(SIGNATURES) -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). +Get the variables in the DFG as a Vector, supporting various filters. + +Arguments +- `regexFilt`: Optional Regex to filter variable labels (deprecated, use `labelFilter` instead). +Keyword arguments +- `tags`: Vector of tags; only variables with at least one matching tag are returned. +- `solvable`: Optional Int; only variables with `solvable >= solvable` are returned. +- `solvableFilter`: Optional function to filter on the `solvable` property, eg `>=(1)`. +- `labelFilter`: Optional function to filter on label e.g., `contains(r"x1")`. +- `tagsFilter`: Optional function to filter on tags, eg. `⊇([:x1])`. +- `typeFilter`: Optional function to filter on the variable type. + +Returns +- `Vector{<:AbstractGraphVariable}` matching the filters. + +See also: [`listVariables`](@ref), [`ls`](@ref) """ -function getVariables( - dfg::G, - regexFilter::Union{Nothing, Regex} = nothing; - tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, -) where {G <: AbstractDFG} - return error("getVariables not implemented for $(typeof(dfg))") -end +function getVariables end function getVariables(dfg::AbstractDFG, labels::Vector{Symbol}) return map(label -> getVariable(dfg, label), labels) @@ -443,14 +421,7 @@ 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} - return error("getFactors not implemented for $(typeof(dfg))") -end +function getFactors end function getFactors(dfg::AbstractDFG, labels::Vector{Symbol}) return map(label -> getFactor(dfg, label), labels) @@ -466,10 +437,9 @@ end 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 VariableCompute) +Implement `isVariable(dfg::AbstractDFG, label::Symbol)` """ -function isVariable(dfg::G, sym::Symbol) where {G <: AbstractDFG} - return error("isVariable not implemented for $(typeof(dfg))") -end +function isVariable end """ $SIGNATURES @@ -477,10 +447,9 @@ end 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 FactorCompute) +Implement `isFactor(dfg::AbstractDFG, label::Symbol)` """ -function isFactor(dfg::G, sym::Symbol) where {G <: AbstractDFG} - return error("isFactor not implemented for $(typeof(dfg))") -end +function isFactor end ##------------------------------------------------------------------------------ ## Neighbors @@ -488,18 +457,16 @@ end """ $(SIGNATURES) Checks if the graph is fully connected, returns true if so. +Implement `isConnected(dfg::AbstractDFG)` """ -function isConnected(dfg::AbstractDFG) - return error("isConnected not implemented for $(typeof(dfg))") -end +function isConnected end """ $(SIGNATURES) Retrieve a list of labels of the immediate neighbors around a given variable or factor specified by its label. +Implement `listNeighbors(dfg::AbstractDFG, label::Symbol; solvable::Int = 0)` """ -function listNeighbors(dfg::AbstractDFG, label::Symbol; solvable::Int = 0) - return error("listNeighbors not implemented for $(typeof(dfg))") -end +function listNeighbors end ##------------------------------------------------------------------------------ ## copy and duplication @@ -509,10 +476,9 @@ end """ $(SIGNATURES) Gets an empty and unique DFG derived from an existing DFG. +Implement `_getDuplicatedEmptyDFG(dfg::AbstractDFG)` """ -function _getDuplicatedEmptyDFG(dfg::AbstractDFG) - return error("_getDuplicatedEmptyDFG not implemented for $(typeof(dfg))") -end +function _getDuplicatedEmptyDFG end ##------------------------------------------------------------------------------ ## CRUD Aliases @@ -543,9 +509,9 @@ end Delete a referenced VariableCompute from the DFG. Notes -- Returns `Tuple{AbstractDFGVariable, Vector{<:AbstractDFGFactor}}` +- Returns `Tuple{AbstractGraphVariable, Vector{<:AbstractGraphFactor}}` """ -function deleteVariable!(dfg::AbstractDFG, variable::AbstractDFGVariable) +function deleteVariable!(dfg::AbstractDFG, variable::AbstractGraphVariable) return deleteVariable!(dfg, variable.label) end @@ -557,24 +523,23 @@ function deleteFactor!( dfg::G, factor::F; suppressGetFactor::Bool = false, -) where {G <: AbstractDFG, F <: AbstractDFGFactor} +) where {G <: AbstractDFG, F <: AbstractGraphFactor} 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. -function isVariable(dfg::G, node::N) where {G <: AbstractDFG, N <: DFGNode} - return isVariable(dfg, node.label) -end -# Alias - bit ridiculous but know it'll come up at some point. Does existential and type check. -function isFactor(dfg::G, node::N) where {G <: AbstractDFG, N <: DFGNode} - return isFactor(dfg, node.label) -end +# rather use isa in code, but ok, here it is +isVariable(dfg::AbstractDFG, node::AbstractGraphVariable) = true +isFactor(dfg::AbstractDFG, node::AbstractGraphFactor) = true ##------------------------------------------------------------------------------ ## Connectivity Alias ##------------------------------------------------------------------------------ -function listNeighbors(dfg::AbstractDFG, node::DFGNode; solvable::Int = 0) +function listNeighbors( + dfg::AbstractDFG, + node::AbstractGraphNode; + solvable::Union{Nothing, Int} = nothing, +) return listNeighbors(dfg, node.label; solvable) end @@ -601,31 +566,8 @@ 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, -) - # - 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{<:VariableStateType}; - tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, -) - # - retlist::Vector{Symbol} = ls(dfg, typeFilter) - if 0 < length(tags) || solvable != 0 - return intersect(retlist, ls(dfg; tags = tags, solvable = solvable)) - else - return retlist - end +function listVariables(dfg::AbstractDFG, args...; kwargs...) + return map(getLabel, getVariables(dfg, args...; kwargs...))::Vector{Symbol} end """ @@ -633,79 +575,15 @@ 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::AbstractDFG, - regexFilter::Union{Nothing, Regex} = nothing; - tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, -) - return map( - f -> f.label, - getFactors(dfg, regexFilter; tags = tags, solvable = solvable), - )::Vector{Symbol} +function listFactors(dfg::AbstractDFG, args...; kwargs...) + return map(getLabel, getFactors(dfg, args...; kwargs...))::Vector{Symbol} end -""" - $TYPEDSIGNATURES -List all the solvekeys used amongst all variables in the distributed factor graph object. - -Related - -[`listSolveKeys`](@ref), [`getSolverDataDict`](@ref), [`listVariables`](@ref) -""" -function listSolveKeys( - variable::VariableCompute, - 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) - return skeys -end - -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{<:VariableStateType}, 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) - for vs in varList #, ky in keys(getSolverDataDict(getVariable(dfg, vs))) - listSolveKeys(dfg, vs, filterSolveKeys, skeys) - end - - # done inside the loop - # #filter the solveKey set with filterSolveKeys regex - # !isnothing(filterSolveKeys) && return filter!(k -> occursin(filterSolveKeys, string(k)), skeys) - - return skeys -end -const listSupersolves = listSolveKeys - ##------------------------------------------------------------------------------ ## Aliases and Other filtered lists ##------------------------------------------------------------------------------ -## Aliases +## ls Shorthands ##-------- """ $(SIGNATURES) @@ -717,12 +595,25 @@ Notes: - Returns `Vector{Symbol}` """ function ls( - dfg::G, + dfg::AbstractDFG, regexFilter::Union{Nothing, Regex} = nothing; tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, -) where {G <: AbstractDFG} - return listVariables(dfg, regexFilter; tags = tags, solvable = solvable) + solvable::Union{Nothing, Int} = nothing, + solvableFilter::Union{Nothing, Function} = nothing, + tagsFilter::Union{Nothing, Function} = nothing, + typeFilter::Union{Nothing, Function} = nothing, + labelFilter::Union{Nothing, Function} = nothing, +) + return listVariables( + dfg, + regexFilter; + tags, + solvable, + solvableFilter, + tagsFilter, + typeFilter, + labelFilter, + ) end #TODO tags kwarg @@ -735,44 +626,51 @@ Notes - Return `Vector{Symbol}` """ function lsf( - dfg::G, + dfg::AbstractDFG, regexFilter::Union{Nothing, Regex} = nothing; tags::Vector{Symbol} = Symbol[], - solvable::Int = 0, -) where {G <: AbstractDFG} - return listFactors(dfg, regexFilter; tags = tags, solvable = solvable) + solvable::Union{Nothing, Int} = nothing, + solvableFilter::Union{Nothing, Function} = nothing, + tagsFilter::Union{Nothing, Function} = nothing, + typeFilter::Union{Nothing, Function} = nothing, + labelFilter::Union{Nothing, Function} = nothing, +) + return listFactors( + dfg, + regexFilter; + tags, + solvable, + solvableFilter, + tagsFilter, + typeFilter, + labelFilter, + ) 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} +function ls( + dfg::AbstractDFG, + node::AbstractGraphNode; + solvable::Union{Nothing, Int} = nothing, +) return listNeighbors(dfg, node; solvable = solvable) end -function ls(dfg::G, label::Symbol; solvable::Int = 0) where {G <: AbstractDFG} +function ls(dfg::AbstractDFG, label::Symbol; solvable::Union{Nothing, Int} = nothing) return listNeighbors(dfg, label; solvable = solvable) end -function lsf(dfg::G, label::Symbol; solvable::Int = 0) where {G <: AbstractDFG} +function lsf(dfg::AbstractDFG, label::Symbol; solvable::Union{Nothing, Int} = nothing) return listNeighbors(dfg, label; solvable = solvable) end ## list by types ##-------------- -function ls(dfg::G, ::Type{T}) where {G <: AbstractDFG, T <: VariableStateType} - 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 <: AbstractFactorObservation} - xx = getFactors(dfg) - names = typeof.(getFactorType.(xx)) .|> nameof - vxx = view(xx, names .== Symbol(T)) - return map(x -> x.label, vxx) +function ls(dfg::AbstractDFG, ::Type{T}) where {T <: StateType} + return listVariables(dfg; typeFilter = ==(T())) end """ @@ -784,8 +682,13 @@ Example, list all the Point2Point2 factors in the factor graph `dfg`: Notes - Return `Vector{Symbol}` """ -function lsf(dfg::G, ::Type{T}) where {G <: AbstractDFG, T <: AbstractFactorObservation} - return ls(dfg, T) +function lsf(dfg::AbstractDFG, ::Type{T}) where {T <: AbstractObservation} + typeFilter = isconcretetype(T) ? x -> x == T : x -> x <: T + return listFactors(dfg; typeFilter) +end + +function ls(dfg::AbstractDFG, ::Type{T}) where {T <: AbstractObservation} + return lsf(dfg, T) end """ @@ -797,7 +700,7 @@ function ls2(dfg::AbstractDFG, label::Symbol) l1 = listNeighborhood(dfg, label, 1) return setdiff(l2, l1) end -ls2(dfg::AbstractDFG, v::AbstractDFGVariable) = ls(dfg, getLabel(v)) +ls2(dfg::AbstractDFG, v::AbstractGraphNode) = ls2(dfg, getLabel(v)) """ $SIGNATURES @@ -807,43 +710,72 @@ 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) - end - end - return priors +function lsfPriors(dfg::AbstractDFG) + return listFactors(dfg; typeFilter = x -> x <: AbstractPriorObservation) end -#TODO is this repeated functionality? +## Listing DataTypes in a DFG """ - $(SIGNATURES) -Gives back all factor labels that fit the bill: - lsWho(dfg, :Pose3) - -Notes -- Returns `Vector{Symbol}` + $SIGNATURES -Dev Notes -- Cloud versions will benefit from less data transfer - - `ls(dfg::C, ::T) where {C <: CloudDFG, T <: ..}` +Return `Vector{DataType}` of all unique variable types in factor graph. +""" +function lsTypes(dfg::AbstractDFG) + vars = getVariables(dfg) + alltypes = Set{DataType}() + for v in vars + varType = typeof(getVariableType(v)) + push!(alltypes, varType) + end + return collect(alltypes) +end -Related +""" + $SIGNATURES -ls, lsf, lsfPriors +Return `::Dict{DataType, Vector{Symbol}}` of all unique variable types with labels in a factor graph. """ -function lsWho(dfg::AbstractDFG, type::Symbol) +function lsTypesDict(dfg::AbstractDFG) vars = getVariables(dfg) - labels = Symbol[] + alltypes = Dict{DataType, Vector{Symbol}}() for v in vars - varType = typeof(getVariableType(v)) |> nameof - varType == type && push!(labels, v.label) + varType = typeof(getVariableType(v)) + d = get!(alltypes, varType, Symbol[]) + push!(d, v.label) end - return labels + return alltypes +end + +""" + $SIGNATURES + +Return `Vector{Symbol}` of all unique factor types in factor graph. +""" +function lsfTypes(dfg::AbstractDFG) + facs = getFactors(dfg) + alltypes = Set{DataType}() + for f in facs + facType = typeof(getFactorType(f)) + push!(alltypes, facType) + end + return collect(alltypes) +end + +""" + $SIGNATURES + +Return `::Dict{DataType, Vector{Symbol}}` of all unique factors types with labels in a factor graph. +""" +function lsfTypesDict(dfg::AbstractDFG) + facs = getFactors(dfg) + alltypes = Dict{DataType, Vector{Symbol}}() + for f in facs + facType = typeof(getFactorType(f)) + d = get!(alltypes, facType, Symbol[]) + push!(d, f.label) + end + return alltypes end ##------------------------------------------------------------------------------ @@ -1002,7 +934,7 @@ function exists(dfg::AbstractDFG, label::Symbol) return hasVariable(dfg, label) || hasFactor(dfg, label) end -function exists(dfg::AbstractDFG, node::DFGNode) +function exists(dfg::AbstractDFG, node::AbstractGraphNode) return exists(dfg, node.label) end @@ -1069,7 +1001,7 @@ function copyGraph!( elseif overwriteDest mergeFactor!(destDFG, factorCopy) else - error("Factor $(factor.label) already exists in destination graph!") + throw(LabelExistsError("Factor", factor.label)) end elseif verbose @warn "Factor $(factor.label) will be an orphan in the destination graph, and therefore not added." @@ -1232,15 +1164,6 @@ function isPathFactorsHomogeneous(dfg::AbstractDFG, from::Symbol, to::Symbol) return (length(utyp) == 1), utyp end -function existsPathOfFactorsType( - dfg::AbstractDFG, - from::Symbol, - to::Symbol, - ftype::AbstractFactorObservation, -) - return error("WIP") -end - ##============================================================================== ## Subgraphs and Neighborhoods ##============================================================================== @@ -1316,10 +1239,8 @@ function buildSubgraph( distance::Int = 0; solvable::Int = 0, graphLabel::Symbol = Symbol(getGraphLabel(dfg), "_sub_$(string(uuid4())[1:6])"), - sessionId = nothing, kwargs..., ) where {G <: AbstractDFG} - !isnothing(sessionId) && @warn "sessionId is deprecated, use graphLabel instead" #build up the neighborhood from variableFactorLabels allvarfacs = listNeighborhood(dfg, variableFactorLabels, distance; solvable = solvable) @@ -1399,10 +1320,13 @@ Note: - rather use getBiadjacencyMatrix - Returns either of `::Matrix{Union{Nothing, Symbol}}` """ -function getAdjacencyMatrixSymbols(dfg::AbstractDFG; solvable::Int = 0) +function getAdjacencyMatrixSymbols( + dfg::AbstractDFG; + solvable::Union{Int, Nothing} = nothing, +) # - varLabels = sort(map(v -> v.label, getVariables(dfg; solvable = solvable))) - factLabels = sort(map(f -> f.label, getFactors(dfg; solvable = solvable))) + varLabels = sort(map(v -> v.label, getVariables(dfg; solvable))) + factLabels = sort(map(f -> f.label, getFactors(dfg; solvable))) vDict = Dict(varLabels .=> [1:length(varLabels)...] .+ 1) adjMat = Matrix{Union{Nothing, Symbol}}( @@ -1414,7 +1338,7 @@ function getAdjacencyMatrixSymbols(dfg::AbstractDFG; solvable::Int = 0) adjMat[2:end, 1] = factLabels adjMat[1, 2:end] = varLabels for (fIndex, factLabel) in enumerate(factLabels) - factVars = listNeighbors(dfg, getFactor(dfg, factLabel); solvable = solvable) + factVars = listNeighbors(dfg, getFactor(dfg, factLabel); solvable) map(vLabel -> adjMat[fIndex + 1, vDict[vLabel]] = factLabel, factVars) end return adjMat diff --git a/src/services/CommonAccessors.jl b/src/services/CommonAccessors.jl index 1f2bf830..a428ae6d 100644 --- a/src/services/CommonAccessors.jl +++ b/src/services/CommonAccessors.jl @@ -5,22 +5,6 @@ # NOTE this could be reduced with macros and function generation to even less code. -# Data levels -const DataLevel0 = Union{VariableDataLevel0, FactorDataLevel0} -const DataLevel1 = Union{VariableDataLevel1, FactorDataLevel1} -const DataLevel2 = Union{VariableDataLevel2, FactorDataLevel2} - -##------------------------------------------------------------------------------ -## label -##------------------------------------------------------------------------------ - -""" -$SIGNATURES - -Return the label for a DFGNode. -""" -getLabel(v::DataLevel0) = v.label - ##------------------------------------------------------------------------------ ## tags ##------------------------------------------------------------------------------ @@ -28,18 +12,18 @@ getLabel(v::DataLevel0) = v.label """ $SIGNATURES -Return the tags for a DFGNode. +Return the tags for a Node. """ -getTags(v::DataLevel0) = v.tags +getTags(node) = node.tags """ $SIGNATURES -Set the tags for a DFGNode. +Set the tags for a Node. """ -function setTags!(f::DataLevel0, tags::Union{Vector{Symbol}, Set{Symbol}}) - f.tags !== tags && empty!(f.tags) - return union!(f.tags, tags) +function setTags!(node, tags::Union{Vector{Symbol}, Set{Symbol}}) + node.tags !== tags && empty!(node.tags) + return union!(node.tags, tags) end ##------------------------------------------------------------------------------ @@ -49,9 +33,9 @@ end """ $SIGNATURES -Get the timestamp of a DFGNode. +Get the timestamp of a AbstractGraphNode. """ -getTimestamp(v::DataLevel1) = v.timestamp +getTimestamp(node) = node.timestamp """ $SIGNATURES @@ -86,7 +70,6 @@ Related: - isSolveInProgress """ getSolvable(var::Union{VariableCompute, FactorCompute}) = var.solvable -#TODO DataLevel2 """ $SIGNATURES @@ -101,13 +84,12 @@ function getSolvable(dfg::AbstractDFG, sym::Symbol) end end -#TODO data level2 for N """ $SIGNATURES Set the `solvable` parameter for either a variable or factor. """ -function setSolvable!(node::N, solvable::Int) where {N <: DFGNode} +function setSolvable!(node::N, solvable::Int) where {N <: AbstractGraphNode} node.solvable = solvable return solvable end @@ -146,7 +128,7 @@ isSolvable(node::Union{VariableCompute, FactorCompute}) = getSolvable(node) > 0 Which variables or factors are currently being used by an active solver. Useful for ensuring atomic transactions. DevNotes: -- Will be renamed to `data.solveinprogress` which will be in VND, not DFGNode -- see DFG #201 +- Will be renamed to `data.solveinprogress` which will be in VND, not AbstractGraphNode -- see DFG #201 Related @@ -189,12 +171,12 @@ $SIGNATURES Return the tags for a variable or factor. """ -function listTags(dfg::AbstractDFG, sym::Symbol) +function getTags(dfg::AbstractDFG, sym::Symbol) getFnc = isVariable(dfg, sym) ? getVariable : getFactor return getTags(getFnc(dfg, sym)) end #alias for completeness -listTags(f::DataLevel0) = getTags(f) +const listTags = getTags """ $SIGNATURES @@ -205,7 +187,7 @@ function mergeTags!(dfg::InMemoryDFGTypes, sym::Symbol, tags::Vector{Symbol}) getFnc = isVariable(dfg, sym) ? getVariable : getFactor return union!(getTags(getFnc(dfg, sym)), tags) end -mergeTags!(f::DataLevel0, tags::Vector{Symbol}) = union!(f.tags, tags) +mergeTags!(node, tags::Vector{Symbol}) = union!(node.tags, tags) """ $SIGNATURES @@ -216,7 +198,7 @@ function removeTags!(dfg::InMemoryDFGTypes, sym::Symbol, tags::Vector{Symbol}) getFnc = isVariable(dfg, sym) ? getVariable : getFactor return setdiff!(getTags(getFnc(dfg, sym)), tags) end -removeTags!(f::DataLevel0, tags::Vector{Symbol}) = setdiff!(f.tags, tags) +removeTags!(node, tags::Vector{Symbol}) = setdiff!(node.tags, tags) """ $SIGNATURES @@ -227,4 +209,4 @@ function emptyTags!(dfg::InMemoryDFGTypes, sym::Symbol) getFnc = isVariable(dfg, sym) ? getVariable : getFactor return empty!(getTags(getFnc(dfg, sym))) end -emptyTags!(f::DataLevel0) = empty!(f.tags) +emptyTags!(node) = empty!(node.tags) diff --git a/src/services/CompareUtils.jl b/src/services/CompareUtils.jl index d5c84e85..5e3c6bc5 100644 --- a/src/services/CompareUtils.jl +++ b/src/services/CompareUtils.jl @@ -6,21 +6,21 @@ import Base.== # Reference https://github.com/JuliaLang/julia/issues/4648 #= -For now abstract `VariableStateType`s are considered equal if they are the same type, dims, and manifolds (abels are deprecated) +For now abstract `StateType`s are considered equal if they are the same type, dims, and manifolds (abels are deprecated) If your implentation has aditional properties such as `DynPose2` with `ut::Int64` (microsecond time) or support different manifolds implement compare if needed. =# -# ==(a::VariableStateType,b::VariableStateType) = typeof(a) == typeof(b) && a.dims == b.dims && a.manifolds == b.manifolds +# ==(a::StateType,b::StateType) = typeof(a) == typeof(b) && a.dims == b.dims && a.manifolds == b.manifolds -==(a::FactorSolverCache, b::FactorSolverCache) = typeof(a) == typeof(b) +==(a::FactorCache, b::FactorCache) = typeof(a) == typeof(b) -==(a::AbstractFactorObservation, b::AbstractFactorObservation) = typeof(a) == typeof(b) +==(a::AbstractObservation, b::AbstractObservation) = typeof(a) == typeof(b) # Generate compares automatically for all in this union const GeneratedCompareUnion = Union{ MeanMaxPPE, - VariableState, - PackedVariableState, + State, + PackedState, VariableCompute, VariableDFG, VariableSummary, @@ -193,8 +193,8 @@ function compareAll( return true end -#Compare VariableState -function compare(a::VariableState, b::VariableState) +#Compare State +function compare(a::State, b::State) 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 && @@ -253,8 +253,8 @@ function compareVariable( union!(skiplist, skip) TP = TP && compareAll(A.solverDataDict, B.solverDataDict; skip = skiplist, show = show) - Ad = getVariableState(A, :default) #FIXME why onlly comparing default? - Bd = getVariableState(B, :default) + Ad = getState(A, :default) #FIXME why onlly comparing default? + Bd = getState(B, :default) # TP = TP && compareAll(A.attributes, B.attributes, skip=[:variableType;], show=show) varskiplist = union(varskiplist, [:variableType]) @@ -544,6 +544,7 @@ function compareFactorGraphs( :solverParams, :factorOperationalMemoryType, :agent, + :graph, ] skiplist = union(skiplist, skip) @warn "compareFactorGraphs will skip comparisons on: $skiplist" diff --git a/src/services/CustomPrinting.jl b/src/services/CustomPrinting.jl index da2f5ae1..ff96416b 100644 --- a/src/services/CustomPrinting.jl +++ b/src/services/CustomPrinting.jl @@ -31,7 +31,7 @@ function printVariable( catch e end vnd = if haskey(vert.solverDataDict, :default) - getVariableState(vert, :default) + getState(vert, :default) else nothing end @@ -43,7 +43,7 @@ function printVariable( println(ioc) println(ioc, " solvable: ", getSolvable(vert)) println(ioc, " tags: ", getTags(vert)) - solk = listSolveKeys(vert) |> collect + solk = listStates(vert) lsolk = length(solk) smsk = lsolk > 0 ? (rand(1:lsolk, 100) |> unique)[1:minimum([4, lsolk])] : nothing # list the marginalization status @@ -57,7 +57,7 @@ function printVariable( println(ioc, "(true=", sum(ismarg), ",false=", length(ismarg) - sum(ismarg), ")") if vnd !== nothing - println(ioc, " :default <-- VariableState") + println(ioc, " :default <-- State") println(ioc, " initialized: ", isInitialized(vert, :default)) println(ioc, " marginalized: ", isMarginalized(vert, :default)) println(ioc, " size bel. samples: ", size(vnd.val)) @@ -177,7 +177,7 @@ end """ $SIGNATURES -Display the content of `VariableState` to console for a given factor graph and variable tag`::Symbol`. +Display the content of `State` to console for a given factor graph and variable tag`::Symbol`. Dev Notes - TODO split as two show macros between AMP and DFG diff --git a/src/services/DFGFactor.jl b/src/services/DFGFactor.jl index f23ea2b6..f0c59bfc 100644 --- a/src/services/DFGFactor.jl +++ b/src/services/DFGFactor.jl @@ -36,7 +36,7 @@ getFactorType(dfg::AbstractDFG, lbl::Symbol) = getFactorType(getFactor(dfg, lbl) Return factor state from factor graph. """ -getFactorState(f::AbstractDFGFactor) = f.state +getFactorState(f::AbstractGraphFactor) = f.state getFactorState(dfg::AbstractDFG, lbl::Symbol) = getFactorState(getFactor(dfg, lbl)) """ @@ -85,7 +85,7 @@ Set the solver cache for a factor, which is used to store intermediate results during the solving process. This is useful for caching results that can be reused across multiple solves, such as Jacobians or other computed values. """ -setCache!(f::FactorCompute, solvercache::FactorSolverCache) = f.solvercache[] = solvercache +setCache!(f::FactorCompute, solvercache::FactorCache) = f.solvercache[] = solvercache """ $SIGNATURES @@ -102,21 +102,19 @@ using RoME @assert RoME.PriorPose2 == DFG._getPriorType(Pose2) ``` """ -function _getPriorType(_type::Type{<:VariableStateType}) +function _getPriorType(_type::Type{<:StateType}) return getfield(_type.name.module, Symbol(:Prior, _type.name.name)) end ##============================================================================== ## Default Factors Function Macro ##============================================================================== -export PackedBelief function pack end function unpack end function packDistribution end function unpackDistribution end -abstract type PackedBelief end StructTypes.StructType(::Type{<:PackedBelief}) = StructTypes.UnorderedStruct() #TODO remove, rather use StructTypes.jl properly @@ -126,7 +124,7 @@ function Base.convert(::Type{<:PackedBelief}, nt::Union{NamedTuple, JSON3.Object end """ - @defObservationType StructName factortype<:AbstractFactorObservation manifolds<:AbstractManifold + @defObservationType StructName factortype<:AbstractObservation manifolds<:AbstractManifold A macro to create a new factor function with name `StructName` and manifold. Note that the `manifold` is an object and *must* be a subtype of `ManifoldsBase.AbstractManifold`. @@ -146,16 +144,16 @@ macro defObservationType(structname, factortype, manifold) string($manifold) * ") is not an `AbstractManifold`" - @assert ($factortype <: AbstractFactorObservation) "@defObservationType factortype (" * - string($factortype) * - ") is not an `AbstractFactorObservation`" + @assert ($factortype <: AbstractObservation) "@defObservationType factortype (" * + string($factortype) * + ") is not an `AbstractObservation`" Base.@__doc__ struct $structname{T} <: $factortype Z::T end #TODO should this be $packedstructname{T <: PackedBelief} - Base.@__doc__ struct $packedstructname <: AbstractPackedFactorObservation + Base.@__doc__ struct $packedstructname <: AbstractPackedObservation Z::PackedBelief end @@ -168,7 +166,7 @@ macro defObservationType(structname, factortype, manifold) ) end -getManifold(obs::AbstractFactorObservation) = getManifold(typeof(obs)) +getManifold(obs::AbstractObservation) = getManifold(typeof(obs)) ##============================================================================== ## Factors @@ -201,7 +199,7 @@ getManifold(obs::AbstractFactorObservation) = getManifold(typeof(obs)) ## COMMON # getTimestamp -function setTimestamp(f::AbstractDFGFactor, ts::DateTime, timezone = localzone()) +function setTimestamp(f::AbstractGraphFactor, ts::DateTime, timezone = localzone()) return setTimestamp(f, ZonedDateTime(ts, timezone)) end function setTimestamp(f::FactorCompute, ts::ZonedDateTime) diff --git a/src/services/DFGVariable.jl b/src/services/DFGVariable.jl index 09976948..fe186c4f 100644 --- a/src/services/DFGVariable.jl +++ b/src/services/DFGVariable.jl @@ -45,7 +45,7 @@ getLastUpdatedTimestamp(est::AbstractPointParametricEst) = est.lastUpdatedTimest Variable nodes `variableType` information holding a variety of meta data associated with the type of variable stored in that node of the factor graph. Notes -- API Quirk in that this function returns and instance of `::T` not a `::Type{<:VariableStateType}`. +- API Quirk in that this function returns and instance of `::T` not a `::Type{<:StateType}`. DevWork - TODO, see IncrementalInference.jl 1228 @@ -56,21 +56,21 @@ getVariableType """ getVariableType(::VariableCompute{T}) where {T} = T() -getVariableType(::VariableState{T}) where {T} = T() +getVariableType(::State{T}) where {T} = T() # TODO: Confirm that we can switch this out, instead of retrieving the complete variable. -# getVariableType(v::VariableCompute) = getVariableType(getVariableState(v)) +# getVariableType(v::VariableCompute) = getVariableType(getState(v)) # Optimized in CGDFG getVariableType(dfg::AbstractDFG, lbl::Symbol) = getVariableType(getVariable(dfg, lbl)) ##------------------------------------------------------------------------------ -## VariableStateType +## StateType ##------------------------------------------------------------------------------ # """ # $SIGNATURES -# Interface function to return the `variableType` manifolds of an VariableStateType, extend this function for all Types<:VariableStateType. +# Interface function to return the `variableType` manifolds of an StateType, extend this function for all Types<:StateType. # """ # function getManifolds end @@ -82,7 +82,7 @@ getVariableType(dfg::AbstractDFG, lbl::Symbol) = getVariableType(getVariable(dfg A macro to create a new variable type with name `StructName` associated with a given manifold and identity point. -- `StructName` is the name of the new variable type, which will be defined as a subtype of `VariableStateType`. +- `StructName` is the name of the new variable type, which will be defined as a subtype of `StateType`. - `manifold` is an object that must be a subtype of `ManifoldsBase.AbstractManifold`. - `point_identity` is the identity point on the manifold, used as a reference for operations. @@ -98,7 +98,7 @@ DFG.@defVariable Pose2 SpecialEuclidean(2) ArrayPartition([0;0.0],[1 0; 0 1.0]) macro defVarstateType(structname, manifold, point_identity) return esc( quote - Base.@__doc__ struct $structname <: VariableStateType{Any} end + Base.@__doc__ struct $structname <: StateType{Any} end # user manifold must be a <:Manifold @assert ($manifold isa AbstractManifold) "@defVariable of " * @@ -125,7 +125,7 @@ end A macro to create a new variable type with name `StructName` that is parameterized by `N` and associated with a given manifold and identity point. -- `StructName` is the name of the new variable type, which will be defined as a subtype of `VariableStateType{N}`. +- `StructName` is the name of the new variable type, which will be defined as a subtype of `StateType{N}`. - `manifold` is an object that must be a subtype of `ManifoldsBase.AbstractManifold`. - `point_identity` is the identity point on the manifold, used as a reference for operations. @@ -141,7 +141,7 @@ DFG.@defVarstateTypeN Pose{N} SpecialEuclidean(N) ArrayPartition(zeros(SVector{N macro defVarstateTypeN(structname, manifold, point_identity) return esc( quote - Base.@__doc__ struct $structname <: VariableStateType{N} end + Base.@__doc__ struct $structname <: StateType{N} end DFG.getManifold(::Type{$structname}) where {N} = $manifold @@ -155,48 +155,48 @@ end function Base.convert( ::Type{<:AbstractManifold}, ::Union{<:T, Type{<:T}}, -) where {T <: VariableStateType} +) where {T <: StateType} return getManifold(T) end """ $SIGNATURES -Interface function to return the `<:ManifoldsBase.AbstractManifold` object of `variableType<:VariableStateType`. +Interface function to return the `<:ManifoldsBase.AbstractManifold` object of `variableType<:StateType`. """ -getManifold(::T) where {T <: VariableStateType} = getManifold(T) +getManifold(::T) where {T <: StateType} = getManifold(T) getManifold(vari::VariableCompute) = getVariableType(vari) |> getManifold -getManifold(state::VariableState) = getVariableType(state) |> getManifold -# covers both <:VariableStateType and <:AbstractFactorObservation +getManifold(state::State) = getVariableType(state) |> getManifold +# covers both <:StateType and <:AbstractObservation getManifold(dfg::AbstractDFG, lbl::Symbol) = getManifold(dfg[lbl]) """ $SIGNATURES -Interface function to return the `variableType` dimension of an VariableStateType, extend this function for all Types<:VariableStateType. +Interface function to return the `variableType` dimension of an StateType, extend this function for all Types<:StateType. """ function getDimension end -getDimension(::Type{T}) where {T <: VariableStateType} = manifold_dimension(getManifold(T)) -getDimension(::T) where {T <: VariableStateType} = manifold_dimension(getManifold(T)) +getDimension(::Type{T}) where {T <: StateType} = manifold_dimension(getManifold(T)) +getDimension(::T) where {T <: StateType} = manifold_dimension(getManifold(T)) getDimension(M::ManifoldsBase.AbstractManifold) = manifold_dimension(M) getDimension(p::Distributions.Distribution) = length(p) getDimension(var::VariableCompute) = getDimension(getVariableType(var)) """ $SIGNATURES -Interface function to return the manifold point type of an VariableStateType, extend this function for all Types<:VariableStateType. +Interface function to return the manifold point type of an StateType, extend this function for all Types<:StateType. """ function getPointType end -getPointType(::T) where {T <: VariableStateType} = getPointType(T) +getPointType(::T) where {T <: StateType} = getPointType(T) """ $SIGNATURES -Interface function to return the user provided identity point for this VariableStateType manifold, extend this function for all Types<:VariableStateType. +Interface function to return the user provided identity point for this StateType manifold, extend this function for all Types<:StateType. Notes - Used in transition period for Serialization. This function will likely be changed or deprecated entirely. """ function getPointIdentity end -getPointIdentity(::T) where {T <: VariableStateType} = getPointIdentity(T) +getPointIdentity(::T) where {T <: StateType} = getPointIdentity(T) """ $SIGNATURES @@ -216,7 +216,7 @@ function getPoint( ::Type{T}, v::AbstractVector, basis = ManifoldsBase.DefaultOrthogonalBasis(), -) where {T <: VariableStateType} +) where {T <: StateType} M = getManifold(T) p0 = getPointIdentity(T) X = ManifoldsBase.get_vector(M, p0, v, basis) @@ -240,7 +240,7 @@ function getCoordinates( ::Type{T}, p, basis = ManifoldsBase.DefaultOrthogonalBasis(), -) where {T <: VariableStateType} +) where {T <: StateType} M = getManifold(T) p0 = getPointIdentity(T) X = ManifoldsBase.log(M, p0, p) @@ -260,9 +260,9 @@ Related isSolved, setSolvedCount! """ -getSolvedCount(v::VariableState) = v.solvedCount -function getSolvedCount(v::VariableDataLevel2, solveKey::Symbol = :default) - return getVariableState(v, solveKey) |> getSolvedCount +getSolvedCount(v::State) = v.solvedCount +function getSolvedCount(v::VariableCompute, solveKey::Symbol = :default) + return getState(v, solveKey) |> getSolvedCount end function getSolvedCount(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol = :default) return getSolvedCount(getVariable(dfg, sym), solveKey) @@ -277,9 +277,9 @@ Related getSolved, isSolved """ -setSolvedCount!(v::VariableState, val::Int) = v.solvedCount = val -function setSolvedCount!(v::VariableDataLevel2, val::Int, solveKey::Symbol = :default) - return setSolvedCount!(getVariableState(v, solveKey), val) +setSolvedCount!(v::State, val::Int) = v.solvedCount = val +function setSolvedCount!(v::VariableCompute, val::Int, solveKey::Symbol = :default) + return setSolvedCount!(getState(v, solveKey), val) end function setSolvedCount!( dfg::AbstractDFG, @@ -299,9 +299,9 @@ Related getSolved, setSolved! """ -isSolved(v::VariableState) = 0 < v.solvedCount -function isSolved(v::VariableDataLevel2, solveKey::Symbol = :default) - return getVariableState(v, solveKey) |> isSolved +isSolved(v::State) = 0 < v.solvedCount +function isSolved(v::VariableCompute, solveKey::Symbol = :default) + return getState(v, solveKey) |> isSolved end function isSolved(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol = :default) return isSolved(getVariable(dfg, sym), solveKey) @@ -319,7 +319,7 @@ Notes: - used by both factor graph variable and Bayes tree clique logic. """ function isInitialized(var::VariableCompute, key::Symbol = :default) - return getVariableState(var, key).initialized + return getState(var, key).initialized end function isInitialized(dfg::AbstractDFG, label::Symbol, key::Symbol = :default) @@ -332,10 +332,10 @@ end Return `::Bool` on whether this variable has been marginalized. Notes: -- VariableState default `solveKey=:default` +- State default `solveKey=:default` """ function isMarginalized(vert::VariableCompute, solveKey::Symbol = :default) - return getVariableState(vert, solveKey).ismargin + return getState(vert, solveKey).ismargin end function isMarginalized(dfg::AbstractDFG, sym::Symbol, solveKey::Symbol = :default) return isMarginalized(DFG.getVariable(dfg, sym), solveKey) @@ -346,11 +346,11 @@ end Mark a variable as marginalized `true` or `false`. """ -function setMarginalized!(vnd::VariableState, val::Bool) +function setMarginalized!(vnd::State, val::Bool) return vnd.ismargin = val end function setMarginalized!(vari::VariableCompute, val::Bool, solveKey::Symbol = :default) - return setMarginalized!(getVariableState(vari, solveKey), val) + return setMarginalized!(getState(vari, solveKey), val) end function setMarginalized!( dfg::AbstractDFG, @@ -423,7 +423,7 @@ function setTimestamp(v::VariableCompute, ts::ZonedDateTime; verbose::Bool = tru end function setTimestamp( - v::AbstractDFGVariable, + v::AbstractGraphVariable, ts::DateTime, timezone = localzone(); verbose::Bool = true, @@ -473,7 +473,7 @@ end Get the PPE dictionary for a variable. Recommended to use CRUD operations instead, [`getPPE`](@ref), [`addPPE!`](@ref), [`updatePPE!`](@ref), [`deletePPE!`](@ref). """ -getPPEDict(v::VariableDataLevel1) = v.ppeDict +getPPEDict(v::AbstractGraphVariable) = v.ppeDict #TODO FIXME don't know if this should exist, should rather always update with fg object to simplify inmem vs cloud """ @@ -488,7 +488,7 @@ Related getMeanPPE, getMaxPPE, getKDEMean, getKDEFit, getPPEs, getVariablePPEs """ -function getPPE(vari::VariableDataLevel1, solveKey::Symbol = :default) +function getPPE(vari::AbstractGraphVariable, solveKey::Symbol = :default) if haskey(getPPEDict(vari), solveKey) return getPPEDict(vari)[solveKey] else @@ -511,11 +511,11 @@ function getPPEs end Return full dictionary of PPEs in a variable, recommended to rather use CRUD: [`getPPE`](@ref), """ -getVariablePPEDict(vari::VariableDataLevel1) = getPPEDict(vari) +getVariablePPEDict(vari::AbstractGraphVariable) = getPPEDict(vari) """ getVariablePPE(::VariableCompute) - getVariablePPE(::VariableState) + getVariablePPE(::State) Get the Parametric Point Estimate of the given variable. """ @@ -538,7 +538,7 @@ getSolverDataDict(v::VariableCompute) = v.solverDataDict Retrieve solver data structure stored in a variable. """ -function getVariableState(v::VariableCompute, label::Symbol) +function getState(v::VariableCompute, label::Symbol) vnd = if haskey(getSolverDataDict(v), label) return getSolverDataDict(v)[label] else @@ -671,13 +671,13 @@ end $(SIGNATURES) Get variable solverdata for a given solve key. """ -function getVariableState(dfg::AbstractDFG, variableLabel::Symbol, label::Symbol) +function getState(dfg::AbstractDFG, variableLabel::Symbol, label::Symbol) v = getVariable(dfg, variableLabel) !haskey(v.solverDataDict, label) && throw(LabelNotFoundError("State", label)) return v.solverDataDict[label] end -function getVariableStates(dfg::AbstractDFG, variableLabel::Symbol) +function getStates(dfg::AbstractDFG, variableLabel::Symbol) v = getVariable(dfg, variableLabel) return collect(values(v.solverDataDict)) end @@ -686,18 +686,18 @@ end $(SIGNATURES) Add variable solver data, errors if it already exists. """ -function addVariableState!(dfg::AbstractDFG, variablekey::Symbol, state::VariableState) +function addState!(dfg::AbstractDFG, variablekey::Symbol, state::State) var = getVariable(dfg, variablekey) if haskey(var.solverDataDict, state.solveKey) - throw(LabelExistsError("VariableState", state.solveKey)) + throw(LabelExistsError("State", state.solveKey)) end var.solverDataDict[state.solveKey] = state return state end -function addVariableState!(v, state::VariableState) +function addState!(v, state::State) if haskey(v.solverDataDict, state.solveKey) - throw(LabelExistsError("VariableState", state.solveKey)) + throw(LabelExistsError("State", state.solveKey)) end v.solverDataDict[state.solveKey] = state return state @@ -709,13 +709,13 @@ Update the variable state if it exists, otherwise add it. Related -mergeVariableStates! +mergeStates! """ -function mergeVariableState!(dfg::AbstractDFG, variablekey::Symbol, vnd::VariableState) +function mergeState!(dfg::AbstractDFG, variablekey::Symbol, vnd::State) v = getVariable(dfg, variablekey) if !haskey(v.solverDataDict, vnd.solveKey) - addVariableState!(dfg, variablekey, vnd) + addState!(dfg, variablekey, vnd) else v.solverDataDict[vnd.solveKey] = vnd end @@ -723,9 +723,9 @@ function mergeVariableState!(dfg::AbstractDFG, variablekey::Symbol, vnd::Variabl return 1 end -function mergeVariableState!(v::VariableCompute, vnd::VariableState) +function mergeState!(v::VariableCompute, vnd::State) if !haskey(v.solverDataDict, vnd.solveKey) - addVariableState!(v, vnd) + addState!(v, vnd) else v.solverDataDict[vnd.solveKey] = vnd end @@ -733,18 +733,32 @@ function mergeVariableState!(v::VariableCompute, vnd::VariableState) return 1 end -function copytoVariableState!( +function mergeStates!(dfg::AbstractDFG, varLabel_state_pairs::Vector{<:Pair{Symbol, <:State}}) + cnt = asyncmap(varLabel_state_pairs) do (varLabel, state) + return mergeState!(dfg, varLabel, state) + end + return sum(cnt) +end + +function mergeStates!(dfg::AbstractDFG, variableLabel::Symbol, states::Vector{<:State}) + cnt = asyncmap(states) do state + return mergeState!(dfg, variableLabel, state) + end + return sum(cnt) +end + +function copytoState!( dfg::AbstractDFG, variableLabel::Symbol, stateLabel::Symbol, - state::VariableState, + state::State, ) - newstate = VariableState( + newstate = State( getVariableType(state); - (k => deepcopy(getproperty(state, k)) for k in fieldnames(VariableState))..., + (k => deepcopy(getproperty(state, k)) for k in fieldnames(State))..., solveKey = stateLabel, ) - return mergeVariableState!(dfg, variableLabel, newstate) + return mergeState!(dfg, variableLabel, newstate) end # @@ -753,11 +767,11 @@ end $(SIGNATURES) Delete variable solver data, returns the number of deleted elements. """ -function deleteVariableState!(dfg::AbstractDFG, variablekey::Symbol, solveKey::Symbol) +function deleteState!(dfg::AbstractDFG, variablekey::Symbol, solveKey::Symbol) var = getVariable(dfg, variablekey) if !haskey(var.solverDataDict, solveKey) - throw(KeyError("VariableState '$(solveKey)' does not exist")) + throw(KeyError("State '$(solveKey)' does not exist")) end pop!(var.solverDataDict, solveKey) return 1 @@ -767,12 +781,8 @@ end $(SIGNATURES) Delete variable solver data, returns the number of deleted elements. """ -function deleteVariableState!( - dfg::AbstractDFG, - sourceVariable::VariableCompute, - solveKey::Symbol, -) - return deleteVariableState!(dfg, sourceVariable.label, solveKey) +function deleteState!(dfg::AbstractDFG, sourceVariable::VariableCompute, solveKey::Symbol) + return deleteState!(dfg, sourceVariable.label, solveKey) end ##------------------------------------------------------------------------------ @@ -781,11 +791,41 @@ end """ $(SIGNATURES) -List all the solver data keys in the variable. +List all the variable state labels. """ -function listVariableStates(dfg::AbstractDFG, variablekey::Symbol) - v = getVariable(dfg, variablekey) - return collect(keys(v.solverDataDict)) +function listStates(v::VariableCompute; labelFilter::Union{Nothing, Function} = nothing) + labels = collect(keys(v.solverDataDict)) + return filterDFG!(labels, labelFilter) +end + +function listStates( + dfg::AbstractDFG, + lbl::Symbol; + labelFilter::Union{Nothing, Function} = nothing, +) + return listStates(getVariable(dfg, lbl); labelFilter) +end + +function listStates( + dfg::AbstractDFG; + labelFilter::Union{Nothing, Function} = nothing, + solvableFilter::Union{Nothing, Function} = nothing, + tagsFilter::Union{Nothing, Function} = nothing, + typeFilter::Union{Nothing, Function} = nothing, + variableLabelFilter::Union{Nothing, Function} = nothing, +) + labels = Set{Symbol}() + vls = listVariables( + dfg; + solvableFilter, + tagsFilter, + typeFilter, + labelFilter = variableLabelFilter, + ) + for vl in vls + union!(labels, listStates(dfg, vl; labelFilter)) + end + return labels end ##============================================================================== @@ -816,7 +856,7 @@ end # Not the most efficient call but it at least reuses above (in memory it's probably ok) function getPPE( dfg::AbstractDFG, - sourceVariable::VariableDataLevel1, + sourceVariable::AbstractGraphVariable, ppekey::Symbol = :default, ) return getPPE(dfg, sourceVariable.label, ppekey) @@ -889,7 +929,7 @@ NOTE: Copies the PPE data. """ function updatePPE!( dfg::AbstractDFG, - sourceVariable::VariableDataLevel1, + sourceVariable::AbstractGraphVariable, ppekey::Symbol = :default; warn_if_absent::Bool = true, ) @@ -907,7 +947,7 @@ Update PPE data if it exists, otherwise add it. """ function updatePPE!( dfg::AbstractDFG, - sourceVariables::Vector{<:VariableDataLevel1}, + sourceVariables::Vector{<:AbstractGraphVariable}, ppekey::Symbol = :default; warn_if_absent::Bool = true, ) @@ -967,7 +1007,10 @@ end Merges and updates solver and estimate data for a variable (variable can be from another graph). Note: Makes a copy of the estimates and solver data so that there is no coupling between graphs. """ -function mergePPEs!(destVariable::AbstractDFGVariable, sourceVariable::AbstractDFGVariable) +function mergePPEs!( + destVariable::AbstractGraphVariable, + sourceVariable::AbstractGraphVariable, +) # We don't know which graph this came from, must be copied! merge!(destVariable.ppeDict, deepcopy(sourceVariable.ppeDict)) return destVariable diff --git a/src/services/Serialization.jl b/src/services/Serialization.jl index acb90cd6..bc36733f 100644 --- a/src/services/Serialization.jl +++ b/src/services/Serialization.jl @@ -11,7 +11,7 @@ function _versionCheck(node::Union{<:VariableDFG, <:FactorDFG}) end end -function stringVariableType(varT::VariableStateType) +function stringVariableType(varT::StateType) T = typeof(varT) #FIXME maybe don't use .parameters Tparams = T.parameters @@ -105,8 +105,8 @@ function getTypeFromSerializationModule(_typeString::AbstractString) return nothing end -# returns a PackedVariableState -function packVariableState(d::VariableState{T}) where {T <: VariableStateType} +# returns a PackedState +function packState(d::State{T}) where {T <: StateType} @debug "Dispatching conversion variable -> packed variable for type $(string(getVariableType(d)))" castval = if 0 < length(d.val) precast = getCoordinates.(T, d.val) @@ -121,7 +121,7 @@ function packVariableState(d::VariableState{T}) where {T <: VariableStateType} "Packing of more than one parametric covariance is NOT supported yet, only packing first." ) - return PackedVariableState( + return PackedState( d.id, _val, size(castval, 1), @@ -146,14 +146,14 @@ function packVariableState(d::VariableState{T}) where {T <: VariableStateType} ) end -function unpackVariableState(d::PackedVariableState) +function unpackState(d::PackedState) @debug "Dispatching conversion packed variable -> variable for type $(string(d.variableType))" # Figuring out the variableType # TODO deprecated remove in v0.11 - for backward compatibility for saved variableTypes. ststring = string(split(d.variableType, "(")[1]) T = parseVariableType(ststring) isnothing(T) && error( - "The variable doesn't seem to have a variableType. It needs to set up with an VariableStateType from IIF. This will happen if you use DFG to add serialized variables directly and try use them. Please use IncrementalInference.addVariable().", + "The variable doesn't seem to have a variableType. It needs to set up with an StateType 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 @@ -172,7 +172,7 @@ function unpackVariableState(d::PackedVariableState) # N = getDimension(T) - return VariableState{T, getPointType(T), N}(; + return State{T, getPointType(T), N}(; id = d.id, val = vals, bw = BW, @@ -212,7 +212,7 @@ function packVariable( nstime = string(v.nstime.value), tags = collect(v.tags), # Symbol.() ppes = collect(values(v.ppeDict)), - solverData = packVariableState.(collect(values(v.solverDataDict))), + solverData = packState.(collect(values(v.solverDataDict))), metadata = base64encode(JSON3.write(v.smallData)), solvable = v.solvable, variableType = stringVariableType(DFG.getVariableType(v)), @@ -244,9 +244,9 @@ function unpackVariable(variable::VariableDFG; skipVersionCheck::Bool = false) Dict{Symbol, MeanMaxPPE}(map(p -> p.solveKey, variable.ppes) .=> variable.ppes) N = getDimension(variableType) - solverDict = Dict{Symbol, VariableState{variableType, pointType, N}}( + solverDict = Dict{Symbol, State{variableType, pointType, N}}( map(sd -> sd.solveKey, variable.solverData) .=> - map(sd -> DFG.unpackVariableState(sd), variable.solverData), + map(sd -> DFG.unpackState(sd), variable.solverData), ) dataDict = Dict{Symbol, Blobentry}( map(de -> de.label, variable.blobEntries) .=> variable.blobEntries, @@ -326,7 +326,7 @@ function unpackObservation(factor::FactorDFG) end packObservation(f::FactorCompute) = packObservation(getObservation(f)) -function packObservation(observ::AbstractFactorObservation) +function packObservation(observ::AbstractObservation) try return pack(observ) catch e @@ -368,8 +368,11 @@ function unpackFactor(factor::FactorDFG; skipVersionCheck::Bool = false) getMetadata(factor), observation, factor.state, - Ref{FactorSolverCache}(), + Ref{FactorCache}(), ) end -# +FactorCompute(f::FactorCompute) = f +FactorCompute(f::FactorDFG) = unpackFactor(f) +FactorDFG(f::FactorDFG) = f +FactorDFG(f::FactorCompute) = packFactor(f) diff --git a/test/FactorGraphsTests.jl b/test/FactorGraphsTests.jl index c11561e9..35698f43 100644 --- a/test/FactorGraphsTests.jl +++ b/test/FactorGraphsTests.jl @@ -40,7 +40,7 @@ end @testset "GraphsDFGs.FactorGraphs" begin @test isa( FactorGraphs.FactorGraph(), - FactorGraph{Int64, AbstractDFGVariable, AbstractDFGFactor}, + FactorGraph{Int64, AbstractGraphVariable, AbstractGraphFactor}, ) fg = FactorGraphs.FactorGraph{Int, VariableSkeleton, FactorSkeleton}() diff --git a/test/GraphsDFGSummaryTypes.jl b/test/GraphsDFGSummaryTypes.jl index dcb80cc7..1ab88c0d 100644 --- a/test/GraphsDFGSummaryTypes.jl +++ b/test/GraphsDFGSummaryTypes.jl @@ -15,10 +15,7 @@ function DistributedFactorGraphs.VariableSummary(label::Symbol) ) end -function DistributedFactorGraphs.VariableSummary( - label::Symbol, - ::VariableState{T}, -) where {T} +function DistributedFactorGraphs.VariableSummary(label::Symbol, ::State{T}) where {T} return VariableSummary( nothing, label, @@ -34,10 +31,7 @@ function DistributedFactorGraphs.VariableSkeleton(label::Symbol, args...) return VariableSkeleton(label) end -function DistributedFactorGraphs.VariableSkeleton( - label::Symbol, - ::VariableState{T}, -) where {T} +function DistributedFactorGraphs.VariableSkeleton(label::Symbol, ::State{T}) where {T} return VariableSkeleton(nothing, label, Set{Symbol}()) end diff --git a/test/compareTests.jl b/test/compareTests.jl index 02cc6117..f9df4611 100644 --- a/test/compareTests.jl +++ b/test/compareTests.jl @@ -7,10 +7,10 @@ using Dates # TestCCW1 ## Generated compare functions -# VariableState -vnd1 = VariableState(TestVariableType1()) +# State +vnd1 = State(TestVariableType1()) vnd2 = deepcopy(vnd1) -vnd3 = VariableState(TestVariableType2()) +vnd3 = State(TestVariableType2()) @test vnd1 == vnd2 push!(vnd1.val, [1.0;]) @@ -59,9 +59,9 @@ f3 = FactorCompute(:f1, [:b, :a], TestFunctorInferenceType1()) @test !(f1 == f3) ## Compare functions -vnd1 = VariableState(TestVariableType1()) +vnd1 = State(TestVariableType1()) vnd2 = deepcopy(vnd1) -vnd3 = VariableState(TestVariableType2()) +vnd3 = State(TestVariableType2()) @test compare(vnd1, vnd2) @test !compare(vnd1, vnd3) diff --git a/test/consol_DataEntryBlobTests.jl b/test/consol_DataEntryBlobTests.jl index 034684c5..a88b4a33 100644 --- a/test/consol_DataEntryBlobTests.jl +++ b/test/consol_DataEntryBlobTests.jl @@ -150,7 +150,7 @@ ade2 = addData!(dfg, :x2, deepcopy(ade), dataset1) @test ade == ade2# == ade3 # @test adb == adb2# == adb3 -deleteData!(dfg, :x2, :random) +@test deleteData!(dfg, :x2, :random) == 2 ##============================================================================== ## Unimplemented store @@ -159,9 +159,9 @@ struct TestStore{T} <: DFG.AbstractBlobstore{T} end 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 deleteBlob!(store, ade) -@test_throws ErrorException listBlobs(store) -@test_throws ErrorException hasBlob(store, uuid4()) +@test_throws MethodError getBlob(store, ade) +@test_throws MethodError addBlob!(store, ade, 1) +@test_throws MethodError updateBlob!(store, ade, 1) +@test_throws MethodError deleteBlob!(store, ade) +@test_throws MethodError listBlobs(store) +@test_throws MethodError hasBlob(store, uuid4()) diff --git a/test/fileDFGTests.jl b/test/fileDFGTests.jl index 946f333e..5de516ee 100644 --- a/test/fileDFGTests.jl +++ b/test/fileDFGTests.jl @@ -19,10 +19,7 @@ using UUIDs 1:numNodes, ) map(v -> setSolvable!(v, Int(round(rand()))), verts) - map( - v -> getVariableState(verts[4], :default).solveInProgress = Int(round(rand())), - verts, - ) + map(v -> getState(verts[4], :default).solveInProgress = Int(round(rand())), verts) map(v -> setSolvedCount!(v, Int(round(10 * rand()))), verts) # Add some data entries diff --git a/test/iifInterfaceTests.jl b/test/iifInterfaceTests.jl index 19289f68..1700399f 100644 --- a/test/iifInterfaceTests.jl +++ b/test/iifInterfaceTests.jl @@ -11,7 +11,7 @@ end #test before anything changes @testset "Producing Dot Files" begin global dfg - todotstr = toDot(dfg) + todotstr = DFG.toDot(dfg) #TODO consider using a regex, but for now test all orders todota = cmp( @@ -45,7 +45,7 @@ end ) |> 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 + @test DFG.toDotFile(dfg, "something.dot") === nothing Base.rm("something.dot") end @@ -119,7 +119,6 @@ end # Existence @test exists(dfg, :a) == true @test exists(dfg, v1) == true - @show exists(dfg, :nope) @test exists(dfg, :nope) == false # isFactor and isVariable @test isFactor(dfg, f1.label) @@ -144,18 +143,17 @@ end @test !isPrior(dfg, :abf1) # f1 is not a prior @test lsfPriors(dfg) == [] - @test DFG.lsfTypes(dfg) == [:LinearRelative] + @test DFG.lsfTypes(dfg)[1] <: LinearRelative @test ls(dfg, LinearRelative) == [:abf1] - @test lsf(dfg, LinearRelative) == [:abf1] + @test lsf(dfg, LinearRelative{1, Normal{Float64}}) == [:abf1] @test getVariableType(v1) isa Position{1} @test getVariableType(dfg, :a) isa Position{1} - @test DFG.lsTypes(dfg) == [Symbol("Position{1}")] + @test DFG.lsTypes(dfg) == [Position{1}] @test issetequal(ls(dfg, Position{1}), [:a, :b]) - @test issetequal(lsWho(dfg, :Position), [:a, :b]) varNearTs = findVariableNearTimestamp(dfg, now()) @test_skip varNearTs[1][1] == [:b] @@ -183,7 +181,7 @@ end @test getTimestamp(v1) == v1.timestamp @test getVariablePPEDict(v1) == v1.ppeDict @test_throws LabelNotFoundError DistributedFactorGraphs.getVariablePPE(v1, :notfound) - @test getVariableState(v1, :default) === v1.solverDataDict[:default] + @test getState(v1, :default) === v1.solverDataDict[:default] @test getSolverDataDict(v1) == v1.solverDataDict # legacy compat test @test getVariablePPEDict(v1) == v1.ppeDict # changed to .ppeDict -- delete by DFG v0.7 @@ -345,7 +343,7 @@ verts = map(n -> addVariable!(dfg, Symbol("x$n"), Position{1}; tags = [:POSE]), #TODO fix this to use accessors setSolvable!(verts[7], 1) setSolvable!(verts[8], 0) -getVariableState(verts[8], :default).solveInProgress = 1 +getState(verts[8], :default).solveInProgress = 1 #call update to set it on cloud mergeVariable!(dfg, verts[7]) mergeVariable!(dfg, verts[8]) diff --git a/test/plottingTest.jl b/test/plottingTest.jl index 72a5430e..487dfa18 100644 --- a/test/plottingTest.jl +++ b/test/plottingTest.jl @@ -6,7 +6,7 @@ using Manifolds ## -# struct TestInferenceVariable1 <: VariableStateType end +# struct TestInferenceVariable1 <: StateType end @defVariable TestInferenceVariable1 Euclidean(1) [0.0;] # Now make a complex graph for connectivity tests diff --git a/test/runtests.jl b/test/runtests.jl index 2cc07373..2e041d32 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -125,36 +125,36 @@ else @warn "Skipping IncrementalInference driver tests" end -struct NotImplementedDFG{T} <: AbstractDFG{T} end +struct NotImplementedDFG{V, T} <: AbstractDFG{V, T} end @testset "No Interface tests" begin - dfg = NotImplementedDFG{NoSolverParams}() + dfg = NotImplementedDFG{VariableDFG, FactorDFG}() v1 = VariableSkeleton(:v1) f1 = FactorSkeleton(:f1, [:v1]) - @test_throws ErrorException exists(dfg, v1) - @test_throws ErrorException exists(dfg, f1) + @test_throws MethodError exists(dfg, v1) + @test_throws MethodError exists(dfg, f1) - @test_throws ErrorException exists(dfg, :s) - @test_throws ErrorException addVariable!(dfg, v1) + @test_throws MethodError exists(dfg, :s) + @test_throws MethodError addVariable!(dfg, v1) - @test_throws ErrorException getVariable(dfg, :a) - @test_throws ErrorException getFactor(dfg, :a) - @test_throws ErrorException mergeVariable!(dfg, v1) - @test_throws ErrorException mergeFactor!(dfg, f1) + @test_throws MethodError getVariable(dfg, :a) + @test_throws MethodError getFactor(dfg, :a) + @test_throws MethodError mergeVariable!(dfg, v1) + @test_throws MethodError mergeFactor!(dfg, f1) - @test_throws ErrorException deleteVariable!(dfg, :a) - @test_throws ErrorException deleteFactor!(dfg, :a) - @test_throws ErrorException getVariables(dfg) - @test_throws ErrorException getFactors(dfg) - @test_throws ErrorException isConnected(dfg) - @test_throws ErrorException listNeighbors(dfg, v1) - @test_throws ErrorException listNeighbors(dfg, :a) + @test_throws MethodError deleteVariable!(dfg, :a) + @test_throws MethodError deleteFactor!(dfg, :a) + @test_throws MethodError getVariables(dfg) + @test_throws MethodError getFactors(dfg) + @test_throws MethodError isConnected(dfg) + @test_throws MethodError listNeighbors(dfg, v1) + @test_throws MethodError listNeighbors(dfg, :a) - @test_throws ErrorException DFG._getDuplicatedEmptyDFG(dfg) + @test_throws MethodError DFG._getDuplicatedEmptyDFG(dfg) - @test_throws ErrorException isVariable(dfg, :a) - @test_throws ErrorException isFactor(dfg, :a) + @test_throws MethodError isVariable(dfg, :a) + @test_throws MethodError isFactor(dfg, :a) end @testset "Testing Code Quality with Aqua" begin diff --git a/test/sandbox.jl b/test/sandbox.jl index 11a45896..ffb3febd 100644 --- a/test/sandbox.jl +++ b/test/sandbox.jl @@ -25,5 +25,3 @@ 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) - -lsWho(dfg, :Position) diff --git a/test/testBlocks.jl b/test/testBlocks.jl index 62bc3cc3..615c31f7 100644 --- a/test/testBlocks.jl +++ b/test/testBlocks.jl @@ -3,7 +3,12 @@ using Test using Dates using Manifolds -using DistributedFactorGraphs: LabelExistsError, LabelNotFoundError +using DistributedFactorGraphs: + LabelExistsError, + LabelNotFoundError, + NoSolverParams, + AbstractGraphVariable, + AbstractGraphFactor import Base: convert # import DistributedFactorGraphs: getData, addData!, updateData!, deleteData! @@ -22,7 +27,7 @@ struct TestAbstractPrior <: PriorObservation end # struct TestAbstractRelativeFactor <: AbstractRelativeRoots end struct TestAbstractRelativeFactorMinimize <: RelativeObservation end -Base.@kwdef struct PackedTestFunctorInferenceType1 <: AbstractPackedFactorObservation +Base.@kwdef struct PackedTestFunctorInferenceType1 <: AbstractPackedObservation s::String = "" end # PackedTestFunctorInferenceType1() = PackedTestFunctorInferenceType1("") @@ -49,7 +54,7 @@ function Base.convert(::Type{TestFunctorInferenceType1}, d::PackedTestFunctorInf return TestFunctorInferenceType1() end -Base.@kwdef struct PackedTestAbstractPrior <: AbstractPackedFactorObservation +Base.@kwdef struct PackedTestAbstractPrior <: AbstractPackedObservation s::String = "" end # PackedTestAbstractPrior() = PackedTestAbstractPrior("") @@ -64,7 +69,7 @@ function Base.convert(::Type{TestAbstractPrior}, d::PackedTestAbstractPrior) return TestAbstractPrior() end -struct TestCCW{T <: AbstractFactorObservation} <: FactorSolverCache +struct TestCCW{T <: AbstractObservation} <: FactorCache usrfnc!::T end @@ -72,14 +77,14 @@ TestCCW{T}() where {T} = TestCCW(T()) Base.:(==)(a::TestCCW, b::TestCCW) = a.usrfnc! == b.usrfnc! -DFG.rebuildFactorCache!(dfg::AbstractDFG{NoSolverParams}, fac::FactorCompute) = fac +# DFG.rebuildFactorCache!(dfg::AbstractDFG{NoSolverParams}, fac::FactorCompute) = fac function DFG.reconstFactorData( dfg::AbstractDFG, vo::AbstractVector, ::Type{<:DFG.FunctionNodeData{TestCCW{F}}}, - d::DFG.PackedFunctionNodeData{<:AbstractPackedFactorObservation}, -) where {F <: DFG.AbstractFactorObservation} + d::DFG.PackedFunctionNodeData{<:AbstractPackedObservation}, +) where {F <: DFG.AbstractObservation} error("obsolete, TODO remove") nF = convert(F, d.fnc) return DFG.FunctionNodeData( @@ -97,8 +102,8 @@ end function Base.convert( ::Type{DFG.PackedFunctionNodeData{P}}, - d::DFG.FunctionNodeData{<:FactorSolverCache}, -) where {P <: AbstractPackedFactorObservation} + d::DFG.FunctionNodeData{<:FactorCache}, +) where {P <: AbstractPackedObservation} return DFG.PackedFunctionNodeData( d.eliminated, d.potentialused, @@ -117,18 +122,18 @@ end # T = testDFGAPI #test Specific definitions -# struct TestInferenceVariable1 <: VariableStateType end -# struct TestInferenceVariable2 <: VariableStateType end -# struct TestFunctorInferenceType1 <: AbstractFactorObservation end +# struct TestInferenceVariable1 <: StateType end +# struct TestInferenceVariable2 <: StateType end +# struct TestFunctorInferenceType1 <: AbstractObservation end # NOTE see note in AbstractDFG.jl setSolverParams! -struct GeenSolverParams <: AbstractParams end +struct GeenSolverParams <: AbstractDFGParams end solparams = NoSolverParams() # DFG Accessors function DFGStructureAndAccessors( ::Type{T}, - solparams::AbstractParams = NoSolverParams(), + solparams::AbstractDFGParams = NoSolverParams(), ) where {T <: AbstractDFG} # "DFG Structure and Accessors" # Constructors @@ -285,16 +290,12 @@ function DFGVariableSCA() TestVariableType1(); tags = v1_tags, solvable = 0, - solverDataDict = Dict(:default => VariableState{TestVariableType1}()), - ) - v2 = VariableCompute( - :b, - VariableState{TestVariableType2}(); - tags = Set([:VARIABLE, :LANDMARK]), + solverDataDict = Dict(:default => State{TestVariableType1}()), ) + v2 = VariableCompute(:b, State{TestVariableType2}(); tags = Set([:VARIABLE, :LANDMARK])) v3 = VariableCompute( :c, - VariableState{TestVariableType2}(); + State{TestVariableType2}(); timestamp = ZonedDateTime("2020-08-11T00:12:03.000-05:00"), ) @@ -303,7 +304,7 @@ function DFGVariableSCA() TestVariableType1(); tags = v1_tags, solvable = 0, - solverDataDict = Dict(:default => VariableState{TestVariableType1}()), + solverDataDict = Dict(:default => State{TestVariableType1}()), ) # v1.solverDataDict[:default].val[1] = [0.0;] @@ -313,7 +314,7 @@ function DFGVariableSCA() # v3.solverDataDict[:default].val[1] = [0.0;0.0] # v3.solverDataDict[:default].bw[1] = [1.0;1.0] - getVariableState(v1, :default).solveInProgress = 1 + getState(v1, :default).solveInProgress = 1 @test getLabel(v1) == v1_lbl @test getTags(v1) == v1_tags @@ -360,7 +361,7 @@ function DFGVariableSCA() # #TODO sort out # getPPEs - # getVariableState + # getState # getVariablePPEs # getVariablePPE # getSolvedCount @@ -587,9 +588,9 @@ function VariablesandFactorsCRUD_SET!(fg, v1, v2, v3, f0, f1, f2) @test lsf(fg) == listFactors(fg) if getVariable(fg, ls(fg)[1]) isa VariableCompute - @test :default in listSolveKeys(fg) - @test :default in listSolveKeys(fg, r"a"; filterSolveKeys = r"default") - @test :default in listSupersolves(fg) + @test :default in DFG.listStates(fg) + @test :default in DFG.listStates(fg; labelFilter = contains("default") ∘ string) + @test :default in DFG.listStates(fg) end # simple broadcast test @@ -750,73 +751,76 @@ function VSDTestBlock!(fg, v1) # "Variable Solver Data" # #### Variable Solver Data # **CRUD** - # - `getVariableState` - # - `addVariableState!` + # - `getState` + # - `addState!` # - `updateVariableSolverData!` - # - `deleteVariableState!` + # - `deleteState!` # - # > - `getVariableStates` #TODO Data is already plural so maybe Variables, All or Dict, or use Datum for singular + # > - `getStates` #TODO Data is already plural so maybe Variables, All or Dict, or use Datum for singular # > - `getVariablesSolverData` # # **Set like** - # - `listVariableStates` + # - `listStates` # # - # **VariableState** + # **State** # - `getSolveInProgress` - vnd = VariableState{TestVariableType1}(; solveKey = :parametric) + vnd = State{TestVariableType1}(; solveKey = :parametric) # vnd.val[1] = [0.0;] # vnd.bw[1] = [1.0;] - @test addVariableState!(fg, :a, vnd) == vnd + @test addState!(fg, :a, vnd) == vnd - @test_throws LabelExistsError addVariableState!(fg, :a, vnd) + @test_throws LabelExistsError addState!(fg, :a, vnd) - @test issetequal(listVariableStates(fg, :a), [:default, :parametric]) + @test issetequal(listStates(fg, :a), [:default, :parametric]) # Get the data back - note that this is a reference to above. - vndBack = getVariableState(fg, :a, :parametric) + vndBack = getState(fg, :a, :parametric) @test vndBack == vnd # Delete it - @test deleteVariableState!(fg, :a, :parametric) == 1 + @test deleteState!(fg, :a, :parametric) == 1 # Update add it - @test mergeVariableState!(fg, :a, vnd) == 1 + @test mergeState!(fg, :a, vnd) == 1 # Bulk copy update x0 - @test DFG.copytoVariableState!(fg, v1.label, :default, getVariableState(fg, v1.label, :default)) == 1 + @test DFG.copytoState!(fg, v1.label, :default, getState(fg, v1.label, :default)) == 1 + @test DFG.mergeStates!(fg, Vector{Pair{Symbol, State}}([:a => vnd])) == 1 + @test DFG.mergeStates!(fg, [:a => vnd]) == 1 + @test DFG.mergeStates!(fg, :a, [vnd]) == 1 altVnd = vnd |> deepcopy - keepVnd = getVariableState(getVariable(fg, :a), :parametric) |> deepcopy + keepVnd = getState(getVariable(fg, :a), :parametric) |> deepcopy # Delete parametric from v1 - @test deleteVariableState!(fg, :a, :parametric) == 1 + @test deleteState!(fg, :a, :parametric) == 1 - @test_throws LabelNotFoundError getVariableState(fg, :a, :parametric) + @test_throws LabelNotFoundError getState(fg, :a, :parametric) #FIXME copied from lower - @test getVariableState(v1, :default) === v1.solverDataDict[:default] + @test getState(v1, :default) === v1.solverDataDict[:default] # Add new VND of type ContinuousScalar to :x0 - # Could also do VariableState(ContinuousScalar()) + # Could also do State(ContinuousScalar()) - vnd = VariableState{TestVariableType1}(; solveKey = :parametric) + vnd = State{TestVariableType1}(; solveKey = :parametric) # vnd.val[1] = [0.0;] # vnd.bw[1] = [1.0;] - addVariableState!(fg, :a, vnd) - @test setdiff(listVariableStates(fg, :a), [:default, :parametric]) == [] + addState!(fg, :a, vnd) + @test setdiff(listStates(fg, :a), [:default, :parametric]) == [] # Get the data back - note that this is a reference to above. - vndBack = getVariableState(fg, :a, :parametric) + vndBack = getState(fg, :a, :parametric) @test vndBack == vnd # Delete it - @test deleteVariableState!(fg, :a, :parametric) == 1 + @test deleteState!(fg, :a, :parametric) == 1 # Update add it - mergeVariableState!(fg, :a, vnd) + mergeState!(fg, :a, vnd) # Update update it - mergeVariableState!(fg, :a, vnd) + mergeState!(fg, :a, vnd) # Delete parametric from v1 - deleteVariableState!(fg, :a, :parametric) + deleteState!(fg, :a, :parametric) return nothing @@ -1135,12 +1139,12 @@ function testGroup!(fg, v1, v2, f0, f1) @test isPrior(fg, :af1) # if f1 is prior @test lsfPriors(fg) == [:af1] - @test issetequal([:TestFunctorInferenceType1, :TestAbstractPrior], DFG.lsfTypes(fg)) + @test issetequal([TestFunctorInferenceType1, TestAbstractPrior], DFG.lsfTypes(fg)) facTypesDict = DFG.lsfTypesDict(fg) @test issetequal(collect(keys(facTypesDict)), DFG.lsfTypes(fg)) - @test issetequal(facTypesDict[:TestFunctorInferenceType1], [:abf1]) - @test issetequal(facTypesDict[:TestAbstractPrior], [:af1]) + @test issetequal(facTypesDict[TestFunctorInferenceType1], [:abf1]) + @test issetequal(facTypesDict[TestAbstractPrior], [:af1]) @test ls(fg, TestFunctorInferenceType1) == [:abf1] @test lsf(fg, TestAbstractPrior) == [:af1] @@ -1153,17 +1157,15 @@ function testGroup!(fg, v1, v2, f0, f1) @test ls2(fg, :a) == [:b] - @test issetequal([:TestVariableType1, :TestVariableType2], DFG.lsTypes(fg)) + @test issetequal([TestVariableType1, TestVariableType2], DFG.lsTypes(fg)) varTypesDict = DFG.lsTypesDict(fg) @test issetequal(collect(keys(varTypesDict)), DFG.lsTypes(fg)) - @test issetequal(varTypesDict[:TestVariableType1], [:a]) - @test issetequal(varTypesDict[:TestVariableType2], [:b]) + @test issetequal(varTypesDict[TestVariableType1], [:a]) + @test issetequal(varTypesDict[TestVariableType2], [:b]) @test ls(fg, TestVariableType1) == [:a] - @test lsWho(fg, :TestVariableType1) == [:a] - # FIXME return: Symbol[:b, :b] == Symbol[:b] varNearTs = findVariableNearTimestamp(fg, now()) @test_skip varNearTs[1][1] == [:b] @@ -1305,8 +1307,10 @@ function testGroup!(fg, v1, v2, f0, f1) #solves in progress @test getSolveInProgress(v1) == 1 @test getSolveInProgress(f1) == 1 - @test !isSolveInProgress(v2) && v2.solverDataDict[:default].solveInProgress == 0 - @test isSolveInProgress(v1) && v1.solverDataDict[:default].solveInProgress > 0 + @test !isSolveInProgress(v2, :default) && + v2.solverDataDict[:default].solveInProgress == 0 + @test isSolveInProgress(v1, :default) && + v1.solverDataDict[:default].solveInProgress > 0 @test setSolvable!(v1, 1) == 1 @test getSolvable(v1) == 1 @@ -1389,12 +1393,9 @@ function connectivityTestGraph( dfg = T(; graphLabel = :testGraph) vars = vcat( + map(n -> VARTYPE(Symbol("x$n"), State{TestVariableType1}()), 1:numNodesType1), map( - n -> VARTYPE(Symbol("x$n"), VariableState{TestVariableType1}()), - 1:numNodesType1, - ), - map( - n -> VARTYPE(Symbol("x$(numNodesType1+n)"), VariableState{TestVariableType2}()), + n -> VARTYPE(Symbol("x$(numNodesType1+n)"), State{TestVariableType2}()), 1:numNodesType2, ), ) @@ -1628,10 +1629,10 @@ function ProducingDotFiles( dotdfg = testDFGAPI(; graphLabel = :testGraph) if v1 === nothing - v1 = VARTYPE(:a, VariableState{TestVariableType1}()) + v1 = VARTYPE(:a, State{TestVariableType1}()) end if v2 === nothing - v2 = VARTYPE(:b, VariableState{TestVariableType1}()) + v2 = VARTYPE(:b, State{TestVariableType1}()) end if f1 === nothing if (FACTYPE == FactorCompute) @@ -1650,7 +1651,7 @@ function ProducingDotFiles( addFactor!(dotdfg, f1) #NOTE hardcoded toDot will have different results so test Graphs seperately if testDFGAPI <: GraphsDFG || testDFGAPI <: GraphsDFG - todotstr = toDot(dotdfg) + todotstr = DFG.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" @@ -1659,10 +1660,10 @@ function ProducingDotFiles( "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) == + @test DFG.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 + @test DFG.toDotFile(dotdfg, "something.dot") == nothing return Base.rm("something.dot") end @@ -1782,7 +1783,7 @@ function FileDFGTestBlock(testDFGAPI; kwargs...) for filename in ["/tmp/fileDFG", "/tmp/FileDFGExtension.tar.gz"] v4 = getVariable(dfg, :x4) - vnd = getVariableState(v4, :default) + vnd = getState(v4, :default) # set everything vnd.BayesNetVertID = :outid push!(vnd.BayesNetOutVertIDs, :id)