Tensor Node Notation
Alternating Optimization
Solving a linear equation
In the following, we will look at the solution of linear systems given in tensor networks
The single networks A, N and T will be assumed to be plain, and that no single node has dublicate mode names.
First we construct (with inner mode names γ) as finite differences Laplacian in the TT-format, which has rank 2, and then approximate it with an HT-representation.
d = 6;
n_discr = 30;
alpha = mna('alpha',1:d);
omega = mna('omega',1:d);
gamma = mna('gamma',1:d-1);
n_alpha = assign_mode_size(alpha,n_discr);
n_omega = assign_mode_size(omega,n_discr);
n_gamma = assign_mode_size(gamma,2);
n = merge_fields(n_alpha,n_omega,n_gamma);
% Parts in Laplacian:
D2 = gallery('tridiag',n_discr,-1,2,-1);
I = eye(n_discr);
O = zeros(n_discr);
mn = cell(1,d);
A = cell(1,d);
mn{1} = [omega(1),alpha(1),gamma(1)];
A{1} = fold([I,D2],mn{1},n);
for i = 2:d-1
mn{i} = [omega(i),gamma(i-1),alpha(i),gamma(i)];
A{i} = fold([I,D2;O,I],mn{i},n);
end
mn{d} = [omega(d),gamma(d-1),alpha(d)];
A{d} = fold([D2;I],mn{d},n);
net_view(A)
We can easily determine the TT-singular values of A:
[~,fA,sigmaA] = STAND(A);
get_data(sigmaA{1})
get_data(sigmaA{2})
get_data(sigmaA{3})
Approximation through an HT-representation
A is given as TT-representation, but with a simple alternating least squares scheme, we may transfer it to any other tree tensor format of rank 2:
S = binary_tree([alpha;omega]);
[G,m,~,~,beta] = RTLGRAPH([alpha,omega],S,'beta');
n_beta = assign_mode_size(beta,2);
n = merge_fields(n,n_beta);
AHT = init_net(m,n);
AHT = randomize_net(AHT);
net_view(AHT)
The simple ALS algorithm performs iter_max steps in order to minimize .
type ALS.m
net_view(AHT,A)
AHT = ALS(AHT,A,1) % one iteration is already sufficient since the rank is exactly 2
net_dist(AHT,A)/net_norm(A)
AHT = ALS(AHT,A,3) % does not help
net_dist(AHT,A)/net_norm(A)
One might of course construct A as HT-representation directly in order to avoid round-off errors.
Solving a linear system
We can solve any linear minimization problem using LINSOLVE, however under the slight mode name assumptions mentioned above. Here T will be rank one and would not need inner mode names. But we will assign such for a better overview. Each single micro step will make use of the normal equation. The correct structure of the network is further ensured using ghost nodes. LINSOLVE is however unreasonable for higher order tensors, since no computations are recycled (other than for LINSOLVE_EQUALNET).
S = linear_tree(omega);
[G,m,~,~,rho] = RTLGRAPH(omega,S,'rho');
n_rho = assign_mode_size(rho,1);
n = merge_fields(n,n_rho);
T = init_net(m,n);
for i = 1:length(T)
T{i}.data(:) = 1;
end
net_view(T)
For , we use a TT-representation with rank 5 and inner mode names δ:
S = linear_tree(alpha);
[G,m,~,~,beta] = RTLGRAPH(alpha,S,'delta');
n_beta = assign_mode_size(beta,6);
n = merge_fields(n,n_beta);
N = init_net(m,n);
N = randomize_net(N);
net_view(N)
type LINSOLVE
b = 2;
all_but_b = ~(1:numel(N)==b);
net_view({A,N(all_but_b),ghost(N{b})},{A,N(all_but_b),ghost(N{b})}); % here with A in a TT-format
boxtimes({A,N(all_but_b),ghost(N{b})},{A,N(all_but_b),ghost(N{b})})
save('Laplacian','AHT','A','N','T')
deactivate_boxtimes_mem()
tic
N = LINSOLVE(AHT,N,T,20)
seconds_without_memory = toc
net_dist({AHT,N},T)/sqrt(get_data(boxtimes(T,T)))
net_view({AHT,N},T,'Layout','force3')
view([-4.70 2.00])
view([-9.10 22.00])
Speed up with boxtimes memory:
load('Laplacian','AHT','A','N','T')
activate_boxtimes_mem()
tic
N = LINSOLVE(AHT,N,T,20)
toc
seconds_without_memory
net_dist({AHT,N},T)/sqrt(get_data(boxtimes(T,T))) % same result as above
Linear equations in equal networks
If the involved networks are all of equal structure, then we can use the faster, more complicated LINSOLVE_EQUALNET, which makes use of the normal equation in each one of the nodes:
where
Unfortunately, we can not resolve the brackets in the lower equation since some mode names will appear twice. This problem can be resolved by renaming mode names until each contraction is uniquely identified by one mode name. We therefore change
to
where and are defined to always have the same value as A and N, but just with different mode names. We can then restate
The mode names in both sides of the right-hand side equation then allow to arbitrarily disassemble each of the two products and evaluate parts of it branch-wise. In the code, the renaming works as follows. Instead of names such as , the mode names in LINSOLVE_EQUALNET will be generic . Sometimes one might therefore prefer to rename modes name manually.
type LINSOLVE_EQUALNET.m
load('Laplacian','AHT','A','N','T')
N = randomize_net(N);
nF = length(T);
nA = length(A);
nN = length(N);
Net = {T,{A,N}};
[Z,glob_repl,outer_mn_id,seed] = get_mn_replacements(Net);
Z
[Z,~,renaming1] = rename_mn(Z,glob_repl,outer_mn_id);
T = Z(1:nF);
A = Z(nF+1:nF+nA);
N = Z(nF+nA+1:end);
renaming1
Net = {A,N};
[Z,glob_repl,outer_mn_id] = get_mn_replacements(Net,seed);
[Z,~,~,prime_rn] = rename_mn(Z,glob_repl,outer_mn_id);
A_prime = Z(1:nA);
N_prime = Z(nA+1:end);
prime_rn
net_view(T,A,N) % no brackets necessary anymore
net_view(N_prime,A_prime,A,N) % no brackets necessary anymore
b = 2;
all_but_b = ~(1:numel(N)==b);
net_view(N_prime(all_but_b),A_prime,A,N(all_but_b)); % also no ghost nodes necessary anymore
Running linsolve_equalnet
The algorithm is not to be understood as a high performance tool. On the other hand, it is not terribly slow either:
data_volume(A)
data_volume(N)
activate_boxtimes_mem();
N = randomize_net(N);
tic
N = LINSOLVE_EQUALNET(A,N,T,5);
toc
net_dist({A,N},T)/net_norm(T)