Find the m-th smallest number in Matlab? [duplicate] - matlab

This question already has answers here:
How to find the index of the n smallest elements in a vector
(2 answers)
Closed 9 years ago.
Is there an efficient way to find the m-th smallest number in a vector of length n in Matlab? Do I have to use sort() function? Thanks and regards!

You don't need to sort the list of numbers to find the mth smallest number. The mth smallest number can be found out in linear time. i.e. if there are n elements in your array you can get a solution in O(n) time by using the selection algorithm and median of median algorithm.
The link is to the Wikipedia article,
http://en.wikipedia.org/wiki/Selection_algorithm#Linear_general_selection_algorithm_-_Median_of_Medians_algorithm

Edit 2: As Eitan pointed the first part of the answer doesn't address the question of finding the smallest m-th value but regarding the m-th element after the min value. The rest of the answer remains... +1 for Eitan's sharpness.
While sort is probably very efficient to begin with, you can try to see whether a find will be better. For example:
id=find(X>min(X),m,'first');
id(end) % is the index of the smallest m-th element in X
the function find has added functionality that lets you find the 'first' or 'last' elements that meet some criterion. For example, if you want to find the first n elements in array X less than a value y, use find(X<y,n,'first')
This operation stops as soon as the first element meeting the condition is encountered, which can result in significant time savings if the array is large and the value you find happens to be far from the end.
I'd also like to recap what #woodchips said already in this SO discussion that is somewhat relevant to your question:
The best way to speed up basic built-in algorithms such as sort is to get a faster hardware. It will speed everything else up too. MATLAB is already doing that in an efficient manner, using an optimized code internally. Saying this, maybe a GPU add-on can improve this too...
Edit:
For what it's worth, adding to Muster's comment, there is a FEX file called nth_element that is a MEX wrap of C++ that will get a solution in O(n) time for what you need. (similar to what #DDD pointed to)

As alternative solution, you may follow this way:
A = randi(100,4000,1);
A = sort(A,'ascend');
m = 5; % the 5 smallest numbers in array A
B = A(1:5);
I hope this helps.

Related

Matlab function NNZ, numerical zero

I am working on a code in Least Square Non Negative solution recovery context on Matlab, and I need (with no more details because it's not that important for this question) to know the number of non zero elements in my matrices and arrays.
The function NNZ on matlab does exactly what I want, but it happens that I need more information about what Matlab thinks of a "zero element", it could be 0 itself, or the numerical zero like 1e-16 or less.
Does anybody has this information about the NNZ function, cause I couldn't get the original script
Thanks.
PS : I am not an expert on Matlab, so accept my apologies if it's a really simple task.
I tried "open nnz", on Matlab but I only get a small script of commented code lines...
Since nnz counts everything that isn't an exact zero (i.e. 1e-100 is non-zero), you just have to apply a relational operator to your data first to find how many values exceed some tolerance around zero. For a matrix A:
n = nnz(abs(A) > 1e-16);
Also, this discussion of floating-point comparison might be of interest to you.
You can add in a tolerance by doing something like:
nnz(abs(myarray)>tol);
This will create a binary array that is 1 when abs(myarray)>tol and 0 otherwise and then count the number of non-zero entries.

(matlab matrix operation), Is it possible to get a group of value from matrix without loop?

I'm currently working on implementing a gradient check function in which it requires to get certain index values from the result matrix. Could someone tell me how to get a group of values from the matrix?
To be specific, for a result matrx res with size M x N, I'll need to get element res(3,1), res(4,2), res(1,3), res(2,4)...
In my case, M is dimension and N is batch size and there's a label array whose size is 1xbatch_size, [3 4 1 2...]. So the desired values are res(label(:),1:batch_size). Since I'm trying to practice vectorization programming and it's better not using loop. Could someone tell me how to get a group of value without a iteration?
Cheers.
--------------------------UPDATE----------------------------------------------
The only idea I found is firstly building a 'mask matrix' then use the original result matrix to do element wise multiplication (technically called 'Hadamard product', see in wiki). After that just get non-zero element out and do the sum operation, the code in matlab should look like:
temp=Mask.*res;
desired_res=temp(temp~=0); %Note: the temp(temp~=0) extract non-zero elements in a 'column' fashion: it searches temp matrix column by column then put the non-zero number into container 'desired_res'.
In my case, what I wanna do next is simply sum(desired_res) so I don't need to consider the order of those non-zero elements in 'desired_res'.
Based on this idea above, creating mask matrix is the key aim. There are two methods to do this job.
Codes are shown below. In my case, use accumarray function to add '1' in certain location (which are stored in matrix 'subs') and add '0' to other space. This will give you a mask matrix size [rwo column]. The usage of full(sparse()) is similar. I made some comparisons on those two methods (repeat around 10 times), turns out full(sparse) is faster and their time costs magnitude is 10^-4. So small difference but in a large scale experiments, this matters. One benefit of using accumarray is that it could define the matrix size while full(sparse()) cannot. The full(sparse(subs, 1)) would create matrix with size [max(subs(:,1)), max(subs(:,2))]. Since in my case, this is sufficient for my requirement and I only know few of their usage. If you find out more, please share with us. Thanks.
The detailed description of those two functions could be found on matlab's official website. accumarray and full, sparse.
% assume we have a label vector
test_labels=ones(10000,1);
% method one, accumarray(subs,1,[row column])
tic
subs=zeros(10000,2);
subs(:,1)=test_labels;
subs(:,2)=1:10000;
k1=accumarray(subs,1,[10, 10000]);
t1=toc % to compare with method two to check which one is faster
%method two: full(sparse(),1)
tic
k2=full(sparse(test_labels,1:10000,1));
t2=toc

What is the meaning of [] in a matlab function argument? [duplicate]

This question already has an answer here:
How to use reshape in Matlab?
(1 answer)
Closed 7 years ago.
I found the following function call:
reshape(A, 1, [])
This flattens matrix A colum major. I am trying to understand the call. The function documentation says after A there should be a size vector for the reshaped matrix, but in here there is a one followed by [] instead of a two-vector. Is this a way of saying "Do whatever it takes so the matrix will have one row, I don't care what the width is"?
How come Matlab lets you exchange one argument for two like this? I tried googling around and did not find an explanation, and I want to understand what's going on here.
[] is an empty matrix. In many MATLAB built-in functions, an empty matrix is interpreted to mean "use the default argument here" or "automatically determine this value". Occasionally it is used to disambiguate two meanings of a function, as with the max function, where max(A,2) compares each element of A to 2 and returns the larger, while max(A,[],2) finds the largest element of each row.
If you read the help for reshape, you will see the following:
You can specify a single dimension size of [] to have the dimension size automatically calculated, such that the number of elements in B matches the number of elements in A. For example, if A is a 10-by-10 matrix, then reshape(A,2,2,[]) reshapes the 100 elements of A into a 2-by-2-by-25 array.

Partitioning a number into a number of almost equal partitions

I would like to partition a number into an almost equal number of values in each partition. The only criteria is that each partition must be in between 60 to 80.
For example, if I have a value = 300, this means that 75 * 4 = 300.
I would like to know a method to get this 4 and 75 in the above example. In some cases, all partitions don't need to be of equal value, but they should be in between 60 and 80. Any constraints can be used (addition, subtraction, etc..). However, the outputs must not be floating point.
Also it's not that the total must be exactly 300 as in this case, but they can be up to a maximum of +40 of the total, and so for the case of 300, the numbers can sum up to 340 if required.
Assuming only addition, you can formulate this problem into a linear programming problem. You would choose an objective function that would maximize the sum of all of the factors chosen to generate that number for you. Therefore, your objective function would be:
(source: codecogs.com)
.
In this case, n would be the number of factors you are using to try and decompose your number into. Each x_i is a particular factor in the overall sum of the value you want to decompose. I'm also going to assume that none of the factors can be floating point, and can only be integer. As such, you need to use a special case of linear programming called integer programming where the constraints and the actual solution to your problem are all in integers. In general, the integer programming problem is formulated thusly:
You are actually trying to minimize this objective function, such that you produce a parameter vector of x that are subject to all of these constraints. In our case, x would be a vector of numbers where each element forms part of the sum to the value you are trying to decompose (300 in your case).
You have inequalities, equalities and also boundaries of x that each parameter in your solution must respect. You also need to make sure that each parameter of x is an integer. As such, MATLAB has a function called intlinprog that will perform this for you. However, this function assumes that you are minimizing the objective function, and so if you want to maximize, simply minimize on the negative. f is a vector of weights to be applied to each value in your parameter vector, and with our objective function, you just need to set all of these to -1.
Therefore, to formulate your problem in an integer programming framework, you are actually doing:
(source: codecogs.com)
V would be the value you are trying to decompose (so 300 in your example).
The standard way to call intlinprog is in the following way:
x = intlinprog(f,intcon,A,b,Aeq,beq,lb,ub);
f is the vector that weights each parameter of the solution you want to solve, intcon denotes which of your parameters need to be integer. In this case, you want all of them to be integer so you would have to supply an increasing vector from 1 to n, where n is the number of factors you want to decompose the number V into (same as before). A and b are matrices and vectors that define your inequality constraints. Because you want equality, you'd set this to empty ([]). Aeq and beq are the same as A and b, but for equality. Because you only have one constraint here, you would simply create a matrix of 1 row, where each value is set to 1. beq would be a single value which denotes the number you are trying to factorize. lb and ub are the lower and upper bounds for each value in the parameter set that you are bounding with, so this would be 60 and 80 respectively, and you'd have to specify a vector to ensure that each value of the parameters are bounded between these two ranges.
Now, because you don't know how many factors will evenly decompose your value, you'll have to loop over a given set of factors (like between 1 to 10, or 1 to 20, etc.), place your results in a cell array, then you have to manually examine yourself whether or not an integer decomposition was successful.
num_factors = 20; %// Number of factors to try and decompose your value
V = 300;
results = cell(1, num_factors);
%// Try to solve the problem for a number of different factors
for n = 1 : num_factors
x = intlinprog(-ones(n,1),1:n,[],[],ones(1,n),V,60*ones(n,1),80*ones(n,1));
results{n} = x;
end
You can then go through results and see which value of n was successful in decomposing your number into that said number of factors.
One small problem here is that we also don't know how many factors we should check up to. That unfortunately I don't have an answer to, and so you'll have to play with this value until you get good results. This is also an unconstrained parameter, and I'll talk about this more later in this post.
However, intlinprog was only released in recent versions of MATLAB. If you want to do the same thing without it, you can use linprog, which is the floating point version of integer programming... actually, it's just the core linear programming framework itself. You would call linprog this way:
x = linprog(f,A,b,Aeq,beq,lb,ub);
All of the variables are the same, except that intcon is not used here... which makes sense as linprog may generate floating point numbers as part of its solution. Due to the fact that linprog can generate floating point solutions, what you can do is if you want to ensure that for a given value of n, you could loop over your results, take the floor of the result and subtract with the final result, and sum over the result. If you get a value of 0, this means that you had a completely integer result. Therefore, you'd have to do something like:
num_factors = 20; %// Number of factors to try and decompose your value
V = 300;
results = cell(1, num_factors);
%// Try to solve the problem for a number of different factors
for n = 1 : num_factors
x = linprog(-ones(n,1),[],[],ones(1,n),V,60*ones(n,1),80*ones(n,1));
results{n} = x;
end
%// Loop through and determine which decompositions were successful integer ones
out = cellfun(#(x) sum(abs(floor(x) - x)), results);
%// Determine which values of n were successful in the integer composition.
final_factors = find(~out);
final_factors will contain which number of factors you specified that was successful in an integer decomposition. Now, if final_factors is empty, this means that it wasn't successful in finding anything that would be able to decompose the value into integer factors. Noting your problem description, you said you can allow for tolerances, so perhaps scan through results and determine which overall sum best matches the value, then choose whatever number of factors that gave you that result as the final answer.
Now, noting from my comments, you'll see that this problem is very unconstrained. You don't know how many factors are required to get an integer decomposition of your value, which is why we had to semi-brute-force it. In fact, this is a more general case of the subset sum problem. This problem is NP-complete. Basically, what this means is that it is not known whether there is a polynomial-time algorithm that can be used to solve this kind of problem and that the only way to get a valid solution is to brute-force each possible solution and check if it works with the specified problem. Usually, brute-forcing solutions requires exponential time, which is very intractable for large problems. Another interesting fact is that modern cryptography algorithms use NP-Complete intractability as part of their ciphertext and encrypting. Basically, they're banking on the fact that the only way for you to determine the right key that was used to encrypt your plain text is to check all possible keys, which is an intractable problem... especially if you use 128-bit encryption! This means you would have to check 2^128 possibilities, and assuming a moderately fast computer, the worst-case time to find the right key will take more than the current age of the universe. Check out this cool Wikipedia post for more details in intractability with regards to key breaking in cryptography.
In fact, NP-complete problems are very popular and there have been many attempts to determine whether there is or there isn't a polynomial-time algorithm to solve such problems. An interesting property is that if you can find a polynomial-time algorithm that will solve one problem, you will have found an algorithm to solve them all.
The Clay Mathematics Institute has what are known as Millennium Problems where if you solve any problem listed on their website, you get a million dollars.
Also, that's for each problem, so one problem solved == 1 million dollars!
(source: quickmeme.com)
The NP problem is amongst one of the seven problems up for solving. If I recall correctly, only one problem has been solved so far, and these problems were first released to the public in the year 2000 (hence millennium...). So... it has been about 14 years and only one problem has been solved. Don't let that discourage you though! If you want to invest some time and try to solve one of the problems, please do!
Hopefully this will be enough to get you started. Good luck!

How can i increase speed of for loop in matlab? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I want to read the value of pixcels in image result to compare this value with some
I use to for loop
function GrdImg= GrdLbp(VarImg,mapping,LbpImg)
tic
p=mapping.samples;
[Ysize,Xsize]=size(result);
GImg=zeros(Ysize,Xsize);
temp=[];
cnt=1;
for n=0:p-1
temp(cnt)=2^n;
temp(cnt+1)=(2^p)-1-(2^n);
cnt=cnt+2;
end
for i=1:Ysize
i
for j=1:Xsize
if isempty(find(result(i,j)==temp(:,:)))==1
GImg(i,j)=sqrtm(Vresult(i,j));
end
end
end
but it works too slow, Could you help me what can I use instead of for loop?
Thanks a lot
You didn't really give enough information to answer your question - since, as was stated in the comments, you aren't doing anything with the values in the loop right now. So let me give you a few ideas:
1) To compare all the pixels with a fixed value, and return the index of all pixels greater than 90% of the maximum:
threshold = 0.9 * max(myImage(:));
prettyBigPixels = find(myImage > threshold);
2) To set all pixels < 5% of max to zero:
threshold = 0.05 * max(myImage(:));
myImage(myImage < threshold) = 0;
In the first case, the find command returns all the indices (note - you can access a 2D matrix of MxN with a single index that goes from 1 to M*N). You can use ind2sub to convert to the individual i, j coefficients if you want to.
In the second case, putting (myImage < threshold) as the index of the matrix is called logical indexing - it is very fast, and will access only those elements that meet the criterion.
If you let us know what you're actually doing with the values found we can speed things up more; because right now, the net result of your code is that when the loop is finished, your value Temp is equal to the last element - and since you did nothing in the loop we can rewrite the whole thing as
Temp = pixel(end);
EDIT Now that you show what you are doing in your inner loop, we can optimize more. Behzad already showed how to speed up the computation of the vector temp - nothing to add there, it's the right way to do it. As for the two nested loops, which are likely the place where most time is spent, you can find all the pixels you are interested in with a single line:
pixelsOfInterest = find(~ismember(result(:), temp(:)));
This will find the index of pixels in result that do not occur in temp. You can then do
GImg(pixelsOfInterest) = sqrt(result(pixelsOfInterest));
These two lines together should replace the functionality of everything in your code from for i=1:Ysize to the last end. Note - your variables seem to be uninitialized, and change names - sometimes it's result, sometimes it's Vresult. I am not trying to debug that; just giving you a fast implementation of your inner loop.
As of question completely edited I answer new rather than edit my former answer, by the way.
You can improve your code in some ways:
1. instead of :
for n=0:p-1
temp(cnt)=2^n;
temp(cnt+1)=(2^p)-1-(2^n);
cnt=cnt+2;
end
use this one:
temp=zeros(1,2*p);
n=0:p-1;
temp(1:2:2*p)=2.^n; %//for odd elements
temp(2:2:2*p)=2^p-1-2.^n; %//for even elements (i supposed p>1)
2.when code is ready for calculating and not for debugging or other times, NEVER make some variables to print on screen because it makes too long time (in cpu cycles) to run. In your code there are some variables like i that prints on screen. remove them or end up them by ;.
3.You can use temp(:) in last rows because temp is one-dimensional
4.Different functions are for different types of variables. in this code you can use sqrt() instead of sqrtm(). it may be slightly faster.
5. The big problem in this code is in your last comparison, if non elemnt of temp matrix is not equal with result specific element then do something! its hard to make this part improved unless knowing the real aim of the code! you may be solve the problem in other algorithm that has completely different code. But if there is no way, so use it in this way (nested loops) Good Luck!
It seems your image is grayscle or monocolor , because Temp=pixel(i,j) gives a number not 3-numbers by the way.
Your question has not more explanation so I think in three type of numbers that you are comparison with.
compare with a constant number
compare with a series of numbers
compare with a two dimensional matrix of numbers
If first or third one is your need, solution is very easy (absolutely in third one, size of matrix must be equal to pixel size)
Comparison with a number (c is number or two-dimensional array)
comp=pixel - c;
But if second one is your need, you can first reshape pixel to one-dimensional matrix then compare it with the series of number s (absolutely length of this serie must be equal to product of pixel rows number and columns number; you can re-reshape pixel matrix after comparison to primary two dimensional matrix.
Comparison with a number serie s
pixel_temp = reshape(pixel,1,[]);
comp = pixel_temp - s;
pixel_compared = reshape(pixel_temp,size(pixel,1),size(pixel,2)); % to re-reshape to primary size