summation values in structure in matlab - matlab

I have a 3-by-3-by-3 struct, struct, with fields bit. In each field I have two values. I want to divide values of each field by a summation of values of each field in dimension 3
for example if
struct(1,1,1).bit=[2, 3]
struct(1,1,2).bit=[4, 5]
struct(1,1,3).bit=[6, 7]
my new struct values must be for example:
newstruct(1,1,1).bit=[2/(2+4+6) , 3/(3+5+7)]
newstruct(1,1,2).bit=[4/(2+4+6) , 5/(3+5+7)]
newstruct(1,1,3).bit=[6/(2+4+6) , 7/(3+5+7)]

As it is MATLAB, you should possibly go with an nD array instead of the struct.
Yet, if you still want to do it this way, don't fear the good old for-loop:
for d1 = 1:size(in,1)
for d2 = 1:size(in,2)
d3sum = sum(cat(1,in(d1,d2,:).bit),1);
for d3 = 1:size(in,3)
out(d1,d2,d3).bit = in(d1,d2,d3).bit./d3sum;
end
end
end

I think the only way to do this is with a for loop, or to use nD arrays:
s(1,1,1).bit = [2 3];
s(1,1,2).bit = [4 5];
s(1,1,3).bit = [6 7];
[m,n,p] = size(s);
[mm,nn] = size(s(1,1,1).bit); % assume all elements of the structure have the same dimension
struct_sum = zeros(1,nn);
% compute the sums
for k=1:p
struct_sum = struct_sum+s(1,1,k).bit;
end
% create the new stucture
for k=1:p
s1(1,1,k).bit = s(1,1,k).bit./struct_sum;
end
UPDATE: option with nD array
s(1,1,1,1:2)=[2 3];
s(1,1,2,1:2)=[4 5];
s(1,1,3,1:2)=[6 7];
s1 = s./sum(s); % you can specify sum(s,3) to sum along the 3rd dimension - you may also need to use squeeze(...) to remove unnecessary dimensions
Check it gives the correct results:
>> s1(1,1,:,1)
ans =
ans(:,:,1) = 0.16667
ans(:,:,2) = 0.33333
ans(:,:,3) = 0.50000
>> [2 4 6]/12
ans =
0.16667 0.33333 0.50000
>> s1(1,1,:,2)
ans =
ans(:,:,1) = 0.20000
ans(:,:,2) = 0.33333
ans(:,:,3) = 0.46667
>> [3 5 7]/15
ans =
0.20000 0.33333 0.46667

Related

MATLAB multidimensional array

I have been trying to use the multidimensional array function to store NxN vectors of length n in each (i,j) entry of a 3d matrix of NxNxn dimensions.
My code looks like:
a=zeros(N,N,n);
a(i,j,:)=v_ij; %here v is a vector of length n, which differs for each i,j
However when I try to extract each vector by typing e.g. a(1,1,:) I don't get a nice vector. Rather I get something like:
ans(:,:,1) = ..
ans(:,:,2) = ..
...
I don't understand why it says ans(:,:)...
That's because each vector v_ij is stored along the 3rd dimension of your matrix, so when you access a(1,1,:), you are looking for a multidimensional array consisting of every value at the location (1,1) along the 3rd dimension of a.
Let's consider a simple example:
N = 2;
n = 3;
a = zeros(N,N,n);
for k = 1:N
for l = 1:N
v_kl = randi([0 10],1,n);
a(k,l,:) = v_kl;
end
end
The randomly-generated matrix a is a 2x2x3 matrix that looks like this:
a(:,:,1) =
4 1
4 10
a(:,:,2) =
0 2
0 5
a(:,:,3) =
2 2
9 5
Therefore, using a(1,1,:) is equivalent to getting the element located at (1,1) for all 3 dimensions, here it would be 4,0 and 2.
Indeed, calling a(1,1,:) yields:
ans(:,:,1) =
4
ans(:,:,2) =
0
ans(:,:,3) =
2
Benoit_11's answer plus squeeze should work, but I would like to propose a different solution.
Rather than creating a NxNxn array, why not make it nxNxN?
N = 2;
n = 3;
a = zeros(n,N,N);
for p = 1:N
for q = 1:N
v_pq = randi([0 10],1,n);
a(:,p,q) = v_pq;
if (p == 1) && (q == 1)
v_pq %// display vector at a(:,1,1)
end
end
end
a
v_pq =
3 4 8
a =
ans(:,:,1) =
3 3
4 9
8 7
ans(:,:,2) =
5 6
10 1
9 5
Now the vectors are stored along the first dimension, so [3 4 8] shows up as the first column of ans(:,:,1). To access it you would use a(:,p,q) rather than a(p,q,:):
a(:,1,1)
ans =
3
4
8

