What is a Mat-lab function for « If-in »? - matlab

Problem statement: Provide a function that does the following: c1) two vectors D1 and D2 have 7 elements each, then form the division between the corresponding components of each vector and assign the result to a vector name D3, placing a statement that avoids division by zero (i.e., does not divide if element to denominator is null);
The idea of the problem, is to set an error message whenever one of the elements of vector D2 is equal to 0.
My attempt:
D1 = [d1 d2 d3 d4 d5 d6 d7]
D2= [d21 d22 d23 d24 d25 d26 d27]
for i= 1:length(D1)
if 0 in D2
fprintf(‘error: division by 0/n’)
else
D3=D1./D2
end
I don’t know if the “if-in” structure exists in Matlab. If it doesn’t, what could be an equivalent?
Thanks in advance!!!

One way to avoid any division by zero is to modify D2 by replacing any 0 with nan. Divisions by nan produce nan, so it's easy to tell which division would have caused a problem by simply inspecting the resulting vector D3. Moreover, almost all Matlab's functions are able to handle nans nicely (i.e. without crashing) or can be instructed to do so by setting some option.
What I've just described can be accomplished by using logical indexing, as follows:
% Definition of D1 and D2
D1 = [d1 d2 d3 d4 d5 d6 d7]
D2 = [d21 d22 d23 d24 d25 d26 d27]
% Replace 0s with NaNs
D2(D2==0) = nan;
% Perform the divisions at once
D3 = D1./D2 ;
For more details on logical indexing, look at the relevant section here.
As the OP requests a function that does the job, here's a possible implementation:
function D3 = vector_divide(D1, D2)
% Verify that vectors are numeric
% and have the same dimensions
if isnumeric(D1) & isnumeric(D2) &...
(size(D1,1) == size(D2,1)) &...
(size(D1,2) == size(D2,2))
% replace 0s with NaNs
D2(D2==0) = nan;
% Perform the divisions at once
D3 = D1./D2 ;
else
disp('D1 and D2 should both be numeric and have the same size!');
D3 = [];
end
Error handling in case of non-numeric arrays or size mismatch might vary depending on project requirements, if any. For instance, I could have used error (instead of disp) to display a message and terminate the program.

Related

Extract Matrix columns and store them in individual vectors

