Multiscale Factorization
Quick Start
In some applications, the input tensor $Y$ to be factorized is a discretization of continuous functions. For example,
\[Y[i,j,k] = f_i(x_j, y_k)\]
for continuous functions $f_i$ and $(i,j,k)\in[I]\times[J]\times[K]$. Instead of calling factorize
factorize(Y; kwargs..)we can use multiscale_factorize, and pass along information about which dimension come from continuously varying values.
multiscale_factorize(Y; continuous_dims=(2,3), kwargs...)For fine discretizations, this is often faster and less memory intensive.
Motivating example
Say we have an order $3$-tensor $Y$ with entries
\[Y[i, j, k] = x[i] y[j] z[k]\]
for $(i,j,k) \in [65]\times[129]\times[257]$ representing a discretization of the box $[-1, 1]\times [0, 10]\times [0,1]$.
We might construct this in Julia with the following code.
f(x, y, z) = x*y*z
x = reshape(range(-1, 1, length=65), 65, 1, 1)
y = reshape(range(0, 10, length=129), 1, 129, 1)
z = reshape(range(0, 1, length=257), 1, 1, 257)
Y = f.(x, y, z)It is true that Y is a CP-rank-$1$ tensor. So we could recover the factors x, y, and z with
decomposition, stats, kwargs = multiscale_factorize(Y;
model=CPDecomposition, rank=1, continuous_dims=(1,2,3))
x, y, z = factors(decomposition)The grid $(i,j,k) \in [65]\times[129]\times[257]$ we chose to discretize the function $f(x,y,z)=xyz$ was arbitrary and we could just as easily discretized $f$ on a smaller grid $(i,j,k)\in[10]^3$ or larger one $(i,j,k)\in[257]^3$.
In this setting, we can first decompose a coarse version of Y, for example only using every second grid-points in each dimension
Y_coarse = Y[begin:2:end, begin:2:end, begin:2:end]and compute a coarse decomposition
model = CPDecomposition
rank = 1
decomposition_coarse, _, _ = factorize(Y_coarse; model, rank)
x_coarse, y_coarse, z_coarse = factors(decomposition_coarse)We could then initialize the fine scale factorization using an interpolation of the coarse factors found.
init = interpolate.(factors(decomposition))
factorize(Y; model, rank, init)We can actually do this starting from the most coarse scale with only $3$ points, and gradually refine the decomposition over multiple scale. This is what multiscale_factorize does.
BlockTensorFactorization.Core.multiscale_factorize — Function
multiscale_factorize(Y; continuous_dims=1:ndims(Y), rank=1, model=Tucker1, kwargs...)Like factorize but uses progressively finer sub-grids of Y to speed up convergence. This is only effective when the dimensions given by dims come from discretizations of continuous data.
For example, if Y has 3 dimensions where Y[i, j, k] are samples from a continuous 2D function fi(xj, y_k) on a grid, use
multiscale_factorize(Y; continuous_dims=(2,3))
since second and third dimensions are continuous.
Related exported functions
BlockTensorFactorization.Core.coarsen — Function
coarsen(Y::AbstractArray, scale::Integer; dims=1:ndims(Y))Coarsens or downsamples Y by scale. Only keeps every scale entries along the dimensions specified.
Example
Y = randn(12, 12, 12)
coarsen(Y, 2) == Y[begin:2:end, begin:2:end, begin:2:end]
coarsen(Y, 4; dims=(1, 3)) == Y[begin:4:end, :, begin:4:end]
coarsen(Y, 3; dims=2) == Y[:, begin:3:end, :]BlockTensorFactorization.Core.interpolate — Function
interpolate(Y, scale; dims=1:ndims(Y), degree=0, kwargs...)Interpolates Y to a larger array with repeated values.
Keywords
scale. How much to scale up the size of Y. A dimension with size k will be scaled to scale*k - (scale - 1) = scale*(k-1) + 1
dims:1:ndims(Y). Which dimensions to interpolate.
degree:0. What degree of interpolation to use. 0 is constant interpolation, 1 is linear.
Like the opposite of coarsen.
Example
julia> Y = collect(reshape(1:6, 2, 3))
2×3 Matrix{Int64}:
1 3 5
2 4 6
julia> interpolate(Y, 2)
3×5 Matrix{Int64}:
1 1 3 3 5
1 1 3 3 5
2 2 4 4 6
julia> interpolate(Y, 3; dims=2)
2×7 Matrix{Int64}:
1 1 1 3 3 3 5
2 2 2 4 4 4 6
julia> interpolate(Y, 1) == Y
trueBlockTensorFactorization.Core.scale_constraint — Function
scale_constraint(constraint::AbstractConstraint, scale, n_continuous_dims)Returns a scaled version of the constraint based off the number of relevant continuous dimensions the constraint acts on.