Tensor Node Notation
Node-QR and Node-SVD
Node-QR
The node-qr is the simple analoge of a matrix-qr for tensor nodes.
In order to proceed a node-qr, we only need to specifiy a mode name in which we want to perform the orthogonalization:
load('TT-format')
G{:}
n = node_size(G)
[Q,R] = node_qr(G{1},'beta_1')
Q is now
-orthogonal and
.
QT_alpha_Q = boxtimes(node_transpose(Q),Q,'_','alpha_1')
unfold(QT_alpha_Q,'beta_1','beta_1')
unfold(R,'beta_1','beta_1')
If we set
and
then we have not changed the tensor represented by G, yet
is now
-orthogonal - or left-orthogonal.
G{1} = Q;
G{2} = boxtimes(R,G{2});
We can also right-orthogonalize
and
. At this point it may feel unusual not transpose R or similar when right-orthogonalizing. Due to the mode name notation, we however do not need to do this. We just have to keep in mind which side of R belongs to Q, which is the left side. Hence, in the following example, the right side belongs to
.
[Q,R] = node_qr(G{4},'beta_3');
G{4} = Q;
G{3} = boxtimes(R,G{3});
[Q,R] = node_qr(G{3},'beta_2');
G{3} = Q;
G{2} = boxtimes(R,G{2});
The network G is now orthogonal with respect to
. This simplifies the calculation of the norm of the represented tensor:
norm(unfold(G{2}))
sqrt(get_data(boxtimes(G{2},G{2})))
T = boxtimes(G);
norm(T.data(:))
Node-SVD
Similarly, we need to specify which mode names we want to split in the SVD, and also how we want to name the new mode names, which will appear in σ.
G{:}
[U,sigma,V] = node_svd(G{2},{'beta_1','alpha_2'},'beta_2')
net_view(U,sigma,V)
We will see easier ways to check the distance between the two tensor nodes in subsequent worksheets, but for now:
norm(unfold(boxtimes(U,sigma,V),G{2}.mode_names)-unfold(G{2}))
We have to be careful not to contract
here:
G{2} = U;
warning('wrong contraction')
net_view(sigma,V,G{3})
sV = boxtimes(sigma,V,'^','beta_2')
net_view(sigma,V,'^','beta_2')
For vectors nodes there is a simple functionality:
Sigma = matrix_node_diag(sigma)
sV = boxtimes(Sigma,V)
G{3} = boxtimes(V,G{3})
At this point,
is an SVD of
with respect to
(because we orthogonalized G with respect to
in the previous section). Note that we only form T to confirm the result.
[U_T,sigma_T,V_T] = node_svd(T,{'alpha_1','alpha_2'},'beta_2')
We compare the singular vectors of both SVDs:
U_U_T = boxtimes(boxtimes(G(1:2)),U_T,'_',{'alpha_1','alpha_2'})
net_view({G(1:2)},U_T,'_',{'alpha_1','alpha_2'}) % net_view is smart here
unfold(U_U_T,'beta_2','beta_2') % same singular vectors
unfold(boxtimes(boxtimes(G(3:4)),V_T,'_',{'alpha_3','alpha_4'}) ,'beta_2','beta_2') % same here
unfold(sigma_T,'beta_2')
unfold(sigma,'beta_2')
net_view(U_T,sigma_T,V_T)
net_view(G(1:2),sigma,G(3:4))
The algorithms ORTHO.m and PATHQR.m
Instead of manual node-QRs we can use to orthogonalize any tree network to one node r, just as we did before with the tensor train format. ORTHO expects N to be a cell containing the nodes of the network corresponding to a tree graph (not a hypergraph!). Each node must not have dublicate mode names. Every mode name must further appear in at most two nodes. We call such a plain network.
help ORTHO
dbtype ORTHO.m 18:36 % it is a rather short code
load('Tucker-format');
Net = [U,C];
Net{:}
net_view(Net)
T = boxtimes(Net);
Net = ORTHO(Net,2);
get_data(boxtimes(T,T))
get_data(boxtimes(Net{2},Net{2}))
Once a network is orthogonal to a node r, it suffices to call PATHQR to change the orthogonalization:
type PATHQR.m
Net = PATHQR(Net,2,5);
get_data(boxtimes(Net{5},Net{5}))