how to find minimum element's index in specific matrix's columns - matlab

I have matrix C (m x n)
I need to find the indices of the minimum element within specific columns (m+1 to n-1).
d = min(c(c>0));
[x,en] = find(c == d);
please help

You can use min() for that:
g = c(:,m+1:n-1); %get the subset first
[d,ind] = min(g(g>0)); %get the minimum and index of that minimum

This might be what you want,
Cm = C(:,m + 1 : n - 1);
d = min(Cm(Cm>0));
[row,col] = find(Cm == d);
if numel(col) > 0
col = col + m;
end

Related

Vectorize the sum of outer products of coresponding columns of two matrices using Matlab/Octave

Suppose I have two matrices A and B which are made up of column vectors as follows.
A = [a_1,a_2,...,a_N];
B = [b_1,b_2,...,b_N];
Is there any way to vectorize the calculation of the sum of outer products for every column in A with the corresponding column in B. Here is my non-vectorized solution.
S = zeros(size(A,1), size(B,1));
for n=1:N
S = S + A(:,n)*B(:,n)'; % S = S + a_n * b_n'
end
Any help would be greatly appreciated.
you are not clear on what N is, but I assume that N = number of column vectors - which means you are simply doing A * B'
A = rand(3,4);
B = rand(3,4);
N = size(A,2);
S = zeros(size(A,1), size(B,1));
for n=1:N
S = S + A(:,n)*B(:,n)'; % S = S + a_n * b_n'
end
%Check that you are doing A*B'
S == A*B'
>> ans =
1 1 1
1 1 1
1 1 1

Multiplying a vector by random numbers while keeping the sum the same (MATLAB)

