The inverse operation of tensor circular unfolding in Julia - arrays

I implemented Tensor Circular Unfolding (TCU) defined in this document (See Definition 2).
The TCU reshapes a tensor (or multidimensional array) X into a matrix (or two-dimensional array). By using TensorToolbox, I implemented that as follows:
using TensorToolbox
function TCU(X,d,k)
N = ndims(X)
#assert d < N
if d <= k
a = k-d+1
else
a = k-d+1+N
end
tenmat(permutedims(X,circshift(1:N,-a+1)),row=1:d)
end
for positive integers d<N and k≦N where N is the depth of input tensor X. The function tenmat comes from TensorToolbox.jl and it is for matricization of a tensor. Please see ReadMe file in TensorToolbox.jl.
Here I put an example with N=4.
X = rand(1:9,3,4,2,2)
#3×4×2×2 Array{Int64, 4}:
#[:, :, 1, 1] =
# 5 7 2 6
# 4 5 6 2
# 6 8 9 1
#
#[:, :, 2, 1] =
# 4 3 7 5
# 8 3 3 1
# 8 2 4 7
#
#[:, :, 1, 2] =
# 4 3 9 6
# 7 4 9 2
# 6 7 2 4
#
#[:, :, 2, 2] =
# 9 2 1 7
# 8 2 1 3
# 6 2 4 9
M = TCU(X, 2, 3)
#8×6 Matrix{Int64}:
# 5 4 4 7 6 6
# 7 3 5 4 8 7
# 2 9 6 9 9 2
# 6 6 2 2 1 4
# 4 9 8 8 8 6
# 3 2 3 2 2 2
# 7 1 3 1 4 4
# 5 7 1 3 7 9
What I need
I would like to write the reverse operation of the above function. That is, I need the function InvTCU that satisfies
X == InvTCU( TCU(X, d, k), d, k )
If we need, InvTCU can require the original tensor size size(X)
X == InvTCU( TCU(X, d, k), d, k, size(X) )
The reason why I need InvTCU
It is required in Equation (18) in the document to implement the algorithm named PTRC. In this situation, the size of the original tensor size(X) are available information.
EDIT
I added the description about tenmat.
I added the description that InvTCU can require the original tensor size.