Design a simple matrix to group values from matrices

This problem is a succession of my previous problem:
1) Extract submatrices, 2) vectorize and then 3) put back
Now, I have two patients, named Ann and Ben.
Indeed the matrices A and B are data for Ann and the matrix C is data for Ben:
Now, I need to design a matrix M such that y = M*x where
y = [a11, a21, a12, a22, b11, b21, b12, b22]' which is a vector, resulting from concatenation of the top-left sub-matrices, Ann and Ben;
x = [2, 5, 4, 6, 7, 9, 6, 2, 9, 3, 4, 2]' which is a vector, resulting from concatenation of sub-matrices A, B and C.
Here, the M is a 8 by 12 matrix that
a11 = 2 + 7, a21 = 5 + 9, .., a22 = 6 + 2 and b11 = 9, ..b22 = 2.
I design the M manually by:
M=zeros(8,12)
M(1,1)=1; M(1,5)=1; % compute a11
M(2,2)=1; M(2,6)=1; % compute a21
M(3,3)=1; M(3,7)=1; % compute a12
M(4,4)=1; M(4,8)=1; % compute a22
M(5,9)=1; % for setting b11 = 9, C(1,1)
M(6,10)=1; % for setting b21 = 3, C(2,1)
M(7,11)=1; % for setting b12 = 4, C(1,2)
M(8,12)=1 % for setting b22 = 2, C(2,2)
Obviously, in general for M(i,j), i means the 8 linear-index position of vector y and j means linear-index position of vector x.
However, I largely simplified my original problem that I want to construct this M automatically.
Thanks in advance for giving me a hand.
Here you have my solution. I have essentially build the matrix M automatically (from the proper indexes) as you suggested.
A = [2 4 8;
5 6 3;
10 3 6];
B = [7 6 3;
9 2 9;
10 2 3];
C = [9 4 7;
3 2 5;
10 3 4];
% All matrices in the same array
concat = cat(3, A, B, C);
concat_sub = concat(1:2,1:2,:);
x = concat_sub(:);
n = numel(x)/3; %Number of elements in each subset
M2 = zeros(12,8); %Transpose of the M matrix (it could be implemented directly over M but that was my first approach)
% The indexes you need
idx1 = 1:13:12*n; % Indeces for A
idx2 = 5:13:12*2*n; % Indices for B and C
M2([idx1 idx2]) = 1;
M = M2';
y = M*x
I have taken advantage of the shape that the matrix M shold take:
You can index into things and extract what you want without multiplication. For your example:
A = [2 4 8; 5 6 3; 10 3 6];
B = [7 6 3; 9 2 9; 10 2 3];
C = [9 4 7;3 2 5; 10 3 4];
idx = logical([1 1 0;1 1 0; 0 0 0]);
Ai = A(idx);
Bi = B(idx);
Ci = C(idx);
output = [Ai; Bi; Ci];
y = [Ai + Bi; Ci]; % desired y vector
This shows each step individually but they can be done in 2 lines. Define the index and then apply it.
idx = logical([1 1 0;1 1 0;0 0 0]);
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Also you can use linear indexing with idx = [1 2 4 5]' This will produce the same subvector for each of A B C. Either way works.
idx = [1 2 4 5]';
or alternatively
idx = [1;2;4;5];
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Either way works. Check out doc sub2ind for some examples of indexing from MathWorks.

cross product of multidimensional arrays

I have two vectors and , each of them has three coordinates which have sizes 80x80x2000.
I want to calculate the cross product in MATLAB of these two vectors for each time moment. I know that I can extract individually coordinates in nested loops but is it possible to make it avoiding any loops?
here is the sample code with loops
m1x = cat(3, [1 2; 3 4], [5 6; 7 8]);
m1y = cat(3, [9 10; 11 12], [13 14; 15 16]);
m1z = cat(3, [17 18; 19 20], [21 22; 23 24]);
m2x = cat(3, [5 6; 2 6], [1 3; 7 9]);
m2y = cat(3, [6 7; 3 5], [2 11; 2 6]);
m2z = cat(3, [3 9; 0 1], [4 2; 3 15]);
result_x(2,2,2)=0; result_y(2,2,2)=0; result_z(2,2,2)=0;
for t=1:2
for i=1:2
for j=1:2
a = [m1x(i,j,t); m1y(i,j,t); m1z(i,j,t);];
b = [m2x(i,j,t); m2y(i,j,t); m2z(i,j,t);];
c = cross(a,b);
result_x(i,j,t) = c(1);
result_y(i,j,t) = c(2);
result_z(i,j,t) = c(3);
end;
end;
end;
so finally I have three components x,y and z of resulting vector for each moment of time
For example, if you have matrices A and B, such that each one has t (time) rows and 3 columns (x, y, z) or if you can reshape them to arrive at this configuration, you can use:
C=cross(A,B);
and each row t in C will be the cross-product of the corresponding rows in A and B. Example:
>> A=[rand(2000,1),rand(2000,1),rand(2000,1)];
>> B=[rand(2000,1),rand(2000,1),rand(2000,1)];
>> C=cross(A,B);
>> C(1,:)
ans =
0.0090 -0.0435 0.0756
>> cross(A(1,:),B(1,:))
ans =
0.0090 -0.0435 0.0756

