Skip to content

Commit 3b491e1

Browse files
Merge pull request #2 from haotian127/master
Merge NGWP.jl to MultiscaleGraphSignalTransforms.jl
2 parents 3a1954e + 93179ed commit 3b491e1

File tree

335 files changed

+12750
-182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

335 files changed

+12750
-182
lines changed

.github/workflows/CompatHelper.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: "Run CompatHelper"
1919
run: |
2020
import CompatHelper
21-
CompatHelper.main(; subdirs = ["", "docs", "test"])
21+
CompatHelper.main()
2222
shell: julia --color=yes {0}
2323
env:
2424
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Project.toml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,46 @@
11
name = "MultiscaleGraphSignalTransforms"
22
uuid = "cc44fc10-d0fb-5545-af72-ba1cb661a341"
3-
authors = ["Naoki Saito <saito@math.ucdavis.edu>", "Yiqun Shao <shaoyiqun1992@gmail.com>"]
4-
version = "1.4.0"
3+
authors = ["Naoki Saito <saito@math.ucdavis.edu>", "Yiqun Shao <shaoyiqun1992@gmail.com>", "Haotian Li <htsli@ucdavis.edu>"]
4+
version = "1.5.0"
55

66
[deps]
77
Arpack = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97"
88
AverageShiftedHistograms = "77b51b56-6f8f-5c3a-9cb4-d71f9594ea6e"
9+
Clp = "e2554f3b-3117-50c0-817c-e040a3ddf72d"
10+
Clustering = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5"
911
Distances = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
1012
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
13+
JLD = "4138dd39-2aa7-5051-a626-17a0bb65d9c8"
1114
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
15+
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
16+
LightGraphs = "093fc24a-ae57-5d10-9952-331d41423f4d"
1217
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
18+
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
1319
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
20+
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
1421
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
22+
SimpleWeightedGraphs = "47aef6b3-ad0c-573a-a1e2-d07658019622"
1523
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1624
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
25+
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1726

1827
[compat]
1928
Arpack = "0.4.0, 0.5"
2029
AverageShiftedHistograms = "0.8.6"
30+
Clp = "0.8.3"
31+
Clustering = "0.14.2"
2132
Distances = "0.10.2"
2233
Distributions = "0.24.18"
34+
JLD = "0.12.3"
2335
JLD2 = "0.4.3"
36+
JuMP = "0.21.3"
37+
LightGraphs = "1.3.5"
38+
Optim = "1.3.0"
2439
Plots = "1.12.0"
40+
QuadGK = "2.4.1"
2541
Reexport = "1.0.0"
42+
SimpleWeightedGraphs = "1.1.1"
43+
StatsBase = "0.33.6"
2644
julia = "1.5, 1.6"
2745

2846
[extras]

README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ Implemented by Jeff Irion, Haotian Li, Naoki Saito, and Yiqun Shao
1111

1212
To install the MultiscaleGraphSignalTransforms.jl, run
1313
```julia
14-
]
15-
(v1.6) pkg> add https://gitlab.com/BoundaryValueProblems/MultiscaleGraphSignalTransforms.jl.git
16-
using MultiscaleGraphSignalTransforms
14+
julia> import Pkg; Pkg.add("MultiscaleGraphSignalTransforms")
15+
julia> using MultiscaleGraphSignalTransforms
1716
```
1817

