tensor_methods

Tensor Methods for DS and SC
git clone git://popovic.xyz/tensor_methods.git
Log | Files | Refs

commit 26bcda26277a4ca3877e9915a319663c9a80a49e
parent 4dcf6389aefd295070c3a96934287983f6929387
Author: miksa234 <milutin@popovic.xyz>
Date:   Wed, 15 Dec 2021 10:05:20 +0100

code as05 done

Diffstat:
Aassingments/hw05_published_2021-12-09.pdf | 0
Msesh4/src/main.jl | 372+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msesh4/src/plots/hosvd-Nj-b.png | 0
Msesh4/src/plots/hosvd-error-B.png | 0
Msesh4/src/plots/hosvd-sigmaratio-a.png | 0
Msesh4/src/plots/hosvd-sigmaratio-b.png | 0
Msesh4/src/plots/hosvd-uniform-error.png | 0
Msesh4/src/plots/ttsvd-uniform-error.png | 0
Msesh4/src/unf-aprx.jl | 21+++++++++++++++++++--
Asesh5/src/arithmetic.jl | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asesh5/src/helpers.jl | 26++++++++++++++++++++++++++
Asesh5/src/main.jl | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asesh5/src/plots/rank_34.png | 0
Asesh5/src/plots/rank_57.png | 0
Asesh5/src/plots/sigma_34.png | 0
Asesh5/src/plots/sigma_57.png | 0
Asesh5/src/ttmps.jl | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17 files changed, 584 insertions(+), 171 deletions(-)

