Three dimensional matrix, Cartesian product - arrays

I have three vectors a, b and c. The value of a_i depends is the sum of the Cartesian product of all the values of the vectors b and c, which again is multiplied by a factor of the three dimensional matrix w:
How do I write that in Matlab?

Let b, c be column vectors. The simplest way is to collapse w to a two dimensional matrix, then multiply by b as follows:
w2 = sum(bsxfun(#times,w,shiftdim(c,-2)),3);
a = w2 * b;
Here I test it for random data, for syntax errors:
n = 10;
w = randn(n,n,n);
b = randn(n,1);
c = randn(n,1);
w2 = sum(bsxfun(#times,w,shiftdim(c,-2)),3);
a = w2 * b;
% using loops:
aalt = zeros(n,1);
for ii=1:n
for jj=1:n
for kk=1:n
aalt(ii,1) = aalt(ii,1) + w(ii,jj,kk) * b(jj) * c(kk);
end
end
end
% up to roundoff error:
max(abs(aalt - a))

a = sum(sum(bsxfun(#times, w, shiftdim(bsxfun(#times, b(:), c(:).'), -1)), 3), 2)
Or replace the inner bsxfun by matrix multiplication:
a = sum(sum(bsxfun(#times, w, reshape(b(:)*c(:).',[1 numel(b) numel(c)])), 3), 2)

Related

How to multiply a vector 3 times to get a 3 dimentional matrix

Suppose I have a vector B = [1; 2; 3]. Then
B*B' = [1*1 1*2 1*3 ; 2*1 2*2 2*3 ; 3*1 3*2 3*3]
Now, I need to multiply the new matrix B*B' again with B, in order to get the following 3 dimensional matrix C:
C(:,:,1) = [1*1*1 1*2*1 1*3*1 ; 2*1*1 2*2*1 2*3*1 ; 3*1*1 3*2*1 3*3*1]
C(:,:,2) = [1*1*2 1*2*2 1*3*2 ; 2*1*2 2*2*2 2*3*2 ; 3*1*2 3*2*2 3*3*2]
C(:,:,3) = [1*1*3 1*2*3 1*3*3 ; 2*1*3 2*2*3 2*3*3 ; 3*1*3 3*2*3 3*3*3]
Any ideas how can I do that?
(My original vector is long so I can not do this manually..)
Before R2016b:
C = bsxfun(#times, permute(B, [3 2 1]), B*B');
After R2016b:
C = permute(B, [3 2 1]) .* (B*B');
You can use bsxfun to perform these operations.
out = bsxfun(#times, bsxfun(#times, B, B.'), reshape(B, 1, 1, []));
Or if you want to make it more legible, you can break it out into two operations. First perform the first multiplication.
tmp = bsxfun(#times, B, B.');
Then multiply this by B again (but we reshape B to be 1 x 1 x 3 to make the result a 3D matrix)
out = bsxfun(#times, reshape(B, 1, 1, []));
If you're on R2016b or later, you can just do the following.
out = (B .* B.') .* reshape(B, 1, 1, []);
Another form is to reshape the result of the first matrix multiplication into a column, perform a second matrix multiplication, and reshape the result:
C = reshape(B*reshape(B*B.',1,[]),numel(B)*[1 1 1]);

MATLAB: ceate a x b matrix (or 2D array) from 2 1Darrays, and populate each cell from another array

I am using MATLAB.
So I have 3 arrays; say a,b,c. a and b represent distances, and c represents a variable with a specific value at the point (a,b).
I have been trying to create a matrix which comprises of (b x a) cells, and the populate it with the values of c, in order to then image, heatmap it etc.
However the issue I have having is that there are many repeating values of a and b; a stays fixed and it then iterates across all values of b, then moves onto the next value of a, and so forth. The range of a and b is fixed and always iterate across equally spaced values though.
Below is the code I have created for this. So for it seems to not to work and I am out of ideas.
z_true_len = length(unique(a)); %number of z distances
r_true_len = length(unique(b)); %number of r disatances
data_matrix = zeros(r_true_len,z_true_len); %create r x z matrix, full of 0s
z_past = 0;
r_past = 0;
z_count = 1;
r_count = 1;
for count = 1: length(a)
z_current = a(count);
if z_past ~= z_current
data_matrix(1:z_count) = c(count);
z_past = z_current;
z_count = z_count + 1;
r_count = 1;
else
data_matrix(r_count:z_count) = c(count);
r_count = r_count + 1;
end
end
data_matrix
Any help would be appriciated
I included a mapping of the a and b arrays into a space of integers:
% Data
a = [ 0.5 0.5 2.5 0.5 2.5 2.5 4.5 4.5 4.5 2.5 4.5 0.5];
b = [-35 -25 -25 -15 -45 -35 -35 -45 -15 -15 -25 -45];
c = [2 1 -2 4 6 4 6 8 4 1 -5 2];
% Mapping from real to integers
a_unique = sort(unique(a));
b_unique = sort(unique(b));
a_idx = zeros(size(a));
b_idx = zeros(size(b));
for ii = 1:numel(a_unique),
a_idx(a_unique(ii)==a) = ii;
end
for ii = 1:numel(b_unique),
b_idx(b_unique(ii)==b) = ii;
end
% Create matrix
data_matrix = zeros(numel(b_unique),numel(a_unique));
for count = 1:length(a_idx),
data_matrix(b_idx(count),a_idx(count)) = c(count);
end
% Plot
figure;
imagesc(data_matrix);
You basically need to define data_matrix with the appropriate dimensions, and then fill values in using linear indexing (see sub2ind):
m = max(b); %// number of rows in result
n = max(a); %// number of columns in result
data_matrix = NaN(m,n); %// define result matrix with appropriate dimensions
data_matrix(sub2ind([m n], b, a)) = c; %// fill values using indexing
If a and b don't always contain integers: first transform into "integer labels" with the third output of unique, and then proceed as above:
[~, ~, bb] = unique(b); %// get integer labels for b
[~, ~, aa] = unique(a); %// get integer labels for a
m = max(bb); %// number of rows in result
n = max(aa); %// number of columns in result
data_matrix = NaN(m,n); %// define result matrix with appropriate dimensions
data_matrix(sub2ind([m n], bb, aa)) = c; %// fill values using indexing

How to reshape 1D RGB to 2D RGB image in Matlab?

Suppose I have 1D RGB array of the following structure:
I = [r1 r2 ... rN; g1 g2 ... gN; b1 b2 ... bN];
where
N = H*W;
ans H and W are height and width of the picture respectively.
How to reshape it to colored image format HxW, which is represented by 3D matrix so that
I2(1,1,1) = r1
I2(1,1,2) = g1
I2(1,1,3) = b1
I2(2,1,1) = r2
I2(2,1,2) = g2
I2(2,1,3) = b2
...
I2(H,W,1) = rN
I2(H,W,2) = gN
I2(H,W,3) = bN
(if I am correct thinking that normal 1D -> 2D reshape works by columns)
UPDATE
This reshaping can be done the following way
R = I(1,:);
R = reshape(R,H,W);
G = I(2,:);
G = reshape(G,H,W);
B = I(3,:);
B = reshape(B,H,W);
I2 = cat(3, R, G, B);
Can it be done shorter, with one reshape call for example?
I think that what you're looking for is: reshape(I', H, W, 3)

Finding the best way to define a function of dot product for a 3D grid

I am trying to build the following function in a three dimensional domain.
where is a constant vector, is the position vector, is a constant, and is time.
is a vector of size [1 3], is the array of size [NX*NY*NZ 3] that represents the points in the three-dimensional domain, is constant, and is array of size [1 NT].
The following is the setup of the problem.
dx = 0.1;
dy = 0.5;
dz = 0.1;
[x, y, z] = meshgrid( (1:100)*dx, (1:100)*dy, (1:100)*dz );
X = [x(:) y(:) z(:)];
k = [1 2 3];
c = 0.5;
t = 0:0.1:1;
In fact, the following loop works but it is very slow (~200 seconds).
f = zeros(numel(X)/3, numel(t));
for n = 1:numel(t)
for i = 1:numel(X)/3
f(i, n) = tan(dot(k, X(i,:)+c*t(n)));
end
end
I thought about using arrayfun and repeating the vector k using repmat and dot it with X in the second dimension but I don't know what I should do for the multiplication of c and t.
What would be an efficient way of defining the function for all the points and all the times? The output of this function, for example, looks like an array of size [NX*NY*NZ NT].
bsxfun approach to speedup f calculation -
t1 = bsxfun(#plus,X,permute(c*t,[1 3 2]));
t2 = permute(k(ones(numel(t),1),:),[3 2 1]);
t3 = bsxfun(#times,t1,t2);
f = tan(squeeze(sum(t3,2)));
Or a slight variant -
t1 = bsxfun(#plus,X,permute(c*t,[1 3 2]));
t3 = bsxfun(#times,t1,k);
f = tan(squeeze(sum(t3,2)));
f = tan(sum(bsxfun(#times, permute(k, [1 3 2]), bsxfun(#plus, permute(X, [1 3 2]), c*t)), 3));
Or replace the outer bsxfun by matrix multiplication. This seems to be slightly faster:
f = tan(reshape(reshape(bsxfun(#plus, permute(X, [1 3 2]), c*t), [], 3) * k(:), [size(X,1) numel(t)]));

Multiplication of two arrays with dimension=5 in a vectorize way

I have a three dimensional domain in MATLAB. For each point in the domain I have defined three arrays of size (NX,NY,NZ) at each point of the domain:
A1; % size(A1) = [NX NY NZ]
A2; % size(A2) = [NX NY NZ]
A3; % size(A3) = [NX NY NZ]
For each element, I am trying to construct an array which holds the value of A1, A2, and A3. Would the following be a good candidate for having a 1×3 vector at each point?
B = [A1(:) A2(:) A3(:)];
B = reshape(B, [size(A1) 1 3]);
If the 1×3 array is named C, I am trying to find C'*C at each point.
C = [A1(i,j,k) A2(i,j,k) A3(i,j,k)]; % size(C) = [1 3]
D = C'*C; % size(D) = [3 3]
My ultimate goal is to find the array D with size 3×3 for all the points in the domain in a vectorize fashion? In fact, the output which consists of array D for each point will have the size [NX NY NZ 3 3]. Could someone help me?
Basically we concatenate A1, A2 and A3 along the 4th and 5th dimensions separately that leaves singleton dimensions in the 5th and 4th dimensions respectively, which are then used by bsxfun [Apply element-by-element binary operation to two arrays with singleton expansion enable] to expand as 3x3 matrices along the 4th-5th dimensions for matrix multiplication result from each triplet of [A1(i,j,k),A2(i,j,k),A3(i,j,k)].
D = bsxfun(#times,cat(4,A1,A2,A3),cat(5,A1,A2,A3));

Resources