Skip to content

Commit

Permalink
Setup formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
dahong67 committed Oct 10, 2023
1 parent 2c14b91 commit 75a1005
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 44 deletions.
7 changes: 7 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
always_for_in = true
remove_extra_newlines = true
always_use_return = true
format_docstrings = true
align_assignment = true
normalize_line_endings = "unix"
separate_kwargs_with_semicolon = true
34 changes: 17 additions & 17 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
using GCPDecompositions
using Documenter

DocMeta.setdocmeta!(GCPDecompositions, :DocTestSetup, :(using GCPDecompositions); recursive=true)
DocMeta.setdocmeta!(
GCPDecompositions,
:DocTestSetup,
:(using GCPDecompositions);
recursive = true,
)

makedocs(;
modules=[GCPDecompositions],
authors="David Hong <[email protected]> and contributors",
repo="https://github.com/dahong67/GCPDecompositions.jl/blob/{commit}{path}#{line}",
sitename="GCPDecompositions.jl",
format=Documenter.HTML(;
prettyurls=get(ENV, "CI", "false") == "true",
canonical="https://dahong67.github.io/GCPDecompositions.jl",
edit_link="master",
assets=String[],
modules = [GCPDecompositions],
authors = "David Hong <[email protected]> and contributors",
repo = "https://github.com/dahong67/GCPDecompositions.jl/blob/{commit}{path}#{line}",
sitename = "GCPDecompositions.jl",
format = Documenter.HTML(;
prettyurls = get(ENV, "CI", "false") == "true",
canonical = "https://dahong67.github.io/GCPDecompositions.jl",
edit_link = "master",
assets = String[],
),
pages=[
"Home" => "index.md",
],
pages = ["Home" => "index.md"],
)

deploydocs(;
repo="github.com/dahong67/GCPDecompositions.jl",
devbranch="master",
)
deploydocs(; repo = "github.com/dahong67/GCPDecompositions.jl", devbranch = "master")
20 changes: 14 additions & 6 deletions ext/LossFunctionsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ Compute an approximate rank-`r` CP decomposition of the tensor `X`
with respect to the loss function `loss` and return a `CPD` object.
# Inputs
+ `X` : multi-dimensional tensor/array to approximate/decompose
+ `r` : number of components for the CPD
+ `loss` : loss function from LossFunctions.jl
+ `lower` : lower bound for factor matrix entries, `default = -Inf`
- `X` : multi-dimensional tensor/array to approximate/decompose
- `r` : number of components for the CPD
- `loss` : loss function from LossFunctions.jl
- `lower` : lower bound for factor matrix entries, `default = -Inf`
"""
GCPDecompositions.gcp(X::Array, r, loss::LossFunctions.SupervisedLoss, lower=-Inf) =
GCPDecompositions._gcp(X, r, (x, m) -> loss(m, x), (x, m) -> LossFunctions.deriv(loss, m, x), lower, (;))
GCPDecompositions.gcp(X::Array, r, loss::LossFunctions.SupervisedLoss, lower = -Inf) =
GCPDecompositions._gcp(
X,
r,
(x, m) -> loss(m, x),
(x, m) -> LossFunctions.deriv(loss, m, x),
lower,
(;),
)

end
4 changes: 3 additions & 1 deletion src/GCPDecompositions.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"Generalized CP Decomposition module. Provides approximate CP tensor decomposition with respect to general losses."
"""
Generalized CP Decomposition module. Provides approximate CP tensor decomposition with respect to general losses.
"""
module GCPDecompositions

# Imports
Expand Down
37 changes: 25 additions & 12 deletions src/gcp-opt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ Compute an approximate rank-`r` CP decomposition of the tensor `X`
with respect to a general loss and return a `CPD` object.
# Inputs
+ `X` : multi-dimensional tensor/array to approximate/decompose
+ `r` : number of components for the CPD
+ `func` : loss function, `default = (x, m) -> (m - x)^2`
+ `grad` : loss function derivative, default uses `ForwardDiff.jl`
+ `lower` : lower bound for factor matrix entries, `default = -Inf`
- `X` : multi-dimensional tensor/array to approximate/decompose
- `r` : number of components for the CPD
- `func` : loss function, `default = (x, m) -> (m - x)^2`
- `grad` : loss function derivative, default uses `ForwardDiff.jl`
- `lower` : lower bound for factor matrix entries, `default = -Inf`
"""
gcp(X::Array, r, func=(x, m) -> (m - x)^2, grad=(x, m) -> ForwardDiff.derivative(m -> func(x, m), m), lower=-Inf) =
_gcp(X, r, func, grad, lower, (;))
gcp(
X::Array,
r,
func = (x, m) -> (m - x)^2,
grad = (x, m) -> ForwardDiff.derivative(m -> func(x, m), m),
lower = -Inf,
) = _gcp(X, r, func, grad, lower, (;))

function _gcp(X::Array{TX,N}, r, func, grad, lower, lbfgsopts) where {TX,N}
T = nonmissingtype(TX)
Expand Down Expand Up @@ -44,7 +50,7 @@ function _gcp(X::Array{TX,N}, r, func, grad, lower, lbfgsopts) where {TX,N}
end

# Run LBFGSB
(lower === -Inf) || (lbfgsopts = (; lb=fill(lower, length(u0)), lbfgsopts...))
(lower === -Inf) || (lbfgsopts = (; lb = fill(lower, length(u0)), lbfgsopts...))
u = lbfgsb(f, g!, u0; lbfgsopts...)[2]
U = map(range -> reshape(u[range], :, r), vec_ranges)
return CPD(ones(T, r), U)
Expand All @@ -55,9 +61,16 @@ function gcp_func(M::CPD{T,N}, X::Array{TX,N}, func) where {T,TX,N}
return sum(func(X[I], M[I]) for I in CartesianIndices(X) if !ismissing(X[I]))
end

function gcp_grad_U!(GU::NTuple{N,TGU}, M::CPD{T,N}, X::Array{TX,N}, grad) where {T,TX,N,TGU<:AbstractMatrix{T}}
Y = [ismissing(X[I]) ? zero(nonmissingtype(eltype(X))) : grad(X[I], M[I])
for I in CartesianIndices(X)]
function gcp_grad_U!(
GU::NTuple{N,TGU},
M::CPD{T,N},
X::Array{TX,N},
grad,
) where {T,TX,N,TGU<:AbstractMatrix{T}}
Y = [
ismissing(X[I]) ? zero(nonmissingtype(eltype(X))) : grad(X[I], M[I]) for
I in CartesianIndices(X)
]

# MTTKRPs (inefficient but simple)
return ntuple(Val(N)) do k
Expand All @@ -67,6 +80,6 @@ function gcp_grad_U!(GU::NTuple{N,TGU}, M::CPD{T,N}, X::Array{TX,N}, grad) where
Zk[:, j] = reduce(kron, [view(M.U[i], :, j) for i in reverse(setdiff(1:N, k))])
end
mul!(GU[k], Yk, Zk)
rmul!(GU[k], Diagonal(M.λ))
return rmul!(GU[k], Diagonal(M.λ))
end
end
29 changes: 21 additions & 8 deletions src/type-cpd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ struct CPD{T,N,Tλ<:AbstractVector{T},TU<:AbstractMatrix{T}}
require_one_based_indexing(λ, U...)
for k in Base.OneTo(N)
size(U[k], 2) == length(λ) || throw(
DimensionMismatch("U[$k] has dimensions $(size(U[k])) but λ has length $(length(λ))")
DimensionMismatch(
"U[$k] has dimensions $(size(U[k])) but λ has length $(length(λ))",
),
)
end
new{T,N,Tλ,TU}(λ, U)
return new{T,N,Tλ,TU}(λ, U)
end
end
CPD::Tλ, U::NTuple{N,TU}) where {T,N,Tλ<:AbstractVector{T},TU<:AbstractMatrix{T}} =
Expand Down Expand Up @@ -58,16 +60,27 @@ function show(io::IO, mime::MIME{Symbol("text/plain")}, M::CPD{T,N}) where {T,N}
end

