From 2f4dd995a4761136fff120b36f64139d44577428 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 21 Apr 2026 13:21:48 +0200 Subject: [PATCH] Cleanup export/public towards DFGv1 and fix some inconsistencies --- src/DistributedFactorGraphs.jl | 528 +++++++-------------- src/GraphsDFG/services/agent_ops.jl | 8 + src/GraphsDFG/services/blobprovider_ops.jl | 3 +- src/GraphsDFG/services/state_ops.jl | 14 +- src/GraphsDFG/services/tag_ops.jl | 12 +- src/Serialization/StateSerialization.jl | 10 +- src/entities/State.jl | 49 +- src/entities/Tags.jl | 6 +- src/entities/equality.jl | 2 +- test/testBlocks.jl | 8 +- test/testSerializingVariables.jl | 49 +- 11 files changed, 280 insertions(+), 409 deletions(-) diff --git a/src/DistributedFactorGraphs.jl b/src/DistributedFactorGraphs.jl index 26d10069..1fca15f1 100644 --- a/src/DistributedFactorGraphs.jl +++ b/src/DistributedFactorGraphs.jl @@ -10,9 +10,9 @@ The package supplies: """ module DistributedFactorGraphs -##============================================================================== -## imports -##============================================================================== +# ============================================================================== +# imports +# ============================================================================== using Base using Base64 @@ -22,7 +22,6 @@ using Random using TimeZones using TimesDates using JSON -export StructUtils # export for use in macros using LinearAlgebra using SparseArrays using UUIDs @@ -47,397 +46,227 @@ import Base.Filesystem: hardlink # used for @defStateType import ManifoldsBase using ManifoldsBase: AbstractManifold, manifold_dimension -export AbstractManifold using RecursiveArrayTools: ArrayPartition -export ArrayPartition using StaticArrays using InteractiveUtils: subtypes using StructUtils: @kwarg, @tags -public @tags -public @kwarg - -##============================================================================== -# Exports -##============================================================================== -##------------------------------------------------------------------------------ -## Abstract types and their aliases -##------------------------------------------------------------------------------ -export AbstractDFG -export AbstractDFGParams, DFGParams -export AbstractBlobprovider, Blobprovider -export AbstractGraphNode, GraphNode -export AbstractGraphVariable, GraphVariable -export AbstractGraphFactor, GraphFactor -export AbstractObservation, Observation -export AbstractPriorObservation, PriorObservation -export AbstractRelativeObservation, RelativeObservation -export AbstractFactorCache, FactorCache -export AbstractStateType, StateType -##------------------------------------------------------------------------------ -## Types -##------------------------------------------------------------------------------ -#TODO types are not yet stable - also, we might not export all types +# ============================================================================== +# Exports - DFG not part of the cross language API but we export it for convenience in Julia +# ============================================================================== +# Re-exports +export StructUtils # export for use in macros +export AbstractManifold +export ArrayPartition +public @format_str # from FileIO + +# DFG exports +const DFG = DistributedFactorGraphs +export DFG # module alias for DistributedFactorGraphs +export getLabel #TODO move +public @defStateType # macro to define custom variable types + +# ------------------------------------------------------------------------------ +# Types +# ------------------------------------------------------------------------------ +export GraphsDFG # in-memory driver type # Variables export VariableDFG # export VariableSummary #TODO not finalized yet. export VariableSkeleton # Factors export FactorDFG -# export FactorSummary TODO not finalized yet. +# export FactorSummary #TODO not finalized yet. export FactorSkeleton +export State export Blobentry +export Bloblet -export State export Agent -##------------------------------------------------------------------------------ -## Functions -##------------------------------------------------------------------------------ -##============================================================================== -## 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 addVariableBlobentry!, getVariableBlobentry, mergeVariableBlobentry!, deleteVariableBlobentry! -# export addVariableBlobentries!, getVariableBlobentries, mergeVariableBlobentries!, deleteVariableBlobentries! -# 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 addVariableBloblet!, getVariableBloblet, mergeVariableBloblet!, deleteVariableBloblet! -# export addVariableBloblets!, getVariableBloblets, mergeVariableBloblets!, deleteVariableBloblets! -# export addFactorBloblet!, getFactorBloblet, mergeFactorBloblet!, deleteFactorBloblet! -# export addFactorBloblets!, getFactorBloblets, mergeFactorBloblets!, deleteFactorBloblets! -# export addAgentBloblet!, getAgentBloblet, mergeAgentBloblet!, deleteAgentBloblet! -# export addAgentBloblets!, getAgentBloblets, mergeAgentBloblets!, deleteAgentBloblets! -# export addGraphBloblet!, getGraphBloblet, mergeGraphBloblet!, deleteGraphBloblet! -# export addGraphBloblets!, getGraphBloblets, mergeGraphBloblets!, deleteGraphBloblets! - -# list -# export listVariables, listFactors, listStates, listVariableBlobentries, listFactorBlobEntries, listGraphBlobentries, listAgentBlobentries -# export listVariableBloblets, listFactorBloblets, listAgentBloblets, listGraphBloblets - -# tags -# export listVariableTags, mergeVariableTags!, deleteVariableTags! -# export listFactorTags, mergeFactorTags!, deleteFactorTags! -# export listGraphTags, mergeGraphTags!, deleteGraphTags! -# export listAgentTags, mergeAgentTags!, deleteAgentTags! - -# has -# export hasVariable, hasFactor, hasState -# export hasVariableBlobentry, hasFactorBlobentry, hasGraphBlobentry, hasAgentBlobentry -# export hasVariableBloblet, hasFactorBloblet, hasGraphBloblet, hasAgentBloblet -# export hasVariableTags, hasFactorTags, hasGraphTags, hasAgentTags - -# v1 name, signiture, return, and error checked -export addVariable! -export getVariable -export mergeVariable! -export deleteVariable! - -export addVariables! -export getVariables -export mergeVariables! -export deleteVariables! - -export addFactor! -export getFactor -export deleteFactor! -export mergeFactor! - -export addFactors! -export getFactors -export mergeFactors! -export deleteFactors! - -export addState! -export getState -export mergeState! -export deleteState! - -export addStates! -export getStates # TODO state filters not implemented yet -export mergeStates! -export deleteStates! - -# has -export hasVariable -export hasState -export hasFactor +# ============================================================================== +# Exports — cross-language CRUD API +# ============================================================================== +# ------------------------------------------------------------------------------ +# Abstract types and their aliases +# ------------------------------------------------------------------------------ +export AbstractDFG +export AbstractDFGParams, DFGParams +export AbstractBlobprovider, Blobprovider +export AbstractGraphNode, GraphNode +export AbstractGraphVariable, GraphVariable +export AbstractGraphFactor, GraphFactor +export AbstractObservation, Observation +export AbstractPriorObservation, PriorObservation +export AbstractRelativeObservation, RelativeObservation +export AbstractFactorCache, FactorCache +export AbstractStateType, StateType -## list +# ----------------------------------------------------------------------------- +# Variable CRUD +# ------------------------------------------------------------------------------ +export addVariable!, getVariable, mergeVariable!, deleteVariable! +export addVariables!, getVariables, mergeVariables!, deleteVariables! export listVariables +export hasVariable + +# Factor CRUD +export addFactor!, getFactor, mergeFactor!, deleteFactor! +export addFactors!, getFactors, mergeFactors!, deleteFactors! export listFactors -export listStates +export hasFactor -## -public getObservation +# State CRUD +export addState!, getState, mergeState!, deleteState! +export addStates!, getStates, mergeStates!, deleteStates! +export listStates +export hasState -##------------------------------------------------------------------------------ -# Tags -export listVariableTags -export mergeVariableTags! -export deleteVariableTags! -export hasVariableTags - -export listFactorTags -export mergeFactorTags! -export deleteFactorTags! -export hasFactorTags - -export listGraphTags -export mergeGraphTags! -export deleteGraphTags! -export hasGraphTags - -export listAgentTags -export mergeAgentTags! -export deleteAgentTags! -export hasAgentTags - -##------------------------------------------------------------------------------ -## Blobentries -##------------------------------------------------------------------------------ -export addVariableBlobentry! -export getVariableBlobentry -export mergeVariableBlobentry! -export deleteVariableBlobentry! - -export addVariableBlobentries! -export getVariableBlobentries -export mergeVariableBlobentries! -export deleteVariableBlobentries! - -export addFactorBlobentry! -export getFactorBlobentry -export mergeFactorBlobentry! -export deleteFactorBlobentry! - -export addFactorBlobentries! -export getFactorBlobentries -export mergeFactorBlobentries! -export deleteFactorBlobentries! - -export addGraphBlobentry! -export getGraphBlobentry -export mergeGraphBlobentry! -export deleteGraphBlobentry! - -export addGraphBlobentries! -export getGraphBlobentries -export mergeGraphBlobentries! -export deleteGraphBlobentries! - -export addAgentBlobentry! -export getAgentBlobentry -export mergeAgentBlobentry! -export deleteAgentBlobentry! - -export addAgentBlobentries! -export getAgentBlobentries -export mergeAgentBlobentries! -export deleteAgentBlobentries! +# Agent CRUD +export addAgent!, getAgent, mergeAgent!, deleteAgent! +export addAgents!, getAgents, mergeAgents!, deleteAgents! +export listAgents +export hasAgent +# ------------------------------------------------------------------------------ +# Variable Blobentries +# ------------------------------------------------------------------------------ +export addVariableBlobentry!, + getVariableBlobentry, mergeVariableBlobentry!, deleteVariableBlobentry! +export addVariableBlobentries!, + getVariableBlobentries, mergeVariableBlobentries!, deleteVariableBlobentries! export listVariableBlobentries -export listFactorBlobentries -export listGraphBlobentries -export listAgentBlobentries - export hasVariableBlobentry + +# Factor Blobentries +export addFactorBlobentry!, + getFactorBlobentry, mergeFactorBlobentry!, deleteFactorBlobentry! +export addFactorBlobentries!, + getFactorBlobentries, mergeFactorBlobentries!, deleteFactorBlobentries! +export listFactorBlobentries export hasFactorBlobentry + +# Graph Blobentries +export addGraphBlobentry!, getGraphBlobentry, mergeGraphBlobentry!, deleteGraphBlobentry! +export addGraphBlobentries!, + getGraphBlobentries, mergeGraphBlobentries!, deleteGraphBlobentries! +export listGraphBlobentries export hasGraphBlobentry -export hasAgentBlobentry -##------------------------------------------------------------------------------ -## Bloblets -##------------------------------------------------------------------------------ -export Bloblet -export getVariableBloblet -export addVariableBloblet! -export mergeVariableBloblet! -export deleteVariableBloblet! - -export addVariableBloblets! -export getVariableBloblets -export mergeVariableBloblets! -export deleteVariableBloblets! - -export addFactorBloblet! -export getFactorBloblet -export mergeFactorBloblet! -export deleteFactorBloblet! - -export addFactorBloblets! -export getFactorBloblets -export mergeFactorBloblets! -export deleteFactorBloblets! - -export getGraphBloblet -export addGraphBloblet! -export mergeGraphBloblet! -export deleteGraphBloblet! - -export addGraphBloblets! -export getGraphBloblets -export mergeGraphBloblets! -export deleteGraphBloblets! - -export getAgentBloblet -export addAgentBloblet! -export mergeAgentBloblet! -export deleteAgentBloblet! - -export addAgentBloblets! -export getAgentBloblets -export mergeAgentBloblets! -export deleteAgentBloblets! +# Agent Blobentries +export addAgentBlobentry!, getAgentBlobentry, mergeAgentBlobentry!, deleteAgentBlobentry! +export addAgentBlobentries!, + getAgentBlobentries, mergeAgentBlobentries!, deleteAgentBlobentries! +export listAgentBlobentries +export hasAgentBlobentry +# Model blobentries: interface defined in services/blobentry_ops.jl but no GraphsDFG implementation yet +# downstream libraries can still implement these and then export. Only export here once we have a stable API and GraphsDFG implementation. +# export addModelBlobentry!, getModelBlobentry, mergeModelBlobentry!, deleteModelBlobentry! +# export addModelBlobentries!, getModelBlobentries, mergeModelBlobentries!, deleteModelBlobentries! +# export listModelBlobentries, hasModelBlobentry + +# ------------------------------------------------------------------------------ +# Bloblet +# ------------------------------------------------------------------------------ +# Variable Bloblets +export addVariableBloblet!, + getVariableBloblet, mergeVariableBloblet!, deleteVariableBloblet! +export addVariableBloblets!, + getVariableBloblets, mergeVariableBloblets!, deleteVariableBloblets! export listVariableBloblets -export listFactorBloblets -export listGraphBloblets -export listAgentBloblets - export hasVariableBloblet + +# Factor Bloblets +export addFactorBloblet!, getFactorBloblet, mergeFactorBloblet!, deleteFactorBloblet! +export addFactorBloblets!, getFactorBloblets, mergeFactorBloblets!, deleteFactorBloblets! +export listFactorBloblets export hasFactorBloblet -export hasGraphBloblet -export hasAgentBloblet -## v1 name, signiture, and return +# Graph Bloblets +export addGraphBloblet!, getGraphBloblet, mergeGraphBloblet!, deleteGraphBloblet! +export addGraphBloblets!, getGraphBloblets, mergeGraphBloblets!, deleteGraphBloblets! +export listGraphBloblets +export hasGraphBloblet -## v1 name only +# Agent Bloblets +export addAgentBloblet!, getAgentBloblet, mergeAgentBloblet!, deleteAgentBloblet! +export addAgentBloblets!, getAgentBloblets, mergeAgentBloblets!, deleteAgentBloblets! +export listAgentBloblets +export hasAgentBloblet -##------------------------------------------------------------------------------ -## Blobproviders and Blobs -##------------------------------------------------------------------------------ -export getBlobprovider -export addBlobprovider! +# ------------------------------------------------------------------------------ +# Tags (set semantics: merge/delete/list/has) +# ------------------------------------------------------------------------------ +export mergeVariableTags!, deleteVariableTags!, listVariableTags, hasVariableTags +export mergeFactorTags!, deleteFactorTags!, listFactorTags, hasFactorTags +export mergeGraphTags!, deleteGraphTags!, listGraphTags, hasGraphTags +export mergeAgentTags!, deleteAgentTags!, listAgentTags, hasAgentTags + +# ------------------------------------------------------------------------------ +# Blobprovider CRUD +# ------------------------------------------------------------------------------ +export addBlobprovider!, getBlobprovider, mergeBlobprovider!, deleteBlobprovider! +export getBlobproviders, mergeBlobproviders! export listBlobproviders +export hasBlobprovider -# public getBlob -# public fetchBlob -# public putBlob! -# public purgeBlob! -# public listBlobs -# public hasBlob -# public verifyBlob - -##------------------------------------------------------------------------------ - -## -const DFG = DistributedFactorGraphs -export DFG +# ============================================================================== +# Public — stable API, not cross-language or advanced use +# ============================================================================== +# Julia re-exports needed for macros and type definitions +public @tags, @kwarg -export GraphsDFGs -export GraphsDFG - -##============================================================================== -## Common Accessors -##============================================================================== -export getLabel +# Julia-specific driver types and aliases +public GraphsDFGs # submodule +public InMemoryDFGTypes # Union{GraphsDFG} +public LocalDFG # alias for GraphsDFG +# Common accessors (Julia convenience, other langs use field access) public getId +public getObservation +public getStateKind +public refStates -##============================================================================== -## Internal or not yet ready -##============================================================================== -##------------------------------------------------------------------------------ -## Types -##------------------------------------------------------------------------------ -public InMemoryDFGTypes -public LocalDFG -# public FolderBlobprovider -# public MemoryBlobprovider -# public CachedBlobprovider - -##------------------------------------------------------------------------------ -## Tags -##------------------------------------------------------------------------------ -# tags is a set: get/list, merge, delete (we don't have add but merge) - +# Node-level tag operations (generic, used internally by scoped tag exports) public listTags public mergeTags! public deleteTags! -# public emptyTags! - -##------------------------------------------------------------------------------ -## FileDFG -##------------------------------------------------------------------------------ -# File import and export -export saveDFG -export loadDFG! -export loadDFG - -##------------------------------------------------------------------------------ -## Aliases -##------------------------------------------------------------------------------ -#TODO is ls alias or more of a shorthand with extra functionality? -# if shorthand kind of function it is likeley only DFG -# public ls # alias for listVariables -# public lsf # alias for listFactors - -##------------------------------------------------------------------------------ -## Other utility functions -##------------------------------------------------------------------------------ - -## Agent CRUD (now in AbstractDFG services) -export addAgent! -export deleteAgent! -export listAgents -export getAgent -export hasAgent -# export mergeAgent! -# public refAgents - -## TODO maybe move to DFG from SDK -# getModel -# getModels -# addModel! - -##============================================================================== -export @format_str # exported from FileIO - -export @defStateType #TODO Should this be exported? - -public refStates -public getStateKind +# Blob operations (cross-language concept, export later if needed) +public getBlob # DFG-level: searches all mounted providers +public fetchBlob # provider-level: fetch by multihash +public putBlob! # provider-level: CAS write +public purgeBlob! # provider-level: physical remove +public listBlobs # provider-level: list all multihashes +public hasBlob # provider/DFG-level: check existence +public verifyBlob # utility: verify blob against blobentry hashes + +# Blobprovider types +public FolderBlobprovider +public MemoryBlobprovider +public CachedBlobprovider +# Blobprovider internals +public refBlobproviders +public stashBlobproviders! # persist provider configs as graph bloblet +public applyBlobproviders! # restore provider configs from graph bloblet + +# Serialization helpers public pack, unpack +# ============================================================================== # list of unstable functions not exported any more # will move to public or deprecate over time const unstable_functions::Vector{Symbol} = [ - # Blobprovider types (public, not exported) - :FolderBlobprovider, - :MemoryBlobprovider, - :CachedBlobprovider, - # Blobprovider operations (not exported) - :deleteBlobprovider!, - :mergeBlobprovider!, - :mergeBlobproviders!, - :hasBlobprovider, - :refBlobproviders, - :getBlobproviders, - # - :getBlob, - :fetchBlob, - :putBlob!, - :purgeBlob!, - :listBlobs, - :hasBlob, - :verifyBlob, + # FileDFG — Julia-specific serialization + #TODO these use the wrong signature and we can just overload julia's write/read or FileIo save/load, deprecate these in favor of read/write or save/load. + :saveDFG, + :loadDFG!, + :loadDFG, # :getGraph, :VariableSummary, @@ -446,7 +275,6 @@ const unstable_functions::Vector{Symbol} = [ :listNeighbors, :findPath, :findPaths, - :InMemoryBlobstore, :exists, :compare, :compareField, @@ -467,7 +295,7 @@ const unstable_functions::Vector{Symbol} = [ :findVariablesNearTimestamp, :findShortestPathDijkstra, :findFactorsBetweenNaive, # TODO not really used - :getGraphLabel, #TODO check and mark as public + :getGraphLabel, #TODO check and maybe mark as public :getDescription, :getSolverParams, :getHash, @@ -532,12 +360,12 @@ const unstable_functions::Vector{Symbol} = [ :PackedBelief, :AbstractPackedObservation, :PackedObservation, - :updateMetadata!,## TODO deprecated or obsolete + :updateMetadata!,# TODO deprecated or obsolete :getFactorState, # FIXME getFactorState were questioned and being reviewed again for name, other than that they are checked. :packDistribution, :unpackDistribution, :hasTagsNeighbors, - # :updateBlobstore!,## TODO deprecated or obsolete + # :updateBlobstore!,# TODO deprecated or obsolete # :emptyMetadata!, #TODO maybe deprecate for just deleteMetadata! # :emptyBlobstore!, #TODO maybe deprecate for just deleteBlobstore! :MetadataTypes, #maybe make public after metadata stable @@ -560,11 +388,9 @@ macro usingDFG(unstable = false) return Expr(:using, Expr(:(:), Expr(:(.), :DistributedFactorGraphs), syms...)) end -##============================================================================== - -##============================================================================== -## Files Includes -##============================================================================== +# ============================================================================== +# Files Includes +# ============================================================================== # Entities include("entities/AbstractDFG.jl") diff --git a/src/GraphsDFG/services/agent_ops.jl b/src/GraphsDFG/services/agent_ops.jl index 8d05722b..c5ec45ae 100644 --- a/src/GraphsDFG/services/agent_ops.jl +++ b/src/GraphsDFG/services/agent_ops.jl @@ -53,6 +53,10 @@ function DFG.mergeAgents!(dfg::GraphsDFG, agents::Vector{Agent}) return count end +function DFG.addAgents!(dfg::GraphsDFG, agents::Vector{Agent}) + return map(agent -> addAgent!(dfg, agent), agents) +end + """ $(SIGNATURES) """ @@ -62,6 +66,10 @@ function DFG.deleteAgent!(dfg::GraphsDFG, label::Symbol) return 1 end +function DFG.deleteAgents!(dfg::GraphsDFG, labels::Vector{Symbol}) + return sum(label -> deleteAgent!(dfg, label), labels; init = 0) +end + """ $(SIGNATURES) """ diff --git a/src/GraphsDFG/services/blobprovider_ops.jl b/src/GraphsDFG/services/blobprovider_ops.jl index 6076501b..d3608e78 100644 --- a/src/GraphsDFG/services/blobprovider_ops.jl +++ b/src/GraphsDFG/services/blobprovider_ops.jl @@ -35,7 +35,8 @@ function DFG.addBlobprovider!(dfg::GraphsDFG, provider::AbstractBlobprovider) ) throw(LabelExistsError("Blobprovider", label)) end - return push!(refBlobproviders(dfg), label => provider) + push!(refBlobproviders(dfg), label => provider) + return provider end # TODO edge api is a work in progress and only internal diff --git a/src/GraphsDFG/services/state_ops.jl b/src/GraphsDFG/services/state_ops.jl index 11a5d8d3..5983bc9d 100644 --- a/src/GraphsDFG/services/state_ops.jl +++ b/src/GraphsDFG/services/state_ops.jl @@ -7,22 +7,20 @@ function DFG.addState!(dfg::GraphsDFG, variableLabel::Symbol, state::State) end function DFG.addStates!(dfg::GraphsDFG, variableLabel::Symbol, states::Vector{<:State}) - cnt = asyncmap(states) do state - addState!(dfg, variableLabel, state) - return 1 + s = asyncmap(states) do state + return addState!(dfg, variableLabel, state) end - return sum(cnt) + return s end function DFG.addStates!( dfg::GraphsDFG, varLabel_state_pairs::Vector{<:Pair{Symbol, <:State}}, ) - cnt = asyncmap(varLabel_state_pairs) do (varLabel, state) - addState!(dfg, varLabel, state) - return 1 + s = asyncmap(varLabel_state_pairs) do (varLabel, state) + return addState!(dfg, varLabel, state) end - return sum(cnt) + return s end # ============================================================================= diff --git a/src/GraphsDFG/services/tag_ops.jl b/src/GraphsDFG/services/tag_ops.jl index 9fdf00c7..e8571b57 100644 --- a/src/GraphsDFG/services/tag_ops.jl +++ b/src/GraphsDFG/services/tag_ops.jl @@ -2,13 +2,11 @@ # Agent Tags # ============================================================================== function DFG.mergeAgentTags!(dfg::GraphsDFG, agentlabel::Symbol, tags) - mergeTags!(getAgent(dfg, agentlabel), tags) - return length(tags) + return mergeTags!(getAgent(dfg, agentlabel), tags) end function DFG.deleteAgentTags!(dfg::GraphsDFG, agentlabel::Symbol, tags) - deleteTags!(getAgent(dfg, agentlabel), tags) - return length(tags) + return deleteTags!(getAgent(dfg, agentlabel), tags) end function DFG.listAgentTags(dfg::GraphsDFG, agentlabel::Symbol) @@ -23,13 +21,11 @@ end # Graph Tags # ============================================================================== function DFG.mergeGraphTags!(dfg::GraphsDFG, tags) - mergeTags!(dfg.graph, tags) - return length(tags) + return mergeTags!(dfg.graph, tags) end function DFG.deleteGraphTags!(dfg::GraphsDFG, tags) - deleteTags!(dfg.graph, tags) - return length(tags) + return deleteTags!(dfg.graph, tags) end function DFG.listGraphTags(dfg::GraphsDFG) diff --git a/src/Serialization/StateSerialization.jl b/src/Serialization/StateSerialization.jl index f4527749..81554721 100644 --- a/src/Serialization/StateSerialization.jl +++ b/src/Serialization/StateSerialization.jl @@ -131,14 +131,10 @@ function unpackOldState(d) label = Symbol(d.solveKey) !isempty(d.covar) && error("covar field is not supported") if label == :parametric - belief = BeliefRepresentation( - GaussianDensityKind(), - statekind; - means = vals, - covariances = [BW], - ) + belief = + StoredBelief(GaussianDensityKind(), statekind; means = vals, covariances = [BW]) else - belief = BeliefRepresentation( + belief = StoredBelief( NonparametricDensityKind(), statekind; points = vals, diff --git a/src/entities/State.jl b/src/entities/State.jl index 7f4781f2..86144b4d 100644 --- a/src/entities/State.jl +++ b/src/entities/State.jl @@ -6,7 +6,7 @@ abstract type AbstractStateType{N} end const StateType = AbstractStateType ##============================================================================== -## BeliefRepresentation +## StoredBelief ##============================================================================== abstract type AbstractDensityKind end @@ -24,9 +24,9 @@ function StructUtils.lower(::StructUtils.StructStyle, p::AbstractDensityKind) end @choosetype AbstractDensityKind resolvePackedType -# TODO naming? Density, DensityRepresentation, BeliefRepresentation, BeliefState, etc? +# TODO naming? Density, DensityRepresentation, StoredBelief, BeliefState, etc? # TODO flatten in State? likeley not for easier serialization of points. -@kwdef struct BeliefRepresentation{T <: StateType, P} +@kwdef struct StoredBelief{T <: StateType, P} statekind::T = T()# NOTE duplication for serialization, TODO maybe only in State and therefore belief cannot deserialize separately. """Discriminator for which representation is active.""" densitykind::AbstractDensityKind = NonparametricDensityKind() @@ -50,14 +50,17 @@ end # JSON.parse(JSON.json(zeros(0, 0)), Matrix{Float64}) errors, so trying with nothing union end -JSON.omit_empty(::Type{<:BeliefRepresentation}) = true +#FIXME remove old name before v0.29 +const BeliefRepresentation = StoredBelief -function BeliefRepresentation(T::AbstractStateType) - return BeliefRepresentation{typeof(T), getPointType(T)}(; statekind = T) +JSON.omit_empty(::Type{<:StoredBelief}) = true + +function StoredBelief(T::AbstractStateType) + return StoredBelief{typeof(T), getPointType(T)}(; statekind = T) end -function BeliefRepresentation(::NonparametricDensityKind, T::AbstractStateType; kwargs...) - return BeliefRepresentation{typeof(T), getPointType(T)}(; +function StoredBelief(::NonparametricDensityKind, T::AbstractStateType; kwargs...) + return StoredBelief{typeof(T), getPointType(T)}(; statekind = T, densitykind = NonparametricDensityKind(), bandwidth = zeros(getDimension(T), getDimension(T)), @@ -65,8 +68,8 @@ function BeliefRepresentation(::NonparametricDensityKind, T::AbstractStateType; ) end -function BeliefRepresentation(::GaussianDensityKind, T::AbstractStateType; kwargs...) - return BeliefRepresentation{typeof(T), getPointType(T)}(; +function StoredBelief(::GaussianDensityKind, T::AbstractStateType; kwargs...) + return StoredBelief{typeof(T), getPointType(T)}(; statekind = T, densitykind = GaussianDensityKind(), bandwidth = nothing, @@ -76,7 +79,7 @@ end function StructUtils.fielddefaults( ::StructUtils.StructStyle, - ::Type{BeliefRepresentation{T, P}}, + ::Type{StoredBelief{T, P}}, ) where {T, P} return ( statekind = T(), @@ -89,12 +92,12 @@ function StructUtils.fielddefaults( ) end -function resolveBeliefRepresentationType(lazyobj) +function resolveStoredBeliefType(lazyobj) statekind = liftStateKind(lazyobj.statekind[]) - return BeliefRepresentation{typeof(statekind), getPointType(statekind)} + return StoredBelief{typeof(statekind), getPointType(statekind)} end -@choosetype BeliefRepresentation resolveBeliefRepresentationType +@choosetype StoredBelief resolveStoredBeliefType ##============================================================================== ## State @@ -116,10 +119,9 @@ $(TYPEDFIELDS) """Singleton type for the state, eg. Pose{3}(), Position{2}(), etc. Used for dispatch and serialization.""" statekind::T = T() """ - Generic Belief representation for this state, including the discriminator for which representation is active - and the associated fields for each representation kind. + Generic stored belief for this state. """ - belief::BeliefRepresentation{T, P} = BeliefRepresentation{T, P}()#; statekind = T()) + belief::StoredBelief{T, P} = StoredBelief{T, P}()#; statekind = T()) """List of symbols for separator variables for this state, used in variable elimination and inference computations.""" separator::Vector{Symbol} = Symbol[] """False if initial numerical values are not yet available or stored values are not ready for further processing yet.""" @@ -131,10 +133,13 @@ $(TYPEDFIELDS) """How many times has a solver updated this state estimate.""" solves::Int = 0 # TODO renamed from solvedCount v0.29 - #TODO belief cache that can be used for caching HomotopyDensity (StateCache or BeliefCache) - # abstract type AbstractStateCache end - # const StateCache = AbstractStateCache - # solvercache::Base.RefValue{<:StateCache} = Ref{StateCache}() & (ignore = true,) + #TODO belief container that can be used for active solver beliefs such as a HomotopyDensity + # The type is defined by a trait saved in the StoredBelief and + # verbs such as `hydrate!(state)` `persist!(state)` can be used at data at checkpoints. + # Forcing an explicit `persist!` acts as a state checkpoint, + #ensuring the graph only ever stores fully committed solver results rather than half-computed intermediate math. + # abstract type AbstractActiveBelief end + # active_belief::Base.RefValue{<:AbstractActiveBelief} = Ref{AbstractActiveBelief}() & (ignore = true,) end # OLD deprecated fields, removed in v0.29, kept here for reference during transition @@ -173,7 +178,7 @@ function StructUtils.fielddefaults( ::Type{State{T, P}}, ) where {T, P} return ( - belief = BeliefRepresentation{T, P}(; statekind = T()), + belief = StoredBelief{T, P}(; statekind = T()), separator = Symbol[], initialized = false, observability = Float64[], diff --git a/src/entities/Tags.jl b/src/entities/Tags.jl index 1fdb5be9..81cea66f 100644 --- a/src/entities/Tags.jl +++ b/src/entities/Tags.jl @@ -14,8 +14,9 @@ listTags(node) = collect(refTags(node)) Merge add tags to a variable or factor (union) """ function mergeTags!(node, tags) + n_before = length(refTags(node)) union!(refTags(node), tags) - return length(tags) + return length(refTags(node)) - n_before end """ $SIGNATURES @@ -23,8 +24,9 @@ $SIGNATURES Remove the tags from the node (setdiff) """ function deleteTags!(node, tags) + n_before = length(refTags(node)) setdiff!(refTags(node), tags) - return length(tags) + return n_before - length(refTags(node)) end """ diff --git a/src/entities/equality.jl b/src/entities/equality.jl index 6d1bc246..3a5eeb14 100644 --- a/src/entities/equality.jl +++ b/src/entities/equality.jl @@ -20,7 +20,7 @@ implement compare if needed. const GeneratedCompareUnion = Union{ Agent, Graphroot, - BeliefRepresentation, + StoredBelief, State, Blobentry, Bloblet, diff --git a/test/testBlocks.jl b/test/testBlocks.jl index 29f98b13..dc9a96ad 100644 --- a/test/testBlocks.jl +++ b/test/testBlocks.jl @@ -300,7 +300,7 @@ function DFGVariableSCA() #TODO here for now, don't reccomend usage. testTags = [:tag1, :tag2] @test DFG.mergeTags!(v3, testTags) == 2 - @test DFG.mergeTags!(v3, Set(testTags)) == 2 + @test DFG.mergeTags!(v3, Set(testTags)) == 0 #NOTE a variable's timestamp is considered similar to its label. setTimestamp! (not implemented) would create a new variable and call mergeVariable! # @test getTimestamp(v1ts) == testTimestamp @@ -373,7 +373,7 @@ function DFGFactorSCA() testTags = [:tag1, :tag2] @test DFG.mergeTags!(f1, testTags) == 2 - @test DFG.mergeTags!(f1, Set(testTags)) == 2 + @test DFG.mergeTags!(f1, Set(testTags)) == 0 #follow with mergeFactor!(fg, v1ts) @@ -786,13 +786,13 @@ function statesExtendedTestBlock!(fg) # addStates! bulk s1 = State{TestVariableType1}(; label = :bulk_s1) s2 = State{TestVariableType1}(; label = :bulk_s2) - @test addStates!(fg, :a, [s1, s2]) == 2 + addStates!(fg, :a, [s1, s2]) @test hasState(fg, :a, :bulk_s1) @test hasState(fg, :a, :bulk_s2) # addStates! with pair syntax s3 = State{TestVariableType2}(; label = :bulk_s3) - @test addStates!(fg, [:b => s3]) == 1 + addStates!(fg, [:b => s3]) @test hasState(fg, :b, :bulk_s3) # deleteStates! bulk diff --git a/test/testSerializingVariables.jl b/test/testSerializingVariables.jl index 0899d4ae..6f4691e1 100644 --- a/test/testSerializingVariables.jl +++ b/test/testSerializingVariables.jl @@ -15,6 +15,13 @@ DFG.@defStateTypeN Pose{N} SpecialEuclideanGroup(N; variant = :right) ArrayParti ) Pose2 = Pose{2} +# Complex scalar point type (CircleGroup identity is ComplexF64) +DFG.@defStateType CircleState CircleGroup() (1.0 + 0.0im) + +# Complex 0-dimensional array point type (circle manifold) +const MB = DFG.ManifoldsBase +DFG.@defStateType CCircle MB.DefaultManifold(1; field = MB.ℂ) fill(1.0 + 0.0im) + ## Build a test variable with states, bloblets, and blobentries function make_test_variable() v = DFG.VariableDFG(:x1, Pose{3}()) @@ -39,27 +46,27 @@ function make_test_variable() end @testset "Serializing Variables" begin - @testset "BeliefRepresentation round-trip" begin - bel = DFG.BeliefRepresentation(Pose{3}()) + @testset "StoredBelief round-trip" begin + bel = DFG.StoredBelief(Pose{3}()) push!(bel.points, DFG.getPointIdentity(Pose{3}())) G = DFG.getManifold(Pose{3}()) push!(bel.points, rand(G, ArrayPartition)) jstr = JSON.json(bel; pretty = true, style = DFG.DFGJSONStyle()) - parsed = JSON.parse(jstr, DFG.BeliefRepresentation; style = DFG.DFGJSONStyle()) + parsed = JSON.parse(jstr, DFG.StoredBelief; style = DFG.DFGJSONStyle()) @test bel == parsed end @testset "GaussianDensityKind round-trip" begin dim = DFG.getDimension(Pose{3}()) - bel = DFG.BeliefRepresentation( + bel = DFG.StoredBelief( DFG.GaussianDensityKind(), Pose{3}(); means = [DFG.getPointIdentity(Pose{3}())], covariances = [diagm(ones(dim))], ) jstr = JSON.json(bel; pretty = true, style = DFG.DFGJSONStyle()) - parsed = JSON.parse(jstr, DFG.BeliefRepresentation; style = DFG.DFGJSONStyle()) + parsed = JSON.parse(jstr, DFG.StoredBelief; style = DFG.DFGJSONStyle()) @test bel == parsed end @@ -105,6 +112,38 @@ end @test vsk.label == :x1 @test vsk.tags == v.tags end + + @testset "Complex (CircleGroup) end-to-end" begin + # CircleState uses ComplexF64 as point type + @test DFG.getPointType(CircleState) == ComplexF64 + @test DFG.getPointIdentity(CircleState) == 1.0 + 0.0im + + v = DFG.VariableDFG(:c1, CircleState()) + state = addState!(v, State(:default, CircleState())) + push!(state.belief.points, 1.0 + 0.0im) + push!(state.belief.points, 0.5 + 0.866im) + DFG.addBloblet!(v, DFG.Bloblet(:meta, "circle")) + + jstr = JSON.json(v; pretty = true, style = DFG.DFGJSONStyle()) + parsed = JSON.parse(jstr, DFG.VariableDFG; style = DFG.DFGJSONStyle()) + @test v == parsed + end + + @testset "AbstractArray{<:Complex, 0} (CCircle) end-to-end" begin + # CCircle uses Array{ComplexF64, 0} as point type + @test DFG.getPointType(CCircle) == Array{ComplexF64, 0} + @test DFG.getPointIdentity(CCircle) == fill(1.0 + 0.0im) + + v = DFG.VariableDFG(:z1, CCircle()) + state = addState!(v, State(:default, CCircle())) + push!(state.belief.points, fill(1.0 + 0.0im)) + push!(state.belief.points, fill(0.5 + 0.5im)) + DFG.addBloblet!(v, DFG.Bloblet(:meta, "ccircle")) + + jstr = JSON.json(v; pretty = true, style = DFG.DFGJSONStyle()) + parsed = JSON.parse(jstr, DFG.VariableDFG; style = DFG.DFGJSONStyle()) + @test v == parsed + end end # TODO deprecated v0.29, remove this test and unpackOldState