I would like to obtain all the permutations with replacement of d elements chosen in a set of n elements (which are numbers from 0 to n-1) in MATLAB. I noticed that on MATLAB Central the method npermutek is available, but I would like to try another implementation.
My idea is to make d for loops, one inside the other, each varying an index from 0 to n-1: i.e., d recursions over a line (from 0 to n-1). However, n and d should be parameters of my code, so I cannot implement my idea of d for loops one inside the other... or could I? Do you have any suggestions?
Thank you for your attention.
I'd suggest you use combn on the File Exchange.
I use combinator. Perhaps somebody should run a benchmark to see which implementation is best.
Related
My task now is want to construct a cell C which contain matrices which first dimensions are contained in a vector
n = [12 23 54].
While their second dimensions are fixed with
r = 3.
So, I want the cell C = {rand(12,3), rand(23,3), rand(54,3)}.
I know for-loop can serve my purpose as:
C=cell(3,1) % pre-allocation
for i = 1 : length(n)
C{i} = rand(n(i),r);
end
May I know if I can do it smarter without using a for loop in Matlab? Thank you
There's really no harm in using a for loop in this particular scenario (and in most cases where the only alternative is cellfun or arrayfun) as it is easier for MATLAB's JIT compiler to handle, but if you're really averse to a for loop you can use arrayfun combined within non-uniform output to give you the result you want.
C = arrayfun(#(x)rand(x, r), n, 'UniformOutput', false);
This may actually be slower than the for loop for the reasons mentioned above. But hey, it's one line so that's all that matters!
for and while loops have their place, even in Matlab. You've probably been told to avoid them because vectorized operations are so much faster when you're iterating over the rows, columns or other dimensions of a packed numeric array. But with higher-level constructs, like cell arrays, there's often no advantage (and a readability penalty) to trying to do things all in neat quasi-vectorized statements. Your existing solution is probably the best approach.
A shorter alternative, just for fun:
C = mat2cell(rand(sum(n),r), n,r)';
But a plain loop is almost certainly fastest in this case, because mat2cell uses a loop, as well as copious checks on its inputs.
My question is that given an array A, how can you give another array identical to A except changing all negatives to 0 (without changing values in A)?
My way to do this is:
B = A;
B(B<0)=0
Is there any one-line command to do this and also not requiring to create another copy of A?
While this particular problem does happen to have a one-liner solution, e.g. as pointed out by Luis and Ian's suggestions, in general if you want a copy of a matrix with some operation performed on it, then the way to do it is exactly how you did it. Matlab doesn't allow chained operations or compound expressions, so you generally have no choice but to assign to a temporary variable in this manner.
However, if it makes you feel better, B=A is efficient as it will not result in any new allocated memory, unless / until B or A change later on. In other words, before the B(B<0)=0 step, B is simply a reference to A and takes no extra memory. This is just how matlab works under the hood to ensure no memory is wasted on simple aliases.
PS. There is nothing efficient about one-liners per se; in fact, you should avoid them if they lead to obscure code. It's better to have things defined over multiple lines if it makes the logic and intent of the algorithm clearer.
e.g, this is also a valid one-liner that solves your problem:
B = subsasgn(A, substruct('()',{A<0}), 0)
This is in fact the literal answer to your question (i.e. this is pretty much code that matlab will call under the hood for your commands). But is this clearer, more elegant code just because it's a one-liner? No, right?
Try
B = A.*(A>=0)
Explanation:
A>=0 - create matrix where each element is 1 if >= 0, 0 otherwise
A.*(A>=0) - multiply element-wise
B = A.*(A>=0) - Assign the above to B.
I've recently learned how to vectorize a "simple" nested loop in a previous question I've asked. However, now I'm trying also to vectorize the following loop
A=rand(80,80,10,6,8,8);
I=rand(size(A1,3),1);
C=rand(size(A1,4),1);
B=rand(size(A1,5),1);
for i=1:numel(I)
for v=1:numel(C)
for j=1:numel(B)
for k=1:j
A(:,:,i,v,j,k)= A(:,:,i,v,j,k)*I(i)*C(v)*B(j)*((k-1>0)+1);
end
end
end
end
So now k depends in j... What have I tried so far:
The combination of j and k terms (i.e. B(j)*((k-1>0)+1) gives a triangular matrix that I manage to vectorize independently:
B2=tril([ones(8,1)*B']');
B2(2:end,2:end)=2*B2(2:end,2:end);
But that gives me the (j,k) matrix properly and not a way to use it to vectorize the remaining loop. Maybe I'm in the wrong path too... So how can I vectorize that type of loop?
In one of your comments to the accepted solution of the previous question, you mentioned that successive bsxfun(#times,..,permute..) based codes were faster. If that's the case, you can use a similar approach here as well. Here's the code that uses such a pattern alongwith tril -
B1 = tril(bsxfun(#times,B,[1 ones(1,numel(B)-1).*2]));
v1 = bsxfun(#times,B1, permute(C,[3 2 1]));
v2 = bsxfun(#times,v1, permute(I,[4 3 2 1]));
A = bsxfun(#times,A, permute(v2,[5 6 4 3 1 2]));
You were close. The vectorization you proposed indeed follows the (j,k) logic, but doing tril adds zeros in places where the loop doesn't go into. Using the solution for your previous question (#david's) is not complete as it multiplies all elements including these zero value elements that the loop doesn't go into. My solution to that, is to find these zero elements and replace them with 1 (so simple):
Starting with your code:
B2=tril([ones(8,1)*B']');
B2(2:end,2:end)=2*B2(2:end,2:end);
and following the vectorization shown in the previous question:
s=size(A);
[b,c,d]=ndgrid(I,C,B2);
F=b.*c.*d;
F(F==0)=1; % this is the step that is important for your case.
A=reshape(A,s(1),s(2),[]);
A=bsxfun(#times,A,permute(F(:),[3 2 1]));
A=reshape(A,s);
For the size of A used in the question this cuts about 50% of the run time, not bad...
My question is very similar to this one but I can't manage exactly how to apply that answer to my problem.
I am looping through a vector with a variable k and want to select the whole vector except the single value at index k.
Any idea?
for k = 1:length(vector)
newVector = vector( exluding index k); <---- what mask should I use?
% other operations to do with the newVector
end
Another alternative without setdiff() is
vector(1:end ~= k)
vector([1:k-1 k+1:end]) will do. Depending on the other operations, there may be a better way to handle this, though.
For completeness, if you want to remove one element, you do not need to go the vector = vector([1:k-1 k+1:end]) route, you can use vector(k)=[];
Just for fun, here's an interesting way with setdiff:
vector(setdiff(1:end,k))
What's interesting about this, besides the use of setdiff, you ask? Look at the placement of end. MATLAB's end keyword translates to the last index of vector in this context, even as an argument to a function call rather than directly used with paren (vector's () operator). No need to use numel(vector). Put another way,
>> vector=1:10;
>> k=6;
>> vector(setdiff(1:end,k))
ans =
1 2 3 4 5 7 8 9 10
>> setdiff(1:end,k)
Error using setdiff (line 81)
Not enough input arguments.
That is not completely obvious IMO, but it can come in handy in many situations, so I thought I would point this out.
Very easy:
newVector = vector([1:k-1 k+1:end]);
This works even if k is the first or last element.
%create a logic vector of same size:
l=ones(size(vector))==1;
l(k)=false;
vector(l);
Another way you can do this which allows you to exclude multiple indices at once (or a single index... basically it's robust to allow either) is:
newVector = oldVector(~ismember(1:end,k))
Works just like setdiff really, but builds a logical mask instead of a list of explicit indices.
I have a vector, A.
A=[3,4,5,2,2,4;2,3,4,5,3,4;2,4,3,2,3,1;1,2,3,2,3,4]
Some of the records in A must be replaced by NaN values, as they are inaccurate.
I have created vector rowid, which records the last value that must be kept after which the existing values must be swapped to NaN.
rowid=[4,5,4,3]
So the vector I wish to create, B, would look as follows:
B=[3,4,5,2,NaN,NaN;2,3,4,5,3,NaN;2,4,3,2,NaN,NaN;1,2,3,NaN,NaN,NaN]
I am at a loss as to how to do this. I have tried to use
A(:,rowid:end)
to start selecting out the data from vector A. I am expecting to be able to use sub2ind or some sort of idx to do this, possibly an if loop, but I don't know where to start and cannot find an appropriate similar question to base my thoughts on!
I would very much appreciate any tips/pointers, many thanks
If you are not yet an expert of matlab, I would stick to simple for-loops for now:
B = A;
for i=1:length(rowid)
B(i, rowid(i)+1:end) = NaN;
end
It is always a sport to write this as a one-liner (see Mohsen's answer), but in many cases an explicit for-loop is much clearer.
A compact one is:
B = A;
B(bsxfun(#lt, rowid.', 1:size(A,2)))=NaN;