Is there a cleaner (as in, ideally built in; I've never used Matlab so apologies if I missed something obvious) way to do k-smallest argmin in Matlab (i.e. if an array is [4,5,6,7] it should return the indexes 1,2 in that order) besides stuff like:
arr = [4,5,6,7];
[~, argmin1] = min(arr);
arr(argmin1) = Inf;
[~, argmin2] = min(arr);
...
Say we want indices of k smallest element in array arr, then:
arr=[4,5,6,7,2];
[~,indices]=sort(arr,'ascend');
argmin=indices(1:k);
If one want k highest values, use descend argument instead.
Related
I have a function A(k) which returns a matrix dependent on k when I type for example A(1). I want to automatically create the matrix:
[A(3)*A(2)*A(1) A(3)*A(2) A(3)]
In Mathematica I can do for example:
Table[Apply[Dot,Table[A(k),{k,3,i,-1}]],{i,1,3}]
Assume A(k) is a function which returns a 3x3 matrix. For example typing A(1) may return:
[1,2,3;4,5,6;7,8,9]
Explanation of Mathematica code: Table[A(k),{k,3,i,-1}] is a "loop" from k=3 to k=i with each iteration decrementing k by -1. Therefore the output would be a list {A(3),A(2),...,A(i)}... obviously k starting from 3 then for i=2 the output list will be {A(3),A(2)}. The function Apply[Dot,Table[A(k),{k,3,i,-1}]] multiplied the elements of the list together. For i=2 this produces A(3)*A(2). Finally, Table[Apply[Dot,Table[A(k),{k,3,i,-1}]],{i,1,3}] applies the same logic as the first statement, looping i from 1 to 3. Because the inner table depends on i, this creates a list of elements {A(3)*A(2)*A(1),A(3)*A(2),A(3)}. A list is Mathematica's version of a matrix.
How can I achieve the same effect in MATLAB, i.e. not use a for loop to achieve the result? Thanks!
For the record, here's a looping version, mostly for subsequent timing checks. This is not the answer you want, but the answer you need;)
N = 10; %size of A
old = eye(N);
M2 = [];
for i=3:-1:1
new = old*A(i);
M2 = [new M2];
old = new;
end
Or if you want to be really efficient (which is probably not the case):
N = 10; %size of A
M2 = A(3);
old = M2;
for i=2:-1:1
new = old*A(i);
M2 = [new M2];
old = new;
end
This answer basically is the solution to the problem, but as we are discussing efficient use of matlab I want to leave my thoughts here how to use Matlab efficient. Instead of the large 2D-Matrix it is much simpler to create a 3D-Matrix where the results of each multiplication are stacked. If a 3D-Matrix is acceptable use the code as it is, otherwise comment in the last line to get a 2D-matrix.
M3=[];
n=3;
M3(:,:,n) = A(n);
for ix=n-1:-1:1
M3(:,:,ix) = M3(:,:,ix+1)*A(i);
end
%M3=reshape(M3,size(M3,1),[]);
You can use arrayfun() with indexes as parameters, eg:
%// Compute the product A(3)*A(2)*...*A(idx)
F = #(idx) prod(reshape(cell2mat(arrayfun(A,3:-1:idx, 'UniformOutput', false)),10,10,4-idx),3);
%// Use the last function with idx=1:3
M = cell2mat(arrayfun(F,1:3, 'UniformOutput', false));
I have a calculation that I want to perform element by element.
foreach i from i=1 to i=N
RES_i = det(A - V_i * I) // notice V_i and RES_i are SCALARS
where for example A is 3x3 , I is 3x3, V and RES are 1xN.
so basically what I do is
idx=1:81
res(idx) = det( A - V(idx)*I );
BUT, this get interperted as taking the whole of V and multiplying by I.
this seems like a simple example but I can't figure out how to vectorize it...
Thanks.
First, this isn't Matlab code...
Second: I think you confuse "vectorization" with an implicit loop. Vectorization means to apply an operation to a whole arrays at once, using vector/matrix/tensor notation and operations. What you want is however an implicit for-each type loop, and it makes total sense that Matlab complains about it.
There's no other way than to write it out explicitly:
res = zeros(81,1);
for ii = 1:numel(res)
res(ii) = det(A-V(ii)*I);
end
You perform element-by-element operation by using . together with the operator of choice. For example:
Element-by-element multiplication: .*
Element-by-element division: ./
and so on... is that what you mean?
I have a matrix with integers and I need to replace all appearances of 2 with -5. What is the most efficient way to do it? I made it the way below, but I am sure there is more elegant way.
a=[1,2,3;1,3,5;2,2,2]
ind_plain = find(a == 2)
[row_indx col_indx] = ind2sub(size(a), ind_plain)
for el_id=1:length(row_indx)
a(row_indx(el_id),col_indx(el_id)) = -5;
end
Instead of loop I I seek for something like: a(row_indx,col_indx) = -5, which does not work.
find is not needed in this case.
Use logical indexing instead:
a(a == 2) = -5
In case of searching whether a matrix is equal to inf you should use
a(isinf(a)) = -5
The general case is:
Mat(boolMask) = val
where Mat is your matrix, boolMask is another matrix of logical values, and val is the assignment value
Try this:
a(a==2) = -5;
The somewhat longer version would be
ind_plain = find(a == 2);
a(ind_plain) = -5;
In other words, you can index a matrix directly using linear indexes, no need to convert them using ind2sub -- very useful! But as demonstrated above, you can get even shorter if you index the matrix using a boolean matrix.
By the way, you should put semicolons after your statements if (as is usually the case) you're not interested in getting the result of the statement dumped out to the console.
The Martin B's method is good if you are changing values in vector. However, to use it in matrix you need to get linear indices.
The easiest solution I found is to use changem function. Very easy to use:
mapout = changem(Z,newcode,oldcode)
In your case: newA = changem(a, 5, -2)
More info: http://www.mathworks.com/help/map/ref/changem.html
Here's a trivial, unoptimised, probably slow implementation of changem from the Mapping Toolbox.
function mapout = changem(Z, newcode, oldcode)
% Idential to the Mapping Toolbox's changem
% Note the weird order: newcode, oldcode. I left it unchanged from Matlab.
if numel(newcode) ~= numel(oldcode)
error('newcode and oldcode must be equal length');
end
mapout = Z;
for ii = 1:numel(oldcode)
mapout(Z == oldcode(ii)) = newcode(ii);
end
end
Is there any way to use a for-loop in MATLAB with a custom step? What I want to do is iterate over all powers of 2 lesser than a given number. The equivalent loop in C++ (for example) would be:
for (int i = 1; i < 65; i *= 2)
Note 1: This is the kind of iteration that best fits for-loops, so I'd like to not use while-loops.
Note 2: I'm actually using Octave, not MATLAB.
Perhaps you want something along the lines of
for i=2.^[1:6]
disp(i)
end
Except you will need to figure out the range of exponents. This uses the fact that since
a_(i+1) = a_i*2 this can be rewritten as a_i = 2^i.
Otherwise you could do something like the following
i=1;
while i<65
i=i*2;
disp(i);
end
You can iterate over any vector, so you can use vector operations to create your vector of values before you start your loop. A loop over the first 100 square numbers, for example, could be written like so:
values_to_iterate = [1:100].^2;
for i = values_to_iterate
i
end
Or you could loop over each position in the vector values_to_iterate (this gives the same result, but has the benefit that i keeps track of how many iterations you have done - this is useful if you are writing a result from each loop sequentially to an output vector):
values_to_iterate = [1:100].^2;
for i = 1:length(values_to_iterate)
values_to_iterate(i)
results_vector(i) = some_function( values_to_iterate(i) );
end
More concisely, you can write the first example as simply:
for i = [1:100].^2
i
end
Unlike in C, there doesn't have to be a 'rule' to get from one value to the next.
The vector iterated over can be completely arbitrary:
for i = [10, -1000, 23.3, 5, inf]
i
end
Let's say I want to take the sin of 1 through 100 (in degrees).
I come from a C background so my instinct is to loop 1 through 100 in a for loop (something I can do in Matlab). In a matrix/vector/array I would store sin(x) where x is the counter of the for loop.
I cannot figure out how to do this in Matlab. Do I create a array like
x = [1 .. 100];
And then do
x[offset] = numberHere;
I know the "correct" way. For operations like addition you use .+ instead of + and with a function like sin I'm pretty sure you just do
resultArray = sin(x);
I just want to know that I could do it the C way in case that ever came up, thus my question here on SO. :)
% vectorized
x = sin((1:100)*pi/180);
or
% nonvectorized
x=[];
for i = 1:100
x(i) = sin(i*pi/180);
end
I beleive this can actually be done as a one liner in MatLab:
x = sind(1:100);
Note that you use sind() instead of sin(). Sin() takes radians as arguments.
As others have already pointed out there are for-loops in MATLAB as well.
help for
should give you everything you need about how it works. The difference from C is that the loop can go over objects and not only an integer:
objects = struct('Name', {'obj1', 'obj2'}, 'Field1', {'Value1','Value2'});
for x = objects
disp(sprintf('Object %s Field1 = %d', x.Name, x.Field1))
end
That example will output:
Object obj1 Field1 = Value1
Object obj2 field1 = Value2
This could have been done as
for i=1:length(objects)
x = objects(i);
disp(sprintf('Object %s Field1 = %d', x.Name, x.Field1))
end
And now to what I really wanted to say: If you ever write a for loop in MATLAB, stop and think!. For most tasks you can vectorize the code so that it uses matrix operations and builtin functions instead of looping over the data. This usually gives a huge speed gain. It is not uncommon that vectorized code executes 100x faster than looping code. Recent versions of MATLAB has JIT compilation which makes it less dramatic than before, but still: Always vectorize if you can.
#Daniel Fath
I think you'll need the final line to read
resultArray(i) = sin(x(i)) (rather than x(1))
I think you can also do:
for i = x
...
though that will behave differently if x is not a simple 1-100 vector
Hmm, if understand correctly you want a loop like structure
resultArray = zeros(1,length(x)) %% initialization aint necessary I just forgot how you dynamically add members :x
for i = 1:length(x) %% starts with 1 instead of zero
resultArray(i) = sin(x(i))
end
Warning I didn't test this but it should be about right.