Before giving the function, it might be noted that to get the matrixfied tensor, it is possible to use views instead of permuting the dimensions, which might be more efficient (depending on processing later). This can be done (I think) with the TrasmuteDims or TensorCast packages (https://docs.juliahub.com/TransmuteDims/NIYrh/0.1.15/).
Here is an attempt at a permutedims approach:
function invTCU(M,d,k, presize)
N = length(presize)
a = d<=k ? k-d+1 : k-d+1+N
X = reshape(M,Tuple(circshift(collect(presize),1-a)))
permutedims(X,circshift(1:N,a-1))
end
with this definition:
julia> X = reshape(1:48,3,4,2,2)
3×4×2×2 reshape(::UnitRange{Int64}, 3, 4, 2, 2) with eltype Int64:
[:, :, 1, 1] =
1 4 7 10
...
julia> X == invTCU(TCU(X, 2, 3), 2, 3, size(X))
true
seems to recover original tensor.

Related

MATLAB: Remove specific elements from array

Question 1: I have a 1x15 array, comprising of positive integers and negative integers. I wish to implement a MATLAB code which keeps all positive integers and skips the cells with negative contents.
I have tried the following:
X = [1 2 3 4 5 -10 1 -5 4 6 8 9 2 4 -2];
[r c] = size(X);
for i=1:r
for j=1:c
if X(i,j)<0
X(i,j)=X(i,j+1)
end
end
end
The output should be:
X_new = [1 2 3 4 5 1 4 6 8 9 2 4]
How do I do this?
Question 2:
X = [1 2 3 4 5 -10 1 -5 4 6 8 9 2 4 -2]
Y = [5 3 8 9 4 5 6 7 4 7 9 5 2 1 4]
From Question 1,
X_new = [1 2 3 4 5 1 4 6 8 9 2 4]
I need to delete the corresponding values in Y so that:
Y_new = [5 3 8 9 4 6 4 7 9 5 2 1]
How do I perform this?
In MATLAB, manipulating arrays and matrices can be done much easier than for-loop solutions,
in your task, can do find and delete negative value in the array, simply, as follows:
Idx_neg = X < 0; % finding X indices corresponding to negative elements
X ( Idx_neg ) = []; % removing elements using [] operator
Y ( Idx_neg ) = []; % removing corresponding elements in Y array

Reshape the array along the reverse dimensions

>> A = [ 1 2 3 3 4 5 5 6 7 7 8 9 ];
>>
>> B = reshape(A, 2, 2, 3)
B(:,:,1) =
1 3
2 3
B(:,:,2) =
4 5
5 6
B(:,:,3) =
7 8
7 9
Since reshape can only change the size of the given array in the way of preserving the linear indices, however I would like to reshape the array along the reverse dimensions.
For example, convert A into
>> C = reverse-reshape(A, 2, 2, 3) % not required to be only one function
C(:,:,1) =
1 3
5 7
C(:,:,2) =
2 4
6 8
C(:,:,3) =
3 5
7 9
Is there any better method than writing loops and fill numbers one by one in version R2017b?
You would first reshape with the dimensions in reverse order, then swap the first and third dimensions with permute to reorder the elements so that they are populated in reverse order:
>> B = permute(reshape(A, 3, 2, 2), [3 2 1])
B(:,:,1) =
1 3
5 7
B(:,:,2) =
2 4
6 8
B(:,:,3) =
3 5
7 9
To do this in general independent of the matrix dimensions and assuming it is a 3D matrix, declare an array called dims that contains the output desired matrix size, reverse the elements and supply this into reshape:
dims = [2 2 3];
B = permute(reshape(A, fliplr(dims)), [3 2 1]);
fliplr reverses the elements in a matrix horizontally.

Extract blocks of certain number from array

I have a vector and I would like to extract all the 4's from it:
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4]
so that I will get 4 vectors or a cell containing the 4 blocks of 4's:
[4 4], [4], [4 4 4], [4 4 4 4]
Thanks!
You can create cells from the appropriate ranges using arrayfun:
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4];
x = [0, x, 0]; D = diff (x==4); % pad array and diff its mask
A = find (D == 1); B = find (D == -1); % find inflection points
out = arrayfun (# (a,b) {x(a+1 : b)}, A, B) % collect ranges in cells
This should be pretty fast, using accumarray:
X = 4;
%// data
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4]
%// mask all 4
mask = x(:) == X
%// get subs for accumarray
subs = cumsum( diff( [0; mask] ) > 0 )
%// filter data and sort into cell array
out = accumarray( subs(mask), x(mask), [], #(y) {y} )
idx=find(x==4);
for (i= 1:length(idx))
if (i==1 || idx(i-1)!=idx(i)-1)if(i!=1) printf(",") endif; printf("[") endif;
printf("4");
if (i<length(idx)&&idx(i+1)==idx(i)+1) printf(",") else printf("]") endif
endfor
Note this won't give the actual vectors, but it will give the output you wanted. The above is OCtave code. I am pretty sure changing endfor and endif to end would work in MAtlab, but without testing in matlab, I am not positive.[edited in light of comment]
with regionprops we can set property PixelValues so the function returns 1s instead of 4s
x = [1 1 1 4 4 5 5 4 6 1 2 4 4 4 9 8 4 4 4 4]
{regionprops(x==4,'PixelValues').PixelValues}
if we set property PixelIdxList the function returns a cell of indices of 4s:
{regionprops(x==4,'PixelIdxList').PixelIdxList}
Update(without image processing toolbox):
this way we can get number of elements of each connected components:
c = cumsum(x~=4)
h=hist(,c(1):c(end));
h(1)=h(1)+~c(1);
result = h(h~=1)-1

Efficient "window-select" array blocks?

Suppose I have the following array:
x = [a b
c d
e f
g h
i j];
I want to "swipe a window of two rows" progressively (one row at a time) along the array to generate the following array:
y = [a b c d e f g h
c d e f g h i j];
What is the most efficient way to do this? I don't want to use cellfun or arrayfun or for loops.
im2col is going to be your best bet here if you have the Image Processing Toolbox.
x = [1 2
3 4
5 6
7 8];
im2col(x.', [1 2])
% 1 2 3 4 5 6
% 3 4 5 6 7 8
If you don't have the Image Processing Toolbox, you can also easily do this with built-ins.
reshape(permute(cat(3, x(1:end-1,:), x(2:end,:)), [3 2 1]), 2, [])
% 1 2 3 4 5 6
% 3 4 5 6 7 8
This combines the all rows with the next row by concatenating a row-shifted version along the third dimension. Then we use permute to shift the dimensions around and then we reshape it to be the desired size.
If you don't have the Image Processing Toolbox, you can do this using simple indexing:
x =
1 2
3 4
5 6
7 8
9 10
y = x.'; %% Transpose it, for simplicity
z = [y(1:end-2); y(3:end)] %% Take elements 1:end-2 and 3:end and concatenate them
z =
1 2 3 4 5 6 7 8
3 4 5 6 7 8 9 10
You can do the transposing and reshaping in a simple step (see Suever's edit), but the above might be easier to read, understand and debug for beginners.
Here's an approach to solve it for a generic case of selecting L rows per window -
[m,n] = size(x) % Store size
% Extend rows by indexing into them with a progressive array of indices
x_ext = x(bsxfun(#plus,(1:L)',0:m-L),:);
% Split the first dim at L into two dims, out of which "push" back the
% second dim thus created as the last dim. This would bring in the columns
% as the second dimension. Then, using linear indexing reshape into the
% desired shape of L rows for output.
out = reshape(permute(reshape(x_ext,L,[],n),[1,3,2]),L,[])
Sample run -
x = % Input array
9 1
3 1
7 5
7 8
4 9
6 2
L = % Window length
3
out =
9 1 3 1 7 5 7 8
3 1 7 5 7 8 4 9
7 5 7 8 4 9 6 2

Building all possible arrays from vector of subarrays. With recursion [duplicate]

This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 8 years ago.
I'm trying to build all possible arrays of length n of a vector of n elements with at least 2 integers in each position. I should be getting 2^n combinations, 16 in this case. My code is generating only half of them, and not saving the output to an array
allinputs = {[1 2] [2 3] [3 4] [5 6]}
A = []
the command I run is
inputArray = inputBuilder(A,[],allinputs,1)
for the function
function inputArray = inputBuilder(A,currBuild, allInputs, currIdx)
if currIdx <= length(allInputs)
for i = 1:length(allInputs{currIdx})
mybuild = [currBuild allInputs{currIdx}(i)];
inputBuilder(A,mybuild,allInputs,currIdx + 1);
end
if currIdx == length(allInputs)
A = [A mybuild];
%debug output
mybuild
end
if currIdx == 1
inputArray = A;
end
end
end
I want all 16 arrays to get output in a vector. Or some easy way to access them all. How can I do this?
EDIT:
Recursion may be a requirement because allinputs will have subarrays of different lengths.
allinputs = {[1] [2 3] [3 4] [5 6 7]}
with this array it will be 1*2*2*3 or 12 possible arrays built
Not sure exactly if this is what you want, but one way of doing what I think you want to do is as follows:
allinputs = {[1 2] [2 3] [3 4] [5 6]};
comb_results = combn([1 2],4);
A = zeros(size(comb_results));
for rowi = 1:size(comb_results, 1)
indices = comb_results(rowi,:);
for idxi = 1:numel(indices)
A(rowi, idxi) = allinputs{idxi}(indices(idxi));
end
end
This gives:
A =
1 2 3 5
1 2 3 6
1 2 4 5
1 2 4 6
1 3 3 5
1 3 3 6
1 3 4 5
1 3 4 6
2 2 3 5
2 2 3 6
2 2 4 5
2 2 4 6
2 3 3 5
2 3 3 6
2 3 4 5
2 3 4 6
combn is here.

Resources