Index out column vector of matrix and then multiply corresponding matrix - matlab

I have heavy computation as follows:
L = ones(100000,200000);
for i = 1:10000
temp = f(i,...);
L = L .* temp(:, index );
end
where temp is a 100,000*3 matrix (values computed from f(i,...); I omit arguments here) and index is a 1*200,000 integer vector (1 to 3).
I have to do above many times in my algorithm. I feel Matlab wastes time creating 100000*200000 from temp(:, index ) in the iteration. But, it may not necessary; that is, we can just extract corresponding column and then multiply to corresponding column of L. Yet, I cannot find a way to do it efficiently...
Hope anyone can give advice on this. Thanks!
I give a small and hypothetical example:
function test
x = rand(5,3);
t = rand(10,1); % could be very long
point = 3;
index = [1 2 1 3 2 3 1 2;...
2 3 2 1 2 3 1 1;...
1 1 1 2 2 3 1 1;...
3 3 2 3 2 2 2 1;...
2 3 2 1 2 1 3 1]; % could be very long
L = ones(10,8);
for i = 1:5
temp = myfun(x(i,:),t,point);
L = L .* temp(:, index(i,:) );
end
function prob = myfun(x,t,point)
prob = ones(size(t,1),point);
for k = 2:point
prob(:,k) = exp( ((k-1).*x(1).*(t) + x(k) ));
end
de = sum(prob,2);
for k = 1:point
prob(:,k) = prob(:,k)./de;
end
end
end

I managed to save just some minor computation during each iteration, perhaps it makes a difference on your large matrices though. What I did was to change one line into prob(:,k) = exp( ((k-1).*x(i,1).*(t) + x(i,k) ));. Notice the elements in x. This saves some unnecessary computation. It is somewhat difficult to optimize this as I have no idea what this is, but here's my code:
x = rand(5,3);
t = rand(10,1);
point = 3;
index = [1 2 1 3 2 3 1 2;...
2 3 2 1 2 3 1 1;...
1 1 1 2 2 3 1 1;...
3 3 2 3 2 2 2 1;...
2 3 2 1 2 1 3 1];
L = ones(10,8);
for i = 1:5
prob = ones(size(t,1),point);
for k = 2:point
prob(:,k) = exp( ((k-1).*x(i,1).*(t) + x(i,k) ));
end
de = sum(prob,2);
for k = 1:point
prob(:,k) = prob(:,k)./de;
end
L = L .* prob(:, index(i,:) );
end
There are some dangerous operations I noticed, e.g. de = sum(prob,2);. Note that if you would change prob(:,k) = prob(:,k)./de; to prob(:,k) = prob(:,k)./sum(prob,2); you have a different result. Perhaps you're aware of this already, but it may be worth mentioning. Let me know if there is anything more I can do to help.

Related

Function to accept a matrix as input and goes element by element using for-loops adding one to each of the elements

I have created a function to add one to an element as follows;
function xz = addOne(x)
nrow = size(x,1);
ncol = size(x,1);
for K = 1:nrow
for J = 1:ncol
xz = x(:) + 1;
end
end
Example: given 1 the function results in 2:
addOne(1) [2]
I have tried using a matrix as an argument for the function...
x = [1 2 3; 0 0 0; 4 5 6];
x =
1 2 3
0 0 0
4 5 6
addOneWithFors(x)
ans =
2
1
5
3
1
6
4
1
7
How would I update this function to accept a matrix with multiple rows and columns and output it as such instead of just 1 number or a list of elements. Any help would be greatly appreciated.
In Matlab, you don't need a special function to do this. Matlab natively supports adding a scalar to a matrix. For example:
x = [1 2 3; 0 0 0; 4 5 6];
y = x + 1
will produce:
y =
2 3 4
1 1 1
5 6 7
However, if you specifically want to write this out explicitly using for loops, then your addOne() function only needs minor modifications. For example:
function xz = addOne(x)
nrow = size(x,1);
ncol = size(x,2);
xz = zeros(nrow,ncol);
for K = 1:nrow
for J = 1:ncol
xz(K,J) = x(K,J) + 1;
end
end
Note that ncol = size(x,2); has been defined correctly.

How to generate matrix in MATLAB where values decrease with increasing coordinates