I'm trying to multiply (element wise) a vector V of length N by a randomly generated number in the range (a,b), while keeping the sum of the vector equal to a total amount, E. I want to do this in MATLAB, but I'm not sure how. Getting random numbers between a certain range I know how to do:
minrand = 0;
maxrand = 1;
randfac = (maxrand-minrand).*rand(1,N) + minrand;
But yeah, beyond that I'm pretty clueless. I guess the random numbers can't really be generated like this, because if we call the random numbers the vector R, then I want that
R_1*V1 + R_2*V2 .... + R_N*V_N = E. So I guess it's a big equation. Is there any way to solve it, while putting constraints on the max and min values of R?
You can pick pairs of two elements (in all combinations) and add and subtract an equal random number.
% Make up a random vector
N=10;
randfac = 10*rand(1,N);
%OP Answer here: Given randfac with sum E re-randomize it
E = sum(randfac);
minrand = 0;
maxrand = 2;
disp(randfac)
% v = [6.4685 2.9652 6.6567 1.6153 7.3581 0.0237 7.1025
% 3.2381 1.9176 1.3561]
disp(sum(randfac))
% E = 38.7019
r = minrand + (maxrand-minrand)*rand(N*N,1);
k = 1;
for i=1:N
for j=1:N
randfac(i) = randfac(i)-r(k);
randfac(j) = randfac(j)+r(k);
k = k + 1;
end
end
disp(randfac)
% v = [5.4905 0.7051 4.7646 1.3479 9.3722 -1.4222 7.9275
% 7.5777 1.7549 1.1836]
disp(sum(randfac))
% E = 38.7019
Just divide the vector with the sum and multiply with the target E.
randfac = (maxrand-minrand).*rand(1,N) + minrand;
randfac = E*randfac/sum(randfac);
as long as the operator is linear, the result is going to retain it's randomness. Below is some sample code:
minrand = 0;
maxrand = 1;
N = 1000; %size
v = (maxrand-minrand).*rand(1,N) + minrand;
E = 100; %Target sum
A = sum(v);
randfac = (E/A)*v;
disp(sum(randfac))
% 100.0000
First of all with random numbers in the interval of [a b] you can't guarantee that you will have the same summation (same E). For example if [a b]=[1 2] of course the E will increase.
Here is an idea, I don't know how random is this!
For even N I randomize V then divide it in two rows and multiply one of them with random numbers in [a b] but the second column will be multiplied to a vector to hold the summation fixed.
N = 10;
V = randi(100,[1 N]);
E = sum(V);
idx = randperm(N);
Vr = V(idx);
[~,ridx] = sort(idx);
Vr = reshape(Vr,[2 N/2]);
a = 1;
b = 3;
r1 = (b - a).*rand(1,N/2) + a;
r2 = (sum(Vr) - r1.*Vr(1,:))./Vr(2,:);
r = reshape([r1;r2],1,[]);
r = r(ridx);
Enew = sum(V.*r);
The example results are,
V = [12 82 25 51 81 51 31 87 6 74];
r = [2.8018 0.7363 1.9281 0.5451 1.9387 -0.4909 1.3076 0.8904 2.9236 0.8440];
with E = 500 as well as Enew.
I'm simply assigning one random number to a pair (It can be considered as half random!).
Okay, I have found a way to somewhat do this, but it is not elegant and there are probably better solutions. Starting with an initial vector e, for which sum(e) = E, I can randomize its values and end up with an e for which sum(e) is in the range [(1-threshold)E,(1+thresholdE)]. It is computationally expensive, and not pretty.
The idea is to first multiply e by random numbers in a certain range. Then, I will check what the sum is. If it is too big, I will decrease the value of the random numbers smaller than half of the range until the sum is no longer too big. If it is too small, I do the converse, and iterate until the sum is within the desired range.
e = somepredefinedvector
minrand = 0;
maxrand = 2;
randfac = (maxrand-minrand).*rand(1,N) + minrand;
e = randfac.*e;
threshold = 0.001;
while sum(e) < (1-threshold)*E || sum(e) > (1+threshold)*E
if sum(e) > (1+threshold)*E
for j = 1:N
if randfac(j) > (maxrand-minrand)/2
e(j) = e(j)/randfac(j);
randfac(j) = ((maxrand-minrand)/2-minrand).*rand(1,1) + minrand;
e(j) = randfac(j)*e(j);
end
if sum(e) > (1-threshold)*E && sum(e) < (1+threshold)*E
break
end
end
elseif sum(e) < (1-threshold)*E
for j = 1:N
if randfac(j) < (maxrand-minrand)/2
e(j) = e(j)/randfac(j);
randfac(j) = (maxrand-(maxrand-minrand)/2).*rand(1,1) + (maxrand-minrand)/2;
e(j) = randfac(j)*e(j);
end
if sum(e) > (1-threshold)*E && sum(e) < (1+threshold)*E
break
end
end
end
end

Matlab: Argmax and dot product for each row in a matrix

