Join Decomposition
A Join Decomposition of a vector $x\in\mathbb R^N$ is a decomposition of the form $x = x_1+\cdots+x_r$, where $x_i\in M_i$ and $M_i\subset \mathbb R^N$ is a given embedded manifold.
For instance, we can approximate a point $p = (1.2, 0.4)\in\mathbb R^2$ by $x=x_1+x_2$, where $x_1,x_2\in S^1$ are points on the circle:
julia> using Manifolds
julia> p = [1.2, 0.4]
julia> S = Sphere(1)
julia> join_res = approx((S, S), p)
ApproxResult{Float64}
Components: 2
Rel. error: 0.0007114699550529457We access the decomposition as follows.
components(join_res)
reconstruct(join_res)<br>
Generic Join Approximation
approx(...) is the main frontend for join decomposition. It works in two stages:
- build an initial point
- refine it with the selected solver
Supported Forms
approx(model; kwargs...)Solve an already constructedJoinModel.approx(manifolds, target; kwargs...)Build a join from a tuple/vector of component manifolds.approx(M::ProductManifold, target; kwargs...)Use the product-manifold factors as join components.approx(base, r, target; kwargs...)Repeat a single base manifoldrtimes to build a join.approx(base, target; kwargs...)Build a single-component join.
Examples:
julia> target = [1.2, 0.4, -0.3]
julia> model = JoinModel(Manifolds.Sphere(2), target)
julia> approx(model; maxiter = 50, verbose = false)
ApproxResult{Float64}
Components: 1
Rel. error: 0.23076923076923075julia> target = randn(2, 3)
julia> approx((Manifolds.Segre((2, 3)), Manifolds.Segre((2, 3))), target; verbose = false)
CPDResult{Float64}julia> target = [1.2, 0.4, -0.3]
julia> approx(Manifolds.Sphere(2), 2, target; verbose = false)
ApproxResult{Float64}Routing
With dispatch = :auto:
- uniform
Manifolds.Segrecomponents route tocpd(...) - uniform
Manifolds.Tuckercomponents route tobtd(...) - otherwise the generic
JoinModel(...)path is used andApproxResultis returned
You can also force the route explicitly:
dispatch = :genericdispatch = :cpddispatch = :btd
Forced routing is validated:
dispatch = :cpdrequires all components to beManifolds.Segrewith identicalfactor_dimsdispatch = :btdrequires all components to beManifolds.Tuckerwith identicalfactor_dimsand compatible multilinear rank
Generic Join Options
For the generic join path:
init = :randomDefault initializer. Built-in initializer support depends on the component manifolds.solver = :rgdSupported generic-join solver options are::rgd:rgd_fixed:rcg:lbfgs
Other common options:
p0 = nothingmaxiter = 500stepsize = 1.0tol = 1e-6gradient_mode = :riemannianverbose = truevector_transport_method = nothing
Built-in init support by component family:
Sphere::random,:deterministic,:targetSegre::random,:deterministicTucker::random,:tucker,:tucker_diag,:sthosvd- other manifolds:
:random
Notes
- Generic joins require every component manifold to embed into the same flattened ambient length as
target. solver = :alsis not available for a truly genericJoinModel. ALS may still be available whenapprox(...)auto-routes tocpd(...)orbtd(...).
Join Decomposition Docs
TensorKitchen.approx — Function
Generic Join Approximation
approx(...) is the main frontend for join decomposition, which works in two stages:
- build an initial point
- refine it with the selected solver
Supported Forms
approx(model; kwargs...): It is for an already constructed join model (JoinModel(...)) and routes to the generic join solver. Model can be aJoinModelof a tuple of manifolds, aProductManifold, or a single manifold.- model means an already constructed JoinModel.
- It fully fixes the decomposition structure and target.
approx(model; ...)just solves that model.
JoinModeland then useapproxto refine it.
target = [1.2, 0.4, -0.3]
model = JoinModel(Manifolds.Sphere(2), target)
approx(model; maxiter = 100, verbose = false)
# returns an ApproxResultapprox(manifolds, target; kwargs...): Builds a generic join model from a tuple of existing manifolds and routes to according to dispatch. Example:
target = randn(2, 3)
approx((Manifolds.Segre((2, 3)), Manifolds.Segre((2, 3))), target; verbose = false)
# This builds a join with 2 copies of Manifolds.Segre((2, 3))".approx(M::ProductManifold, target; kwargs...): Uses the factors of a product manifold and route to CPD, BTD, or the generic join solver according todispatch.- M::ProductManifold means that you already have a product manifold whose factors are the join components.
- approx(M, target; ...) uses those factors directly.
- It is more explicit than
base, because the components are already listed.
# Example 1
target = randn(2, 3)
M = ProductManifold(Manifolds.Segre((2, 3)), Manifolds.Segre((2, 3)))
approx(M, target; verbose = false)
# returns an CPDResult
# Example 2
target = randn(4, 3, 2)
M = ProductManifold(
Manifolds.Tucker((4, 3, 2), (2, 2, 2)),
Manifolds.Tucker((4, 3, 2), (2, 2, 2)),
)
approx(M, target; verbose = false)
# returns an BTDResultapprox(base, r, target; kwargs...): builds a rank-r Segre join and routes to CPD when base isa Manifolds.Segre and BTD when base isa Manifolds.Tucker unless generic
dispatch is explicitly requested. - base means one manifold template, not yet a full join. - approx(base, r, target; ...) repeats that same manifold r times to build a join. - approx(base, target; ...) builds a one-component join.
target = randn(2, 3)
approx(Manifolds.Segre((2, 3)), 2, target; verbose = false)
# returns an CPDResultapprox(base, target; kwargs...): Builds a single-component generic join and route to the generic join solver. Example:
target = [1.2, 0.4, -0.3]
approx(Manifolds.Sphere(2), target; verbose = false)
# returns an ApproxResult- By default,
approxauto-routes by manifold family:- uniform
Manifolds.Segresummands callscpd(...) - uniform
Manifolds.Tuckersummands callsbtd(...) - otherwise calls
JoinModel(...)and returns aApproxResult
- uniform
Return Types
- Depending on the manifold family,
approx(...)may return:ApproxResultfor the generic join pathCPDResultwhen auto-routed tocpd(...)BTDResultwhen auto-routed tobtd(...)
Main Options
For the generic join path:
init = :random: Sets the algorithm to find the initial point.solver = :rgd: Sets the algorithm for refinement. Possible options are:rgd(default): Riemannian gradient descentrgd_fixed: Riemannian gradient descent with fixed step sizercg: Riemannian conjugate gradientlbfgs: Limited-memory quasi-Newton
##Notes##
:alsis not a solver option forapprox(...). However, ifapprox(...)auto-routes tocpd(...)orbtd(...), then those specialized pipelines may support ALS separately.warm_stepsandwarm_initare not part of the genericapprox(...)path. Generic joins start from random initial point and then use manifold solvers for refinement.- For generic mixed joins, use manifold solvers such as
:rgd,:rcg, or:lbfgs.
approx(M::ProductManifold, target; dispatch=:auto, kwargs...)Use the factors of a product manifold as join components and route to CPD, BTD, or the generic join solver according to dispatch.
approx(base::Manifolds.Segre, r, target; dispatch=:auto, kwargs...)Build a rank-r Segre join and route to the CPD pipeline unless generic dispatch is explicitly requested.
approx(base::Manifolds.Tucker, r, target; dispatch=:auto, kwargs...)Build a r-block Tucker join and route to the BTD pipeline unless generic dispatch is explicitly requested.
approx(base::AbstractManifold, r, target; dispatch=:auto, kwargs...)Fallback rank-r join constructor for non-specialized manifolds. Forced CPD or BTD dispatch is rejected because the base manifold family is not known.
approx(base::AbstractManifold, target; dispatch=:auto, kwargs...)Single-component generic approximation fallback. Use this when no CPD/BTD family-specific routing is intended.
TensorKitchen.ApproxResult — Type
ApproxResult{T}Generic result of approx(manifolds, target) (generic join decomposition).
point: final point on the join manifoldcomponents: extracted component descriptionscost: the value of the optimization objective at the final returned point, that is typically the least-squares objective.rel_error: relative error of the decomposition which is the ratio of the cost to the target norm. is scale-normalized and easier to compare across problemsgrad_norm: norm of the final optimization gradient reported by the solver; for manifold solvers this is typically the Riemannian gradient normiterations: number of iterations usedconverged: whether the decomposition convergedsolver: solver used for the decompositionsolver_info: solver-specific diagnostics/metadata (NamedTuple)
TensorKitchen.reconstruct — Method
reconstruct(res::ApproxResult)Reconstruct the dense ambient object represented by a generic join approximation result by summing its component tensors.
TensorKitchen.join_product — Function
join_product(base, r)Decides how to expand base into r components:
- Manifolds.Segre → flattened (Euclidean(1), Sphere, ...) × r (one λ + spheres per rank-1).
- Manifolds.Tucker / ProductManifold → repeat each factor r times.
- Generic manifold → ProductManifold(base, base, ..., base).
TensorKitchen.SegreProduct — Function
SegreProduct(dims, r)- Product manifold
Manifolds.Segre(dims) × ... × Manifolds.Segre(dims)(r factors). - Each component point uses the
Manifolds.Segrelayout[[λ], x₁, …, x_d]. SegreProductis used to build a join model for CPD.