function summary(io::IO, M::CPD)
dimstring = ndims(M) == 0 ? "0-dimensional" :
ndims(M) == 1 ? "$(size(M,1))-element" : join(map(string, size(M)), '×')
dimstring =
ndims(M) == 0 ? "0-dimensional" :
ndims(M) == 1 ? "$(size(M,1))-element" : join(map(string, size(M)), '×')
ncomps = ncomponents(M)
print(io, dimstring, " ", typeof(M),
" with ", ncomps, ncomps == 1 ? " component" : " components")
return print(
io,
dimstring,
" ",
typeof(M),
" with ",
ncomps,
ncomps == 1 ? " component" : " components",
)
end

function getindex(M::CPD{T,N}, I::Vararg{Int,N}) where {T,N}
@boundscheck Base.checkbounds_indices(Bool, axes(M), I) || Base.throw_boundserror(M, I)
return sum(M.λ[j] * prod(M.U[k][I[k], j] for k in Base.OneTo(ndims(M)))
for j in Base.OneTo(ncomponents(M)); init=zero(eltype(T)))
return sum(
M.λ[j] * prod(M.U[k][I[k], j] for k in Base.OneTo(ndims(M))) for
j in Base.OneTo(ncomponents(M));
init = zero(eltype(T)),
)
end
getindex(M::CPD{T,N}, I::CartesianIndex{N}) where {T,N} = getindex(M, Tuple(I)...)

0 comments on commit 75a1005

Please sign in to comment.