From abdfae36ce2ddfcb851b6f584034fbe4e3c97fcf Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 6 May 2026 02:37:53 -0700 Subject: [PATCH 1/6] move legacy type to HomotopyDensity.jl file --- src/DistributedFactorGraphs.jl | 1 + src/entities/HomotopyDensity.jl | 155 ++++++++++++++++++++++++++++++++ src/entities/State.jl | 155 -------------------------------- 3 files changed, 156 insertions(+), 155 deletions(-) create mode 100644 src/entities/HomotopyDensity.jl diff --git a/src/DistributedFactorGraphs.jl b/src/DistributedFactorGraphs.jl index 14c93843..4e1e92b3 100644 --- a/src/DistributedFactorGraphs.jl +++ b/src/DistributedFactorGraphs.jl @@ -403,6 +403,7 @@ include("entities/Tags.jl") include("entities/Timestamp.jl") include("entities/Agent_and_Graph.jl") include("entities/Factor.jl") +include("entities/HomotopyDensity.jl") include("entities/State.jl") include("entities/Variable.jl") include("entities/equality.jl") diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl new file mode 100644 index 00000000..78fe4da1 --- /dev/null +++ b/src/entities/HomotopyDensity.jl @@ -0,0 +1,155 @@ + +# ============================================================================== +# StoredHomotopyBelief +# ============================================================================== +""" + AbstractHomotopyTopology + +Describes the physical layout of the nodes within a `StoredHomotopyBelief`. + +Since all beliefs in the Caesar ecosystem are fundamentally Homotopy densities, +this trait acts as a lightweight dispatch hint (a "Lens Selector"). It indicates +which parts of the tree (Roots vs. Leaves) are currently populated and how they +are wired, without requiring downstream packages to inspect the underlying vectors. + +**Role of the Topology Trait:** +- **DFG:** Determines how to serialize and spatial-index the belief in the database. +- **Visualizers:** Decides how to render the data (e.g., drawing ellipses for roots vs. a point cloud for leaves). +- **IIF/AMP:** Selects the correct mathematical view to construct (e.g., `MvNormal` vs. `ManifoldKernelDensity` vs. a full `HomotopyDensity`). + +!!! note "State, not Strategy" + The trait purely describes the *current physical shape* of the data (e.g., "I currently only have Roots populated"). + It does *not* dictate the solver strategy (e.g., "You must use a parametric solver"). + The math engine is always free to convert or expand the data based on the graph's needs. + +**Extending:** +If the standard tree-based Homotopy model does not fit your specific data layout +or solver requirements, you are encouraged to extend this abstract type with your +own custom topology struct. Alternatively, if you believe your use case represents +a missing core layout, please open an issue to discuss adding it to the +foundational ecosystem. +""" +abstract type AbstractHomotopyTopology end + +# --- 1. The Roots --- +"L1 structural nodes only. No L2 samples. (Schema: `means`, `weights`, `shapes` populated. `points` empty.)" +struct RootsOnlyTopology <: AbstractHomotopyTopology end + +# --- 2. The Leaves --- +"L2 raw samples only. No L1 structure. (Schema: `points`, `bandwidths` populated. `means` empty.)" +struct LeavesOnlyTopology <: AbstractHomotopyTopology end + +# --- 3. The Full Trees --- +"Tree packed in arrays using 2i, 2i+1 math.(Schema: L1 and L2 populated. Parent arrays empty.)" +struct ImplicitTreeTopology <: AbstractHomotopyTopology end + +"Full tree using adjacency lists. (Schema: L1, L2, and Parent arrays fully populated.)" +struct ExplicitTreeTopology <: AbstractHomotopyTopology end + +function StructUtils.lower(::StructUtils.StructStyle, p::AbstractHomotopyTopology) + return StructUtils.lower(Packed(p)) +end +@choosetype AbstractHomotopyTopology resolvePackedType + +""" + StoredHomotopyBelief{T <: StateType, P} + +A multi-resolution "Grove of Trees" representing a manifold belief. +Each tree can be as deep (ExplicitTreeTopology) or as shallow (RootsOnlyTopology) +as the evidence requires, but they all speak the same language of Nodes and Parents. + +These are the internal raw beliefs and need to be viewed through a lens such as +provided by AMP for features like pdf evaluation. Organized into structural +Tree/Branch layers (L1) and empirical Leaf layers (L2). + +!!! warning "Raw Data Container" + `StoredHomotopyBelief` 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!`. +""" +@kwdef struct StoredHomotopyBelief{T <: StateType, P} + statekind::T = T()# NOTE duplication for serialization and self description. + """A hint for downstream solvers on how to interpret this data (The 'How')""" + topologykind::AbstractHomotopyTopology = LeavesOnlyTopology() + + # L1 Nodes + """ + [Order 0] The relative importance or probability of each node in L1. + """ + weights::Vector{Float64} = Float64[] + """ + [Order 1] The location/center of each node, stored directly on the manifold. + """ + means::Vector{P} = P[] # previously `val[1]` for Gaussian + """ + [Order 2] The spread/curvature of each node (e.g., Covariance or Precision matrix). + """ + shapes::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) + + # L2 Nodes + """ + The raw empirical samples on the manifold. Used for KDE and particle representations. + """ + points::Vector{P} = P[] # previously `val` + """ + The second-order bandwidths for the non-parametric points, supports variable bandwidth kernels. + """ + bandwidths::Vector{Matrix{Float64}} = Matrix{Float64}[] #previously `bw` --- + + # --- Topology (The Hierarchy) --- + """ + L1 Internal Topology: mean_parents[i] = j means means[i] is a child of means[j]. A value of 0 indicates a Root node. + """ + mean_parents::Vector{Int} = Int[] + """ + L2-to-L1 Bridge: point_parents[i] = j means points[i] is governed by means[j]. Points are leaves. + """ + point_parents::Vector{Int} = Int[] +end + +JSON.omit_empty(::Type{<:StoredHomotopyBelief}) = true + +function StoredHomotopyBelief(T::AbstractStateType) + return StoredHomotopyBelief{typeof(T), getPointType(T)}(; statekind = T) +end + +function StoredHomotopyBelief(::LeavesOnlyTopology, T::AbstractStateType; kwargs...) + return StoredHomotopyBelief{typeof(T), getPointType(T)}(; + statekind = T, + topologykind = LeavesOnlyTopology(), + bandwidths = [zeros(getDimension(T), getDimension(T))], + kwargs..., + ) +end + +function StoredHomotopyBelief(::RootsOnlyTopology, T::AbstractStateType; kwargs...) + return StoredHomotopyBelief{typeof(T), getPointType(T)}(; + statekind = T, + topologykind = RootsOnlyTopology(), + kwargs..., + ) +end + +function StructUtils.fielddefaults( + ::StructUtils.StructStyle, + ::Type{StoredHomotopyBelief{T, P}}, +) where {T, P} + return ( + statekind = T(), + topologykind = LeavesOnlyTopology(), + means = P[], + shapes = Matrix{Float64}[], + weights = Float64[], + points = P[], + bandwidths = Matrix{Float64}[], + mean_parents = Int[], + point_parents = Int[], + ) +end + +function resolveStoredBeliefType(lazyobj) + statekind = liftStateKind(lazyobj.statekind[]) + return StoredHomotopyBelief{typeof(statekind), getPointType(statekind)} +end + +@choosetype StoredHomotopyBelief resolveStoredBeliefType diff --git a/src/entities/State.jl b/src/entities/State.jl index 7caccdad..a377f2a2 100644 --- a/src/entities/State.jl +++ b/src/entities/State.jl @@ -5,161 +5,6 @@ abstract type AbstractStateType{N} end const StateType = AbstractStateType -# ============================================================================== -# StoredHomotopyBelief -# ============================================================================== -""" - AbstractHomotopyTopology - -Describes the physical layout of the nodes within a `StoredHomotopyBelief`. - -Since all beliefs in the Caesar ecosystem are fundamentally Homotopy densities, -this trait acts as a lightweight dispatch hint (a "Lens Selector"). It indicates -which parts of the tree (Roots vs. Leaves) are currently populated and how they -are wired, without requiring downstream packages to inspect the underlying vectors. - -**Role of the Topology Trait:** -- **DFG:** Determines how to serialize and spatial-index the belief in the database. -- **Visualizers:** Decides how to render the data (e.g., drawing ellipses for roots vs. a point cloud for leaves). -- **IIF/AMP:** Selects the correct mathematical view to construct (e.g., `MvNormal` vs. `ManifoldKernelDensity` vs. a full `HomotopyDensity`). - -!!! note "State, not Strategy" - The trait purely describes the *current physical shape* of the data (e.g., "I currently only have Roots populated"). - It does *not* dictate the solver strategy (e.g., "You must use a parametric solver"). - The math engine is always free to convert or expand the data based on the graph's needs. - -**Extending:** -If the standard tree-based Homotopy model does not fit your specific data layout -or solver requirements, you are encouraged to extend this abstract type with your -own custom topology struct. Alternatively, if you believe your use case represents -a missing core layout, please open an issue to discuss adding it to the -foundational ecosystem. -""" -abstract type AbstractHomotopyTopology end - -# --- 1. The Roots --- -"L1 structural nodes only. No L2 samples. (Schema: `means`, `weights`, `shapes` populated. `points` empty.)" -struct RootsOnlyTopology <: AbstractHomotopyTopology end - -# --- 2. The Leaves --- -"L2 raw samples only. No L1 structure. (Schema: `points`, `bandwidths` populated. `means` empty.)" -struct LeavesOnlyTopology <: AbstractHomotopyTopology end - -# --- 3. The Full Trees --- -"Tree packed in arrays using 2i, 2i+1 math.(Schema: L1 and L2 populated. Parent arrays empty.)" -struct ImplicitTreeTopology <: AbstractHomotopyTopology end - -"Full tree using adjacency lists. (Schema: L1, L2, and Parent arrays fully populated.)" -struct ExplicitTreeTopology <: AbstractHomotopyTopology end - -function StructUtils.lower(::StructUtils.StructStyle, p::AbstractHomotopyTopology) - return StructUtils.lower(Packed(p)) -end -@choosetype AbstractHomotopyTopology resolvePackedType - -""" - StoredHomotopyBelief{T <: StateType, P} - -A multi-resolution "Grove of Trees" representing a manifold belief. -Each tree can be as deep (ExplicitTreeTopology) or as shallow (RootsOnlyTopology) -as the evidence requires, but they all speak the same language of Nodes and Parents. - -These are the internal raw beliefs and need to be viewed through a lens such as -provided by AMP for features like pdf evaluation. Organized into structural -Tree/Branch layers (L1) and empirical Leaf layers (L2). - -!!! warning "Raw Data Container" - `StoredHomotopyBelief` 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!`. -""" -@kwdef struct StoredHomotopyBelief{T <: StateType, P} - statekind::T = T()# NOTE duplication for serialization and self description. - """A hint for downstream solvers on how to interpret this data (The 'How')""" - topologykind::AbstractHomotopyTopology = LeavesOnlyTopology() - - # L1 Nodes - """ - [Order 0] The relative importance or probability of each node in L1. - """ - weights::Vector{Float64} = Float64[] - """ - [Order 1] The location/center of each node, stored directly on the manifold. - """ - means::Vector{P} = P[] # previously `val[1]` for Gaussian - """ - [Order 2] The spread/curvature of each node (e.g., Covariance or Precision matrix). - """ - shapes::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) - - # L2 Nodes - """ - The raw empirical samples on the manifold. Used for KDE and particle representations. - """ - points::Vector{P} = P[] # previously `val` - """ - The second-order bandwidths for the non-parametric points, supports variable bandwidth kernels. - """ - bandwidths::Vector{Matrix{Float64}} = Matrix{Float64}[] #previously `bw` --- - - # --- Topology (The Hierarchy) --- - """ - L1 Internal Topology: mean_parents[i] = j means means[i] is a child of means[j]. A value of 0 indicates a Root node. - """ - mean_parents::Vector{Int} = Int[] - """ - L2-to-L1 Bridge: point_parents[i] = j means points[i] is governed by means[j]. Points are leaves. - """ - point_parents::Vector{Int} = Int[] -end - -JSON.omit_empty(::Type{<:StoredHomotopyBelief}) = true - -function StoredHomotopyBelief(T::AbstractStateType) - return StoredHomotopyBelief{typeof(T), getPointType(T)}(; statekind = T) -end - -function StoredHomotopyBelief(::LeavesOnlyTopology, T::AbstractStateType; kwargs...) - return StoredHomotopyBelief{typeof(T), getPointType(T)}(; - statekind = T, - topologykind = LeavesOnlyTopology(), - bandwidths = [zeros(getDimension(T), getDimension(T))], - kwargs..., - ) -end - -function StoredHomotopyBelief(::RootsOnlyTopology, T::AbstractStateType; kwargs...) - return StoredHomotopyBelief{typeof(T), getPointType(T)}(; - statekind = T, - topologykind = RootsOnlyTopology(), - kwargs..., - ) -end - -function StructUtils.fielddefaults( - ::StructUtils.StructStyle, - ::Type{StoredHomotopyBelief{T, P}}, -) where {T, P} - return ( - statekind = T(), - topologykind = LeavesOnlyTopology(), - means = P[], - shapes = Matrix{Float64}[], - weights = Float64[], - points = P[], - bandwidths = Matrix{Float64}[], - mean_parents = Int[], - point_parents = Int[], - ) -end - -function resolveStoredBeliefType(lazyobj) - statekind = liftStateKind(lazyobj.statekind[]) - return StoredHomotopyBelief{typeof(statekind), getPointType(statekind)} -end - -@choosetype StoredHomotopyBelief resolveStoredBeliefType - ##============================================================================== ## State ##============================================================================== From d4630f8d01a6cda82e8f134553ee0e24a53ddb6e Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 6 May 2026 02:52:28 -0700 Subject: [PATCH 2/6] wip HomotopyDensityDFG replaces StoredHomotopyBelief --- src/Serialization/StateSerialization.jl | 4 +- src/entities/HomotopyDensity.jl | 295 +++++++++++++++++------- src/entities/State.jl | 8 +- src/entities/equality.jl | 2 +- test/testSerializingVariables.jl | 10 +- 5 files changed, 223 insertions(+), 96 deletions(-) diff --git a/src/Serialization/StateSerialization.jl b/src/Serialization/StateSerialization.jl index 8001697b..1cd26164 100644 --- a/src/Serialization/StateSerialization.jl +++ b/src/Serialization/StateSerialization.jl @@ -131,14 +131,14 @@ function unpackOldState(d) label = Symbol(d.solveKey) !isempty(d.covar) && error("covar field is not supported") if label == :parametric - belief = StoredHomotopyBelief( + belief = HomotopyDensityDFG( RootsOnlyTopology(), statekind; means = vals, shapes = [BW], ) else - belief = StoredHomotopyBelief( + belief = HomotopyDensityDFG( LeavesOnlyTopology(), statekind; points = vals, diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index 78fe4da1..cafd05a6 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -1,18 +1,63 @@ # ============================================================================== -# StoredHomotopyBelief +# HomotopyDensityDFG # ============================================================================== + + + +export + AbstractPartialTraits, + AbstractHomotopyTruncation, + MajorMaxDepth + +export + getStateType, + getManifold, + getReprType, + getTruncation, + getPartial + + +# Forward looking abstract for DFG v1.x development of partials using traits, but not yet implemented +abstract type AbstractPartialTraits end + +abstract type AbstractHomotopyTruncation end + +abstract type AbstractDensityBasis end + + + """ - AbstractHomotopyTopology +HomotopyRepr is a struct that encapsulates the representation of a homotopy density. + HomotopyDensity is a very broad and 99% agnostic serialization type whose method implementations should dispatch + on the type of the representation, which is expected to be a concrete type with necessary dispatch info. -Describes the physical layout of the nodes within a `StoredHomotopyBelief`. +Comment on future-proofing: at time of writing (26Q2), we anticipate a long and methodic development of + hybrid-(non)parametric computational methods which can all fit in the same general LTS framework (i.e. DFG v1). + +Future-proofing is achieved by making the representation type a concrete struct which is JSON.jl compliant, barr +- elementary lift and lower implementations for HomotopyRepr. + +Describes the physical layout of the nodes within a `HomotopyDensityDFG`. Since all beliefs in the Caesar ecosystem are fundamentally Homotopy densities, -this trait acts as a lightweight dispatch hint (a "Lens Selector"). It indicates +HomotopyRepr trait acts as a lightweight dispatch hint (a "Lens Selector"). It indicates which parts of the tree (Roots vs. Leaves) are currently populated and how they are wired, without requiring downstream packages to inspect the underlying vectors. -**Role of the Topology Trait:** + +Comments on type parameters: +- statetype is the type of the state, + which is either a Manifolds.jl manifold type or a DFG statetype +- L is the type of the partial, future expectation is for improved traits-based partials while, + legacy used tuples to specify coord dims. +- reprtype is the type of the density basis, + e.g. ConcentratedGaussianKernel and is expected to evolve into continuous eigen vectors and wavelets. +- truncation type relates to model order reduction technique embedded in the HomotopyDensity, + e.g. MajorMaxDepth is a simple binary tree truncation with N major levels. + + +**Role of the HomotopyRepr Trait:** - **DFG:** Determines how to serialize and spatial-index the belief in the database. - **Visualizers:** Decides how to render the data (e.g., drawing ellipses for roots vs. a point cloud for leaves). - **IIF/AMP:** Selects the correct mathematical view to construct (e.g., `MvNormal` vs. `ManifoldKernelDensity` vs. a full `HomotopyDensity`). @@ -29,114 +74,196 @@ own custom topology struct. Alternatively, if you believe your use case represen a missing core layout, please open an issue to discuss adding it to the foundational ecosystem. """ -abstract type AbstractHomotopyTopology end +struct HomotopyRepr{ + truncation <: AbstractHomotopyTruncation, + reprtype <: AbstractDensityBasis, + statetype <: Union{<:AbstractManifold, <:AbstractStateType}, + L <: AbstractPartialLegacyCompat, # Future use <:AbstractPartialTraits +} + """ + Used for either DistributedFactorGraphs statetype or Manifolds.jl manifold type, depending on context. + Expect official support for serde only for DFG statetypes. Note, DFG statetypes are built on top of Manifolds.jl. + Use `getManifold(::HomotopyRepr)` to get the manifold type regardless of context. -# --- 1. The Roots --- -"L1 structural nodes only. No L2 samples. (Schema: `means`, `weights`, `shapes` populated. `points` empty.)" -struct RootsOnlyTopology <: AbstractHomotopyTopology end + Note, and explicit object `statekind` is needed for the Manifolds.jl only context, but note this field is not serialized + """ + statekind::statetype + """ + Future of partials is to use traits, so an abstract type is warranted. + Legacy is object of either Nothing, Tuple, or Vector{Int}, but something better is needed + """ + partial::L +end -# --- 2. The Leaves --- -"L2 raw samples only. No L1 structure. (Schema: `points`, `bandwidths` populated. `means` empty.)" -struct LeavesOnlyTopology <: AbstractHomotopyTopology end -# --- 3. The Full Trees --- -"Tree packed in arrays using 2i, 2i+1 math.(Schema: L1 and L2 populated. Parent arrays empty.)" -struct ImplicitTreeTopology <: AbstractHomotopyTopology end +struct MajorMaxDepth{ + N +} <: AbstractHomotopyTruncation end -"Full tree using adjacency lists. (Schema: L1, L2, and Parent arrays fully populated.)" -struct ExplicitTreeTopology <: AbstractHomotopyTopology end -function StructUtils.lower(::StructUtils.StructStyle, p::AbstractHomotopyTopology) - return StructUtils.lower(Packed(p)) -end -@choosetype AbstractHomotopyTopology resolvePackedType +getMajorsLength(::Type{<:AbstractHomotopyTruncation}) = 1 +getMajorsLength(repr::HomotopyRepr) = getMajorsLength(getTruncation(repr)) + +# Binary tree with N major levels +getMajorsLength(::Type{MajorMaxDepth{N}}) where {N} = N^2 - 1 + +# trivial case -- should be in DFG instead FIXME +getManifold(manif::AbstractManifold) = manif + +getStateType(::HomotopyRepr{T,R,statetype}) where {T,R,statetype} = statetype +getPartial(hr::HomotopyRepr) = hr.partial +getReprType(::HomotopyRepr{T,reprtype}) where {T, reprtype} = reprtype +getTruncation(::HomotopyRepr{truncation}) where {truncation} = truncation +# supports both DFG and ManifoldsBase +getManifold(repr::HomotopyRepr) = getManifold(repr.statekind) + + + + + +# # --- 1. The Roots --- +# "L1 structural nodes only. No L2 samples. (Schema: `means`, `weights`, `shapes` populated. `points` empty.)" +# struct RootsOnlyTopology <: AbstractHomotopyTopology end + +# # --- 2. The Leaves --- +# "L2 raw samples only. No L1 structure. (Schema: `points`, `bandwidths` populated. `means` empty.)" +# struct LeavesOnlyTopology <: AbstractHomotopyTopology end + +# # --- 3. The Full Trees --- +# "Tree packed in arrays using 2i, 2i+1 math.(Schema: L1 and L2 populated. Parent arrays empty.)" +# struct ImplicitTreeTopology <: AbstractHomotopyTopology end + +# "Full tree using adjacency lists. (Schema: L1, L2, and Parent arrays fully populated.)" +# struct ExplicitTreeTopology <: AbstractHomotopyTopology end + +# function StructUtils.lower(::StructUtils.StructStyle, p::AbstractHomotopyTopology) +# return StructUtils.lower(Packed(p)) +# end +# @choosetype AbstractHomotopyTopology resolvePackedType """ - StoredHomotopyBelief{T <: StateType, P} + HomotopyDensityDFG{T <: StateType, P} -A multi-resolution "Grove of Trees" representing a manifold belief. -Each tree can be as deep (ExplicitTreeTopology) or as shallow (RootsOnlyTopology) -as the evidence requires, but they all speak the same language of Nodes and Parents. +Hybrid belief representation with natural transition between (non)parametric representations. These are the internal raw beliefs and need to be viewed through a lens such as -provided by AMP for features like pdf evaluation. Organized into structural -Tree/Branch layers (L1) and empirical Leaf layers (L2). +provided by AMP for features like pdf evaluation. + +Notes: +- Refactoring and renaming of ManellicTree + ManifoldKernelDensity +- Replaces kernel density estimate, Gaussian mixture models, Principle component analysis, Homotopy methods, Model order reduction +- Allows partials as identified by list of coordinate dimensions e.g. `partial = [1;3]` + - When building a partial belief, use full points with necessary information in the specified partial coords. + +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. !!! warning "Raw Data Container" - `StoredHomotopyBelief` is the raw data schema used for database storage and serialization. + `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!`. """ -@kwdef struct StoredHomotopyBelief{T <: StateType, P} - statekind::T = T()# NOTE duplication for serialization and self description. - """A hint for downstream solvers on how to interpret this data (The 'How')""" - topologykind::AbstractHomotopyTopology = LeavesOnlyTopology() - - # L1 Nodes - """ - [Order 0] The relative importance or probability of each node in L1. +@kwdef struct HomotopyDensityDFG{ + H <: HomotopyRepr, # serde friendly when using DFG.statekind representation, but also supports Manifolds.jl direclty + # parameters below auto generate during JSON lift, only above needs to be serde friendly + P, # serde relies on DFG statekind mechanism, does not guarantee serde when directly using Manifolds wo DFG.statekind +} + reprkind::H + observability::Vector{Float64} = zeros(manifold_dimension(getManifold(reprkind))) + points::Vector{P} + weights::Vector{Float64} = Vector{Float64}(ones(length(points))) ./ length(points) + majors_coeff::Vector{Float64} = Vector{Float64}(undef, getMajorsLength(reprkind)) + majors_element::Vector{P} = Vector{P}(undef, getMajorsLength(reprkind)) + majors_detail::Vector{Matrix{Float64}} = Vector{SMatrix{Float64}}(undef, getMajorsLength(reprkind)) """ - weights::Vector{Float64} = Float64[] + Store minor details such as leaf bandwidth or eigenvectors associated with minor eigenvalues. + - 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}}. """ - [Order 1] The location/center of each node, stored directly on the manifold. - """ - means::Vector{P} = P[] # previously `val[1]` for Gaussian - """ - [Order 2] The spread/curvature of each node (e.g., Covariance or Precision matrix). + minors_detail::SparseArrays.SparseVector{SMatrix{Float64}, Int} = SparseArrays.sparsevec( + Dict(1 => Matrix{Float64}(I, manifold_dimension(getManifold(reprkind)), manifold_dimension(getManifold(reprkind))),), + 1 + ) + """ + 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]. """ - shapes::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) + structure::SparseArrays.SparseVector{Vector{Int}, Int} = SparseArrays.sparsevec( + Dict(1 => collect(1:length(points))), + 5*(length(points)) # large buffer space where impact on resources mitigated via sparsevec + ) +end - # L2 Nodes - """ - The raw empirical samples on the manifold. Used for KDE and particle representations. - """ - points::Vector{P} = P[] # previously `val` - """ - The second-order bandwidths for the non-parametric points, supports variable bandwidth kernels. - """ - bandwidths::Vector{Matrix{Float64}} = Matrix{Float64}[] #previously `bw` --- +# @kwdef struct HomotopyDensityDFG{T <: StateType, P} +# statekind::T = T()# NOTE duplication for serialization and self description. +# """A hint for downstream solvers on how to interpret this data (The 'How')""" +# topologykind::AbstractHomotopyTopology = LeavesOnlyTopology() - # --- Topology (The Hierarchy) --- - """ - L1 Internal Topology: mean_parents[i] = j means means[i] is a child of means[j]. A value of 0 indicates a Root node. - """ - mean_parents::Vector{Int} = Int[] - """ - L2-to-L1 Bridge: point_parents[i] = j means points[i] is governed by means[j]. Points are leaves. - """ - point_parents::Vector{Int} = Int[] -end +# # L1 Nodes +# """ +# [Order 0] The relative importance or probability of each node in L1. +# """ +# weights::Vector{Float64} = Float64[] +# """ +# [Order 1] The location/center of each node, stored directly on the manifold. +# """ +# means::Vector{P} = P[] # previously `val[1]` for Gaussian +# """ +# [Order 2] The spread/curvature of each node (e.g., Covariance or Precision matrix). +# """ +# shapes::Vector{Matrix{Float64}} = Matrix{Float64}[] # previously `covar` existed but was stored in `bw` (hacky) -JSON.omit_empty(::Type{<:StoredHomotopyBelief}) = true +# # L2 Nodes +# """ +# The raw empirical samples on the manifold. Used for KDE and particle representations. +# """ +# points::Vector{P} = P[] # previously `val` +# """ +# The second-order bandwidths for the non-parametric points, supports variable bandwidth kernels. +# """ +# bandwidths::Vector{Matrix{Float64}} = Matrix{Float64}[] #previously `bw` --- -function StoredHomotopyBelief(T::AbstractStateType) - return StoredHomotopyBelief{typeof(T), getPointType(T)}(; statekind = T) -end +# # --- Topology (The Hierarchy) --- +# """ +# L1 Internal Topology: mean_parents[i] = j means means[i] is a child of means[j]. A value of 0 indicates a Root node. +# """ +# mean_parents::Vector{Int} = Int[] +# """ +# L2-to-L1 Bridge: point_parents[i] = j means points[i] is governed by means[j]. Points are leaves. +# """ +# point_parents::Vector{Int} = Int[] +# end -function StoredHomotopyBelief(::LeavesOnlyTopology, T::AbstractStateType; kwargs...) - return StoredHomotopyBelief{typeof(T), getPointType(T)}(; - statekind = T, - topologykind = LeavesOnlyTopology(), - bandwidths = [zeros(getDimension(T), getDimension(T))], - kwargs..., - ) -end +JSON.omit_empty(::Type{<:HomotopyDensityDFG}) = true -function StoredHomotopyBelief(::RootsOnlyTopology, T::AbstractStateType; kwargs...) - return StoredHomotopyBelief{typeof(T), getPointType(T)}(; - statekind = T, - topologykind = RootsOnlyTopology(), - kwargs..., - ) +function HomotopyDensityDFG(T::AbstractStateType) + return HomotopyDensityDFG{typeof(T), getPointType(T)}(; statekind = T) end +# function HomotopyDensityDFG(::LeavesOnlyTopology, T::AbstractStateType; kwargs...) +# return HomotopyDensityDFG{typeof(T), getPointType(T)}(; +# statekind = T, +# topologykind = LeavesOnlyTopology(), +# bandwidths = [zeros(getDimension(T), getDimension(T))], +# kwargs..., +# ) +# end + +# function HomotopyDensityDFG(::RootsOnlyTopology, T::AbstractStateType; kwargs...) +# return HomotopyDensityDFG{typeof(T), getPointType(T)}(; +# statekind = T, +# topologykind = RootsOnlyTopology(), +# kwargs..., +# ) +# end + function StructUtils.fielddefaults( ::StructUtils.StructStyle, - ::Type{StoredHomotopyBelief{T, P}}, + ::Type{HomotopyDensityDFG{T, P}}, ) where {T, P} return ( statekind = T(), - topologykind = LeavesOnlyTopology(), means = P[], shapes = Matrix{Float64}[], weights = Float64[], @@ -149,7 +276,7 @@ end function resolveStoredBeliefType(lazyobj) statekind = liftStateKind(lazyobj.statekind[]) - return StoredHomotopyBelief{typeof(statekind), getPointType(statekind)} + return HomotopyDensityDFG{typeof(statekind), getPointType(statekind)} end -@choosetype StoredHomotopyBelief resolveStoredBeliefType +@choosetype HomotopyDensityDFG resolveStoredBeliefType diff --git a/src/entities/State.jl b/src/entities/State.jl index a377f2a2..e8701eba 100644 --- a/src/entities/State.jl +++ b/src/entities/State.jl @@ -27,7 +27,7 @@ $(TYPEDFIELDS) """ Generic stored belief for this state. """ - belief::StoredHomotopyBelief{T, P} = StoredHomotopyBelief{T, P}()#; statekind = T()) + belief::HomotopyDensityDFG{T, P} = HomotopyDensityDFG{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.""" @@ -53,7 +53,7 @@ end # ============================================================================== # FUTURE VIEW WRAPPER (Internal DFG Placeholder) # ============================================================================== -# NOTE: The `StoredHomotopyBelief` is currently expressive and fast enough that +# NOTE: The `HomotopyDensityDFG` is currently expressive and fast enough that # DFG does not need to store a resolved view next to it in memory. # # If future profiling requires it, DFG will introduce a verbose View wrapper @@ -62,7 +62,7 @@ end # abstract type AbstractHomotopyBeliefView end # # struct HomotopyBeliefView{T, P, M} <: AbstractHomotopyBeliefView -# stored::StoredHomotopyBelief{T, P} +# stored::HomotopyDensityDFG{T, P} # math_engine::M # Read-only instantiated solver object (e.g., AMP.HomotopyDensity) # end @@ -91,7 +91,7 @@ function StructUtils.fielddefaults( ::Type{State{T, P}}, ) where {T, P} return ( - belief = StoredHomotopyBelief{T, P}(; statekind = T()), + belief = HomotopyDensityDFG{T, P}(; statekind = T()), separator = Symbol[], initialized = false, observability = Float64[], diff --git a/src/entities/equality.jl b/src/entities/equality.jl index 72f38f31..d85d1ddb 100644 --- a/src/entities/equality.jl +++ b/src/entities/equality.jl @@ -20,7 +20,7 @@ implement compare if needed. const GeneratedCompareUnion = Union{ Agent, Graphroot, - StoredHomotopyBelief, + HomotopyDensityDFG, State, Blobentry, Bloblet, diff --git a/test/testSerializingVariables.jl b/test/testSerializingVariables.jl index f4de87b5..f47ee24d 100644 --- a/test/testSerializingVariables.jl +++ b/test/testSerializingVariables.jl @@ -46,27 +46,27 @@ function make_test_variable() end @testset "Serializing Variables" begin - @testset "StoredHomotopyBelief round-trip" begin - bel = DFG.StoredHomotopyBelief(Pose{3}()) + @testset "HomotopyDensityDFG round-trip" begin + bel = DFG.HomotopyDensityDFG(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.StoredHomotopyBelief; style = DFG.DFGJSONStyle()) + parsed = JSON.parse(jstr, DFG.HomotopyDensityDFG; style = DFG.DFGJSONStyle()) @test bel == parsed end @testset "RootsOnlyTopology round-trip" begin dim = DFG.getDimension(Pose{3}()) - bel = DFG.StoredHomotopyBelief( + bel = DFG.HomotopyDensityDFG( DFG.RootsOnlyTopology(), Pose{3}(); means = [DFG.getPointIdentity(Pose{3}())], shapes = [diagm(ones(dim))], ) jstr = JSON.json(bel; pretty = true, style = DFG.DFGJSONStyle()) - parsed = JSON.parse(jstr, DFG.StoredHomotopyBelief; style = DFG.DFGJSONStyle()) + parsed = JSON.parse(jstr, DFG.HomotopyDensityDFG; style = DFG.DFGJSONStyle()) @test bel == parsed end From b0e7365fc156cf843262db66da7535c7151c48f5 Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 6 May 2026 03:10:58 -0700 Subject: [PATCH 3/6] bump docs --- src/entities/HomotopyDensity.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index cafd05a6..ff0ca806 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -142,7 +142,7 @@ getManifold(repr::HomotopyRepr) = getManifold(repr.statekind) # @choosetype AbstractHomotopyTopology resolvePackedType """ - HomotopyDensityDFG{T <: StateType, P} + HomotopyDensityDFG{H <: HomotopyRepr, P} Hybrid belief representation with natural transition between (non)parametric representations. From ed368f5fc541c7a0e2cbe95fee993a5831c94bcb Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 6 May 2026 18:54:40 -0700 Subject: [PATCH 4/6] checkpoint, refac name improvements --- src/DistributedFactorGraphs.jl | 4 + src/Serialization/StateSerialization.jl | 58 ++++++++ src/entities/HomotopyDensity.jl | 179 +++++++++++------------- src/entities/State.jl | 6 - 4 files changed, 144 insertions(+), 103 deletions(-) diff --git a/src/DistributedFactorGraphs.jl b/src/DistributedFactorGraphs.jl index 4e1e92b3..62f89bb6 100644 --- a/src/DistributedFactorGraphs.jl +++ b/src/DistributedFactorGraphs.jl @@ -106,6 +106,10 @@ export AbstractRelativeObservation, RelativeObservation export AbstractFactorCache, FactorCache export AbstractStateType, StateType +# Related to HomotopyDensity +export AbstractPartialTraits, AbstractHomotopyTopology, MajorMaxDepth +export getStateType, getManifold, getReprType, getTopology, getPartial + # ----------------------------------------------------------------------------- # Variable CRUD # ------------------------------------------------------------------------------ diff --git a/src/Serialization/StateSerialization.jl b/src/Serialization/StateSerialization.jl index 1cd26164..629ccded 100644 --- a/src/Serialization/StateSerialization.jl +++ b/src/Serialization/StateSerialization.jl @@ -1,4 +1,62 @@ + + +function lowerHomotopyReprKind( + varT::HomotopyRepr{R,K,T,L} +) where { + R <: AbstractHomotopyTopology, + K <: AbstractDensityBasis, + T <: AbstractStateType, + L <: AbstractPartialLegacyCompat, # FIXME use <:AbstractPartialTraits +} + typemeta = TypeMetadata(typeof(varT)) + # if N == Any + # return typemeta + # # return string(parentmodule(T), ".", nameof(T)) + # elseif N isa Integer + # return TypeMetadata( + # typemeta.pkg, + # Symbol(typemeta.name, "{", N, "}"), + # typemeta.version, + # ) + # # return string(parentmodule(T), ".", nameof(T), "{", join(N, ","), "}") + # else + # throw( + # SerializationError( + # "Serializing Variable State type only supports an integer parameter, got '$(N)'.", + # ), + # ) + # end +end + +#NOTE Cannot resolve with `resolveType` because of the N parameter +# tried resolveType(JSON.Object(:type=>obj)) +function liftHomotopyReprKind(type::DFG.JSON.Object) + pkg = Base.require(Main, Symbol(type.pkg)) + if !isdefined(Main, Symbol(type.pkg)) + throw(SerializationError("Module $(pkg) is available, but not loaded in `Main`.")) + end + m = match(r"{(\d+)}", type.name) + if !isnothing(m) #parameters in type + param = parse(Int, m[1]) + typeString = type.name[1:(m.offset - 1)] + return getfield(pkg, Symbol(typeString)){param}() + else + typeString = type.name + return getfield(pkg, Symbol(typeString))() + end +end + +# StructUtils.structlike(::Type{<:HomotopyDensityDFG}) = false +# StructUtils.lower(T::HomotopyDensityDFG) = lowerStateKind(T) +# StructUtils.lift(::Type{HomotopyDensityDFG}, s) = liftStateKind(s) + + +## ==================================================================================================== +## +## ==================================================================================================== + + function lowerStateKind(varT::AbstractStateType{N}) where {N} typemeta = TypeMetadata(typeof(varT)) if N == Any diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index ff0ca806..e2c37315 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -1,29 +1,30 @@ -# ============================================================================== -# HomotopyDensityDFG -# ============================================================================== +##============================================================================== +## Abstract Types +##============================================================================== +abstract type AbstractStateType{N} end +const StateType = AbstractStateType +""" +AbstractHomotopyTopology +""" +abstract type AbstractHomotopyTopology end # FIXME add parameter{N}? -export - AbstractPartialTraits, - AbstractHomotopyTruncation, - MajorMaxDepth +# Forward looking abstract for DFG v1.x development of partials using traits, but not yet implemented +abstract type AbstractPartialTraits end -export - getStateType, - getManifold, - getReprType, - getTruncation, - getPartial +abstract type AbstractDensityBasis end -# Forward looking abstract for DFG v1.x development of partials using traits, but not yet implemented -abstract type AbstractPartialTraits end +# DO NOT EXPORT AbstractPartialLegacyCompat +const AbstractPartialLegacyCompat = Union{<:DistributedFactorGraphs.AbstractPartialTraits, Nothing, Tuple, Vector{Int}} +# FIXME, drop Nothing, <:Tuple for type refactor compat period -abstract type AbstractHomotopyTruncation end -abstract type AbstractDensityBasis end +# ============================================================================== +# HomotopyDensityDFG +# ============================================================================== @@ -75,10 +76,10 @@ a missing core layout, please open an issue to discuss adding it to the foundational ecosystem. """ struct HomotopyRepr{ - truncation <: AbstractHomotopyTruncation, + topology <: AbstractHomotopyTopology, reprtype <: AbstractDensityBasis, - statetype <: Union{<:AbstractManifold, <:AbstractStateType}, - L <: AbstractPartialLegacyCompat, # Future use <:AbstractPartialTraits + statetype <: AbstractStateType, + L <: AbstractPartialLegacyCompat, # FIXME use <:AbstractPartialTraits } """ Used for either DistributedFactorGraphs statetype or Manifolds.jl manifold type, depending on context. @@ -96,16 +97,9 @@ struct HomotopyRepr{ end -struct MajorMaxDepth{ - N -} <: AbstractHomotopyTruncation end - -getMajorsLength(::Type{<:AbstractHomotopyTruncation}) = 1 -getMajorsLength(repr::HomotopyRepr) = getMajorsLength(getTruncation(repr)) - -# Binary tree with N major levels -getMajorsLength(::Type{MajorMaxDepth{N}}) where {N} = N^2 - 1 +getMajorsLength(::Type{<:AbstractHomotopyTopology}) = 1 +getMajorsLength(repr::HomotopyRepr) = getMajorsLength(getTopology(repr)) # trivial case -- should be in DFG instead FIXME getManifold(manif::AbstractManifold) = manif @@ -113,85 +107,88 @@ getManifold(manif::AbstractManifold) = manif getStateType(::HomotopyRepr{T,R,statetype}) where {T,R,statetype} = statetype getPartial(hr::HomotopyRepr) = hr.partial getReprType(::HomotopyRepr{T,reprtype}) where {T, reprtype} = reprtype -getTruncation(::HomotopyRepr{truncation}) where {truncation} = truncation +getTopology(::HomotopyRepr{truncation}) where {truncation} = truncation # supports both DFG and ManifoldsBase getManifold(repr::HomotopyRepr) = getManifold(repr.statekind) - - -# # --- 1. The Roots --- -# "L1 structural nodes only. No L2 samples. (Schema: `means`, `weights`, `shapes` populated. `points` empty.)" -# struct RootsOnlyTopology <: AbstractHomotopyTopology end - -# # --- 2. The Leaves --- -# "L2 raw samples only. No L1 structure. (Schema: `points`, `bandwidths` populated. `means` empty.)" -# struct LeavesOnlyTopology <: AbstractHomotopyTopology end - -# # --- 3. The Full Trees --- -# "Tree packed in arrays using 2i, 2i+1 math.(Schema: L1 and L2 populated. Parent arrays empty.)" -# struct ImplicitTreeTopology <: AbstractHomotopyTopology end - -# "Full tree using adjacency lists. (Schema: L1, L2, and Parent arrays fully populated.)" -# struct ExplicitTreeTopology <: AbstractHomotopyTopology end - -# function StructUtils.lower(::StructUtils.StructStyle, p::AbstractHomotopyTopology) -# return StructUtils.lower(Packed(p)) -# end -# @choosetype AbstractHomotopyTopology resolvePackedType +function StructUtils.lower(::StructUtils.StructStyle, p::AbstractHomotopyTopology) + return StructUtils.lower(Packed(p)) +end +@choosetype AbstractHomotopyTopology resolvePackedType """ HomotopyDensityDFG{H <: HomotopyRepr, P} Hybrid belief representation with natural transition between (non)parametric representations. -These are the internal raw beliefs and need to be viewed through a lens such as -provided by AMP for features like pdf evaluation. - -Notes: -- Refactoring and renaming of ManellicTree + ManifoldKernelDensity -- Replaces kernel density estimate, Gaussian mixture models, Principle component analysis, Homotopy methods, Model order reduction -- Allows partials as identified by list of coordinate dimensions e.g. `partial = [1;3]` - - When building a partial belief, use full points with necessary information in the specified partial coords. - -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. +**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!`. + +Notes: +- These are the internal raw beliefs and need to be viewed through a lens such as +provided by AMP for features like pdf evaluation. +- Allows partials as identified by list of coordinate dimensions via `.reprkind{...L}.partial` + - e.g. legacy `partial = [1;3] or (1,3)` + - When building a partial belief, use full points with necessary information in the specified partial coords. +- Replaces ManellicTree, ManifoldKernelDensity, KernelDensityEstimate, GaussianMixtureModel, PCA, Mixtures + - a.k.a. model order reduction given a topology selection """ @kwdef struct HomotopyDensityDFG{ H <: HomotopyRepr, # serde friendly when using DFG.statekind representation, but also supports Manifolds.jl direclty - # parameters below auto generate during JSON lift, only above needs to be serde friendly - P, # serde relies on DFG statekind mechanism, does not guarantee serde when directly using Manifolds wo DFG.statekind + P, # serde relies on reprkind.statekind <: StateKind mechanism } reprkind::H observability::Vector{Float64} = zeros(manifold_dimension(getManifold(reprkind))) points::Vector{P} weights::Vector{Float64} = Vector{Float64}(ones(length(points))) ./ length(points) - majors_coeff::Vector{Float64} = Vector{Float64}(undef, getMajorsLength(reprkind)) - majors_element::Vector{P} = Vector{P}(undef, getMajorsLength(reprkind)) - majors_detail::Vector{Matrix{Float64}} = Vector{SMatrix{Float64}}(undef, getMajorsLength(reprkind)) """ - Store minor details such as leaf bandwidth or eigenvectors associated with minor eigenvalues. + 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_coeffs::Vector{Float64} = Vector{Float64}(undef, getMajorsLength(reprkind)) + # FIXME, future proof with Vector{Matrix{Float64}} instead, using affine_matrix + principal_elements::Vector{P} = Vector{P}(undef, getMajorsLength(reprkind)) + principal_details::Vector{Matrix{Float64}} = Vector{Matrix{Float64}}(undef, getMajorsLength(reprkind)) + """ + 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}}. """ - minors_detail::SparseArrays.SparseVector{SMatrix{Float64}, Int} = SparseArrays.sparsevec( - Dict(1 => Matrix{Float64}(I, manifold_dimension(getManifold(reprkind)), manifold_dimension(getManifold(reprkind))),), - 1 + trailing_details::Dict{Int, Matrix{Float64}} = Dict( + 1 => Matrix{Float64}(I, manifold_dimension(getManifold(reprkind)), manifold_dimension(getManifold(reprkind))) ) - """ + """ 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]. """ - structure::SparseArrays.SparseVector{Vector{Int}, Int} = SparseArrays.sparsevec( - Dict(1 => collect(1:length(points))), - 5*(length(points)) # large buffer space where impact on resources mitigated via sparsevec + structure::Dict{Int,Vector{Int}} = Dict( + 1 => collect(1:length(points)) + ) +end + +# UPGRADE WISHLIST, REPLACE WITH SMatrix over Matrix, or SparseVector over Dict +function StructUtils.fielddefaults( + ::StructUtils.StructStyle, + ::Type{HomotopyDensityDFG{T, P}}, +) where {T, P} + return ( + reprkind = T(), + observability = Float64[], + points = P[], + weights = Float64[], + principal_coeffs = Float64[], + principal_elements = P[], # FIXME convert to Vector{Matrix{Float64}} instead, using affine_matrix + principal_details = Matrix{Float64}[], # TODO, upgrade to SMatrix, needs dimension + trailing_details = Dict{Int,Matrix{Float64}}(), # TODO, upgrade to sparsevec + mean_parents = Int[], + structure = Dict{Int,Vector{Int}}(), # TODO, upgrade to sparsevec of Vector{Int} ) end @@ -237,9 +234,9 @@ end JSON.omit_empty(::Type{<:HomotopyDensityDFG}) = true -function HomotopyDensityDFG(T::AbstractStateType) - return HomotopyDensityDFG{typeof(T), getPointType(T)}(; statekind = T) -end +# function HomotopyDensityDFG(T::AbstractStateType) +# return HomotopyDensityDFG{typeof(T), getPointType(T)}(; statekind = T) +# end # function HomotopyDensityDFG(::LeavesOnlyTopology, T::AbstractStateType; kwargs...) # return HomotopyDensityDFG{typeof(T), getPointType(T)}(; @@ -258,25 +255,13 @@ end # ) # end -function StructUtils.fielddefaults( - ::StructUtils.StructStyle, - ::Type{HomotopyDensityDFG{T, P}}, -) where {T, P} - return ( - statekind = T(), - means = P[], - shapes = Matrix{Float64}[], - weights = Float64[], - points = P[], - bandwidths = Matrix{Float64}[], - mean_parents = Int[], - point_parents = Int[], - ) -end -function resolveStoredBeliefType(lazyobj) - statekind = liftStateKind(lazyobj.statekind[]) - return HomotopyDensityDFG{typeof(statekind), getPointType(statekind)} + + +function resolveHomotopyDensityDFGType(lazyobj) + reprkind = liftReprKind(lazyobj.reprkind[]) + # statekind = liftStateKind(lazyobj.statekind[]) + return HomotopyDensityDFG{typeof(reprkind), getPointType(reprkind.statekind)} end @choosetype HomotopyDensityDFG resolveStoredBeliefType diff --git a/src/entities/State.jl b/src/entities/State.jl index e8701eba..c678d896 100644 --- a/src/entities/State.jl +++ b/src/entities/State.jl @@ -1,9 +1,3 @@ -##============================================================================== -## Abstract Types -##============================================================================== - -abstract type AbstractStateType{N} end -const StateType = AbstractStateType ##============================================================================== ## State From 1bf223b33c2d1f2db14e5183775cd6d37323afec Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 6 May 2026 19:58:01 -0700 Subject: [PATCH 5/6] restore AMP tests, fix --- src/entities/HomotopyDensity.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index e2c37315..cd83838a 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -78,7 +78,7 @@ foundational ecosystem. struct HomotopyRepr{ topology <: AbstractHomotopyTopology, reprtype <: AbstractDensityBasis, - statetype <: AbstractStateType, + statetype <: Union{<:AbstractStateType, <:AbstractManifold}, # AbstractManifold used by AMP, but only StateType supports serde L <: AbstractPartialLegacyCompat, # FIXME use <:AbstractPartialTraits } """ From d059b86ee7098954b0541be396187b7d04f86595 Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 6 May 2026 20:06:31 -0700 Subject: [PATCH 6/6] minor cleanup, drop obsolete --- src/DistributedFactorGraphs.jl | 2 +- src/entities/HomotopyDensity.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DistributedFactorGraphs.jl b/src/DistributedFactorGraphs.jl index 62f89bb6..d4b5f006 100644 --- a/src/DistributedFactorGraphs.jl +++ b/src/DistributedFactorGraphs.jl @@ -107,7 +107,7 @@ export AbstractFactorCache, FactorCache export AbstractStateType, StateType # Related to HomotopyDensity -export AbstractPartialTraits, AbstractHomotopyTopology, MajorMaxDepth +export AbstractPartialTraits, AbstractHomotopyTopology export getStateType, getManifold, getReprType, getTopology, getPartial # ----------------------------------------------------------------------------- diff --git a/src/entities/HomotopyDensity.jl b/src/entities/HomotopyDensity.jl index cd83838a..877ac7cf 100644 --- a/src/entities/HomotopyDensity.jl +++ b/src/entities/HomotopyDensity.jl @@ -17,9 +17,9 @@ abstract type AbstractPartialTraits end abstract type AbstractDensityBasis end -# DO NOT EXPORT AbstractPartialLegacyCompat -const AbstractPartialLegacyCompat = Union{<:DistributedFactorGraphs.AbstractPartialTraits, Nothing, Tuple, Vector{Int}} +# DO NOT EXPORT AbstractPartialLegacyCompat -- THIS MUST BE DEPRECATED AFTER DFG v0.29 # FIXME, drop Nothing, <:Tuple for type refactor compat period +const AbstractPartialLegacyCompat = Union{<:DistributedFactorGraphs.AbstractPartialTraits, Nothing, Tuple, Vector{Int}} # ============================================================================== @@ -55,7 +55,7 @@ Comments on type parameters: - reprtype is the type of the density basis, e.g. ConcentratedGaussianKernel and is expected to evolve into continuous eigen vectors and wavelets. - truncation type relates to model order reduction technique embedded in the HomotopyDensity, - e.g. MajorMaxDepth is a simple binary tree truncation with N major levels. + e.g. BinaryTruncFixedDepth is a simple binary tree truncation with N major levels. **Role of the HomotopyRepr Trait:**