How to save multiple output in recursive function - matlab

Given a matrix A, I have to make all possible combinations of entries of A such that only one number is selected for each row. I have made a recursive program which is running successfully. But I am not able to save the output vector. So, for example in the following matrix A, there will be 27 such combinations, I want to save them in matrix of order 3x27.
A = [3 4 0; 2 3 7; 45 7 0]
n = 1;
X = zeros(3,1);
comb(n, X, A);
%function to calculate all combinations.
function X = comb(n, X, A)
if (n > 3)
X
return
end
for i = 1:3
X(n) = A(n, i);
comb(n + 1, X, A);
end
end

Here's one of the possible approaches:
To make your variable visible in all contexts, you need to declare a global variable:
global OUT;
%rest of the code
Then, you just define OUT in you main file as empty variable:
OUT = [];
And in function script, you instruct to append X to OUT whenever the if-statement is satisfied:
if (n > 3)
OUT = [OUT,X];
return
end
The resulting code is as follows:
global OUT;
OUT = [];
A = [3 4 0; 2 3 7; 45 7 0];
n = 1;
X = zeros(3,1);
comb_SO(n, X, A);
OUT
function X = comb_SO(n, X, A)
global OUT;
if (n > 3)
OUT = [OUT,X];
return
end
for i = 1:3
X(n) = A(n, i);
comb_SO(n + 1, X, A);
end
end
The sought result is in OUT variable:
3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0
2 2 2 3 3 3 7 7 7 2 2 2 3 3 3 7 7 7 2 2 2 3 3 3 7 7 7
45 7 0 45 7 0 45 7 0 45 7 0 45 7 0 45 7 0 45 7 0 45 7 0 45 7 0
But, MATLAB functionality allows your goal to be achieved without any recursion:
A = [3 4 0; 2 3 7; 45 7 0];
OUT = combvec(A(1,:),A(2,:),A(3,:))
Or, even without combvec, for arbitrary size of A:
A = reshape(1:20,4,5);
[n,m] = size(A);
Q = repmat({1:m},n,1);
B = cell(n,1);
[B{:}] = ndgrid(Q{:})
tmp = [];
OUT = [];
for k = 1:n
tmp = [tmp,B{k}(:)];
OUT = [OUT;A(k,tmp(:,k))];
end
Hope, that helps

Related

How do I program a function that takes two matrices A and B as input and outputs the product matrix A*B?

How do I program a function that takes two matrices A and B as input and outputs the product matrix A*B? Using MATLAB, with loops and conditionals.
My attempt:
function prodAB=MultiplicoMatrices(A,B)
prod=0;
prodAB=[];
for i=1:length(A)
for j=1:length(B)
prod=prod+A(i,j)*B(j,i);
end
prodAB(i,j)=prod;
prod=0;
end
A =
1 2
3 4
B=[5 6 ; 7 8]
B =
5 6
7 8
>> prodAB=MultiplicoMatrices([1 2; 3 4],[5 6; 7 8])
prodAB =
0 19
0 50
You mean the triple-loop algorithm? You could write the function as follows.
function prodAB = MultiplicoMatrices(A,B)
prodAB = zeros(size(A,1),size(B,2));
for i = 1:size(A,1)
for j = 1:size(B,2)
prod = 0;
for k = 1:size(A,2)
prod = prod + A(i,k) * B(k,j);
end
prodAB(i,j) = prod;
end
end
end
Now test it,
A = [1 2; 3 4];
B = [5 6; 7 8];
MultiplicoMatrices(A,B)
ans =
19 22
43 50
A * B
ans =
19 22
43 50
so, it works.

How to resize MATLAB matrix

