Skip to content

Commit

Permalink
Drop normalizecomps since CPDComp is immutable
Browse files Browse the repository at this point in the history
  • Loading branch information
dahong67 committed Aug 29, 2024
1 parent 034d6c1 commit 34a3f26
Showing 1 changed file with 0 additions and 104 deletions.
104 changes: 0 additions & 104 deletions src/cpdcomp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,107 +60,3 @@ Array(A::CPDComp) = Array(AbstractArray(A))
norm(M::CPDComp, p::Real = 2) =
p == 2 ? norm2(M) : norm((M[I] for I in CartesianIndices(size(M))), p)
norm2(M::CPDComp{T,N}) where {T,N} = sqrt(abs2(M.λ) * prod(sum(abs2, M.u[i]) for i in 1:N))

"""
normalizecomps(M::CPDComp, p::Real = 2)
Normalize `M` so that all its factor vectors have `p`-norm equal to unity,
i.e., `norm(M.u[k], p) == 1` for all `k ∈ 1:ndims(M)`. The excess weight is absorbed into `M.λ`.
Norms equal to zero are ignored (i.e., treated as though they were equal to one).
The following keyword arguments can be used to modify this behavior:
- `dims` specifies what to normalize (default: `[:λ; 1:ndims(M)]`)
- `distribute_to` specifies where to distribute the excess weight (default: `:λ`)
Valid options for these arguments are the symbol `:λ`, an integer in `1:ndims(M)`,
or a collection of these.
See also: `normalizecomps!`, `norm`.
"""
normalizecomps(M::CPDComp, p::Real = 2; dims = [; 1:ndims(M)], distribute_to = ) =
normalizecomps!(deepcopy(M), p; dims, distribute_to)

"""
normalizecomps!(M::CPDComp, p::Real = 2)
Normalize `M` in-place so that all its factor vectors have `p`-norm equal to unity,
i.e., `norm(M.u[k], p) == 1` for all `k ∈ 1:ndims(M)`. The excess weight is absorbed into `M.λ`.
Norms equal to zero are ignored (i.e., treated as though they were equal to one).
The following keyword arguments can be used to modify this behavior:
- `dims` specifies what to normalize (default: `[:λ; 1:ndims(M)]`)
- `distribute_to` specifies where to distribute the excess weight (default: `:λ`)
Valid options for these arguments are the symbol `:λ`, an integer in `1:ndims(M)`,
or a collection of these.
See also: `normalizecomps`, `norm`.
"""
function normalizecomps!(
M::CPDComp{T,N},
p::Real = 2;
dims = [; 1:N],
distribute_to = ,
) where {T,N}
# Check dims and put into standard (mask) form
dims_iterable = dims isa Symbol ? (dims,) : dims
all(d -> d === || (d isa Integer && d in 1:N), dims_iterable) || throw(
ArgumentError(
"`dims` must be `:λ`, an integer specifying a mode, or a collection, got $dims",
),
)
dims_λ = in dims_iterable
dims_u = ntuple(in(dims_iterable), N)

# Check distribute_to and put into standard (mask) form
dist_iterable = distribute_to isa Symbol ? (distribute_to,) : distribute_to
all(d -> d === || (d isa Integer && d in 1:N), dist_iterable) || throw(
ArgumentError(
"`distribute_to` must be `:λ`, an integer specifying a mode, or a collection, got $distribute_to",
),
)
dist_λ = in dist_iterable
dist_u = ntuple(in(dist_iterable), N)

# Call inner function
return _normalizecomps!(M, p, dims_λ, dims_u, dist_λ, dist_u)
end

function _normalizecomps!(
M::CPDComp{T,N},
p::Real,
dims_λ::Bool,
dims_u::NTuple{N,Bool},
dist_λ::Bool,
dist_u::NTuple{N,Bool},
) where {T,N}
# Utility function to handle zero weights and norms
zero_to_one(x) = iszero(x) ? oneunit(x) : x

# Normalize components and collect excess weight
excess = oneunit(T)
if dims_λ
_norm = zero_to_one(abs(M.λ))
M.λ /= _norm
excess *= _norm
end
for k in Base.OneTo(N)
if dims_u[k]
_norm = zero_to_one(norm(M.u[k], p))
M.u[k] ./= _norm
excess *= _norm
end
end

# Distribute excess weight (uniformly across specified parts)
excess = excess^(1 / count((dist_λ, dist_u...)))
if dist_λ
M.λ *= excess
end
for k in Base.OneTo(N)
if dist_u[k]
M.u[k] .*= excess
end
end

# Return normalized CPDComp
return M
end

0 comments on commit 34a3f26

Please sign in to comment.