From 7a31691d8d043a40ed45a7d2072e5df2be1478df Mon Sep 17 00:00:00 2001 From: Viktor Petukhov Date: Thu, 17 May 2018 18:48:08 +0300 Subject: [PATCH 1/5] Remove FunctionalDataUtils dependency. Compatibility with julia 0.6. Minimum v0.5 --- REQUIRE | 5 +++-- src/QuickShiftClustering.jl | 11 +++++------ src/memtest.jl | 3 +-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/REQUIRE b/REQUIRE index 7b60616..8eff6b2 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,5 @@ -julia 0.4 -FunctionalDataUtils +julia 0.5 +Distances +FunctionalData NearestNeighbors ProgressMeter diff --git a/src/QuickShiftClustering.jl b/src/QuickShiftClustering.jl index 858371f..9bc65f8 100644 --- a/src/QuickShiftClustering.jl +++ b/src/QuickShiftClustering.jl @@ -7,11 +7,11 @@ isinstalled("PyPlot") && begin using PyPlot end -using NearestNeighbors, ProgressMeter, FunctionalDataUtils +using NearestNeighbors, ProgressMeter, Distances, FunctionalData export quickshift, quickshiftlabels, quickshiftplot -type QuickShift +mutable struct QuickShift rootind links sigma @@ -50,7 +50,7 @@ end quickshift(data, a...) = quickshift(convert(Array{Float32,2},data), a...) quickshift(data::Array{Float32,2}, sigma) = quickshift(data, convert(Float32,sigma)) -function quickshift(data::Array{Float32,2}, sigma::Float32 = convert(Float32,median(distance(randsample(data,1000)))/100)) +function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32,median(pairwise(Euclidean(), randsample(data,1000)))/100)) tree = KDTree(data) # @show sigma N = len(data) @@ -103,8 +103,7 @@ function cut_internal(ind, links, labels, maxlength, label, maxlabel) if x[1] > maxlength maxlabel += 1 end - maxlabel = max(label, cut_internal(x[2], links, labels, maxlength, - x[1] > maxlength ? maxlabel : label, maxlabel)) + maxlabel = max(label, cut_internal(x[2], links, labels, maxlength, x[1] > maxlength ? maxlabel : label, maxlabel)) end maxlabel end @@ -126,7 +125,7 @@ function quickshiftplot(a::QuickShift, data, labels) end end - scatter(data[1,:],data[2,:], c = asint(labels), edgecolor = "none") + scatter(data[1,:],data[2,:], c = Array{Int, 1}(labels), edgecolor = "none") end end diff --git a/src/memtest.jl b/src/memtest.jl index f17e13c..e177842 100644 --- a/src/memtest.jl +++ b/src/memtest.jl @@ -1,5 +1,4 @@ -using FunctionalData, QuickShiftClustering -data = @p map unstack(1:10) (x->10*randn(2,1).+randn(2,1000)) | flatten +data = vcat([10*randn(2,1).+randn(2,1000) for i in 1:10]...) @time a = quickshift(data) Profile.clear_malloc_data() @time a = quickshift(data) From 512e4ba90abac28e5edb0c8948b208d8572a3833 Mon Sep 17 00:00:00 2001 From: Viktor Petukhov Date: Wed, 24 Apr 2019 15:38:11 -0700 Subject: [PATCH 2/5] Removed FunctionalData dependency. Some refactoring. Julia 1.0. --- .travis.yml | 3 +-- REQUIRE | 3 +-- src/QuickShiftClustering.jl | 49 +++++++++++++++++++++---------------- test/REQUIRE | 1 - test/runtests.jl | 3 +-- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index 111cc8e..cb7b7fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,7 @@ os: - linux - osx julia: - - 0.5 - - 0.6 + - 1.0 - nightly notifications: email: diff --git a/REQUIRE b/REQUIRE index 8eff6b2..922872e 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,5 +1,4 @@ -julia 0.5 +julia 1.0 Distances -FunctionalData NearestNeighbors ProgressMeter diff --git a/src/QuickShiftClustering.jl b/src/QuickShiftClustering.jl index 9bc65f8..5039589 100644 --- a/src/QuickShiftClustering.jl +++ b/src/QuickShiftClustering.jl @@ -1,13 +1,12 @@ -__precompile__() - module QuickShiftClustering -isinstalled(a) = isa(Pkg.installed(a), VersionNumber) -isinstalled("PyPlot") && begin +using Pkg + +if "PyPlot" in keys(Pkg.installed()) using PyPlot end -using NearestNeighbors, ProgressMeter, Distances, FunctionalData +using NearestNeighbors, ProgressMeter, Distances export quickshift, quickshiftlabels, quickshiftplot @@ -22,7 +21,8 @@ function dist(a::Array{Float32,2}, i::Int, b::Array{Float32,2}, j::Int) for d = 1:size(a,1) sum += (a[d,i]-b[d,j])^2 end - sum + + return sum end function link(i, inds, G, data) @@ -37,7 +37,8 @@ function link(i, inds, G, data) end end end - minind, mindist + + return minind, mindist end function gauss(data, n, ind, factor1, factor2) @@ -45,7 +46,8 @@ function gauss(data, n, ind, factor1, factor2) for m = ind s += exp(-dist(data,n,data,m)*factor1) end - factor2 * s + + return factor2 * s end quickshift(data, a...) = quickshift(convert(Array{Float32,2},data), a...) @@ -53,13 +55,13 @@ quickshift(data::Array{Float32,2}, sigma) = quickshift(data, convert(Float32,sig function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32,median(pairwise(Euclidean(), randsample(data,1000)))/100)) tree = KDTree(data) # @show sigma - N = len(data) + N = size(data, 2) factor1 = 1f0 / (2*sigma^2) ::Float32 factor2 = 1/(2*pi*sigma^2*N) G = zeros(Float32, 1, N) nninds = [Array(Int,0) for n in 1:N] @showprogress 1 "Computing kernel distances ... " for n = 1:N - knnind = @p knn tree vec(at(data,n)) 100 true | fst + knnind = knn(tree, vec(data[:,n]), 100, true)[1] ind = length(knnind) > 10 ? knnind : 1:N nninds[n] = ind G[n] = gauss(data, n, ind, factor1, factor2) @@ -88,44 +90,49 @@ function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32,media push!(links[minind], (sqrt(mindist), i)) end end - QuickShift(rootind, links, sigma) + + return QuickShift(rootind, links, sigma) end function quickshiftlabels(a::QuickShift, maxlength = 10*a.sigma) labels = zeros(Int32,length(a.links)) - cut_internal(a.rootind, a.links, labels, maxlength, 1, 2) - labels + cut_internal!(labels, a.rootind, a.links, maxlength, 1, 2) + + return labels end -function cut_internal(ind, links, labels, maxlength, label, maxlabel) +function cut_internal!(labels, ind, links, maxlength, label, maxlabel) labels[ind] = label for x in links[ind] if x[1] > maxlength maxlabel += 1 end - maxlabel = max(label, cut_internal(x[2], links, labels, maxlength, x[1] > maxlength ? maxlabel : label, maxlabel)) + maxlabel = max(label, cut_internal!(labels, x[2], links, maxlength, x[1] > maxlength ? maxlabel : label, maxlabel)) end - maxlabel + + return maxlabel end -function quickshiftplot(a::QuickShift, data, labels) +function quickshiftplot(a::QuickShift, data::Array{T, 2} where T, labels::Array{Int, 1}) if !isdefined(:PyPlot) error("quickshiftplot needs PyPlot installed and loaded using 'using PyPlot'") end - if size(data,1) != 2 + + if size(data, 1) != 2 error("quickshiftplot only works on 2D data, i.e. size(data,1)==2") end - for i = 1:len(a.links) + for i = 1:length(a.links) from = data[:,i] for x = a.links[i] to = data[:,x[2]] p = hcat(from,to)' - plot(fst(p),snd(p),"b-") + plot(p[:,1],p[:,2],"b-") end end - scatter(data[1,:],data[2,:], c = Array{Int, 1}(labels), edgecolor = "none") + + scatter(data[1,:],data[2,:], c = labels, edgecolor = "none") end end diff --git a/test/REQUIRE b/test/REQUIRE index bc3e234..e69de29 100644 --- a/test/REQUIRE +++ b/test/REQUIRE @@ -1 +0,0 @@ -FactCheck diff --git a/test/runtests.jl b/test/runtests.jl index fb6bcf0..947b5cc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,7 @@ println("\n\n\nRunning tests ...") -using QuickShiftClustering, FactCheck +using QuickShiftClustering quickshift(rand(2,1000)) println(" done running tests!") - From b2b9ab485da458a5b5eafd9c524d1dc47224b6f7 Mon Sep 17 00:00:00 2001 From: Viktor Petukhov Date: Wed, 24 Apr 2019 15:56:24 -0700 Subject: [PATCH 3/5] Fixed missed functions --- src/QuickShiftClustering.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/QuickShiftClustering.jl b/src/QuickShiftClustering.jl index 5039589..15c1bb6 100644 --- a/src/QuickShiftClustering.jl +++ b/src/QuickShiftClustering.jl @@ -6,6 +6,7 @@ if "PyPlot" in keys(Pkg.installed()) using PyPlot end +using Statistics using NearestNeighbors, ProgressMeter, Distances export quickshift, quickshiftlabels, quickshiftplot @@ -52,7 +53,8 @@ end quickshift(data, a...) = quickshift(convert(Array{Float32,2},data), a...) quickshift(data::Array{Float32,2}, sigma) = quickshift(data, convert(Float32,sigma)) -function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32,median(pairwise(Euclidean(), randsample(data,1000)))/100)) + +function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32, median(pairwise(Euclidean(), data[:,rand(1:size(data, 2), 1000)] / 100)))) tree = KDTree(data) # @show sigma N = size(data, 2) From 5a95bb5ad615fe12b4c93fdf03400761c62412ff Mon Sep 17 00:00:00 2001 From: Viktor Petukhov Date: Wed, 24 Apr 2019 16:05:27 -0700 Subject: [PATCH 4/5] Fixed version incompatibilities --- src/QuickShiftClustering.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/QuickShiftClustering.jl b/src/QuickShiftClustering.jl index 15c1bb6..94d7ac6 100644 --- a/src/QuickShiftClustering.jl +++ b/src/QuickShiftClustering.jl @@ -54,29 +54,29 @@ end quickshift(data, a...) = quickshift(convert(Array{Float32,2},data), a...) quickshift(data::Array{Float32,2}, sigma) = quickshift(data, convert(Float32,sigma)) -function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32, median(pairwise(Euclidean(), data[:,rand(1:size(data, 2), 1000)] / 100)))) +function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32, median(pairwise(Euclidean(), data[:,rand(1:size(data, 2), 1000)] / 100, dims=2)))) tree = KDTree(data) # @show sigma N = size(data, 2) factor1 = 1f0 / (2*sigma^2) ::Float32 factor2 = 1/(2*pi*sigma^2*N) G = zeros(Float32, 1, N) - nninds = [Array(Int,0) for n in 1:N] + nninds = [Array{Int, 1}() for n in 1:N] @showprogress 1 "Computing kernel distances ... " for n = 1:N knnind = knn(tree, vec(data[:,n]), 100, true)[1] ind = length(knnind) > 10 ? knnind : 1:N nninds[n] = ind G[n] = gauss(data, n, ind, factor1, factor2) end - # println("median lenghts:",(@p map nninds length | flatten | median)) + links = [Any[] for i in 1:N] rootind = -1 inflength = typemax(eltype(G)) - Nrange = 1:N + minind = 0 mindist = inflength @showprogress 1 "Linking ... " for i in 1:N - for inds = [nninds[i]; Nrange] + for inds = [nninds[i]; 1:N] minind, mindist = link(i, inds, G, data) if minind != 0 break From 47964c0a540fb576f52d7689850ae550ec320eb8 Mon Sep 17 00:00:00 2001 From: Viktor Petukhov Date: Wed, 24 Apr 2019 16:29:06 -0700 Subject: [PATCH 5/5] Fixed PyPlot import and Int32 issue. --- src/QuickShiftClustering.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/QuickShiftClustering.jl b/src/QuickShiftClustering.jl index 94d7ac6..d67d52c 100644 --- a/src/QuickShiftClustering.jl +++ b/src/QuickShiftClustering.jl @@ -3,7 +3,7 @@ module QuickShiftClustering using Pkg if "PyPlot" in keys(Pkg.installed()) - using PyPlot + import PyPlot end using Statistics @@ -97,7 +97,7 @@ function quickshift(data::Array{Float32,2}, sigma::Float32=convert(Float32, medi end function quickshiftlabels(a::QuickShift, maxlength = 10*a.sigma) - labels = zeros(Int32,length(a.links)) + labels = zeros(Int,length(a.links)) cut_internal!(labels, a.rootind, a.links, maxlength, 1, 2) return labels @@ -116,7 +116,7 @@ function cut_internal!(labels, ind, links, maxlength, label, maxlabel) end function quickshiftplot(a::QuickShift, data::Array{T, 2} where T, labels::Array{Int, 1}) - if !isdefined(:PyPlot) + if !isdefined(Main, :PyPlot) error("quickshiftplot needs PyPlot installed and loaded using 'using PyPlot'") end @@ -129,12 +129,12 @@ function quickshiftplot(a::QuickShift, data::Array{T, 2} where T, labels::Array{ for x = a.links[i] to = data[:,x[2]] p = hcat(from,to)' - plot(p[:,1],p[:,2],"b-") + PyPlot.plot(p[:,1],p[:,2],"b-") end end - scatter(data[1,:],data[2,:], c = labels, edgecolor = "none") + PyPlot.scatter(data[1,:],data[2,:], c = labels, edgecolor = "none") end end