Compute Bell numbers in Matlab - arrays

This is what I already implemented:
function B = bell(n)
B(1,1) = 1;
for i=2:n
B(i,1) = B(1,end);
for j = 1:i-1
B(i-j,j+1) = B(i-1,j)+B(i,j);
end
end
end
When n=3, i got:
1 2 3
1 3 0
2 0 0
instead of:
1 2 5
1 3 0
2 0 0

You need to change your line
B(i-j,j+1) = B(i-1,j)+B(i,j);
into
B(i-j,j+1) = B(i-j+1,j)+B(i-j,j);
Example: for n=5,
B =
1 2 5 15 52
1 3 10 37 0
2 7 27 0 0
5 20 0 0 0
15 0 0 0 0
in accordance with this.

Related

MATLAB : How to construct block bi-diagonal matrix from input arguments [duplicate]

I have a matrix B and I want to obtain a matrix C of dimension (L+k)*m by L*n. L and k are input values. B0 , B1 , ... , Bk has size m by n.
For example :
If I have a matrix B = [1 1 ; 1 1 ; 1 1] with B0 = [1 1], B1 = [1 1] and B2 = [1 1], and each B0 , B1 , B2 of dimension 1 by 2 with k = 2 and L = 4.
Then the matrix C obtained is given by C = [1 1 0 0 0 0 0 0 ; 1 1 1 1 0 0 0 0 ; 1 1 1 1 1 1 0 0 ; 0 0 1 1 1 1 1 1 ; 0 0 0 0 1 1 1 1 ; 0 0 0 0 0 0 1 1] and of dimension
6 by 8.
I would like to generalize my program for any size matrix B.
My program solves the problem for B = [1 1 ; 1 1 ; 1 1] with m = 1 , n = 2 , k = 2 and L = 4.
My code :
clc;
clear;
k = 2;
L = 4;
B = [1 1 ; 1 1 ; 1 1];
B0 = [1 1];
B1 = [1 1];
B2 = [1 1];
m = size(B0,1);
n = size(B0,2);
c = [B ; zeros(size(B))];
C = zeros((L+k)*m,L*n);
for i = 1:L
C(:,2*i-1:2*i) = circshift(c,i-1,1);
end
Result : C =
1 1 0 0 0 0 0 0
1 1 1 1 0 0 0 0
1 1 1 1 1 1 0 0
0 0 1 1 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 0 0 1 1
I have difficulties to generalize for any given matrix B and for any value of k and L.
Any suggestions?
B = [1 2 3; 4 5 6; 7 8 9; 100 110 120; 130 140 150; 160 170 180]; % input
L = 4; % input
k = 2; % input
m = size(B,1)/(k+1); % obtain m
n = size(B,2); % obtain n
C = zeros((L-1)*m+1, (L-1)*n+1); % initiallize result
C(1:((L-1)*m+1)*n+m:end) = 1; % each 1 marks the upper-left corner for a copy of B
C = conv2(C, B); % insert copies of B, extending size
The second-to-last line uses linear indexing. The last line applies two-dimensional convolution. The result in this example is
B =
1 2 3
4 5 6
7 8 9
100 110 120
130 140 150
160 170 180
C =
1 2 3 0 0 0 0 0 0 0 0 0
4 5 6 0 0 0 0 0 0 0 0 0
7 8 9 1 2 3 0 0 0 0 0 0
100 110 120 4 5 6 0 0 0 0 0 0
130 140 150 7 8 9 1 2 3 0 0 0
160 170 180 100 110 120 4 5 6 0 0 0
0 0 0 130 140 150 7 8 9 1 2 3
0 0 0 160 170 180 100 110 120 4 5 6
0 0 0 0 0 0 130 140 150 7 8 9
0 0 0 0 0 0 160 170 180 100 110 120
0 0 0 0 0 0 0 0 0 130 140 150
0 0 0 0 0 0 0 0 0 160 170 180
In addition to #LuisMendo's answer:
If size(B,1)/(k+1) do not produce an integer, then his solution can fail.
I would suggest to create the C matrix with sparse():
n = size(B,2)
C = full(sparse(1:k:k*L,1:n:n*L,1))
So the whole code become:
B = ones(7,3); % An input matrix that will produce an error with the linear indexing solution.
L = 6; % number of repetition
k = 2; % row-shift
n = size(B,2); % obtain n
C = full(sparse(1:k:k*L,1:n:n*L,1)); % Create C using full(sparse())
C = conv2(C, B) % insert copies of B, extending size
(all credits goes to LuisMendo for the idea)
This solution as #obchardon's answer uses sparse but unlike the #LuisMendo's answer doesn't use conv2. Indices of blocks are computed and used in sparse to form the desired matrix.
[row col] = find(true(size(B)));
ROW = row + (0:L-1)*k;
COL = col + (0:L-1)*size(B,2);
C = sparse (ROW, COL, repmat (B, 1, L));

