From 75a10050f5301fb3c1950d74f69b18078bab0c93 Mon Sep 17 00:00:00 2001 From: David Hong Date: Tue, 10 Oct 2023 10:56:51 -0400 Subject: [PATCH] Setup formatter --- .JuliaFormatter.toml | 7 +++++++ docs/make.jl | 34 +++++++++++++++++----------------- ext/LossFunctionsExt.jl | 20 ++++++++++++++------ src/GCPDecompositions.jl | 4 +++- src/gcp-opt.jl | 37 +++++++++++++++++++++++++------------ src/type-cpd.jl | 29 +++++++++++++++++++++-------- 6 files changed, 87 insertions(+), 44 deletions(-) create mode 100644 .JuliaFormatter.toml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..4e3e5a6 --- /dev/null +++ b/.JuliaFormatter.toml @@ -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 diff --git a/docs/make.jl b/docs/make.jl index df1cc81..fb0751f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -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 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 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") diff --git a/ext/LossFunctionsExt.jl b/ext/LossFunctionsExt.jl index 6adae88..667411f 100644 --- a/ext/LossFunctionsExt.jl +++ b/ext/LossFunctionsExt.jl @@ -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 diff --git a/src/GCPDecompositions.jl b/src/GCPDecompositions.jl index b4aad5a..e2220ba 100644 --- a/src/GCPDecompositions.jl +++ b/src/GCPDecompositions.jl @@ -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 diff --git a/src/gcp-opt.jl b/src/gcp-opt.jl index 22efbb1..1cc2620 100644 --- a/src/gcp-opt.jl +++ b/src/gcp-opt.jl @@ -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) @@ -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) @@ -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 @@ -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 diff --git a/src/type-cpd.jl b/src/type-cpd.jl index 78b0b3e..9425f09 100644 --- a/src/type-cpd.jl +++ b/src/type-cpd.jl @@ -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}} = @@ -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)...)