I'm trying to generate an n x n matrix like
5 4 3 2 1
4 4 3 2 1
3 3 3 2 1
2 2 2 2 1
1 1 1 1 1
where n = 5 or n 50. I'm at an impasse and can only generate a portion of the matrix. It is Problem 2.14 from Numerical Methods using MATLAB 3rd Edition by Penny and Lindfield. This is the best I have so far:
n = 5;
m = n;
A = zeros(m,n);
for i = 1:m
for j = 1:n
A(i,j) = m;
end
m = m - 1;
end
Any feedback is appreciated.
That was a nice brain-teaser, here’s my solution:
[x,y] = meshgrid(5:-1:1);
out = min(x,y)
Output:
ans =
5 4 3 2 1
4 4 3 2 1
3 3 3 2 1
2 2 2 2 1
1 1 1 1 1
Here's one loop-based approach:
n = 5;
m = n;
A = zeros(m, n);
for r = 1:m
for c = 1:n
A(r, c) = n+1-max(r, c);
end
end
And here's a vectorized approach (probably not faster, just for fun):
n = 5;
A = repmat(n:-1:1, n, 1);
A = min(A, A.');
That's one of the matrices in Matlab's gallery, except that it needs a 180-degree rotation, which you can achieve with rot90:
n = 5;
A = rot90(gallery('minij', n), 2);

Vectorize code in MATLAB

How to vectorize this code in MATLAB?
n = 3;
x = zeros(n);
y = x;
for i = 1:n
x(:,i) = i;
y(i,:) = i;
end
I am not able to vectorize it. Please help.
You can use meshgrid :
n = 3;
[x,y] = meshgrid(1:n,1:n)
x =
1 2 3
1 2 3
1 2 3
y =
1 1 1
2 2 2
3 3 3
n=3;
[x,y]=meshgrid(1:n);
This uses meshgrid which does this automatically.
Or you can use bsxfun as Divakar suggests:
bsxfun(#plus,1:n,zeros(n,1))
Just as a note on your initial looped code: it's bad practise to use i as a variable
If I can add something to the mix, create a row vector from 1 to n, then use repmat on this vector to create x. After, transpose x to get y:
n = 3;
x = repmat(1:n, n, 1);
y = x.';
Running this code, we get:
>> x
x =
1 2 3
1 2 3
1 2 3
>> y
y =
1 1 1
2 2 2
3 3 3

Divide list of numbers into 3 groups in matlab

I have a list of numbers, [1:9], that I need to divide three groups. Each group must contain at least one number. I need to enumerate all of the combinations (i.e. order does not matter). Ideally, the output is a x by 3 array. Any ideas of how to do this in matlab?
Is this what you want:
x = 1:9;
n = length(x);
T=3;
out = {};
%// Loop over all possible solutions
for k=1:T^n
s = dec2base(k, T, n);
out{k}{T} = [];
for p=1:n
grpIndex = str2num(s(p))+1;
out{k}{grpIndex} = [out{k}{grpIndex} x(p)];
end
end
%// Print result. size of out is the number of ways to divide the input. out{k} contains 3 arrays with the values of x
out
Maybe this is what you want. I'm assuming that the division in groups is "monotonous", that is, first come the elements of the first group, then those of the second etc.
n = 9; %// how many numbers
k = 3; %// how many groups
b = nchoosek(1:n-1,k-1).'; %'// "breaking" points
c = diff([ zeros(1,size(b,2)); b; n*ones(1,size(b,2)) ]); %// result
Each column of c gives the sizes of the k groups:
c =
Columns 1 through 23
1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 5
1 2 3 4 5 6 7 1 2 3 4 5 6 1 2 3 4 5 1 2 3 4 1
7 6 5 4 3 2 1 6 5 4 3 2 1 5 4 3 2 1 4 3 2 1 3
Columns 24 through 28
5 5 6 6 7
2 3 1 2 1
2 1 2 1 1
This produces what I was looking for. The function nchoosekr_rec() is shown below as well.
for x=1:7
numgroups(x)=x;
end
c=nchoosekr_rec(numgroups,modules);
i=1;
d=zeros(1,modules);
for x=1:length(c(:,1))
c(x,modules+1)=sum(c(x,1:modules));
if c(x,modules+1)==length(opt_mods)
d(i,:)=c(x,1:modules);
i=i+1;
end
end
numgroups=[];
for x=1:length(opt_mods)
numgroups(x)=x;
end
count=0;
for x=1:length(d(:,1))
combos=combnk(numgroups,d(x,1));
for y=1:length(combos(:,1))
for z=1:nchoosek(9-d(x,1),d(x,2))
new_mods{count+z,1}=combos(y,:);
numgroups_temp{count+z,1}=setdiff(numgroups,new_mods{count+z,1});
end
count=count+nchoosek(9-d(x,1),d(x,2));
end
end
count=0;
for x=1:length(d(:,1))
for y=1:nchoosek(9,d(x,1))
combos=combnk(numgroups_temp{count+1},d(x,2));
for z=1:length(combos(:,1))
new_mods{count+z,2}=combos(z,:);
new_mods{count+z,3}=setdiff(numgroups_temp{count+z,1},new_mods{count+z,2});
end
count=count+length(combos(:,1));
end
end
function y = nchoosekr_rec(v, n)
if n == 1
y = v;
else
v = v(:);
y = [];
m = length(v);
if m == 1
y = zeros(1, n);
y(:) = v;
else
for i = 1 : m
y_recr = nchoosekr_rec(v(i:end), n-1);
s_repl = zeros(size(y_recr, 1), 1);
s_repl(:) = v(i);
y = [ y ; s_repl, y_recr ];
end
end
end

specific tuples generation and counting (matlab)

I need to generate (I prefere MATLAB) all "unique" integer tuples k = (k_1, k_2, ..., k_r) and
its corresponding multiplicities, satisfying two additional conditions:
1. sum(k) = n
2. 0<=k_i<=w_i, where vector w = (w_1,w_2, ..., w_r) contains predefined limits w_i.
"Unique" tuples means, that it contains unique unordered set of elements
(k_1,k_2, ..., k_r)
[t,m] = func(n,w)
t ... matrix of tuples, m .. vector of tuples multiplicities
Typical problem dimensions are about:
n ~ 30, n <= sum(w) <= n+10, 5 <= r <= n
(I hope that exist any polynomial time algorithm!!!)
Example:
n = 8, w = (2,2,2,2,2), r = length(w)
[t,m] = func(n,w)
t =
2 2 2 2 0
2 2 2 1 1
m =
5
10
in this case exist only two "unique" tuples:
(2,2,2,2,0) with multiplicity 5
there are 5 "identical" tuples with same set of elements
0 2 2 2 2
2 0 2 2 2
2 2 0 2 2
2 2 2 0 2
2 2 2 2 0
and
(2,2,2,1,1) with multiplicity 10
there are 10 "identical" tuples with same set of elements
1 1 2 2 2
1 2 1 2 2
1 2 2 1 2
1 2 2 2 1
2 1 1 2 2
2 1 2 1 2
2 1 2 2 1
2 2 1 1 2
2 2 1 2 1
2 2 2 1 1
Thanks in advance for any help.
Very rough (extremely ineffective) solution. FOR cycle over 2^nvec-1 (nvec = r*maxw) test samples and storage of variable res are really terrible things!!!
This solution is based on tho following question.
Is there any more effective way?
function [tup,mul] = tupmul(n,w)
r = length(w);
maxw = max(w);
w = repmat(w,1,maxw+1);
vec = 0:maxw;
vec = repmat(vec',1,r);
vec = reshape(vec',1,r*(maxw+1));
nvec = length(vec);
res = [];
for i = 1:(2^nvec - 1)
ndx = dec2bin(i,nvec) == '1';
if sum(vec(ndx)) == n && all(vec(ndx)<=w(ndx)) && length(vec(ndx))==r
res = [res; vec(ndx)];
end
end
tup = unique(res,'rows');
ntup = size(tup,1);
mul = zeros(ntup,1);
for i=1:ntup
mul(i) = size(unique(perms(tup(i,:)),'rows'),1);
end
end
Example:
> [tup mul] = tupmul(8,[2 2 2 2 2])
tup =
0 2 2 2 2
1 1 2 2 2
mul =
5
10
Or same case but with changed limits for first two positions:
>> [tup mul] = tupmul(8,[1 1 2 2 2])
tup =
1 1 2 2 2
mul =
10
This is far more better algorithm, created by Bruno Luong (phenomenal MATLAB programmer):
function [t, m, v] = tupmul(n, w)
v = tmr(length(w), n, w);
t = sort(v,2);
[t,~,J] = unique(t,'rows');
m = accumarray(J(:),1);
end % tupmul
function v = tmr(p, n, w, head)
if p==1
if n <= w(end)
v = n;
else
v = zeros(0,1);
end
else
jmax = min(n,w(end-p+1));
v = cell2mat(arrayfun(#(j) tmr(p-1, n-j, w, j), (0:jmax)', ...
'UniformOutput', false));
end
if nargin>=4 % add a head column
v = [head+zeros(size(v,1),1,class(head)) v];
end
end %tmr