Nx SVD/SVF factorization primitives for model surgery and artifact export.
This package is intentionally narrow. It owns numerical factorization, reconstruction, tensor traversal, manifest helpers, and router-vector splitting. It avoids provider, tracing, orchestration, and application runtime dependencies. Callers that use product-specific artifact names should pass those names explicitly at the API boundary.
CrucibleFactorization.SVD.thin/2andthin!/2run reduced SVD with timing, backend, rank, and sync metadata.CrucibleFactorization.SVD.reconstruct/3rebuilds tensors from SVD components and scale offsets.CrucibleFactorization.SVD.decompose_tensors/2,reconstruct_tensors/3, andadapt_tensors/3operate on selected tensor entries from nested parameter trees.CrucibleFactorization.SVFprovides low-rank singular-vector-field helpers forbase_tensor + low_rank_deltaworkflows.CrucibleFactorization.StageCheckandParityReportprovide math-only tensor comparison summaries.CrucibleFactorization.SVD.load_router_vector!/2andsplit_router_vector/4load and split a flat vector into scale offsets and dense head weights. The default tensor name is the generic"router_vector".
If available in Hex, the package can be installed
by adding crucible_factorization to your list of dependencies in mix.exs:
def deps do
[
{:crucible_factorization, "~> 0.1.0"}
]
endDocumentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/crucible_factorization.
alias CrucibleFactorization.SVD
matrix = Nx.tensor([[2.0, 4.0], [1.0, 2.0]], type: :f32)
{:ok, result} = SVD.thin(matrix, rank: 1, compute_type: :f32, force_sync?: true)
reconstructed = SVD.reconstruct(result, Nx.broadcast(0.0, {result.rank}))result includes :u, :s, :v, :rank, source type, backend label,
decompose timing, and optional force-sync timing.
alias CrucibleFactorization.SVF
base = Nx.tensor([[1.0, 1.0], [1.0, 1.0]], type: :f32)
delta = Nx.tensor([[2.0, 4.0], [1.0, 2.0]], type: :f32)
{:ok, svf} = SVF.decompose(delta, rank: 1)
{:ok, adapted} = SVF.reconstruct(base, svf)entries =
params
|> SVD.decomposable_tensor_entries(path_filter: SVD.layer_index_filter([26]))
manifest = SVD.tensor_manifest(entries)
count = SVD.singular_value_count(entries)The helpers accept generic nested maps, lists, tuples, and structs with a
:data field. They do not require a framework runtime struct.
vector = SVD.load_router_vector!("router_vector.safetensors")
split =
SVD.split_router_vector(
vector,
scale_count,
hidden_size,
output_count
)
split.scale_offsets
split.head_weightsFor product-specific safetensors keys, pass the key explicitly:
vector = SVD.load_router_vector!("artifact.safetensors", "product_router_vector")thin/2 accepts:
:rankfor reduced rank selection.:compute_type, either:sourceor:f32.:backendforNx.backend_transfer/2.:force_sync?and:sync_funfor timing asynchronous backends.
mix ciCUDA is opt-in:
XLA_TARGET=cuda12 mix test --only cudamix ci runs dependency fetch, format check, warning-as-error compile, tests,
Credo strict, Dialyzer, and docs generation.