Expanding a matrix diagonally with Matlab

I have a matrix B and I want to obtain a matrix C of dimension (L+k)*m by L*n. L and k are input values. B0 , B1 , ... , Bk has size m by n.
For example :
If I have a matrix B = [1 1 ; 1 1 ; 1 1] with B0 = [1 1], B1 = [1 1] and B2 = [1 1], and each B0 , B1 , B2 of dimension 1 by 2 with k = 2 and L = 4.
Then the matrix C obtained is given by C = [1 1 0 0 0 0 0 0 ; 1 1 1 1 0 0 0 0 ; 1 1 1 1 1 1 0 0 ; 0 0 1 1 1 1 1 1 ; 0 0 0 0 1 1 1 1 ; 0 0 0 0 0 0 1 1] and of dimension
6 by 8.
I would like to generalize my program for any size matrix B.
My program solves the problem for B = [1 1 ; 1 1 ; 1 1] with m = 1 , n = 2 , k = 2 and L = 4.
My code :
clc;
clear;
k = 2;
L = 4;
B = [1 1 ; 1 1 ; 1 1];
B0 = [1 1];
B1 = [1 1];
B2 = [1 1];
m = size(B0,1);
n = size(B0,2);
c = [B ; zeros(size(B))];
C = zeros((L+k)*m,L*n);
for i = 1:L
C(:,2*i-1:2*i) = circshift(c,i-1,1);
end
Result : C =
1 1 0 0 0 0 0 0
1 1 1 1 0 0 0 0
1 1 1 1 1 1 0 0
0 0 1 1 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 0 0 1 1
I have difficulties to generalize for any given matrix B and for any value of k and L.
Any suggestions?
B = [1 2 3; 4 5 6; 7 8 9; 100 110 120; 130 140 150; 160 170 180]; % input
L = 4; % input
k = 2; % input
m = size(B,1)/(k+1); % obtain m
n = size(B,2); % obtain n
C = zeros((L-1)*m+1, (L-1)*n+1); % initiallize result
C(1:((L-1)*m+1)*n+m:end) = 1; % each 1 marks the upper-left corner for a copy of B
C = conv2(C, B); % insert copies of B, extending size
The second-to-last line uses linear indexing. The last line applies two-dimensional convolution. The result in this example is
B =
1 2 3
4 5 6
7 8 9
100 110 120
130 140 150
160 170 180
C =
1 2 3 0 0 0 0 0 0 0 0 0
4 5 6 0 0 0 0 0 0 0 0 0
7 8 9 1 2 3 0 0 0 0 0 0
100 110 120 4 5 6 0 0 0 0 0 0
130 140 150 7 8 9 1 2 3 0 0 0
160 170 180 100 110 120 4 5 6 0 0 0
0 0 0 130 140 150 7 8 9 1 2 3
0 0 0 160 170 180 100 110 120 4 5 6
0 0 0 0 0 0 130 140 150 7 8 9
0 0 0 0 0 0 160 170 180 100 110 120
0 0 0 0 0 0 0 0 0 130 140 150
0 0 0 0 0 0 0 0 0 160 170 180
In addition to #LuisMendo's answer:
If size(B,1)/(k+1) do not produce an integer, then his solution can fail.
I would suggest to create the C matrix with sparse():
n = size(B,2)
C = full(sparse(1:k:k*L,1:n:n*L,1))
So the whole code become:
B = ones(7,3); % An input matrix that will produce an error with the linear indexing solution.
L = 6; % number of repetition
k = 2; % row-shift
n = size(B,2); % obtain n
C = full(sparse(1:k:k*L,1:n:n*L,1)); % Create C using full(sparse())
C = conv2(C, B) % insert copies of B, extending size
(all credits goes to LuisMendo for the idea)
This solution as #obchardon's answer uses sparse but unlike the #LuisMendo's answer doesn't use conv2. Indices of blocks are computed and used in sparse to form the desired matrix.
[row col] = find(true(size(B)));
ROW = row + (0:L-1)*k;
COL = col + (0:L-1)*size(B,2);
C = sparse (ROW, COL, repmat (B, 1, L));

