From f72a40437f65087037faa86dd62f511561a0473d Mon Sep 17 00:00:00 2001 From: Dehann Fourie <6412556+dehann@users.noreply.github.com> Date: Mon, 11 May 2026 22:06:41 -0700 Subject: [PATCH 1/9] HoDe.observability instead of State.observability --- src/entities/State.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/entities/State.jl b/src/entities/State.jl index f783728f..9a44ed6c 100644 --- a/src/entities/State.jl +++ b/src/entities/State.jl @@ -26,8 +26,6 @@ $(TYPEDFIELDS) separator::Vector{Symbol} = Symbol[] """False if initial numerical values are not yet available or stored values are not ready for further processing yet.""" initialized::Bool = false - """Stores the amount of information captured in each coordinate dimension.""" - observability::Vector{Float64} = Float64[]#zeros(getDimension(T)) #TODO renamed from infoPerCoord in v0.29 """Should this state be treated as marginalized in inference computations.""" marginalized::Bool = false #TODO renamed from ismargin v0.29 """How many times has a solver updated this state estimate.""" @@ -88,7 +86,6 @@ function StructUtils.fielddefaults( belief = HomotopyDensityDFG{T, P}(), separator = Symbol[], initialized = false, - observability = Float64[], marginalized = false, solves = 0, statekind = T(), From f5c73d733d813fbf202c3c1eef40b217e6399982 Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 11 May 2026 22:29:25 -0700 Subject: [PATCH 2/9] HoDe.observability and impr hode docs --- src/entities/HomotopyDensity.jl | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index d1c3742a..1f1cc723 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -77,26 +77,29 @@ provided by AMP for features like pdf evaluation. HomotopyReprDFG(DefaultTopologyKind(), DefaultFormKind(), T(), nothing) """A hint for downstream solvers on how to interpret this data (The 'How')""" topologykind::AbstractHomotopyTopology = DefaultTopologyKind() - + """Stores the amount of information captured in each coordinate dimension.""" + observability::Vector{Float64} = Float64[] #zeros(getDimension(T)) #TODO renamed from infoPerCoord in v0.29 + """Hard decision that input data are sample points from some manifold, but note the reconstruction might not use points at all.""" points::Vector{P} = P[] # previously `val` + """Input points may be weighted, and/or reused as part of reconstruction in the trailing forms.""" weights::Vector{Float64} = Float64[] """ In model order reduction, PCA, and modal analysis, the terms for the eigenvectors associated with the largest and smallest eigenvalues are commonly: - Major eigenvectors are often called "dominant eigenvectors," or simply "leading modes." In Principal Component Analysis (PCA), these are the "principal components." - Minor eigenvectors are sometimes called "trailing eigenvectors," or "residual modes." In PCA, these correspond to the components with the smallest variance. + Principal/major/dominant/leading recon-basis/eigen vectors. In Principal Component Analysis (PCA), these are the "principal components." + Trailing/minor/residual recon-basis/eigen vectors. In PCA, these correspond to the components with the smallest variance. """ principal_coeffs::Vector{Float64} = Vector{Float64}() # FIXME getMajorsLength(reprkind)) principal_elements::Vector{P} = P[] # previously `val[1]` for Gaussian principal_forms::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) """ Store minor eigenvalue details such as leaf bandwidth or reconstruction vectors. - - When lifted for compute efficiency, this field is likely to hold something like PDMats. - - When lowered or for serde, this field is likely to hold Dict{Int, Vector{Float64}}. + - Live compute version may hold something like PDMats/Cholesky. """ trailing_forms::SparseVector{Matrix{Float64}, Int} = spzeros(Matrix{Float64}, 1) #previously `bw` """ Geometric points permute field, allows fast binary tree operations and geometric points splits for manellic (ball) trees. - - Geometric split reqs at least 2*(N+1)-1 points -- e.g. when nodes have only right children, points=[1,2,-3]. + - Balanced split reqs at least 2*(N+1)-1 points, incl. right-only case -- e.g. when nodes have only right children, points=[1,2,-3]. + - Unclear at time of writing whether DFG v1.X will exceed binary tree representations, but at least `.structure` allows for e.g. n-many child topologies. """ structure::SparseVector{Vector{Int}, Int} = spzeros(Vector{Int}, 1) end From 77dd6d3b11b0705e8dd48cbf8c64f803ade4f74f Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 11 May 2026 22:31:14 -0700 Subject: [PATCH 3/9] HoDe.obse field default --- src/entities/HomotopyDensity.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index 1f1cc723..0b848736 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -116,6 +116,7 @@ function StructUtils.fielddefaults( ) where {T, P} return ( topologykind = DefaultTopologyKind(), + observability = Float64[], principal_coeffs = Float64[], principal_elements = P[], principal_forms = Matrix{Float64}[], From d7b3c9d46beaf9fd40002d7583e05b5321b08b5b Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 11 May 2026 22:38:11 -0700 Subject: [PATCH 4/9] compare(::State) not .observability --- src/services/compare.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/compare.jl b/src/services/compare.jl index bae84288..20a25a68 100644 --- a/src/services/compare.jl +++ b/src/services/compare.jl @@ -180,9 +180,9 @@ function compare(a::State, b::State) a.initialized != b.initialized && @debug("initialized is not equal") === nothing && return false - !isapprox(a.observability, b.observability; atol = 1e-13) && - @debug("infoPerCoord is not equal") === nothing && - return false + # !isapprox(a.observability, b.observability; atol = 1e-13) && + # @debug("infoPerCoord is not equal") === nothing && + # return false a.marginalized != b.marginalized && @debug("ismargin is not equal") === nothing && return false From 301bfd02f670debbcdd09ccf34a56ddf4ef6aa30 Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 11 May 2026 22:43:30 -0700 Subject: [PATCH 5/9] update tests for drop of state.obsv, use belief.obsv instead --- src/Serialization/StateSerialization.jl | 9 +++++---- test/testBlocks.jl | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Serialization/StateSerialization.jl b/src/Serialization/StateSerialization.jl index 95d2e6ec..d13a489c 100644 --- a/src/Serialization/StateSerialization.jl +++ b/src/Serialization/StateSerialization.jl @@ -130,15 +130,17 @@ function unpackOldState(d) # label = Symbol(d.solveKey) !isempty(d.covar) && error("covar field is not supported") - if label == :parametric - belief = HomotopyDensityDFG{T, getPointType(T)}(; + belief = if label == :parametric + HomotopyDensityDFG{T, getPointType(T)}(; principal_elements = vals, principal_forms = [BW], + observability = d.infoPerCoord, ) else - belief = HomotopyDensityDFG{T, getPointType(T)}(; + HomotopyDensityDFG{T, getPointType(T)}(; points = vals, trailing_forms = sparsevec(Dict(1 => BW)), + observability = d.infoPerCoord, ) end return State{T, getPointType(T)}(; @@ -146,7 +148,6 @@ function unpackOldState(d) belief, separator = Symbol.(d.separator), initialized = d.initialized, - observability = d.infoPerCoord, marginalized = d.ismargin, solves = d.solvedCount, ) diff --git a/test/testBlocks.jl b/test/testBlocks.jl index dc9a96ad..ceaeeb1b 100644 --- a/test/testBlocks.jl +++ b/test/testBlocks.jl @@ -1865,7 +1865,7 @@ function FileDFGTestBlock(testDFGAPI; VARTYPE = VariableDFG, FACTYPE = FactorDFG # vnd.bw[1] = [1.0;] # vnd.dontmargin = true # vnd.eliminated = true - vnd.observability .= Float64[1.5;] + # vnd.observability .= Float64[1.5;] vnd.initialized = true vnd.marginalized = true push!(vnd.separator, :sep) From 832b19fa736cc7855cf99c4fb83c1be5637c21fa Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 11 May 2026 22:52:44 -0700 Subject: [PATCH 6/9] more HoDe cleanup and docs --- src/entities/HomotopyDensity.jl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index 0b848736..73f51319 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -54,14 +54,15 @@ end """ HomotopyDensityDFG{T <: StateType, P} -Hybrid belief representation with natural transition between (non)parametric representations. +Hybrid belief representation with natural transition between hybrid-(non)parametric representations. **THIS IS IMPORTANT**: Fundamentally related to `HomotopyDensity` definition in AMP.jl. !!! warning "Raw Data Container" `HomotopyDensityDFG` is the raw data schema used for database storage and serialization. Mutating this structure in-place is discouraged. Rather, construct a new `State` object - and call `addState!` or `mergeState!`. + and call `addState!` or `mergeState!`. Interaction should use API from HomotopyDensity provider + rather than raw reference access. Notes: - These are the internal raw beliefs and need to be viewed through a lens such as @@ -73,16 +74,14 @@ provided by AMP for features like pdf evaluation. - a.k.a. model order reduction given a topology selection """ @kwdef struct HomotopyDensityDFG{T <: StateType, P} + """To make apples vs apples comparison of one belief to another, only the reprkind between densities are needed for understanding + how to interpret this object. By analogy, and image is an image, but might be stored bitmap, jpeg, png, and use RGB24, YCbCr, etc.""" reprkind::HomotopyReprDFG{T} = HomotopyReprDFG(DefaultTopologyKind(), DefaultFormKind(), T(), nothing) """A hint for downstream solvers on how to interpret this data (The 'How')""" topologykind::AbstractHomotopyTopology = DefaultTopologyKind() """Stores the amount of information captured in each coordinate dimension.""" observability::Vector{Float64} = Float64[] #zeros(getDimension(T)) #TODO renamed from infoPerCoord in v0.29 - """Hard decision that input data are sample points from some manifold, but note the reconstruction might not use points at all.""" - points::Vector{P} = P[] # previously `val` - """Input points may be weighted, and/or reused as part of reconstruction in the trailing forms.""" - weights::Vector{Float64} = Float64[] """ In model order reduction, PCA, and modal analysis, the terms for the eigenvectors associated with the largest and smallest eigenvalues are commonly: Principal/major/dominant/leading recon-basis/eigen vectors. In Principal Component Analysis (PCA), these are the "principal components." @@ -91,11 +90,17 @@ provided by AMP for features like pdf evaluation. principal_coeffs::Vector{Float64} = Vector{Float64}() # FIXME getMajorsLength(reprkind)) principal_elements::Vector{P} = P[] # previously `val[1]` for Gaussian principal_forms::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) + + """Input points may be weighted, and/or reused as part of reconstruction in the trailing forms.""" + weights::Vector{Float64} = Float64[] + """Hard decision that input data are sample points from some manifold, but note the reconstruction might not use points at all.""" + points::Vector{P} = P[] # previously `val` """ Store minor eigenvalue details such as leaf bandwidth or reconstruction vectors. - Live compute version may hold something like PDMats/Cholesky. """ trailing_forms::SparseVector{Matrix{Float64}, Int} = spzeros(Matrix{Float64}, 1) #previously `bw` + """ Geometric points permute field, allows fast binary tree operations and geometric points splits for manellic (ball) trees. - Balanced split reqs at least 2*(N+1)-1 points, incl. right-only case -- e.g. when nodes have only right children, points=[1,2,-3]. From 322222a25374e02a7b27a0e0ba3bef39f797a7f5 Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 11 May 2026 23:05:16 -0700 Subject: [PATCH 7/9] iif tests, reqs depr getObservability --- src/Deprecated.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Deprecated.jl b/src/Deprecated.jl index 5c7614aa..0332ba52 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -797,4 +797,5 @@ refWeights(state::State) = state.belief.weights refPoints(state::State) = state.belief.points refBandwidth(state::State) = state.belief.trailing_forms[1] refBandwidths(state::State) = SparseArrays.nonzeros(state.belief.trailing_forms) +refObservability(state::State) = state.belief.observability getTopologyKind(state::State) = state.belief.topologykind From cf35764f65c7e44db48fafd1d7734a230852382a Mon Sep 17 00:00:00 2001 From: Dehann Fourie <6412556+dehann@users.noreply.github.com> Date: Mon, 11 May 2026 23:13:40 -0700 Subject: [PATCH 8/9] Update src/entities/HomotopyDensity.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/entities/HomotopyDensity.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index 73f51319..918f4287 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -90,7 +90,6 @@ provided by AMP for features like pdf evaluation. principal_coeffs::Vector{Float64} = Vector{Float64}() # FIXME getMajorsLength(reprkind)) principal_elements::Vector{P} = P[] # previously `val[1]` for Gaussian principal_forms::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) - """Input points may be weighted, and/or reused as part of reconstruction in the trailing forms.""" weights::Vector{Float64} = Float64[] """Hard decision that input data are sample points from some manifold, but note the reconstruction might not use points at all.""" From 322f55b4d697cd15107509e164ccc2c5b426f995 Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 11 May 2026 23:23:26 -0700 Subject: [PATCH 9/9] docs and pending fixmes on HoDe field types --- src/entities/HomotopyDensity.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index 918f4287..b6d60b51 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -55,6 +55,8 @@ end HomotopyDensityDFG{T <: StateType, P} Hybrid belief representation with natural transition between hybrid-(non)parametric representations. +This type better allows apples to apples comparisons between divergent beliefs, by means of + a powerful enough density representation. **THIS IS IMPORTANT**: Fundamentally related to `HomotopyDensity` definition in AMP.jl. @@ -88,8 +90,8 @@ provided by AMP for features like pdf evaluation. Trailing/minor/residual recon-basis/eigen vectors. In PCA, these correspond to the components with the smallest variance. """ principal_coeffs::Vector{Float64} = Vector{Float64}() # FIXME getMajorsLength(reprkind)) - principal_elements::Vector{P} = P[] # previously `val[1]` for Gaussian - principal_forms::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) + principal_elements::Vector{P} = P[] # FIXME, use ArrayPartion instead. previously `val[1]` for Gaussian + principal_forms::Vector{Matrix{Float64}} = Matrix{Float64}[] # FIXME, use ArrayPartition instead # previously `covar` existed but was stored in `bw` (hacky) """Input points may be weighted, and/or reused as part of reconstruction in the trailing forms.""" weights::Vector{Float64} = Float64[] """Hard decision that input data are sample points from some manifold, but note the reconstruction might not use points at all.""" @@ -97,8 +99,9 @@ provided by AMP for features like pdf evaluation. """ Store minor eigenvalue details such as leaf bandwidth or reconstruction vectors. - Live compute version may hold something like PDMats/Cholesky. + - Stored version might be similar to a Gaussian splat """ - trailing_forms::SparseVector{Matrix{Float64}, Int} = spzeros(Matrix{Float64}, 1) #previously `bw` + trailing_forms::SparseVector{Matrix{Float64}, Int} = spzeros(Matrix{Float64}, 1) # FIXME use ArrayPartion instead # previously `bw` """ Geometric points permute field, allows fast binary tree operations and geometric points splits for manellic (ball) trees.