1918
## GETTING STARTED
@@ -26,7 +25,7 @@ Currently, you can run a set of very small tests via ```] test MultiscaleGraphSi
2625

2726
2. J. Irion and N. Saito, [The generalized Haar-Walsh transform](http://dx.doi.org/10.1109/SSP.2014.6884678), *Proc. 2014 IEEE Statistical Signal Processing Workshop*, pp. 488-491, 2014.
2827

29-
3. J. Irion and N. Saito, [Applied and computational harmonic analysis on
28+
3. J. Irion and N. Saito, [Applied and computational harmonic analysis on
3029
graphs and networks](http://dx.doi.org/10.1117/12.2186921), *Wavelets and Sparsity XVI*, (M. Papadakis, V. K. Goyal, D. Van De Ville, eds.), *Proc. SPIE 9597*, Paper #95971F, Invited paper, 2015.
3130

3231
4. J. Irion, [Multiscale Transforms for Signals on Graphs: Methods and Applications](https://jefflirion.github.io/publications_and_presentations/irion_dissertation.pdf), Ph.D. dissertation, University of California, Davis, Dec. 2015.
@@ -36,3 +35,11 @@ graphs and networks](http://dx.doi.org/10.1117/12.2186921), *Wavelets and Sparsi
3635
6. J. Irion and N. Saito, [Efficient approximation and denoising of graph signals using the multiscale basis dictionaries](http://dx.doi.org/10.1109/TSIPN.2016.2632039), *IEEE Transactions on Signal and Information Processing over Networks*, Vol. 3, no. 3, pp. 607-616, 2017.
3736

3837
7. Y. Shao and N. Saito, [The extended Generalized Haar-Walsh Transform and applications](https://www.math.ucdavis.edu/~saito/publications/saito_eghwt.pdf), *Wavelets and Sparsity XVIII*, (D. Van De Ville, M. Papadakis, and Y. M. Lu, eds.), *Proc. SPIE 11138*, Paper #111380C, 2019.
38+
39+
8. Y. Shao, The Extended Generalized Haar-Walsh Transform and Applications, Ph.D. dissertation, University of California, Davis, Sep. 2020.
40+
41+
9. H. Li and N. Saito, [Metrics of graph Laplacian eigenvectors](https://www.math.ucdavis.edu/~saito/publications/metgraphlap.html), *Wavelets and Sparsity XVIII*, (D. Van De Ville, M. Papadakis, and Y. M. Lu, eds.), *Proc. SPIE 11138*, Paper #111381K, 2019.
42+
43+
10. C. Alexander, H. Li and N. Saito, [Natural graph wavelet packet dictionaries](https://link.springer.com/article/10.1007/s00041-021-09832-3), *J. Fourier Anal. Appl.*, vol. 27, Article \#41, 2021.
44+
45+
11. H. Li, Natural Graph Wavelet Dictionaries: Methods and Applications, Ph.D. dissertation, University of California, Davis, Jun. 2021.

src/LP-HGLET.jl

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
"""
2+
function LPHGLET_Synthesis(dvec::Vector{Float64}, GP::GraphPart, BS::BasisSpec, G::GraphSig; method::Symbol = :L, ϵ::Float64 = 0.3)
3+
4+
Perform Lapped-HGLET Synthesis transform
5+
6+
### Input Arguments
7+
* `dvec`: the expansion coefficients corresponding to the chosen basis
8+
* `GP`: a GraphPart object
9+
* `BS`: a BasisSpec object
10+
* `G`: a GraphSig object
11+
* `method`: :L or :Lsym, indicating which eigenvectors are used
12+
* `ϵ`: relative action bandwidth (default: 0.3)
13+
14+
### Output Argument
15+
* `f`: the reconstructed signal
16+
* `GS`: the reconstructed GraphSig object
17+
"""
18+
function LPHGLET_Synthesis(dvec::Matrix{Float64}, GP::GraphPart, BS::BasisSpec, G::GraphSig; method::Symbol = :L, ϵ::Float64 = 0.3)
19+
# Preliminaries
20+
W = G.W
21+
inds = GP.inds
22+
rs = GP.rs
23+
N = size(W, 1)
24+
jmax = size(rs, 2)
25+
Uf = Matrix{Float64}(I, N, N)
26+
used_node = Set()
27+
28+
# fill in the appropriate entries of dmatrix
29+
dmatrix = dvec2dmatrix(dvec, GP, BS)
30+
31+
f = zeros(size(dmatrix[:, jmax, :]))
32+
33+
34+
# Perform the synthesis transform
35+
for j = 1:jmax
36+
regioncount = count(!iszero, rs[:,j]) - 1
37+
# assemble orthogonal folding operator at level j - 1
38+
keep_folding!(Uf, used_node, W, GP; ϵ = ϵ, j = j - 1)
39+
for r = 1:regioncount
40+
# indices of current region
41+
indr = rs[r, j]:(rs[r + 1, j] - 1)
42+
# indices of current region's nodes
43+
indrs = inds[indr, j]
44+
# number of nodes in current region
45+
n = length(indrs)
46+
47+
# only proceed forward if coefficients do not exist
48+
if (j == jmax || count(!iszero, dmatrix[indr, j + 1, :]) == 0) && count(!iszero, dmatrix[indr, j, :]) > 0
49+
# compute the eigenvectors
50+
W_temp = W[indrs,indrs]
51+
D_temp = sparse(Diagonal(dropdims(sum(W_temp, dims = 1), dims = 1)))
52+
if method == :L
53+
# compute the eigenvectors of L ==> svd(L)
54+
vec = svd(Matrix(D_temp - W_temp)).U
55+
elseif method == :Lsym
56+
# check if one can assemble the Lsym
57+
if minimum(sum(W[indrs, indrs], dims = 1)) > 10^3 * eps()
58+
### eigenvectors of L_sym ==> svd(L_sym)
59+
D_temp_p = sparse(Diagonal(dropdims(sum(W_temp, dims = 1), dims = 1).^(-1/2)))
60+
vec = svd(Matrix(D_temp_p * (D_temp - W_temp) * D_temp_p)).U
61+
else
62+
### eigenvectors of L ==> svd(L)
63+
vec = svd(Matrix(D_temp - W_temp)).U
64+
end
65+
end
66+
vec = vec[:, end:-1:1]
67+
68+
69+
# standardize the eigenvector signs
70+
standardize_eigenvector_signs!(vec)
71+
72+
# construct unfolder operator custom to current region
73+
P = Uf[indrs, :]'
74+
75+
# reconstruct the signal
76+
f += (P * vec) * dmatrix[indr, j, :]
77+
78+
end
79+
end
80+
end
81+
82+
# creat a GraphSig object with the reconstructed data
83+
GS = deepcopy(G)
84+
replace_data!(GS, f)
85+
86+
return f, GS
87+
end
88+
89+
90+
91+
"""
92+
function LPHGLET_Analysis_All(G::GraphSig, GP::GraphPart; ϵ::Float64 = 0.3)
93+
94+
For a GraphSig object 'G', generate the 2 matrices of Lapped-HGLET expansion coefficients
95+
corresponding to the eigenvectors of L and Lsym
96+
97+
### Input Arguments
98+
* `G`: a GraphSig object
99+
* `GP`: a GraphPart object
100+
* `ϵ`: relative action bandwidth (default: 0.3)
101+
102+
### Output Argument
103+
* `dmatrixlH`: the matrix of expansion coefficients for L
104+
* `dmatrixlHsym`: the matrix of expansion coefficients for Lsym
105+
* `GP`: a GraphPart object
106+
"""
107+
function LPHGLET_Analysis_All(G::GraphSig, GP::GraphPart; ϵ::Float64 = 0.3)
108+
# Preliminaries
109+
W = G.W
110+
inds = GP.inds
111+
rs = GP.rs
112+
N = size(W, 1)
113+
jmax = size(rs, 2)
114+
fcols = size(G.f, 2)
115+
Uf = Matrix{Float64}(I, N, N)
116+
used_node = Set()
117+
dmatrixlH = zeros(N, jmax, fcols)
118+
dmatrixlHsym = deepcopy(dmatrixlH)
119+
120+
for j = 1:jmax
121+
regioncount = count(!iszero, rs[:,j]) - 1
122+
# assemble orthogonal folding operator at level j - 1
123+
keep_folding!(Uf, used_node, W, GP; ϵ = ϵ, j = j - 1)
124+
for r = 1:regioncount
125+
# indices of current region
126+
indr = rs[r, j]:(rs[r + 1, j] - 1)
127+
# indices of current region's nodes
128+
indrs = inds[indr, j]
129+
# number of nodes in current region
130+
n = length(indrs)
131+
132+
# compute the eigenvectors
133+
W_temp = W[indrs,indrs]
134+
D_temp = sparse(Diagonal(dropdims(sum(W_temp, dims = 1), dims = 1)))
135+
## eigenvectors of L ==> svd(L)
136+
vec = svd(Matrix(D_temp - W_temp)).U
137+
## eigenvectors of L_sym ==> svd(L_sym)
138+
if minimum(sum(W[indrs, indrs], dims = 1)) > 10^3 * eps()
139+
### eigenvectors of L_sym ==> svd(L_sym)
140+
D_temp_p = sparse(Diagonal(dropdims(sum(W_temp, dims = 1), dims = 1).^(-1/2)))
141+
vec_sym = svd(Matrix(D_temp_p * (D_temp - W_temp) * D_temp_p)).U
142+
else
143+
### eigenvectors of L ==> svd(L)
144+
vec_sym = deepcopy(vec)
145+
end
146+
147+
# standardize the eigenvector signs
148+
vec = vec[:, end:-1:1]
149+
standardize_eigenvector_signs!(vec)
150+
vec_sym = vec_sym[:, end:-1:1]
151+
standardize_eigenvector_signs!(vec_sym)
152+
153+
# construct unfolding operator custom to current region
154+
P = Uf[indrs, :]'
155+
# obtain the expansion coefficients
156+
dmatrixlH[indr, j, :] = (P * vec)' * G.f
157+
dmatrixlHsym[indr, j, :] = (P * vec_sym)' * G.f
158+
end
159+
end
160+
161+
return dmatrixlH, dmatrixlHsym
162+
163+
end
164+
165+
166+
167+
function standardize_eigenvector_signs!(vec)
168+
# standardize the eigenvector signs for HGLET (different with NGWPs)
169+
for col = 1:size(vec, 2)
170+
row = 1
171+
standardized = false
172+
while !standardized
173+
if vec[row, col] > 10^3 * eps()
174+
standardized = true
175+
elseif vec[row,col] < -10^3 * eps()
176+
vec[:, col] = -vec[:, col]
177+
else
178+
row += 1
179+
end
180+
end
181+
end
182+
end
183+
184+
"""
185+
HGLET_dictionary(GP::GraphPart, G::GraphSig; method::Symbol = :L)
186+
187+
assemble the whole HGLET dictionary
188+
189+
### Input Arguments
190+
* `GP`: a GraphPart object
191+
* `G`: a GraphSig object
192+
* `method`: `:L` or `:Lsym`
193+
194+
### Output Argument
195+
* `dictionary`: the HGLET dictionary
196+
197+
"""
198+
function HGLET_dictionary(GP::GraphPart, G::GraphSig; method::Symbol = :L)
199+
N = size(G.W, 1)
200+
jmax = size(GP.rs, 2)
201+
dictionary = zeros(N, jmax, N)
202+
for j = 1:jmax
203+
BS = BasisSpec(collect(enumerate(j * ones(Int, N))))
204+
dictionary[:, j, :] = HGLET_Synthesis(Matrix{Float64}(I, N, N), GP, BS, G; method = method)[1]'
205+
end
206+
return dictionary
207+
end
208+
209+
"""
210+
LPHGLET_dictionary(GP::GraphPart, G::GraphSig; method::Symbol = :L, ϵ::Float64 = 0.3)
211+
212+
assemble the whole LP-HGLET dictionary
213+
214+
### Input Arguments
215+
* `GP`: a GraphPart object
216+
* `G`: a GraphSig object
217+
* `method`: `:L` or `:Lsym`
218+
* `ϵ`: relative action bandwidth (default: 0.3)
219+
220+
### Output Argument
221+
* `dictionary`: the LP-HGLET dictionary
222+
223+
"""
224+
function LPHGLET_dictionary(GP::GraphPart, G::GraphSig; method::Symbol = :L, ϵ::Float64 = 0.3)
225+
N = size(G.W, 1)
226+
jmax = size(GP.rs, 2)
227+
dictionary = zeros(N, jmax, N)
228+
for j = 1:jmax
229+
BS = BasisSpec(collect(enumerate(j * ones(Int, N))))
230+
dictionary[:, j, :] = LPHGLET_Synthesis(Matrix{Float64}(I, N, N), GP, BS, G; method = method, ϵ = ϵ)[1]'
231+
end
232+
return dictionary
233+
end

0 commit comments

Comments
 (0)