Create a matrix blockwise attaching blocks like a stairway MATLAB

I want to build an Array containing of different blocks in the following way.
Given the block I want to repeat the block n-times so that it looks like this:
A =
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
and I want the Array look like this, n times repeating the scheme:
newArray =
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
and so on...
With the free space being zeros, since the final array should be a sparse array either way.
How can I repeat and attach the block without using loops?
I'm assuming that the leftward offset of each block with respect to a pure block-diagonal matrix is the number of rows of A, as in your example.
You can build a matrix t that 2D-convolved with A gives the result, as follows:
A = [1 2 3 4; 5 6 7 8]; % data matrix
n = 3; % number of repetitions
[r, c] = size(A);
d = c-r;
t = zeros(r*(n-1)+1, d*(n-1)+1);
t(1:(r*(n-1)+1)*d+r:end) = 1;
result = conv2(t,A);
This gives
A =
1 2 3 4
5 6 7 8
result =
1 2 3 4 0 0 0 0
5 6 7 8 0 0 0 0
0 0 1 2 3 4 0 0
0 0 5 6 7 8 0 0
0 0 0 0 1 2 3 4
0 0 0 0 5 6 7 8
Here is a solution using kron:
n = 5; % number of repetitions
v = 3; % overlapping
s = size(A);
B = A(:,1:s(2)-v)
C = zeros(s(1),s(2)-v);
C(:,end-v+1:end) = A(:,end-v+1:end);
result = kron(eye(n) , B);
result(end,end+v)=0;
result(:,v+1:end) = result(:,v+1:end) + kron(eye(n) , C);
When the matrix size is large you can use sparse matrix:
n = 5;
v = 3;
s = size(A);
B = sparse(A(:,1:s(2)-v));
C = sparse(s(1),s(2)-v);
C(:,end-v+1:end) = A(:,end-v+1:end);
result = kron(eye(n) , B);
result(end,end+v) = 0;
result(:,v+1:end) = result(:,v+1:end) + kron(eye(n) , C);

Find regions of contiguous zeros in a binary array

I have
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
I want to find all the regions that have more than 5 zeros in a row. I want to find the index where it starts and where it stops.
In this case I want this: c=[12 18]. I can do it using for loops but I wonder if there is any better way, at least to find if there are some regions where this 'mask' ( mask=[0 0 0 0 0] ) appears.
A convolution based approach:
n = 5;
x = [0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0];
end_idx = find(diff(conv(~x, ones(1,n))==n)==-1)
start_idx = find(diff(conv(~x, ones(1,n))==n)==1) - n + 2
returning
end_idx =
6 14 25
start_idx =
1 9 20
Note that this part is common to both lines: diff(conv(~x, ones(1,n))==n) so it would be more efficient to pull it out:
kernel = ones(1,n);
convolved = diff(conv(~x, kernel)==n);
end_idx = find(convolved==-1)
start_idx = find(convolved==1) - n + 2
You can use regexp this way:
convert the array into a string
remove the blanks
use regexp to find the sequence of 0
A possible implementation could be:
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
% Convert the array to string and remove the blanks
str=strrep(num2str(x),' ','')
% Find the occurrences
[start_idx,end_idx]=regexp(str,'0{6,}')
This gives:
start_idx = 12
end_idx = 17
where x(start_idx) is the first element of the sequence and x(end_idx) is the last one
Applied to a more long sequence, start_idx and end_idx results being arrays:
x=[0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0]
start_idx =
1 9 20
end_idx =
6 14 25