I have a A matrix of size MxN where M is large and N is around 30.
[A,B,C,...,AD] = A(:,1:30)
The reason I am asking that is that I would like to give the columns a specific name (here A,B a,c,...,AD) and not being force to write:
[A,B,C,...,AD] = deal(A(:,1),A(:,2),A(:,3),...,A(:,30))
It's usually better to keep all columns together in the matrix and just access them through their column index.
Anyway, if you really need to separate them into variables, you can convert the matrix to a cell array of its columns with num2cell, and then generate a comma-separated list to be used in the right-hand side of the assignment. Note also that in recent Matlab versions you can remove deal:
A = magic(3); % example matrix
Ac = num2cell(A, 1);
[c1 c2 c3] = Ac{:}; % or [c1 c2 c3] = deal(Ac{:});
For generating that lexicographical sequence I recently, out of ignorance, wrote this
Data = rand(2,671);
r = rem(size(Data,2),26);
m = floor(size(Data,2)/26);
Alf = char('A'+(0:25)'); %TeX-like char seq
if m == 0
zzz = Alf(1:r);
else
zzz = Alf;
for x = 1:m-1
zzz = char(zzz,[char(Alf(x)*ones(26,1)),Alf]);
end
if r > 0
zzz = char(zzz, [char(Alf(m+1)*ones(r,1)),Alf(1:r)] );
end
end
Depending on the number of columns it generates column names until ZZ. Please let me know if there is a readily made command for this in matlab.
You would never ever use eval for such things!!! eval use is dangerous and wrong (but you can't resist):
% ==========
% Assign Data to indices
% ==========
for ind = 1:size(Data,2)
eval([zzz(ind,:) '= Data(:,' num2str(ind) ');']);
end
and your workspace looks like an alphabet soup.

Generating all combinations without repetition using MATLAB

i have 4 sets each contain 6 elements from which I want to generate all possible vectors of size 8 were the first two elements are from set1 second 2 from set2 third 2 from set3 forth 2 from set4 without repetition in the points taken from each set such that the elements 1,2 / 3,4 / 5,6/ 7,8 are always different. My target number combinations is (6choose2)^4 . Any help please.
D1=[2+2i,2+1i,1+2i,1+1i,2,1i];
D2=[-2+2i,-2+1i,-1+2i,-1+1i,-1,2i];
D3=[-2-2i,-2-i,-1-i,-1-1i,-2,-1i];
D4=[2-2i,2-i,1-2i,-1+1i,1,-2i];
So I found a way to get your combinations. You should really have given an more minimal example to explain your problem (that's how I solved it by the way).
The procedure is:
Get all the {2 element} unique combination for each set.
Then build an index of the result you obtain. Normally there should be an index for each subset but since they are all the same length, the number of unique combinations will be the same so you can just reuse 4x the same index.
Get all the combinations of these 4 sets of indices
Finally, rebuild the final matrix based on the indices combinations
The code look like:
%// prepare a few helper numbers
nSets = 4 ;
nElemPerSet = 2 ;
nCombs = nchoosek( numel(D1) ,nElemPerSet).^nSets ; %// <= nCombs=50625
%// for each set, get the unique combinations of 2 elements
s1 = nchoosek( D1 , nElemPerSet ) ;
s2 = nchoosek( D2 , nElemPerSet ) ;
s3 = nchoosek( D3 , nElemPerSet ) ;
s4 = nchoosek( D4 , nElemPerSet ) ;
%// now get the index of all the combinations of the above subsets
s = 1:size(s1,1) ;
combindex = all_combinations( repmat({s},1,4) ) ; %// <= size(combindex)=[50625 4]
%// now rebuild the full combinations based on above indices
combinations = zeros( nCombs , nSets*nElemPerSet ) ;
for ic = 1:nCombs
combinations(ic,:) = [s1(combindex(ic,1),:) s2(combindex(ic,2),:) s3(combindex(ic,3),:) s4(combindex(ic,4),:)] ;
end
There is probably a way to get rid of the last loop with an intelligent use of arrayfun but I leave that as an exercise to the reader.
This code works for your initial values of D1, D2, D3 and D4 as described in your question, but if you or anybody want to run it step by step to understand what's happening, I strongly recommend to try it with much simpler starting values. Something like:
%// define 4 non-complex sets of 4 values each (all different)
nVal=4 ;
D1 = 1:nVal ;
D2 = D1(end)+1:D1(end)+nVal ;
D3 = D2(end)+1:D2(end)+nVal ;
D4 = D3(end)+1:D3(end)+nVal ;
Note the use of the function all_combinations. This is just the answer I was mentioning in the comment (Generate a matrix containing all combinations of elements taken from n vectors) repackaged in a function. I suggest you have a look and bookmark it if you deal with combination problem often (also you can upvote it if it helps you, which it does here).
The repackaged function is:
function combs = all_combinations( vectors )
%// function combs = all_combinations( vectors )
%//
%// example input :
%// vectors = { [1 2], [3 6 9], [10 20] }; %//cell array of vectors
%//
%// Credit: Luis Mendo : https://stackoverflow.com/questions/21895335/generate-a-matrix-containing-all-combinations-of-elements-taken-from-n-vectors
n = numel(vectors); %// number of vectors
combs = cell(1,n); %// pre-define to generate comma-separated list
[combs{end:-1:1}] = ndgrid(vectors{end:-1:1}); %// the reverse order in these two
%// comma-separated lists is needed to produce the rows of the result matrix in
%// lexicographical order
combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
combs = reshape(combs,[],n); %// reshape to obtain desired matrix

Multiple constant to a matrix and convert them into block diagonal matrix in matlab

I have a1 a2 a3. They are constants. I have a matrix A. What I want to do is to get a1*A, a2*A, a3*A three matrices. Then I want transfer them into a diagonal block matrix. For three constants case, this is easy. I can let b1 = a1*A, b2=a2*A, b3=a3*A, then use blkdiag(b1, b2, b3) in matlab.
What if I have n constants, a1 ... an. How could I do this without any looping?I know this can be done by kronecker product but this is very time-consuming and you need do a lot of unnecessary 0 * constant.
Thank you.
Discussion and code
This could be one approach with bsxfun(#plus that facilitates in linear indexing as coded in a function format -
function out = bsxfun_linidx(A,a)
%// Get sizes
[A_nrows,A_ncols] = size(A);
N_a = numel(a);
%// Linear indexing offsets between 2 columns in a block & between 2 blocks
off1 = A_nrows*N_a;
off2 = off1*A_ncols+A_nrows;
%// Get the matrix multiplication results
vals = bsxfun(#times,A,permute(a,[1 3 2])); %// OR vals = A(:)*a_arr;
%// Get linear indices for the first block
block1_idx = bsxfun(#plus,[1:A_nrows]',[0:A_ncols-1]*off1); %//'
%// Initialize output array base on fast pre-allocation inspired by -
%// http://undocumentedmatlab.com/blog/preallocation-performance
out(A_nrows*N_a,A_ncols*N_a) = 0;
%// Get linear indices for all blocks and place vals in out indexed by them
out(bsxfun(#plus,block1_idx(:),(0:N_a-1)*off2)) = vals;
return;
How to use: To use the above listed function code, let's suppose you have the a1, a2, a3, ...., an stored in a vector a, then do something like this out = bsxfun_linidx(A,a) to have the desired output in out.
Benchmarking
This section compares or benchmarks the approach listed in this answer against the other two approaches listed in the other answers for runtime performances.
Other answers were converted to function forms, like so -
function B = bsxfun_blkdiag(A,a)
B = bsxfun(#times, A, reshape(a,1,1,[])); %// step 1: compute products as a 3D array
B = mat2cell(B,size(A,1),size(A,2),ones(1,numel(a))); %// step 2: convert to cell array
B = blkdiag(B{:}); %// step 3: call blkdiag with comma-separated list from cell array
and,
function out = kron_diag(A,a_arr)
out = kron(diag(a_arr),A);
For the comparison, four combinations of sizes of A and a were tested, which are -
A as 500 x 500 and a as 1 x 10
A as 200 x 200 and a as 1 x 50
A as 100 x 100 and a as 1 x 100
A as 50 x 50 and a as 1 x 200
The benchmarking code used is listed next -
%// Datasizes
N_a = [10 50 100 200];
N_A = [500 200 100 50];
timeall = zeros(3,numel(N_a)); %// Array to store runtimes
for iter = 1:numel(N_a)
%// Create random inputs
a = randi(9,1,N_a(iter));
A = rand(N_A(iter),N_A(iter));
%// Time the approaches
func1 = #() kron_diag(A,a);
timeall(1,iter) = timeit(func1); clear func1
func2 = #() bsxfun_blkdiag(A,a);
timeall(2,iter) = timeit(func2); clear func2
func3 = #() bsxfun_linidx(A,a);
timeall(3,iter) = timeit(func3); clear func3
end
%// Plot runtimes against size of A
figure,hold on,grid on
plot(N_A,timeall(1,:),'-ro'),
plot(N_A,timeall(2,:),'-kx'),
plot(N_A,timeall(3,:),'-b+'),
legend('KRON + DIAG','BSXFUN + BLKDIAG','BSXFUN + LINEAR INDEXING'),
xlabel('Datasize (Size of A) ->'),ylabel('Runtimes (sec)'),title('Runtime Plot')
%// Plot runtimes against size of a
figure,hold on,grid on
plot(N_a,timeall(1,:),'-ro'),
plot(N_a,timeall(2,:),'-kx'),
plot(N_a,timeall(3,:),'-b+'),
legend('KRON + DIAG','BSXFUN + BLKDIAG','BSXFUN + LINEAR INDEXING'),
xlabel('Datasize (Size of a) ->'),ylabel('Runtimes (sec)'),title('Runtime Plot')
Runtime plots thus obtained at my end were -
Conclusions: As you can see, either one of the bsxfun based methods could be looked into, depending on what kind of datasizes you are dealing with!
Here's another approach:
Compute the products as a 3D array using bsxfun;
Convert into a cell array with one product (matrix) in each cell;
Call blkdiag with a comma-separated list generated from the cell array.
Let A denote your matrix, and a denote a vector with your constants. Then the desired result B is obtained as
B = bsxfun(#times, A, reshape(a,1,1,[])); %// step 1: compute products as a 3D array
B = mat2cell(B,size(A,1),size(A,2),ones(1,numel(a))); %// step 2: convert to cell array
B = blkdiag(B{:}); %// step 3: call blkdiag with comma-separated list from cell array
Here's a method using kron which seems to be faster and more memory efficient than Divakar's bsxfun based solution. I'm not sure if this is different to your method, but the timing seems pretty good. It might be worth doing some testing between the different methods to work out which is more efficient for you problem.
A=magic(4);
a1=1;
a2=2;
a3=3;
kron(diag([a1 a2 a3]),A)

Vectorising 5 nested FOR loops

I am writing a program in MATLAB as a part of my project based on DFT.
Let the N x N data matrix be X and the corresponding DFT matrix be Y, then the DFT coefficients can be expressed as
Y(k1,k2) = ∑(n1=0:N-1)∑(n2=0:N-1)[X(n1,n2)*(WN^(n1k1+n2k2))] (1)
0≤k1,k2≤N-1
Where WN^k=e^((-j2πk)/N)
Since the twiddle factor WN is periodic, (1) can be expressed as
Y(k1,k2)=∑(n1=0:N-1)∑(n1=0:N-1)[X(n1,n2)*(WN^([(n1k1+n2k2)mod N) ] (2)
The exponent ((n1k1 +n2k2)) N = p is satisfied by a set of (n1,n2) for a given (k1,k2). Hence, by grouping such data and applying the property that WN^(p+N /2) = -(WN^P),
(2) can be expressed as
Y(k1,k2)= ∑(p=0:M-1)[Y(k1,k2,p)*(WN^p)] (3)
Where
Y(k1,k2,p)= ∑(∀(n1,n2)|z=p)X(n1,n2) - ∑(∀(n1,n2)|z=p+M)X(n1,n2) (4)
z=[(n1k1+n2k2)mod N] (5)
I am coding a program to find Y(k1,k2,p).ie I need to create slices of 2d matrices(ie a 3D matrix in which each slice is a 2D matrix )from a given 2D square matrix (which is the matrix X)..Dimensions of X can be upto 512.
Based on the above equations,I have written a code as follows.I need to vectorise it.
N=size(X,1);
M=N/2;
Y(1:N,1:N,1:M)=0;
for k1 = 1:N
for k2 = 1:N
for p= 1:M
for n1=1:N
for n2=1:N
N1=n1-1; N2=n2-1; P=p-1; K1=k1-1; K2=k2-1;
z=mod((N1*K1+N2*K2),N);
if (z==P)
Y(k1,k2,p)= Y(k1,k2,p)+ X(n1,n2);
elsif (z==(P+M))
Y(k1,k2,p)= Y(k1,k2,p)- X(n1,n2);
end
end
end
end
end
As there is 5 FOR loops, the execution time is very large for large dimensions of N. Hence please provide me a solution for eliminating the FOR loops and vectorising the code..I need to make the code execute in maximum speed...Thanks Again..
Here is a first hint to vectorize the most inner loop.
From your code, we can notice that n1, N1, P, K1 and K2 are constant in this loop.
So we can rewrite z as a mask vector as follows:
z = mod(N1*K1+K2*(0:N-1));
Then your if-statement is equivalent to adding the sum of all elements in X so that z==P minus the sum of all elements in X so that z==P+M. Rewriting this is straightforward:
Y(k1,k2,p)= Y(k1,k2,p)+sum(X(n1,z==P))-sum(X(n1,z==P+M));
So your program can be first written as follows:
N=size(X,1);
M=N/2;
Y(1:N,1:N,1:M)=0;
for k1 = 1:N
for k2 = 1:N
for p= 1:M
for n1=1:N
N1=n1-1; P=p-1; K1=k1-1; K2=k2-1;
z=mod(N1*K1+K2*(0:N-1),N);
Y(k1,k2,p) = sum(X(n1,z==P))-sum(X(n1,z==P+M));
end
end
end
end
Then you can do the same thing with n1; for that, you need to construct a 2D array for z, such as:
z = mod(K1*repmat(0:N-1,N,1)+K2*repmat((0:N-1).',1,N));
Notice that size(z)==size(X).Then the 2D sum for Y becomes:
Y(k1,k2,p) = Y(k1,k2,p)+sum(X(z==P))-sum(X(z==P+M));
The += operation is here no longer needed, since you access only once to each element of Y:
Y(k1,k2,p)= sum(X(n1,z==P))-sum(X(n1,z==P+M));
And so we discard one more loop:
N=size(X,1);
M=N/2;
Y(1:N,1:N,1:M)=0;
for k1 = 1:N
for k2 = 1:N
for p= 1:M
P=p-1; K1=k1-1; K2=k2-1;
z = mod(K1*repmat(0:N-1,N,1)+K2*repmat((0:N-1).',1,N));
Y(k1,k2,p) = sum(X(z==P))-sum(X(z==P+M));
end
end
end
Concerning the other loops, I don't think it worths it to vectorize them, as you have to build a 5D array, which could be very huge in memory. My advise is to keep z as a 2D array, as it is of the size of X. If it does not fit well in memory, just vectorize the most inner loop.

MATLAB: Transform a flat file list into a multi-dimensional array

I am completely stuck with this: I start out with a flat file type of list I get from an SQL statement like this and want to transform it into a 4D array.
SELECT a1, a2, a3, a4, v FROM table A;
a1 a2 a3 a4 v
--------------
2 2 3 3 100
2 1 2 2 200
3 3 3 3 300
...
a1 to a4 are some identifiers (integers) from a range of (1:5), which are also the coordinates for the new to be populated 4D array.
v is a value (double) e.g. a result from a measurement.
What I now want is to transform this list into a 4D array of dimension (5,5,5,5) where each v is put at the right coordinates.
This could easily be done using a for loop, however as I have lots of data this is not really feasible.
If I had just 1 dimension, I would do somesthing like this:
a1 = [2;5;7]; % Identifiers
v = [17;18;19]; % Values
b1 = (1:10)'; % Range of Identifiers
V = zeros(10,1); % Create result vector with correct dimensions
idx = ismember(b1, a1); % Do the look up
V(idx) = v; % Insert
My question: How can I do this for the above mentioned 4D array without using a for loop. Is there a "Matlab Way" of doing it?
Any help is greatly appreciated!
Thanks,
Janosch
You should be able to do what you want using linear indexing, and the sub2ind function. It would look something like this.
x=zeros(5,5,5,5); %initialize output vector
i = sub2ind(size(x),a1,a2,a3,a4);
x(i) = v;