how to omit for loop when there is constrains - matlab

I have the following two arrays:
A = [1 2;3 4] and B = [1 5 4]
I want to do the following operation:
for each element of A(call it A(i))
for each element of B~=b do
( (A(i) - 1)/(b-1) ) * ( (A(i) - 5)/(b-5) ) * ( (A(i)- 4)/(b-4) )
end
end
It means that, sometimes the numerator equals to zero, so the product should be zeros. And I want to do the operation for the elements of B which are not equal to the b in denominator to not make it Inf.
How can I do this for the whole matrix A instead of using for loop?

Code
A = [1 2;3 4];
B = [1 5 4];
m1 = bsxfun(#minus,A,permute([1 5 4],[3 1 2]));
m2 = bsxfun(#minus,B,permute([1 5 4],[3 1 2]));
for k1=1:size(A,1)
for k2=1:size(A,2)
t2 = squeeze(bsxfun(#rdivide,m1(k1,k2,:),m2));
t2(1:size(t2,1)+1:end)=1;
A1(k1,k2) = prod(t2(:)); %%// Output
end
end
Output
A1 =
0 -0.2500
-0.1111 0
You can remove the nested loops, but at least two issues there -
You would be going to 4th and 5th dimension with it, using bsxfun. So, debugging would be tough.
bsxfun with higher dimensions to my knowledge seems to get slower.

You could just do the operation, and correct later:
C = (A-1)./(B-1) .* (A-5)./(B-5) .* (A-4)./(B-4)
C(isinf(C)) = 0;
or
C(B==b) = 0;
Possibly you'd need bsxfun, I'm not clear on the size of the output you want...

Related

Matlab- sparse- element wise division

Consider the following;
A = [1 0 0; 0 2 0; 0 0 5];
B = [2 0 0; 0 4 0; 0 0 10];
A = sparse(A);
B = sparse(B);
C = B./A
I expected matlab to do sparse operations only on non-zero entries. But it also does operation on zero entries and returnNAN.
I saw few solutions in this site.
1. Using logical indexing
>> c = B(logical(A))./A(logical(A))
c =
(1,1) 2
(2,1) 2
(3,1) 2
As you can see, this does not preserve the sparse structure.
2. Replacing output with zero, where A is zero
This is an elegant solution if B./A is the only operation I do. What if I B./A is a part of a bigger operation? E.g K = 3*(B./A)*rand(3) + 5*(A./B)*rand(3)
Is there a simple way of dividing sparse matrices(having same structure) element-wise without getting NAN?
When you index (logical or not), you need to index the result as well to preserve the sparse structure.
idx = find(A); %# assumes A and B have the same sparsity pattern!
C = A; %# initialize C to have the correct size and shape
C(idx) = B(idx)./A(idx);
One more option:
B = spfun(#(x) 1./x, B);
C = A.*B;

MATLAB : 3 dimensional matrix with multipication with a vector

I have A matrix which is 16x16x155460. I have a B vector which is 12955x1. I want to multiply each 1:16x1:16x1+12*n:12+12*nwith the elements of B(n). So my goal is to find the weighted sum of the A according to B. My way to do this as follows (I don't want to use for-loop and my method gives wrong answer, I could not obtain the 1:12 vectors which is consecutive) :
B = repmat(B,[1 16 16]);
B = permute(B,[2 3 1]);
B = repmat(B,[1 1 12]);
result = B.*(A);
As a small example n=2 :
A(:,:,1)=[1 2; 3 4]
A(:,:,2)=[1 2; 3 4]
A(:,:,3)=[1 2; 3 4]
A(:,:,4)=[1 2; 3 4]
B = [2,3]
Result would be:
result(:,:,1)=A(:,:,1)*B(1);
result(:,:,2)=A(:,:,2)*B(1);
result(:,:,3)=A(:,:,1)*B(2);
result(:,:,4)=A(:,:,2)*B(2);
If I understood the problem correctly, you can use the powerful trio of bsxfun, permute and reshape to solve it, like so -
[M,N,R] = size(A);
mult_out = bsxfun(#times,reshape(A,M,N,numel(B),[]),permute(B(:),[4 3 1 2]))
out = reshape(mult_out,M,N,[])

How to write this matrix in matlab,

I want to write this matrix in matlab,
s=[0 ..... 0
B 0 .... 0
AB B .... 0
. . .
. . .
. . . 0 ....
A^(n-1)*B ... AB B ]
I have tried this below code but giving error,
N = 50;
A=[2 3;4 1];
B=[3 ;2];
[nx,ny] = size(A);
s(nx,ny,N) = 0;
for n=1:1:N
s(:,:,n)=A.^n;
end
s_x=cat(3, eye(size(A)) ,s);
for ii=1:1:N-1
su(:,:,ii)=(A.^ii).*B ;
end
z= zeros(1,60,1);
su1 = [z;su] ;
s_u=repmat(su1,N);
seems like the concatenation of matrix is not being done.
I am a beginner so having serious troubles,please help.
Use cell arrays and the answer to your previous question
A = [2 3; 4 1];
B = [3 ;2 ];
N = 60;
[cs{1:(N+1),1:N}] = deal( zeros(size(B)) ); %// allocate space, setting top triangle to zero
%// work on diagonals
x = B;
for ii=2:(N+1)
[cs{ii:(N+2):((N+1)*(N+2-ii))}] = deal(x); %//deal to diagonal
x = A*x;
end
s = cell2mat(cs); %// convert cells to a single matrix
For more information you can read about deal and cell2mat.
Important note about the difference between matrix operations and element-wise operations
In your question (and in your previous one) you confuse between matrix power: A^2 and element-wise operation A.^2:
matrix power A^2 = [16 9;12 13] is the matrix product of A*A
element-wise power A.^2 takes each element separately and computes its square: A.^2 = [4 9; 16 1]
In yor question you ask about matrix product A*b, but the code you write is A.*b which is an element-by-element product. This gives you an error since the size of A and the size of b are not the same.
I often find that Matlab gives itself to a coding approach of "write what it says in the equation". That also leads to code that is easy to read...
A = [2 3; 4 1];
B = [3; 2];
Q = 4;
%// don't need to...
s = [];
%// ...but better to pre-allocate s for performance
s = zeros((Q+1)*2, Q);
X = B;
for m = 2:Q+1
for n = m:Q+1
s(n*2+(-1:0), n-m+1) = X;
end
X = A * X;
end

Vector of the occurence number

I have a vector a=[1 2 3 1 4 2 5]'
I am trying to create a new vector that would give for each row, the occurence number of the element in a. For instance, with this matrix, the result would be [1 1 1 2 1 2 1]': The fourth element is 2 because this is the first time that 1 is repeated.
The only way I can see to achieve that is by creating a zero vector whose number of rows would be the number of unique elements (here: c = [0 0 0 0 0] because I have 5 elements).
I also create a zero vector d of the same length as a. Then, going through the vector a, adding one to the row of c whose element we read and the corresponding number of c to the current row of d.
Can anyone think about something better?
This is a nice way of doing it
C=sum(triu(bsxfun(#eq,a,a.')))
My first suggestion was this, a not very nice for loop
for i=1:length(a)
F(i)=sum(a(1:i)==a(i));
end
This does what you want, without loops:
m = max(a);
aux = cumsum([ ones(1,m); bsxfun(#eq, a(:), 1:m) ]);
aux = (aux-1).*diff([ ones(1,m); aux ]);
result = sum(aux(2:end,:).');
My first thought:
M = cumsum(bsxfun(#eq,a,1:numel(a)));
v = M(sub2ind(size(M),1:numel(a),a'))
on a completely different level, you can look into tabulate to get info about the frequency of the values. For example:
tabulate([1 2 4 4 3 4])
Value Count Percent
1 1 16.67%
2 1 16.67%
3 1 16.67%
4 3 50.00%
Please note that the solutions proposed by David, chappjc and Luis Mendo are beautiful but cannot be used if the vector is big. In this case a couple of naïve approaches are:
% Big vector
a = randi(1e4, [1e5, 1]);
a1 = a;
a2 = a;
% Super-naive solution
tic
x = sort(a);
x = x([find(diff(x)); end]);
for hh = 1:size(x, 1)
inds = (a == x(hh));
a1(inds) = 1:sum(inds);
end
toc
% Other naive solution
tic
x = sort(a);
y(:, 1) = x([find(diff(x)); end]);
y(:, 2) = histc(x, y(:, 1));
for hh = 1:size(y, 1)
a2(a == y(hh, 1)) = 1:y(hh, 2);
end
toc
% The two solutions are of course equivalent:
all(a1(:) == a2(:))
Actually, now the question is: can we avoid the last loop? Maybe using arrayfun?

Matlab swap

I am trying to create a function that will swap a specific number in a matrix with a specific number in the same matrix. For examlpe, if I start with A = [1 2 3;1 3 2], I want to be able to create B = [2 1 3; 2 3 1], simply by telling matlab to swap the 1's with the 2's. Any advice would be appreciated. Thanks!
If you have the following matrix:
A = [1 2 3; 1 3 2];
and you want all the ones to become twos and the twos to become ones, the following would be the simplest way to do it:
B = A;
B(find(A == 1)) = 2;
B(find(A == 2)) = 1;
EDIT:
As Kenny suggested, this can even be further simplified as:
B = A;
B(A == 1) = 2;
B(A == 2) = 1;
Another way to deal with the original problem is to create a permutation vector indicating to which numbers should the original entries be mapped to. For the example, entries [1 2 3] should be mapped respectively to [2 1 3], so that we can write
A = [1 2 3; 1 3 2];
perm = [2 1 3];
B = perm(A)
(advantage here is that everything is done in one step, and that it also works for operations more complicated than swaps ; drawback is that all elements of A must be positive integers with a known maximum)
Not sure why you would to perform that particular swap (row/column interchanges are more common). Matlab often denotes ':' to represent all of something. Here's how to swap rows and columns:
To swap rows:
A = A([New order of rows,,...], :)
To Swap columns:
A = A(:, [New order of columns,,...])
To change the entire i-th column:
A(:, i) = [New; values; for; i-th; column]
For example, to swap the 2nd and 3rd columns of A = [1 2 3;1 3 2]
A = A(:, [1, 3, 2])
A = [1 2 3; 1 3 2]
alpha = 1;
beta = 2;
indAlpha = (A == alpha);
indBeta = (A == beta);
A(indAlpha) = beta;
A(indBeta ) = alpha
I like this solution, it makes it clearer what is going on. Less magic numbers, could easily be made into a function. Recycles the same matrix if that is important.
I don't have a copy of MatLab installed, but I think you can do some thing like this;
for i=1:length(A)
if (A(i)=1), B(i) = 2, B(i)=A(i)
end
Note, that's only convert 1's to 2's and it looks like you also want to convert 2's to 1's, so you'll need to do a little more work.
There also probably a much more elegant way of doing it given you can do this sort of thing in Matlab
>> A = 1:1:3
A = [1,2,3]
>> B = A * 2
B = [2,4,6]
There might be a swapif primitive you can use, but I haven't used Matlab in a long time, so I'm not sure the best way to do it.
In reference to tarn's more elegant way of swapping values you could use a permutation matrix as follows:
>> a =[1 2 3];
>> T = [1 0 0;
0 0 1;
0 1 0];
>> b = a*T
ans =
1 3 2
but this will swap column 2 and column 3 of the vector (matrix) a; whereas the question asked about swapping the 1's and 2's.
Update
To swap elements of two different values look into the find function
ind = find(a==1);
returns the indices of all the elements with value, 1. Then you can use Mitch's suggestion to change the value of the elements using index arrays. Remeber that find returns the linear index into the matrix; the first element has index 1 and the last element of an nxm matrix has linear index n*m. The linear index is counted down the columns. For example
>> b = [1 3 5;2 4 6];
>> b(3) % same as b(1,2)
ans = 3
>> b(5) % same as b(1,3)
ans = 5
>> b(6) % same as b(2,3)
ans = 6