TensorKitchen Pipeline
This document explains how public APIs route into models, solvers, and result converters.
Public entry points
- CP Decomposition
cpd(A, r; ...) - Nonnegative CP Decomposition
nncpd(A, r; ...) - Block Term Decomposition
btd(A, blocks, ranks; ...) - Tucker Decomposition
tucker(A, ranks; method=...) - Join Decomposition
approx(...)
Default behavior (quick reference)
cpd(A, r):init = :alswarmsolver = :rgd
nncpd(A, r):init = :alswarmsolver = :rgd
btd(A, blocks, ranks):init = :alswarmwarm_steps = 200warm_init = BTDHOSVDMultistartInit(candidates=64, screening_steps=10, block_maxiter=12)warm_rel_error_gate = nothing(run manifold refinement by default; set e.g.5e-2to short-circuit on poor warm starts)solver = :rgd- final BTD-ALS polish enabled by default for non-ALS solvers
max_stagnation_restarts = 1(retry with stronger multistart when ALS fit-change stalls at high rel-error)
tucker(A, ranks):method = :sthosvd
approx(model::JoinModel):init = :randomsolver = :rgd
Core execution architecture
Most optimization APIs share this core pattern:
- Build a model (
JoinModel+ backend) - Call
_solve_model(...) - Convert to a public result struct
_solve_model lives in src/solvers/solve_dispatch.jl and is the common symbol-to-solver dispatch layer (:rgd, :rcg, :lbfgs, :als, :btd_tsd).
API flows
CPD (cpd, nncpd)
cpd(A, r; ...):
- Build
JoinModel(A, r; geometry=...)withCPDBackend - Normalize/validate options (
solver,geometry,gradient_mode, normalization policy) - Solve through
_solve_model(...) - Convert to
CPDResult
Notes:
:alsmeans CP-ALS.- Manifold solvers (
:rgd,:rgd_fixed,:rcg,:lbfgs) share dispatch with other pipelines. - For
solver != :als,init = :autoresolves to:alswarm, so CPD and NNCPD start from an ALS warm point before manifold refinement. - Generic
approx(...)does not use CPD's ALS warm-start path unless it auto-routes tocpd(...).
BTD (btd)
btd(A, blocks, ranks; ...):
- Build a uniform Tucker family via
TuckerJoin(...) - Wrap as
JoinModelwithBTDBackend - Choose effective initializer:
solver == :als: use requested init directly (default multistart)solver != :als: useBTDALSWarmStartInit(...)so first-order methods start from a good BTD-ALS warm point
- If the warm-start rel-error exceeds
warm_rel_error_gate, return the warm BTD-ALS result directly - Otherwise solve through
_solve_model(...) - If
solver != :als, optionally polish with BTD-ALS (btd_als_polish_maxiter) - Convert to
BTDResult
Polish step usefulness:
- Usually helpful for a small final
rel_errorreduction after RGD converges near a good basin. - Most useful for quality-focused runs (benchmarks, final fits).
- Can be skipped for speed-sensitive runs (
btd_als_polish_maxiter=0) when small extra gains are not worth runtime.
BTD-specific initialization options:
:hosvd: sequential block initialization on residual:hosvd_multistart: HOSVD subspace split candidates, optional screening ALS, keep lowest-cost candidate:alswarm: short BTD-ALS warm-start wrapper around base initializer
BTD-ALS stabilization behavior:
- Tracks per-iteration fit change (
|rel_t - rel_{t-1}|) - Detects stagnation when fit change is tiny but
rel_errorremains high - Can restart from fresh multistart pool (
max_stagnation_restarts) - Reports true final Riemannian gradient norm (
grad_norm)
Tucker (tucker)
tucker(A, ranks; method=...) does not use _solve_model. It dispatches directly to decomposition routines:
:sthosvd:hooi
Generic approx(...) routing
approx(manifolds, target; dispatch=:auto) routes by manifold family:
- uniform
Manifolds.Segre->cpd(...) - uniform
Manifolds.Tuckermatching target shape/rank ->btd(...) - mixed or non-uniform family -> generic
JoinModel(...)path ->ApproxResult
dispatch=:cpd, :btd, and :generic force behavior.
For the generic JoinModel path, approx(...) starts from init = :random by default and then runs the selected manifold solver. It does not run an ALS warm-start stage, because a general join component does not necessarily expose factor matrices or least-squares block updates.
Result types and post-processing
CPDResultBTDResultTuckerResultApproxResult
Common utilities:
reconstruct(result)rel_error(A, result)
File map
- API entry points:
src/api/approx.jl,src/api/cpd.jl,src/api/nncpd.jl,src/api/btd.jl,src/api/tucker.jl