Create a "pyramid" matrix

Say I'm given a symmetric row vector with an odd length where each element is smaller than the next one in the first half of the vector and each element is bigger than the next one in the second half and the middle element is the biggest. (e.g [1 2 3 2 1] or [10 20 50 20 10]).
I want to create a square matrix where this row vector is its middle row and the equivalent column vector (v') is its middle column and each other row or column is a reduced version of the given vector according to the middle element in this row or column. And when there are no more "original elements" we put 0.
Examples:
if v = [1 2 3 2 1] we get
0 0 1 0 0
0 1 2 1 0
1 2 3 2 1
0 1 2 1 0
0 0 1 0 0
if v = [3 5 3] we get
0 3 0
3 5 3
0 3 0
What I did so far: I managed to create a matrix with v as the middle row and v' as the middle column with this code I wrote:
s = length(vector);
matrix= zeros(s);
matrix(round(s/2),:) = vector;
matrix(:, round(s/2)) = vector';
but got stuck with assigning the other values.
A more hands-on approach is to produce your matrix as a mosaic, starting from a hankel matrix. For performance comparison, here's a version using the same format as #Divakar's solution:
function out=pyramid_hankel(v)
%I suggest checking v here
%it should be odd in length and a palindrome
i0=ceil(length(v)/2);
v2=v(i0:end);
Mtmp=hankel(v2);
out=zeros(length(v));
out(i0:end,i0:end)=Mtmp;
out(1:i0-1,i0:end)=flipud(Mtmp(2:end,:));
out(:,1:i0-1)=fliplr(out(:,i0+1:end));
>> pyramid_hankel([1 2 3 2 1])
ans =
0 0 1 0 0
0 1 2 1 0
1 2 3 2 1
0 1 2 1 0
0 0 1 0 0
For v=[1 2 3 2 1] the starting block is hankel([3 2 1]), which is
ans =
3 2 1
2 1 0
1 0 0
From here it should be clear what's happening.
Here's one approach -
function out = pyramid(v)
hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
upper_part = cumsum(bsxfun(#le,(hlen:-1:1)',updown_vec)); %//'
out = [upper_part ; flipud(upper_part(1:end-1,:))];
out = changem(out,v,updown_vec);
Here's another approach, sort of simpler maybe -
function out = pyramid_v2(v)
hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
mask = bsxfun(#le,([hlen:-1:1 2:hlen])',updown_vec); %//'
M = double(mask);
M(hlen+1:end,:) = -1;
out = changem(cumsum(M).*mask,v,updown_vec);
Sample runs -
>> v = [1 2 3 2 1];
>> pyramid(v)
ans =
0 0 1 0 0
0 1 2 1 0
1 2 3 2 1
0 1 2 1 0
0 0 1 0 0
>> v = [3 5 3];
>> pyramid(v)
ans =
0 3 0
3 5 3
0 3 0
>> v = [99,3,78,55,78,3,99];
>> pyramid(v)
ans =
0 0 0 99 0 0 0
0 0 99 3 99 0 0
0 99 3 78 3 99 0
99 3 78 55 78 3 99
0 99 3 78 3 99 0
0 0 99 3 99 0 0
0 0 0 99 0 0 0
Here's another approach:
v = [1 2 3 2 1]; %// symmetric, odd size
m = (numel(v)-1)/2;
w = [0 v(1:m+1)];
t = abs(-m:m);
result = w(max(m+2-bsxfun(#plus, t, t.'),1));

Resources