If I have matrix size(mat)= X*Y*6
let call mat(:,:,1)=A
and mat(:,:,2)=B and so on
how do i rezise mat to X*Y*12
where
mat(:,:,1)=mat(:,:,2)= A
mat(:,:,3)=mat(:,:,4)=B
and so on
You can use the following syntax:
%defines input matrix (in your case it is already defined)
m = 500;
n = 400;
z = 6;
mat = rand(m,n,z);
%initialize output matrix
newMat = zeros(m,n,z*2);
%assign old matrix values into the new matrix
newMat(:,:,1:2:end) = mat;
newMat(:,:,2:2:end) = mat;
If you have Matlab 2015a or newer you can use repelem:
N = 2; %// number of times to repeat
result = repelem(mat, 1, 1, N); %// repeat N times along 3rd dim
For older Matlab versions you can do it manually as follows:
N = 2; %// number of times to repeat
ind = ceil(1/N:1/N:size(mat,3)); %// build index with repetitions
result = mat(:,:,ind); %// apply index along desired dim
Example:
>> %// Data
>> mat = randi(9,2,4,2)
mat(:,:,1) =
5 8 9 2
7 3 1 5
mat(:,:,2) =
5 7 1 1
1 8 8 2
>> %// First approach
>> N = 2;
>> result = repelem(mat, 1, 1, N)
result(:,:,1) =
5 8 9 2
7 3 1 5
result(:,:,2) =
5 8 9 2
7 3 1 5
result(:,:,3) =
5 7 1 1
1 8 8 2
result(:,:,4) =
5 7 1 1
1 8 8 2
>> %// Second approach
>> N = 2;
>> ind = ceil(1/N:1/N:size(mat,3));
>> result = mat(:,:,ind)
result(:,:,1) =
5 8 9 2
7 3 1 5
result(:,:,2) =
5 8 9 2
7 3 1 5
result(:,:,3) =
5 7 1 1
1 8 8 2
result(:,:,4) =
5 7 1 1
1 8 8 2

Find and replace the rows of an array having repeated number by a fixed given row

I have a matrix having rows with repeated numbers. I want to find those rows and replace them with a dummy row so as to keep the number of rows of the matrix constant.
Dummy_row = [1 2 3]
(5x3) Matrix A
A = [2 3 6;
4 7 4;
8 7 2;
1 3 1;
7 8 2]
(5x3) Matrix new_A
new_A = [2 3 6;
1 2 3;
8 7 2;
1 2 3;
7 8 2]
I tried the following which deleted the rows having repeated numbers.
y = [1 2 3]
w = sort(A,2)
v = all(diff(t,1,2)~=0|w(:,1:2)==0,2) % When v is zero, the row has repeated numbers
z = A(w,:)
Can you please help?
bsxfun based solution -
%// Create a row mask of the elements that are to be edited
mask = any(sum(bsxfun(#eq,A,permute(A,[1 3 2])),2)>1,3);
%// Setup output variable and set to-be-edited rows as copies of [1 2 3]
new_A = A;
new_A(mask,:) = repmat(Dummy_row,sum(mask),1)
Code run -
A =
2 3 6
4 7 4
8 7 2
1 3 1
7 8 2
new_A =
2 3 6
1 2 3
8 7 2
1 2 3
7 8 2
You could use the following:
hasRepeatingNums = any(diff(sort(A, 2), 1, 2)==0, 2);
A(hasRepeatingNums,:) = repmat(Dummy_row, nnz(hasRepeatingNums), 1);
See if this works for you,
A= [ 2 3 6;
4 7 4;
8 7 2;
5 5 5;
1 8 8;
1 3 1;
7 8 2 ];
Dummy_row = [1 2 3];
b = diff(sort(A,2),1,2);
b = sum(b == 0,2);
b = b > 0;
c = repmat(Dummy_row,sum(b),1);
b = b' .* (1:length(b));
b = b(b > 0);
newA = A;
newA(b,:) = c;
gives,
newA =
2 3 6
1 2 3
8 7 2
1 2 3
1 2 3
1 2 3
7 8 2
Edit
Not much change is needed, try this,
Dummy_row = [1 2 3];
b = sum(A == 0,2);
b = b > 0;
c = repmat(Dummy_row,sum(b),1);
b = b' .* (1:length(b));
b = b(b > 0);
newA = A;
newA(b,:) = c;

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

Expand matrix based on first row value (MATLAB)

My input is the following:
X = [1 1; 1 2; 1 3; 1 4; 2 5; 1 6; 2 7; 1 8];
X =
1 1
1 2
1 3
1 4
2 5
1 6
2 7
1 8
I am looking to output a new matrix based on the value of the first column. If the value is equal to 1 -- the output will remain the same, when the value is equal to 2 then I would like to output two of the values contained in the second row. Like this:
Y =
1
2
3
4
5
5
6
7
7
8
Where 5 is output two times because the value in the first column is 2 and the same for 7
Here it is (vectorized):
C = cumsum(X(:,1))
A(C) = X(:,2)
D = hankel(A)
D(D==0) = inf
Y = min(D)
Edit:
Had a small bug, now it works.
% untested code:
Y = []; % would be better to pre-allocate
for ii = 1:size(X,1)
Y = [Y; X(ii,2)*ones(X(ii,1),1)];
end