Skip to content

Commit

Permalink
Updates for 1.0 (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
ararslan authored Oct 6, 2018
1 parent a89658e commit 63bafcf
Show file tree
Hide file tree
Showing 16 changed files with 97 additions and 101 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ language: julia
os:
- linux
julia:
- 0.6
- 0.7
- 1.0
- nightly
notifications:
email: false
Expand All @@ -12,4 +13,4 @@ notifications:
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
# - julia -e 'Pkg.clone(pwd()); Pkg.build("NMF"); Pkg.test("NMF"; coverage=true)'
after_success:
- julia -e 'cd(Pkg.dir("NMF")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())';
- julia -e 'using Pkg; Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())';
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ A Julia package for non-negative matrix factorization (NMF).

[![Build Status](https://travis-ci.org/JuliaStats/NMF.jl.svg?branch=master)](https://travis-ci.org/JuliaStats/NMF.jl)
[![Coverage Status](https://coveralls.io/repos/github/JuliaStats/NMF.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaStats/NMF.jl?branch=master)
[![NMF](http://pkg.julialang.org/badges/NMF_0.6.svg)](http://pkg.julialang.org/?pkg=NMF)

---------------------------

Expand Down
3 changes: 1 addition & 2 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
julia 0.6
Compat 0.34.0
julia 0.7
StatsBase
2 changes: 1 addition & 1 deletion examples/densenmf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function main(args)
run(a)
end
else
warn("Invalid command line arguments.")
@warn("Invalid command line arguments.")
print_help()
end
end
Expand Down
7 changes: 3 additions & 4 deletions src/NMF.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module NMF
using Compat
using StatsBase

import Compat: view
import Base: sum!
using Statistics
using Printf
using LinearAlgebra

export nnmf

Expand Down
68 changes: 35 additions & 33 deletions src/alspgrad.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,21 @@ struct ALSGradUpdH_State{T}

function ALSGradUpdH_State{T}(X, W, H) where T
k, n = size(H)
new{T}(Array{T,2}(k, n),
Array{T,2}(k, n),
Array{T,2}(k, n),
Array{T,2}(k, n),
Array{T,2}(k, k),
Array{T,2}(k, n),
Array{T,2}(k, n))
new{T}(Matrix{T}(undef, k, n),
Matrix{T}(undef, k, n),
Matrix{T}(undef, k, n),
Matrix{T}(undef, k, n),
Matrix{T}(undef, k, k),
Matrix{T}(undef, k, n),
Matrix{T}(undef, k, n))
end
end
ALSGradUpdH_State(X, W::VecOrMat{T}, H::VecOrMat{T}) where {T} = ALSGradUpdH_State{T}(X, W, H)

function set_w!(s::ALSGradUpdH_State, X, W)
At_mul_B!(s.WtW, W, W)
At_mul_B!(s.WtX, W, X)
Wt = transpose(W)
mul!(s.WtW, Wt, W)
mul!(s.WtX, Wt, X)
end

function alspgrad_updateh!(X,
Expand Down Expand Up @@ -120,7 +121,7 @@ function _alspgrad_updateh!(X, # size (p, n)
t += 1

# compute gradient
A_mul_B!(G, WtW, H)
mul!(G, WtW, H)
for i = 1:length(G)
G[i] -= WtX[i]
end
Expand Down Expand Up @@ -150,7 +151,7 @@ function _alspgrad_updateh!(X, # size (p, n)

# compute criterion
dv1 = BLAS.dot(G, D) # <G, D>
A_mul_B!(WtWD, WtW, D)
mul!(WtWD, WtW, D)
dv2 = BLAS.dot(WtWD, D) # <D, WtW * D>

# back-track
Expand All @@ -164,20 +165,20 @@ function _alspgrad_updateh!(X, # size (p, n)
if !suff_decr
α *= β
else
copy!(H, Hn)
copyto!(H, Hn)
break
end
else
if suff_decr
if α/β < αmax
copy!(Hp, Hn)
copyto!(Hp, Hn)
α /= β
else
copy!(H, Hn)
copyto!(H, Hn)
break
end
else
copy!(H, Hp)
copyto!(H, Hp)
break
end
end
Expand All @@ -186,7 +187,7 @@ function _alspgrad_updateh!(X, # size (p, n)

# print info
if verbose
A_mul_B!(WH, W, H)
mul!(WH, W, H)
preobjv = objv
objv = sqL2dist(X, WH)
@printf("%5d %12.5e %12.5e %12.5e %8.4f %12d\n",
Expand All @@ -210,20 +211,21 @@ struct ALSGradUpdW_State{T}

function ALSGradUpdW_State{T}(X, W, H) where T
p, k = size(W)
new{T}(Array{T,2}(p, k),
Array{T,2}(p, k),
Array{T,2}(p, k),
Array{T,2}(p, k),
Array{T,2}(k, k),
Array{T,2}(p, k),
Array{T,2}(p, k))
new{T}(Matrix{T}(undef, p, k),
Matrix{T}(undef, p, k),
Matrix{T}(undef, p, k),
Matrix{T}(undef, p, k),
Matrix{T}(undef, k, k),
Matrix{T}(undef, p, k),
Matrix{T}(undef, p, k))
end
end
ALSGradUpdW_State(X, W::VecOrMat{T}, H::VecOrMat{T}) where {T} = ALSGradUpdW_State{T}(X, W, H)

function set_h!(s::ALSGradUpdW_State, X, H)
A_mul_Bt!(s.HHt, H, H)
A_mul_Bt!(s.XHt, X, H)
Ht = transpose(H)
mul!(s.HHt, H, Ht)
mul!(s.XHt, X, Ht)
end


Expand Down Expand Up @@ -282,7 +284,7 @@ function _alspgrad_updatew!(X, # size (p, n)
t += 1

# compute gradient
A_mul_B!(G, W, HHt)
mul!(G, W, HHt)
for i = 1:length(G)
G[i] -= XHt[i]
end
Expand Down Expand Up @@ -312,7 +314,7 @@ function _alspgrad_updatew!(X, # size (p, n)

# compute criterion
dv1 = BLAS.dot(G, D) # <G, D>
A_mul_B!(DHHt, D, HHt)
mul!(DHHt, D, HHt)
dv2 = BLAS.dot(DHHt, D) # <D * HHt, D>

# back-track
Expand All @@ -326,20 +328,20 @@ function _alspgrad_updatew!(X, # size (p, n)
if !suff_decr
α *= β
else
copy!(W, Wn)
copyto!(W, Wn)
break
end
else
if suff_decr
if α/β < αmax
copy!(Wp, Wn)
copyto!(Wp, Wn)
α /= β
else
copy!(W, Wn)
copyto!(W, Wn)
break
end
else
copy!(W, Wp)
copyto!(W, Wp)
break
end
end
Expand All @@ -348,7 +350,7 @@ function _alspgrad_updatew!(X, # size (p, n)

# print info
if verbose
A_mul_B!(WH, W, H)
mul!(WH, W, H)
preobjv = objv
objv = sqL2dist(X, WH)
@printf("%5d %12.5e %12.5e %12.5e %8.4f %12d\n",
Expand Down Expand Up @@ -419,6 +421,6 @@ function update_wh!(upd::ALSPGradUpd, s::ALSPGradUpd_State, X, W, H)
upd.maxsubiter, 20, upd.tolg, convert(T, 0.2), convert(T, 0.01), false)

# update WH
A_mul_B!(s.WH, W, H)
mul!(s.WH, W, H)
end

8 changes: 4 additions & 4 deletions src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ function nmf_skeleton!(updater::NMFUpdater{T},

# init
state = prepare_state(updater, X, W, H)
preW = Array{T,2}(size(W)...)
preH = Array{T,2}(size(H)...)
preW = Matrix{T}(undef, size(W))
preH = Matrix{T}(undef, size(H))
if verbose
objv = evaluate_objv(updater, state, X, W, H)
@printf("%-5s %-13s %-13s %-13s\n", "Iter", "objv", "objv.change", "(W & H).change")
Expand All @@ -57,8 +57,8 @@ function nmf_skeleton!(updater::NMFUpdater{T},
t = 0
while !converged && t < maxiter
t += 1
copy!(preW, W)
copy!(preH, H)
copyto!(preW, W)
copyto!(preH, H)

# update H
update_wh!(updater, state, X, W, H)
Expand Down
8 changes: 4 additions & 4 deletions src/initialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function _nndsvd!(X, W, Ht, inith::Bool, variant::Int)
T = eltype(W)

# compute SVD
(U, s, V) = svd(X, thin=true)
(U, s, V) = svd(X, full=false)

# main loop
v0 = variant == 0 ? zero(T) :
Expand Down Expand Up @@ -76,14 +76,14 @@ function nndsvd(X, k::Integer; zeroh::Bool=false, variant::Symbol=:std)
variant == :ar ? 2 :
throw(ArgumentError("Invalid value for variant"))

W = Array{T,2}(p, k)
H = Array{T,2}(k, n)
W = Matrix{T}(undef, p, k)
H = Matrix{T}(undef, k, n)
if zeroh
Ht = reshape(view(H,:,:), (n, k))
_nndsvd!(X, W, Ht, false, ivar)
fill!(H, 0)
else
Ht = Array{T,2}(n, k)
Ht = Matrix{T}(undef, n, k)
_nndsvd!(X, W, Ht, true, ivar)
for j = 1:k
for i = 1:n
Expand Down
40 changes: 21 additions & 19 deletions src/multupd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ struct MultUpdMSE_State{T}
function MultUpdMSE_State{T}(X, W::Matrix{T}, H::Matrix{T}) where T
p, n, k = nmf_checksize(X, W, H)
new{T}(W * H,
Array{T,2}(k, n),
Array{T,2}(k, n),
Array{T,2}(p, k),
Array{T,2}(p, k))
Matrix{T}(undef, k, n),
Matrix{T}(undef, k, n),
Matrix{T}(undef, p, k),
Matrix{T}(undef, p, k))
end
end

Expand All @@ -74,22 +74,24 @@ function update_wh!(upd::MultUpdMSE{T}, s::MultUpdMSE_State{T}, X, W::Matrix{T},
WHHt = s.WHHt

# update H
At_mul_B!(WtX, W, X)
At_mul_B!(WtWH, W, WH)
Wt = transpose(W)
mul!(WtX, Wt, X)
mul!(WtWH, Wt, WH)

@inbounds for i = 1:length(H)
H[i] *= (WtX[i] / (WtWH[i] + lambda))
end
A_mul_B!(WH, W, H)
mul!(WH, W, H)

# update W
A_mul_Bt!(XHt, X, H)
A_mul_Bt!(WHHt, WH, H)
Ht = transpose(H)
mul!(XHt, X, Ht)
mul!(WHHt, WH, Ht)

@inbounds for i = 1:length(W)
W[i] *= (XHt[i] / (WHHt[i] + lambda))
end
A_mul_B!(WH, W, H)
mul!(WH, W, H)
end


Expand All @@ -110,11 +112,11 @@ struct MultUpdDiv_State{T}
function MultUpdDiv_State{T}(X, W::Matrix{T}, H::Matrix{T}) where T
p, n, k = nmf_checksize(X, W, H)
new{T}(W * H,
Array{T,2}(1, k),
Array{T,2}(k, 1),
Array{T,2}(p, n),
Array{T,2}(k, n),
Array{T,2}(p, k))
Matrix{T}(undef, 1, k),
Matrix{T}(undef, k, 1),
Matrix{T}(undef, p, n),
Matrix{T}(undef, k, n),
Matrix{T}(undef, p, k))
end
end

Expand Down Expand Up @@ -143,21 +145,21 @@ function update_wh!(upd::MultUpdDiv{T}, s::MultUpdDiv_State{T}, X, W::Matrix{T},
@inbounds for i = 1:length(X)
Q[i] = X[i] / (WH[i] + lambda)
end
At_mul_B!(WtQ, W, Q)
mul!(WtQ, transpose(W), Q)
sum!(fill!(sW, 0), W)
@inbounds for j = 1:n, i = 1:k
H[i,j] *= (WtQ[i,j] / sW[i])
end
A_mul_B!(WH, W, H)
mul!(WH, W, H)

# update W
@inbounds for i = 1:length(X)
Q[i] = X[i] / (WH[i] + lambda)
end
A_mul_Bt!(QHt, Q, H)
mul!(QHt, Q, transpose(H))
sum!(fill!(sH, 0), H)
@inbounds for j = 1:k, i = 1:p
W[i,j] *= (QHt[i,j] / sH[j])
end
A_mul_B!(WH, W, H)
mul!(WH, W, H)
end
Loading

0 comments on commit 63bafcf

Please sign in to comment.