diff --git a/assingments/hw05_published_2021-12-09.pdf b/assingments/hw05_published_2021-12-09.pdf Binary files differ. diff --git a/sesh4/src/main.jl b/sesh4/src/main.jl @@ -16,66 +16,213 @@ include("functions.jl") function main() # Exercise 2 - d = 4; - n = [20+k for k=1:d]; - r = [2*k for k=1:d]; - V = [rand(Uniform(-1, 1), n[k], r[k]) for k=1:d]; - S = rand(Uniform(-1, 1), r...); - C = tucker_eval(S, V); - Vs, S0, vals, errors = my_hosvd(C, r); + #d = 4; + #n = [20+k for k=1:d]; + #r = [2*k for k=1:d]; + #V = [rand(Uniform(-1, 1), n[k], r[k]) for k=1:d]; + #S = rand(Uniform(-1, 1), r...); + #C = tucker_eval(S, V); + #Vs, S0, vals, errors = my_hosvd(C, r); - p = plot(errors, - ylabel="error", - label=L"$\frac{\|\hat{A}_k - A\|_F}{\|A\|_F}$", - xlabel=L"k", - lw = 1, - xticks=collect(1:d), - markershape=:circle, - legend=:topleft, - margin=5mm, - dpi=300, - title="HOSVD of Uniform Tensor") - savefig(p, "./plots/hosvd-uniform-error.png") + #p = plot(errors, + # ylabel="error", + # label=L"$\frac{\|\hat{A}_k - A\|_F}{\|A\|_F}$", + # xlabel=L"k", + # lw = 1, + # xticks=collect(1:d), + # markershape=:circle, + # legend=:topleft, + # margin=5mm, + # dpi=300, + # title="HOSVD of Uniform Tensor") + #savefig(p, "./plots/hosvd-uniform-error.png") + + ## Exercise 3 + #d = 4; n = 51; + #A = [f([t1, t2, t3, t4]) for t1 in t(n), t2 in t(n), t3 in t(n), t4 in t(n)]; + #B = [g([t1, t2, t3, t4]) for t1 in t(n), t2 in t(n), t3 in t(n), t4 in t(n)]; + + ## Exercise 3a + #σ_unf_a = σ_unfold(A, d); + #σ_unf_b = σ_unfold(B, d); + #p1 = plot(margin=5mm) + #p2 = plot(margin=5mm) + #for k=1:d + # plot!(p1, + # σ_unf_a[k], + # ylabel=L"$\log(\Sigma_{A_k})$", + # label=L"$\Sigma_{A_%$k}$", + # xlabel=L"n", + # lw = 1, + # yaxis=:log, + # markershape=:circle, + # dpi=300, + # title="Unfolding of A") + # plot!(p2, + # σ_unf_b[k], + # ylabel=L"$\log(\Sigma_{B_k})$", + # label=L"$\Sigma_{_B%$k}$", + # xlabel=L"n", + # lw = 1, + # dpi=300, + # markershape=:circle, + # yaxis=:log, + # title="Unfolding of B") + #end + #savefig(p1, "./plots/singular-dec-A.png") + #savefig(p2, "./plots/singular-dec-B.png") + + ϵ_s = [1/(10^(j*2)) for j=1:5] # computer not goode enough for j = 6 + + #r_jk_a, ϵ_jk_a, σ_jk_a = rank_approx(A, tucker_unfold); + #r_jk_b, ϵ_jk_b, σ_jk_b = rank_approx(B, tucker_unfold); + #p1 = plot(size=[700, 350], margin=5mm, dpi=300) + #p2 = plot(size=[700, 350], margin=5mm, dpi=300) + #for k=1:d + # plot!(p1, + # 1 ./ ϵ_s, + # r_jk_a[:, k], + # ylabel=L"$r_{jk}$", + # label=L"A-$\varepsilon_{j%$k}$", + # xlabel=L"\varepsilon_{j}^{-1}", + # lw = 2, + # markershape=:circle, + # xaxis=:log10, + # legend=:topleft, + # title=L"Tensor $f(x_1, x_2, x_3, x_4)$") + # plot!(p2, + # 1 ./ ϵ_s, + # r_jk_b[:, k], + # ylabel=L"$r_{jk}$", + # label=L"B-$\varepsilon_{j%$k}$", + # xlabel=L"\varepsilon_{j}^{-1}", + # lw = 2, + # markershape=:circle, + # xaxis=:log10, + # legend=:topleft, + # title=L"Tensor $g(x_1, x_2, x_3, x_4)$") + #end + #savefig(p1, "./plots/hosvd-error-A.png") + #savefig(p2, "./plots/hosvd-error-B.png") + + ## Exercise 3b + #Nj_hosvd_a = []; ϵ_hosvd_a = []; σ_hosvd_a = []; + #Nj_hosvd_b = []; ϵ_hosvd_b = []; σ_hosvd_b = []; + + #println("Checking validity of error analysis for HOSVD") + #for j=1:length(ϵ_s) + # S0_a, Vs_a, vals_a, errors_a = my_hosvd(A, r_jk_a[j, :]) + # N_vals = 0 + # for V in Vs_a + # N_vals += length(V) + # end + # append!(Nj_hosvd_a, N_vals + length(S0_a)) + # append!(ϵ_hosvd_a, errors_a[end]) + # append!(σ_hosvd_a, [vals_a]) + # println("ϵ_hosvd_a[j] <= |ϵ_jk_a|_f : $(ϵ_hosvd_a[j] <= norm(ϵ_jk_a)) ϵ_hosvd_a[j] = $(ϵ_hosvd_a[j])") + + # S0_b, Vs_b, vals_b, errors_b = my_hosvd(B, r_jk_b[j, :]) + # N_vals = 0 + # for V in Vs_b + # N_vals += length(V) + # end + # append!(Nj_hosvd_b, N_vals + length(S0_b)) + # append!(ϵ_hosvd_b, errors_b[end]) + # append!(σ_hosvd_b, [vals_b]) + # println("ϵ_hosvd_b[j] <= |ϵ_jk_b|_f : $(ϵ_hosvd_b[j] <= norm(ϵ_jk_b)) ϵ_hosvd_b[j] = $(ϵ_hosvd_b[j])") + #end + + ## Exercise 3b + #j = 5 + #p1 = plot(dpi=300, size=[800, 350], margin=5mm) + #p2 = plot(dpi=300, size=[800, 350], margin=5mm) + #for k=1:d + # plot!(p1, σ_unf_a[k][1:r_jk_a[j, k]] ./ σ_hosvd_a[j][k], + # ylabel=L"\frac{\sigma^{A_k}_\alpha}{\sigma^{hosvd}_{k\alpha}}", + # label=L"k=%$k", + # xlabel=L"j", + # xticks=collect(1:length(r_jk_a)), + # yticks=[1, 1.001], + # ylim=[1, 1.001], + # lw = 2, + # markershape=:circle, + # legend=:topleft, + # title=L"$f(x_1, x_2, x_3, x_4)$") + # plot!(p2, σ_unf_b[k][1:r_jk_b[j, k]] ./ σ_hosvd_b[j][k], + # ylabel=L"\frac{\sigma^{B_k}_\alpha}{\sigma^{hosvd}_{k\alpha}}", + # label=L"k=%$k", + # xlabel=L"j", + # yticks=[1, 1.001], + # ylim=[1, 1.001], + # lw = 2, + # markershape=:circle, + # legend=:topleft, + # title=L"$g(x_1, x_2, x_3, x_4)$") + #end + #savefig(p1, "./plots/hosvd-sigmaratio-a.png") + #savefig(p2, "./plots/hosvd-sigmaratio-b.png") + + ## Exercise 3d + + #p1 = plot(size=[700, 350], margin=5mm, dpi=300) + #p2 = plot(size=[700, 350], margin=5mm, dpi=300) + #plot!(p1, + # 1 ./ ϵ_s, + # Nj_hosvd_a, + # ylabel=L"$N_{j}$", + # label=L"A-$N_{j}$", + # xlabel=L"\varepsilon_{j}^{-1}", + # lw = 2, + # markershape=:circle, + # xaxis=:log10, + # legend=:topleft, + # title=L"Tucker of $f(x_1, x_2, x_3, x_4)$") + #plot!(p2, + # 1 ./ ϵ_s, + # Nj_hosvd_b, + # ylabel=L"$N_{j}$", + # label=L"B-$N_{j}$", + # xlabel=L"\varepsilon_{j}^{-1}", + # lw = 2, + # markershape=:circle, + # xaxis=:log10, + # legend=:topleft, + # title=L"Tucker of $g(x_1, x_2, x_3, x_4)$") + #savefig(p1, "./plots/hosvd-Nj-a.png") + #savefig(p2, "./plots/hosvd-Nj-b.png") + + ## exercise 6 + #d = 4; + #n = [20+k for k=1:d]; + #r = [[2*k for k=1:(d-1)]..., 1]; + #r_new = [1, r...] + #V = [rand(Uniform(-1, 1), (r_new[i], n[i], r_new[i+1])) for i=1:d]; + #D = ttmps_eval(V, n) + #C, singular_val, errors= tt_svd(D, n, r, d); + #p = plot(errors, + # ylabel="error", + # label=L"$\frac{\|\hat{A}_k - A\|_f}{\|A\|_f}$", + # xlabel=L"k", + # lw = 1, + # xticks=collect(1:d), + # markershape=:circle, + # legend=:topleft, + # margin=5mm, + # dpi=300, + # title="TT-SVD of uniform tensor") + #savefig(p, "./plots/ttsvd-uniform-error.png") + + ## exercise 7 - # Exercise 3 d = 4; n = 51; + ndim = [n for i=1:d] A = [f([t1, t2, t3, t4]) for t1 in t(n), t2 in t(n), t3 in t(n), t4 in t(n)]; B = [g([t1, t2, t3, t4]) for t1 in t(n), t2 in t(n), t3 in t(n), t4 in t(n)]; - # Exercise 3a - σ_unf_a = σ_unfold(A, d); - σ_unf_b = σ_unfold(B, d); - p1 = plot(margin=5mm) - p2 = plot(margin=5mm) - for k=1:d - plot!(p1, - σ_unf_a[k], - ylabel=L"$\log(\Sigma_{A_k})$", - label=L"$\Sigma_{A_%$k}$", - xlabel=L"n", - lw = 1, - yaxis=:log, - markershape=:circle, - dpi=300, - title="Unfolding of A") - plot!(p2, - σ_unf_b[k], - ylabel=L"$\log(\Sigma_{B_k})$", - label=L"$\Sigma_{_B%$k}$", - xlabel=L"n", - lw = 1, - dpi=300, - markershape=:circle, - yaxis=:log, - title="Unfolding of B") - end - savefig(p1, "./plots/singular-dec-A.png") - savefig(p2, "./plots/singular-dec-B.png") + ## Exercise 7a - ϵ_s = [1/(10^(j*2)) for j=1:5] # computer not goode enough for j = 6 - - r_jk_a, ϵ_jk_a, σ_jk_a = rank_approx(A); - r_jk_b, ϵ_jk_b, σ_jk_b = rank_approx(B); + r_jk_a, ϵ_jk_a, σ_jk_a = rank_approx(A, ttmps_unfold); + r_jk_b, ϵ_jk_b, σ_jk_b = rank_approx(B, ttmps_unfold); p1 = plot(size=[700, 350], margin=5mm, dpi=300) p2 = plot(size=[700, 350], margin=5mm, dpi=300) for k=1:d @@ -102,122 +249,8 @@ function main() legend=:topleft, title=L"Tensor $g(x_1, x_2, x_3, x_4)$") end - savefig(p1, "./plots/hosvd-error-A.png") - savefig(p2, "./plots/hosvd-error-B.png") - - # Exercise 3b - Nj_hosvd_a = []; ϵ_hosvd_a = []; σ_hosvd_a = []; - Nj_hosvd_b = []; ϵ_hosvd_b = []; σ_hosvd_b = []; - - println("Checking validity of error analysis for HOSVD") - for j=1:length(ϵ_s) - S0_a, Vs_a, vals_a, errors_a = my_hosvd(A, r_jk_a[j, :]) - N_vals = 0 - for V in Vs_a - N_vals += length(V) - end - append!(Nj_hosvd_a, N_vals + length(S0_a)) - append!(ϵ_hosvd_a, errors_a[end]) - append!(σ_hosvd_a, [vals_a]) - println("ϵ_hosvd_a[j] <= |ϵ_jk_a|_f : $(ϵ_hosvd_a[j] <= norm(ϵ_jk_a)) ϵ_hosvd_a[j] = $(ϵ_hosvd_a[j])") - - S0_b, Vs_b, vals_b, errors_b = my_hosvd(B, r_jk_b[j, :]) - N_vals = 0 - for V in Vs_b - N_vals += length(V) - end - append!(Nj_hosvd_b, N_vals + length(S0_b)) - append!(ϵ_hosvd_b, errors_b[end]) - append!(σ_hosvd_b, [vals_b]) - println("ϵ_hosvd_b[j] <= |ϵ_jk_b|_f : $(ϵ_hosvd_b[j] <= norm(ϵ_jk_b)) ϵ_hosvd_b[j] = $(ϵ_hosvd_b[j])") - end - - # exercise 3b - j = 5 - p1 = plot(dpi=300, size=[800, 350], margin=5mm) - p2 = plot(dpi=300, size=[800, 350], margin=5mm) - for k=1:d - plot!(p1, σ_unf_a[k][1:r_jk_a[j, k]] ./ σ_hosvd_a[j][k], - ylabel=L"\frac{\sigma^{A_k}_\alpha}{\sigma^{hosvd}_{k\alpha}}", - label=L"k=%$k", - xlabel=L"j", - xticks=collect(1:length(r_jk_a)), - yticks=[1, 1.001], - ylim=[1, 1.001], - lw = 2, - markershape=:circle, - legend=:topleft, - title=L"$f(x_1, x_2, x_3, x_4)$") - plot!(p2, σ_unf_b[k][1:r_jk_b[j, k]] ./ σ_hosvd_b[j][k], - ylabel=L"\frac{\sigma^{B_k}_\alpha}{\sigma^{hosvd}_{k\alpha}}", - label=L"k=%$k", - xlabel=L"j", - yticks=[1, 1.001], - ylim=[1, 1.001], - lw = 2, - markershape=:circle, - legend=:topleft, - title=L"$g(x_1, x_2, x_3, x_4)$") - end - savefig(p1, "./plots/hosvd-sigmaratio-a.png") - savefig(p2, "./plots/hosvd-sigmaratio-b.png") - - # Exercise 3d - - p1 = plot(size=[700, 350], margin=5mm, dpi=300) - p2 = plot(size=[700, 350], margin=5mm, dpi=300) - plot!(p1, - 1 ./ ϵ_s, - Nj_hosvd_a, - ylabel=L"$N_{j}$", - label=L"A-$N_{j}$", - xlabel=L"\varepsilon_{j}^{-1}", - lw = 2, - markershape=:circle, - xaxis=:log10, - legend=:topleft, - title=L"Tucker of $f(x_1, x_2, x_3, x_4)$") - plot!(p2, - 1 ./ ϵ_s, - Nj_hosvd_b, - ylabel=L"$N_{j}$", - label=L"B-$N_{j}$", - xlabel=L"\varepsilon_{j}^{-1}", - lw = 2, - markershape=:circle, - xaxis=:log10, - legend=:topleft, - title=L"Tucker of $g(x_1, x_2, x_3, x_4)$") - savefig(p1, "./plots/hosvd-Nj-a.png") - savefig(p2, "./plots/hosvd-Nj-b.png") - - # exercise 6 - d = 4; - n = [20+k for k=1:d]; - r = [[2*k for k=1:(d-1)]..., 1]; - r_new = [1, r...] - V = [rand(Uniform(-1, 1), (r_new[i], n[i], r_new[i+1])) for i=1:d]; - D = ttmps_eval(V, n) - C, singular_val, errors= tt_svd(D, n, r, d); - p = plot(errors, - ylabel="error", - label=L"$\frac{\|\hat{A}_k - A\|_f}{\|A\|_f}$", - xlabel=L"k", - lw = 1, - xticks=collect(1:d), - markershape=:circle, - legend=:topleft, - margin=5mm, - dpi=300, - title="TT-SVD of uniform tensor") - savefig(p, "./plots/ttsvd-uniform-error.png") - - # exercise 7 - - d = 4; n = 51; - ndim = [n for i=1:d] - A = [f([t1, t2, t3, t4]) for t1 in t(n), t2 in t(n), t3 in t(n), t4 in t(n)]; - B = [g([t1, t2, t3, t4]) for t1 in t(n), t2 in t(n), t3 in t(n), t4 in t(n)]; + savefig(p1, "./plots/tucker-error-A.png") + savefig(p2, "./plots/tucker-error-B.png") # exercise 7b Nj_ttsvd_a = []; ϵ_ttsvd_a = []; σ_ttsvd_a = []; @@ -275,6 +308,7 @@ function main() savefig(p1, "./plots/ttsvd-sigmaratio-a.png") savefig(p2, "./plots/ttsvd-sigmaratio-b.png") + # Exercise 7d p1 = plot(size=[700, 350], margin=5mm, dpi=300) p2 = plot(size=[700, 350], margin=5mm, dpi=300) diff --git a/sesh4/src/plots/hosvd-Nj-b.png b/sesh4/src/plots/hosvd-Nj-b.png Binary files differ. diff --git a/sesh4/src/plots/hosvd-error-B.png b/sesh4/src/plots/hosvd-error-B.png Binary files differ. diff --git a/sesh4/src/plots/hosvd-sigmaratio-a.png b/sesh4/src/plots/hosvd-sigmaratio-a.png Binary files differ. diff --git a/sesh4/src/plots/hosvd-sigmaratio-b.png b/sesh4/src/plots/hosvd-sigmaratio-b.png Binary files differ. diff --git a/sesh4/src/plots/hosvd-uniform-error.png b/sesh4/src/plots/hosvd-uniform-error.png Binary files differ. diff --git a/sesh4/src/plots/ttsvd-uniform-error.png b/sesh4/src/plots/ttsvd-uniform-error.png Binary files differ. diff --git a/sesh4/src/unf-aprx.jl b/sesh4/src/unf-aprx.jl @@ -18,12 +18,29 @@ function σ_unfold(C, d) return Σ_s end +function ttmps_unfold(A, k) + n = size(A) + d = length(n) + C = copy(A) + A_k = reshape(C, (prod([n[i] for i in 1:k]), prod([n[i] for i in k+1:d]))) + return A_k +end + +function tucker_unfold(A, k) + n = size(A) + d = length(n) + C = copy(A) + C_perm = permutedims(C, ([i for i=1:d if i!=k]..., k)) + A_k = reshape(C_perm, (prod([n[i] for i=1:d if i!=k]), n[k])) + return A_k +end + ϵ_s = [1/(10^(j*2)) for j=1:5] # computer not goode enough for j = 6 -function rank_approx(C, ϵ_s=ϵ_s) +function rank_approx(C, method,ϵ_s=ϵ_s) d = length(size(C)) ϵ_jk = []; r_jk = []; σ_jk = [] for k=1:d - C_k = tenmat(C, k) + C_k = method(C, k) for (j, ϵ_j) in enumerate(ϵ_s) for r=1:rank(C_k) U_hat, Σ_hat, V_hat = tsvd(C_k, r) diff --git a/sesh5/src/arithmetic.jl b/sesh5/src/arithmetic.jl @@ -0,0 +1,93 @@ +#/usr/bin/julia + +using LinearAlgebra +using Plots +using Plots.Measures +using Distributions +using LaTeXStrings +using TSVD: tsvd +using TensorToolbox: tenmat, ttm, contract # todo:implement + +@doc raw""" + Addition of two tensors in the TT-MPS format of $A$ and $B$ of the same size + $n_1 × ⋯ × n_d$ with different TT-MPS decompositions U with ranks $p_1, … , p_{d-1}$ + and V with ranks $q_1, … ,q_{d-1}$ respectively. + + Output is the TT-MPS representation of $A+B$ with ranks $(q_1 + p_1), ⋯ , (q_{d-1} + p_{d-1})$. +""" +function tt_add(U, V, α, β) + W = [] + d = length(U) + for k ∈ 1:d + U_k = U[k]; V_k = V[k] + p_k, n_k, p_k1 = size(U_k) + q_k, n_k, q_k1 = size(V_k) + if k == 1 + W_1 = zeros(1, n_k, q_k1 + p_k1) + for i=1:n_k + W_1[:, i, :] += hcat(α * U_k[:, i, :], β * V_k[:, i, :]) + end + append!(W, [W_1]) + elseif k == d + W_d = zeros(q_k + p_k, n_k, 1) + for i=1:n_k + W_d[:, i, :] += vcat(U_k[:, i, :], V_k[:, i, :]) + end + append!(W, [W_d]) + else + W_k = zeros(p_k + q_k, n_k, q_k1 + p_k1) + for i=1:n_k + W_k[:, i, :] += hcat(vcat(U_k[:, i, :], zeros(q_k, p_k1)), + vcat(zeros(p_k, q_k1), V_k[:, i, :])) + end + append!(W, [W_k]) + end + end + return W +end + +@doc raw""" + Hadamard product of two tensors in the TT-MPS format of $A$ and $B$ of the same size + $n_1 × ⋯ × n_d$ with different TT-MPS decompositions U with ranks $p_1, … , p_{d-1}$ + and V with ranks $q_1, … ,q_{d-1}$ respectively. + + Output is the representation of $A ⊙ B$ with ranks $(q_1 ⋅ p_1), ⋯ , (q_{d-1} ⋅ p_{d-1})$. +""" +function tt_mult(U, V) + W = [] + d = length(U) + for k ∈ 1:d + p_k, n_k, p_k1 = size(U[k]) + q_k, n_k, q_k1 = size(V[k]) + W_k = zeros(p_k*q_k, n_k, p_k1 * q_k1) + for i_k ∈ 1:n_k + W_k[:, i_k, :] += kron(U[k][:, i_k, :], V[k][:, i_k, :]) + end + append!(W, [W_k]) + end + return W +end + +@doc raw""" + Matrix Vector product of two tensors in the TT-MPS format of $A$, size $(m_1⋯m_d×n_1⋯n_d)$ and $u$ size $(n_1⋯n_d)$ + with different TT-MPS decompositions U with ranks $p_1, … , p_{d-1}$ + and V with ranks $q_1, … ,q_{d-1}$ respectively. + + Output is the TT-MPS representation of $Au$ with ranks $(q_1 ⋅ p_1), ⋯ , (q_{d-1} ⋅ p_{d-1})$. +""" +function tt_matvec(A, U) + W = [] + d = length(U) + for k ∈ 1:d + α_k, m_k, n_k, α_k1 = size(A[k]) + β_k, m_k, β_k1 = size(U[k]) + W_k = zeros(α_k * β_k, n_k, α_k1 * β_k1) + for i_k ∈ 1:m_k + for j_k ∈ 1:n_k + W_k[:, i_k, :] += A[k][:, i_k, j_k, :] * U[k][:, j_k, :] + end + end + append!(W, [W_k]) + end + return W +end diff --git a/sesh5/src/helpers.jl b/sesh5/src/helpers.jl @@ -0,0 +1,26 @@ +#/usr/bin/julia + +using LinearAlgebra +using Plots +using Plots.Measures +using Distributions +using LaTeXStrings +using TSVD: tsvd +using TensorToolbox: tenmat, ttm, contract # todo:implement + +@doc raw""" + Helper functions to calculated the tensor values of the Chebyshev Polynomials \textit{che_pol} + on a Grid \textit{t(n)} +""" + +t(n) = [2*(i-1)/(n-1)-1 for i ∈ 1:n] + +function che_pol(x, q) + if abs(x) ≤ 1 + return cos(q*acos(x)) + elseif x ≥ 1 + return cosh(q*acosh(x)) + elseif x ≤ -1 + return (-1)^q * cosh(q*acosh(-x)) + end +end diff --git a/sesh5/src/main.jl b/sesh5/src/main.jl @@ -0,0 +1,91 @@ +#/usr/bin/julia + +using LinearAlgebra +using Plots +using Plots.Measures +using Distributions +using LaTeXStrings +using TSVD: tsvd +using TensorToolbox: tenmat, ttm, contract # todo:implement + +include("arithmetic.jl") +include("helpers.jl") +include("ttmps.jl") + +function main() + # Exercise 3a) + n = 10 + d = 4 + p_Σ = [] + p_R = [] + for (p, q) ∈ ([3, 4], [5, 7]) + X = [che_pol(sum([t_1/1, t_2/2, t_3/3, t_4/4]), p) for t_1 ∈ t(n), t_2 ∈ t(n), t_3 ∈ t(n), t_4 ∈ t(n)]; + Y = [che_pol(sum([t_1/1, t_2/2, t_3/3, t_4/4]), q) for t_1 ∈ t(n), t_2 ∈ t(n), t_3 ∈ t(n), t_4 ∈ t(n)]; + S = X .+ Y; + Z = X .* Y; + global X_Σ = []; global Y_Σ = []; global S_Σ = []; global Z_Σ = [] + global r_x = []; global r_y = []; global r_s = []; global r_z = [] + for k ∈ 1:d-1 + X_k = ttmps_unfold(X, k) + Y_k = ttmps_unfold(Y, k) + S_k = ttmps_unfold(S, k) + Z_k = ttmps_unfold(Z, k) + _, σ_x, _ = svd(X_k) + _, σ_y, _ = svd(Y_k) + _, σ_s, _ = svd(S_k) + _, σ_z, _ = svd(Z_k) + append!(X_Σ, [σ_x]) + append!(Y_Σ, [σ_y]) + append!(S_Σ, [σ_s]) + append!(Z_Σ, [σ_z]) + append!(r_x, [rank(X_k)]) + append!(r_y, [rank(Y_k)]) + append!(r_s, [rank(S_k)]) + append!(r_z, [rank(Z_k)]) + end + p_σ = plot(layout = 4, margin=5mm, size=(800, 800), title="p=$p, q=$q", dpi=500) + plot!(p_σ[1], X_Σ, markershape=:circle, ylabel=L"\Sigma_{X_k}", label=[L"X_1" L"X_2" L"X_3"]) + plot!(p_σ[2], Y_Σ, markershape=:circle, ylabel=L"\Sigma_{Y_k}", label=[L"Y_1" L"Y_2" L"Y_3"]) + plot!(p_σ[3], S_Σ, markershape=:circle, ylabel=L"\Sigma_{S_k}", label=[L"S_1" L"S_2" L"S_3"]) + plot!(p_σ[4], Z_Σ, markershape=:circle, ylabel=L"\Sigma_{Z_k}", label=[L"Z_1" L"Z_2" L"Z_3"]) + append!(p_Σ, [p_σ]) + p_r = plot(margin=5mm, size=(700, 350), title="p=$p, q=$q", ylabel=L"r_k", dpi=300) + plot!(p_r, r_x, markershape=:circle, label=L"r_X") + plot!(p_r, r_y, markershape=:circle, label=L"r_Y") + plot!(p_r, r_s, markershape=:circle, label=L"r_S", alpha=0.5) + plot!(p_r, r_z, markershape=:circle, label=L"r_Z") + append!(p_R, [p_r]) + + end + savefig(p_Σ[1], "./plots/sigma_34.png") + savefig(p_Σ[2], "./plots/sigma_57.png") + savefig(p_R[1], "./plots/rank_34.png") + savefig(p_R[2], "./plots/rank_57.png") + + + # Exercise 3b) + n = 10; p = 5; q = 7 + dims = [10 for i ∈ 1:4] + + X = [che_pol(sum([t_1/1, t_2/2, t_3/3, t_4/4]), p) for t_1 ∈ t(n), t_2 ∈ t(n), t_3 ∈ t(n), t_4 ∈ t(n)]; + Y = [che_pol(sum([t_1/1, t_2/2, t_3/3, t_4/4]), q) for t_1 ∈ t(n), t_2 ∈ t(n), t_3 ∈ t(n), t_4 ∈ t(n)]; + S = X .+ Y + Z = X .* Y + + C_x, r_x, σ_x, ϵ_x = tt_svd_ϵ(X, 1e-12); + C_y, r_y, σ_y, ϵ_y = tt_svd_ϵ(Y, 1e-12); + C_s = tt_add(C_x, C_y, 1, 1); + C_z = tt_mult(C_x, C_y); + + Q_s, r_s = t_mpstt_ϵ(C_s, 1e-12); + Q_z, r_z = t_mpstt_ϵ(C_z, 1e-7); + + println("Exercise 3b") + println("|ttmps_eval(C_s) - S||_F/||S||_F = $(norm(S - ttmps_eval(C_s, dims))/norm(S))") + println("|ttmps_eval(C_z) - Z||_F/||Z||_F = $(norm(Z - ttmps_eval(C_z, dims))/norm(Z))") + println() + println("|ttmps_eval(Q_s) - S||_F/||S||_F = $(norm(S - ttmps_eval(Q_s, dims))/norm(S))") + println("|ttmps_eval(Q_z) - Z||_F/||Z||_F = $(norm(Z - ttmps_eval(Q_z, dims))/norm(Z))") +end + +main() diff --git a/sesh5/src/plots/rank_34.png b/sesh5/src/plots/rank_34.png Binary files differ. diff --git a/sesh5/src/plots/rank_57.png b/sesh5/src/plots/rank_57.png Binary files differ. diff --git a/sesh5/src/plots/sigma_34.png b/sesh5/src/plots/sigma_34.png Binary files differ. diff --git a/sesh5/src/plots/sigma_57.png b/sesh5/src/plots/sigma_57.png Binary files differ. diff --git a/sesh5/src/ttmps.jl b/sesh5/src/ttmps.jl @@ -0,0 +1,152 @@ +#/usr/bin/julia + +using LinearAlgebra +using Plots +using Plots.Measures +using Distributions +using LaTeXStrings +using TSVD: tsvd +using TensorToolbox: tenmat, ttm, contract # todo:implement + +@doc raw""" + Output: the k-th TT-MPS unfolding matrix of $A$. + A_{i_1, … , i_n} -> A_{i_1 ⋯ i_{k}, i_{k+1} ⋯ i_d} +""" +function ttmps_unfold(A, k) + n = size(A) + d = length(n) + C = copy(A) + A_k = reshape(C, (prod([n[i] for i in 1:k]), prod([n[i] for i in k+1:d]))) + return A_k +end + +@doc raw""" + TT-MPS decomposition evaluation to a Tensor +""" +function ttmps_eval(U, n) + A = U[1] + for U_k ∈ U[2:end] + A = contract(A, U_k) + end + return reshape(A, n...) +end + +@doc raw""" + Truncated MPS-TT: + Given a decomposition U of ranks $p_1, … ,p_{d-1}$ produce a decomposition of target + ranks not exceeding $r = [r_1, … ,r_{d-1}]$ with the TT-MPS orthogonalization algorithm +""" +function t_mpstt(U, r) + r_n = [1, r..., 1] + d = length(U) + Q = []; U_k = U[1] + for k ∈ 2:d + α_k_1, i_k, α_k = size(U_k) + U_k_bar = reshape(U_k, (α_k_1*i_k, α_k)) + + P_k, Σ_k, W_k = tsvd(U_k_bar, r_n[k]) + Q_k = reshape(P_k, (α_k_1, i_k, r_n[k])) + Z_k = Diagonal(Σ_k) * transpose(W_k) + U_k = contract(Z_k, U[k]) + append!(Q, [Q_k]) + if k == d + append!(Q, [U_k]) + end + end + return Q +end + +@doc raw""" + Truncated MPS-TT: + Same as above but with a tolerace = ϵ, with which the ranks are + approximated. The difference is there are no target ranks required +""" +function t_mpstt_ϵ(U, ϵ) + r = [1] + d = length(U) + dims = [size(U[k], 2) for k ∈ 1:d] + δ = ϵ/sqrt(d-1) * norm(ttmps_eval(U, dims)) + Q = []; U_k = U[1] + for k ∈ 2:d + α_k_1, i_k, α_k = size(U_k) + U_k_bar = reshape(U_k, (α_k_1*i_k, α_k)) + for r_k ∈ 1:rank(U_k_bar) + global P_k, Σ_k, W_k = tsvd(U_k_bar, r_k) + U_k_bar_hat = P_k * Diagonal(Σ_k) * transpose(W_k) + if norm(U_k_bar - U_k_bar_hat)/norm(U_k_bar) ≤ δ + append!(r, r_k) + break + end + end + Q_k = reshape(P_k, (α_k_1, i_k, r[k])) + Z_k = Diagonal(Σ_k) * transpose(W_k) + U_k = contract(Z_k, U[k]) + append!(Q, [Q_k]) + if k == d + append!(Q, [U_k]) + end + end + return Q, r +end + + +@doc raw""" + TT-SVD algorithm +""" +function tt_svd(A, r) + n = size(A) + d = length(n) + r_new = [1, r...] + S_0_hat = copy(A) + S0s = [] + C = []; σ = []; ϵ = [] + for k=2:d + B_k = reshape(S_0_hat, (r_new[k-1] * n[k-1], prod([n[i] for i=k:d]))) + U_hat, Σ_hat, V_hat = tsvd(convert(Matrix{Float64}, B_k), r_new[k]) + C_k = reshape(U_hat, (r_new[k-1], n[k-1], r_new[k])) + W_k_hat = Diagonal(Σ_hat) * transpose(V_hat) + S_0_hat = reshape(W_k_hat, (r_new[k], [n[i] for i=k:d]...)) + + append!(C, [C_k]) + append!(σ, [Σ_hat]) + A_hat = ttmps_eval([C..., S_0_hat], n) + append!(ϵ, norm(A_hat - A)/norm(A)) + end + append!(C, [reshape(S_0_hat, (size(S_0_hat)..., 1))]) + return C, σ, ϵ +end + +@doc raw""" + Tolerace bound TT-SVD algorithm, no target ranks required. + The ranks are calculated based on the tolerace specified. +""" +function tt_svd_ϵ(A, tol) + n = size(A) + d = length(n) + r = [1] + S_0_hat = copy(A) + δ = tol/sqrt(d-1) * norm(A) + C = []; σ = []; ϵ = [] + for k=2:d + B_k = reshape(S_0_hat, (r[k-1] * n[k-1], prod([n[i] for i=k:d]))) + for r_k = 1:rank(B_k) + global U_hat, Σ_hat, V_hat = tsvd(convert(Matrix{Float64}, B_k), r_k) + B_k_hat = U_hat * Diagonal(Σ_hat) * transpose(V_hat) + if norm(B_k - B_k_hat)/norm(B_k) ≤ δ + append!(r, r_k) + break + end + end + C_k = reshape(U_hat, (r[k-1], n[k-1], r[k])) + W_k_hat = Diagonal(Σ_hat) * transpose(V_hat) + S_0_hat = reshape(W_k_hat, (r[k], [n[i] for i=k:d]...)) + + append!(C, [C_k]) + append!(σ, [Σ_hat]) + A_hat = ttmps_eval([C..., S_0_hat], n) + append!(ϵ, norm(A_hat - A)/norm(A)) + end + append!(C, [reshape(S_0_hat, (size(S_0_hat)..., 1))]) + return C, r, σ, ϵ +end +