Extracting a specific element from each cell within cell array

I have a cell array A of size 10x10 (say). Each cell in turn contains a 5x20 matrix. I want to select (i,j) element from each cell, where (i,j) are indices within a loop. I can run 4 for loops and easily get the answer. It may even be faster as it has been discussed many times that loops could be faster than cellfun, structfun etc.
Still, is there any solution using cellfun which I can use in a loop over (i,j) and extract (i,j) element in each cell? I tried writing a function which will act as handle to cellfun but I couldn't access two-leves down i.e. A{eachCellRow,eachCellCol}(i,j).
Example:
If A={[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
Then for i=1, j=1 and i=2, j=1 output should be:
B=[1 3; 3 9] and B=[5 6; 6 5]
CELL2MAT gets all the data from a cell array that consists of numeric data only, into a numeric array. So, that helped us here. For your original problem, try this -
celldim_i = 10;
celldim_j = 10;
block_size_i = 5;
block_size_j = 20;
search_i = i; %// Edit to your i
search_j = j; %// Edit to your j
A_mat = cell2mat(A);
out = A_mat(search_i+block_size_i*(0:celldim_i-1),search_j+block_size_j*(0:celldim_j-1))
The easy to use cellfun one-liner would be:
ii = 2;
jj = 1;
A = {[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
B = cell2mat( cellfun( #(x) x(ii,jj), A, 'uni', 0) )
gives:
B =
5 6
6 5
Advantage over Divakar's Solution: it works also for inconsistent matrix sizes in A.
And if you want to avoid also the outer loop, another fancy two-liner:
dim = [2 2];
[II, JJ] = meshgrid( 1:dim(1), 1:dim(2) );
C = cellfun( #(y) ...
{ cell2mat( cellfun( #(x) x( real(y), imag(y) ), A, 'uni', 0) ) },...
num2cell( II(:)+1i*JJ(:) ))
gives:
>> celldisp(C)
C{1} = % ii = 1 , jj = 1
1 3
3 9
C{2} = % ii = 1 , jj = 2
2 4
4 8
C{3} = % ii = 2 , jj = 1
5 6
6 5
C{4} = % ii = 2 , jj = 2
6 7
7 6
If memory is not an issue, you can concat all matrices along a third dim; and then indexing is very easy:
%// Example data
A = {[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
ii = 2;
jj = 1;
%// Compute the result B
A2 = cat(3,A{:}); %// concat along third dim
B = reshape(A2(ii,jj,:),size(A{1})); %// index A2 and reshape

Extracting subvector of a vector

I have a set of values (say 20 values) in an array .
A = [1:20]
I want to divide it in to subsets of known size.
If I want to divide it in to 4 sets of size 5 then I can use
y = reshape(A,5,4)'
But my problem is when I dont have matching multiples of sizes.
Say I want to divide array in to sets of 3. So there will be 7 sets but the last set will be short.
what exactly I want is
a1= [1 2 3]
a2= [4 5 6]
a3= [7 8 9]
a4= [10 11 12]
a5= [13 14 15]
a6= [16 17 18]
a7= [19 20]
How can I do this kind of subgrouping to a vector in MATLAB?
You can use
y = mat2cell(A,1, diff([0:n:numel(A)-1 numel(A)]));
Then a1=y{1} and so on.
You'll need to write your own function for this. For example:
A = 1:20;
n = length(A);
x = 3;
y = ceil(n/x);
out = cell(y,1);
for i = 1:y
startIdx = x*(i-1)+1;
endIdx = min(startIdx + x - 1,n);
out{i} = A(startIdx:endIdx);
end
Then you can access each row in the cell array:
a1 = out{1};
a2 = out{2};
...
A = 1:20;
n = 3;
% y = number of sets
y = ceil(length(A) / n);
ai = num2cell(reshape(A(1:n*y),m,n)');
if length(A) > n * y
ai = [ai; A(n*y+1:end)];
end