I have 2 matrices = X in R^(n*m) and W in R^(k*m) where k<<n.
Let x_i be the i-th row of X and w_j be the j-th row of W.
I need to find, for each x_i what is the j that maximizes <w_j,x_i>
I can't see a way around iterating over all the rows in X, but it there a way to find the maximum dot product without iterating every time over all of W?
A naive implementation would be:
n = 100;
m = 50;
k = 10;
X = rand(n,m);
W = rand(k,m);
Y = zeros(n, 1);
for i = 1 : n
max_ind = 1;
max_val = dot(W(1,:), X(i,:));
for j = 2 : k
cur_val = dot(W(j,:),X(i,:));
if cur_val > max_val
max_val = cur_val;
max_ind = j;
end
end
Y(i,:) = max_ind;
end
Dot product is essentially matrix multiplication:
[~, Y] = max(W*X');
bsxfun based approach to speed-up things for you -
[~,Y] = max(sum(bsxfun(#times,X,permute(W,[3 2 1])),2),[],3)
On my system, using your dataset I am getting a 100x+ speedup with this.
One can think of two more "closeby" approaches, but they don't seem to give any huge improvement over the earlier one -
[~,Y] = max(squeeze(sum(bsxfun(#times,X,permute(W,[3 2 1])),2)),[],2)
and
[~,Y] = max(squeeze(sum(bsxfun(#times,X',permute(W,[2 3 1]))))')

Using results of find to index into multi-dimensional matrix in Matlab

A = 100 x 3 matrix
B = 200 x 10 x 100 matrix
column 2 of A contains index to dimension 1 of B.
column 3 of A contains 2 possible values: 0 or 1.
Based on the following conditions, I want to extract the values in B.
x = find(A(:, 3) == 0);
y = find(A(:, 3) == 1);
The index to dimension 1 of B is:
x_idx = A(x, 2);
y_idx = A(y, 2);
How can I get a 2-d matrix, such that:
C = B(x_idx, :, x);
D = B(y_idx, :, y);
See if this works for you -
ind1 = sub2ind(size(B), x_idx, ones(numel(x),1), x)
C = B(bsxfun(#plus,ind1,size(B,1)*[0:size(B,2)-1])') %%//'
ind2 = sub2ind(size(B), y_idx, ones(numel(y),1), y)
D = B(bsxfun(#plus,ind2,size(B,1)*[0:size(B,2)-1])')

Subtracting each elements of a row vector , size (1 x n) from a matrix of size (m x n)

I have two matrices of big sizes, which are something similar to the following matrices.
m; with size 1000 by 10
n; with size 1 by 10.
I would like to subtract each element of n from all elements of m to get ten different matrices, each has size of 1000 by 10.
I started as follows
clc;clear;
nrow = 10000;
ncol = 10;
t = length(n)
for i = 1:nrow;
for j = 1:ncol;
for t = 1:length(n);
m1(i,j) = m(i,j)-n(1);
m2(i,j) = m(i,j)-n(2);
m3(i,j) = m(i,j)-n(3);
m4(i,j) = m(i,j)-n(4);
m5(i,j) = m(i,j)-n(5);
m6(i,j) = m(i,j)-n(6);
m7(i,j) = m(i,j)-n(7);
m8(i,j) = m(i,j)-n(8);
m9(i,j) = m(i,j)-n(9);
m10(i,j) = m(i,j)-n(10);
end
end
end
can any one help me how can I do it without writing the ten equations inside the loop? Or can suggest me any convenient way especially when the two matrices has many columns.
Why can't you just do this:
m01 = m - n(1);
...
m10 = m - n(10);
What do you need the loop for?
Even better:
N = length(n);
m2 = cell(N, 1);
for k = 1:N
m2{k} = m - n(k);
end
Here we go loopless:
nrow = 10000;
ncol = 10;
%example data
m = ones(nrow,ncol);
n = 1:ncol;
M = repmat(m,1,1,ncol);
N = permute( repmat(n,nrow,1,ncol) , [1 3 2] );
result = bsxfun(#minus, M, N );
%or just
result = M-N;
Elapsed time is 0.018499 seconds.
or as recommended by Luis Mendo:
M = repmat(m,1,1,ncol);
result = bsxfun(#minus, m, permute(n, [1 3 2]) );
Elapsed time is 0.000094 seconds.
please make sure that your input vectors have the same orientation like in my example, otherwise you could get in trouble. You should be able to obtain that by transposements or you have to modify this line:
permute( repmat(n,nrow,1,ncol) , [1 3 2] )
according to your needs.
You mentioned in a comment that you want to count the negative elements in each of the obtained columns:
A = result; %backup results
A(A > 0) = 0; %set non-negative elements to zero
D = sum( logical(A),3 );
which will return the desired 10000x10 matrix with quantities of negative elements. (Please verify it, I may got a little confused with the dimensions ;))
Create the three dimensional result matrix. Store your results, for example, in third dimension.
clc;clear;
nrow = 10000;
ncol = 10;
N = length(n);
resultMatrix = zeros(nrow, ncol, N);
neg = zeros(ncol, N); % amount of negative values
for j = 1:ncol
for i = 1:nrow
for t = 1:N
resultMatrix(i,j,t) = m(i,j) - n(t);
end
end
for t = 1:N
neg(j,t) = length( find(resultMatrix(:,j,t) < 0) );
end
end