Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
block diagonal simple question

Subject: block diagonal simple question

From: leo nidas

Date: 11 May, 2010 22:45:23

Message: 1 of 7



Hi there,

Let the vector a=[1 1 1 2 2 3 3].

Given the above vector I want to come up with the block diagonal matrix whose first block will be a 3 by 3 matrix of ones, the second a two by two matrix of twos, and the third a two by two matrix of threes.

Well I think it is clear.. suppose that we have an extra four in "a" i.e. a=[1 1 1 2 2 3 3 4]. Then the fourth block of the wanted matrix will be an one by one matrix of 4 (i.e. one element). and so on...

I played a bit with blkdiag and kron functions but I can't figure it out. I tried some for inside for loops but still could not make something that works generally...

Thanx in advance for any answers!.

P.S.1. The elements of vector "a" will be integers beginning from 1 with unknown maximum. Moreover, it will contain all integers from 1 to its maximum element at least once.

P.S.2. I think this is obvious that this is not a homework and didn't post my effort because it does not work and wanted to save space. It is a 50 line code. I think that this could be done straightforward somehow.

Thanks again!

Subject: block diagonal simple question

From: John D'Errico

Date: 11 May, 2010 23:14:04

Message: 2 of 7

"leo nidas" <bleonidas25@yahoo.gr> wrote in message <hscmm3$cdj$1@fred.mathworks.com>...
>
>
> Hi there,
>
> Let the vector a=[1 1 1 2 2 3 3].
>
> Given the above vector I want to come up with the block diagonal matrix whose first block will be a 3 by 3 matrix of ones, the second a two by two matrix of twos, and the third a two by two matrix of threes.
>
> Well I think it is clear.. suppose that we have an extra four in "a" i.e. a=[1 1 1 2 2 3 3 4]. Then the fourth block of the wanted matrix will be an one by one matrix of 4 (i.e. one element). and so on...
>
> I played a bit with blkdiag and kron functions but I can't figure it out. I tried some for inside for loops but still could not make something that works generally...
>
> Thanx in advance for any answers!.
>
> P.S.1. The elements of vector "a" will be integers beginning from 1 with unknown maximum. Moreover, it will contain all integers from 1 to its maximum element at least once.
>
> P.S.2. I think this is obvious that this is not a homework and didn't post my effort because it does not work and wanted to save space. It is a 50 line code. I think that this could be done straightforward somehow.
>
> Thanks again!

Easy, peasy. ;-)

Count the number of ones, twos, threes, etc.
Do that simply by a find applied to diff. Then
cellfun, and a blkdiag.

a=[1 1 1 2 2 3 3];
na = diff([0, find(diff(a)), numel(a)]);
b = cellfun(@ones,mat2cell(na,1,ones(1,numel(na))),'uniformoutput',false);
b = blkdiag(b{:});

John

Subject: block diagonal simple question

From: Sean

Date: 12 May, 2010 13:02:06

Message: 3 of 7

"John D'Errico" <woodchips@rochester.rr.com> wrote in message <hscobs$quo$1@fred.mathworks.com>...
> "leo nidas" <bleonidas25@yahoo.gr> wrote in message <hscmm3$cdj$1@fred.mathworks.com>...
> >
> >
> > Hi there,
> >
> > Let the vector a=[1 1 1 2 2 3 3].
> >
> > Given the above vector I want to come up with the block diagonal matrix whose first block will be a 3 by 3 matrix of ones, the second a two by two matrix of twos, and the third a two by two matrix of threes.
> >
> > Well I think it is clear.. suppose that we have an extra four in "a" i.e. a=[1 1 1 2 2 3 3 4]. Then the fourth block of the wanted matrix will be an one by one matrix of 4 (i.e. one element). and so on...
> >
> > I played a bit with blkdiag and kron functions but I can't figure it out. I tried some for inside for loops but still could not make something that works generally...
> >
> > Thanx in advance for any answers!.
> >
> > P.S.1. The elements of vector "a" will be integers beginning from 1 with unknown maximum. Moreover, it will contain all integers from 1 to its maximum element at least once.
> >
> > P.S.2. I think this is obvious that this is not a homework and didn't post my effort because it does not work and wanted to save space. It is a 50 line code. I think that this could be done straightforward somehow.
> >
> > Thanks again!
>
> Easy, peasy. ;-)
>
> Count the number of ones, twos, threes, etc.
> Do that simply by a find applied to diff. Then
> cellfun, and a blkdiag.
>
> a=[1 1 1 2 2 3 3];
> na = diff([0, find(diff(a)), numel(a)]);
> b = cellfun(@ones,mat2cell(na,1,ones(1,numel(na))),'uniformoutput',false);
> b = blkdiag(b{:});
>
> John

John, your code above gives this:
 a=[1 1 1 2 2 3 3];
na = diff([0, find(diff(a)), numel(a)]);
b = cellfun(@ones,mat2cell(na,1,ones(1,numel(na))),'uniformoutput',false);
b = blkdiag(b{:});
b =

     1 1 1 0 0 0 0
     1 1 1 0 0 0 0
     1 1 1 0 0 0 0
     0 0 0 1 1 0 0
     0 0 0 1 1 0 0
     0 0 0 0 0 1 1
     0 0 0 0 0 1 1



I think this is what was wanted:
a=[1 1 1 2 2 3 3];
na = diff([0, find(diff(a)), numel(a)]);
b = cellfun(@repmat,mat2cell(unique(a),1,ones(1,numel(unique(a)))),mat2cell(na,1,ones(1,numel(na))),'uniformoutput',false);
b = blkdiag(b{:});
b=
     1 1 1 0 0 0 0
     1 1 1 0 0 0 0
     1 1 1 0 0 0 0
     0 0 0 2 2 0 0
     0 0 0 2 2 0 0
     0 0 0 0 0 3 3
     0 0 0 0 0 3 3

Subject: block diagonal simple question

From: John D'Errico

Date: 12 May, 2010 14:03:05

Message: 4 of 7

"Sean " <sean.dewolski@nospamplease.umit.maine.edu> wrote in message <hse8se$haj$1@fred.mathworks.com>...
> "John D'Errico" <woodchips@rochester.rr.com> wrote in message <hscobs$quo$1@fred.mathworks.com>...
> > "leo nidas" <bleonidas25@yahoo.gr> wrote in message <hscmm3$cdj$1@fred.mathworks.com>...
> > >
> > >
> > > Hi there,
> > >
> > > Let the vector a=[1 1 1 2 2 3 3].
> > >
> > > Given the above vector I want to come up with the block diagonal matrix whose first block will be a 3 by 3 matrix of ones, the second a two by two matrix of twos, and the third a two by two matrix of threes.
> > >
> > > Well I think it is clear.. suppose that we have an extra four in "a" i.e. a=[1 1 1 2 2 3 3 4]. Then the fourth block of the wanted matrix will be an one by one matrix of 4 (i.e. one element). and so on...
> > >
> > > I played a bit with blkdiag and kron functions but I can't figure it out. I tried some for inside for loops but still could not make something that works generally...
> > >
> > > Thanx in advance for any answers!.
> > >
> > > P.S.1. The elements of vector "a" will be integers beginning from 1 with unknown maximum. Moreover, it will contain all integers from 1 to its maximum element at least once.
> > >
> > > P.S.2. I think this is obvious that this is not a homework and didn't post my effort because it does not work and wanted to save space. It is a 50 line code. I think that this could be done straightforward somehow.
> > >
> > > Thanks again!
> >
> > Easy, peasy. ;-)
> >
> > Count the number of ones, twos, threes, etc.
> > Do that simply by a find applied to diff. Then
> > cellfun, and a blkdiag.
> >
> > a=[1 1 1 2 2 3 3];
> > na = diff([0, find(diff(a)), numel(a)]);
> > b = cellfun(@ones,mat2cell(na,1,ones(1,numel(na))),'uniformoutput',false);
> > b = blkdiag(b{:});
> >
> > John
>
> John, your code above gives this:
> a=[1 1 1 2 2 3 3];
> na = diff([0, find(diff(a)), numel(a)]);
> b = cellfun(@ones,mat2cell(na,1,ones(1,numel(na))),'uniformoutput',false);
> b = blkdiag(b{:});
> b =
>
> 1 1 1 0 0 0 0
> 1 1 1 0 0 0 0
> 1 1 1 0 0 0 0
> 0 0 0 1 1 0 0
> 0 0 0 1 1 0 0
> 0 0 0 0 0 1 1
> 0 0 0 0 0 1 1
>
>
>
> I think this is what was wanted:
> a=[1 1 1 2 2 3 3];
> na = diff([0, find(diff(a)), numel(a)]);
> b = cellfun(@repmat,mat2cell(unique(a),1,ones(1,numel(unique(a)))),mat2cell(na,1,ones(1,numel(na))),'uniformoutput',false);
> b = blkdiag(b{:});
> b=
> 1 1 1 0 0 0 0
> 1 1 1 0 0 0 0
> 1 1 1 0 0 0 0
> 0 0 0 2 2 0 0
> 0 0 0 2 2 0 0
> 0 0 0 0 0 3 3
> 0 0 0 0 0 3 3

You could be right on this matter. The difference is
minor, and easy enough to implement.

John

Subject: block diagonal simple question

From: Florin

Date: 12 May, 2010 16:04:04

Message: 5 of 7

"leo nidas" <bleonidas25@yahoo.gr> wrote in message <hscmm3$cdj$1@fred.mathworks.com>...
>
>
> Hi there,
>
> Let the vector a=[1 1 1 2 2 3 3].
>
> Given the above vector I want to come up with the block diagonal matrix whose first block will be a 3 by 3 matrix of ones, the second a two by two matrix of twos, and the third a two by two matrix of threes.
>
> Well I think it is clear.. suppose that we have an extra four in "a" i.e. a=[1 1 1 2 2 3 3 4]. Then the fourth block of the wanted matrix will be an one by one matrix of 4 (i.e. one element). and so on...
>
> I played a bit with blkdiag and kron functions but I can't figure it out. I tried some for inside for loops but still could not make something that works generally...
>
> Thanx in advance for any answers!.
>
> P.S.1. The elements of vector "a" will be integers beginning from 1 with unknown maximum. Moreover, it will contain all integers from 1 to its maximum element at least once.
>
> P.S.2. I think this is obvious that this is not a homework and didn't post my effort because it does not work and wanted to save space. It is a 50 line code. I think that this could be done straightforward somehow.
>
> Thanks again!

Is it possible to have a =[1 1 1 2 2 3 3 1 1] ? If so, are the last two '1' forming a new block 2x2, or are they merged with the initial block of 3x3, hence having a 5x5 ?

Subject: block diagonal simple question

From: John D'Errico

Date: 12 May, 2010 16:47:05

Message: 6 of 7

"Florin " <fneacsu2@gmail.com> wrote in message <hsejhk$iu6$1@fred.mathworks.com>...
> "leo nidas" <bleonidas25@yahoo.gr> wrote in message <hscmm3$cdj$1@fred.mathworks.com>...
> >
> >
> > Hi there,
> >
> > Let the vector a=[1 1 1 2 2 3 3].
> >
> > Given the above vector I want to come up with the block diagonal matrix whose first block will be a 3 by 3 matrix of ones, the second a two by two matrix of twos, and the third a two by two matrix of threes.
> >
> > Well I think it is clear.. suppose that we have an extra four in "a" i.e. a=[1 1 1 2 2 3 3 4]. Then the fourth block of the wanted matrix will be an one by one matrix of 4 (i.e. one element). and so on...
> >
> > I played a bit with blkdiag and kron functions but I can't figure it out. I tried some for inside for loops but still could not make something that works generally...
> >
> > Thanx in advance for any answers!.
> >
> > P.S.1. The elements of vector "a" will be integers beginning from 1 with unknown maximum. Moreover, it will contain all integers from 1 to its maximum element at least once.
> >
> > P.S.2. I think this is obvious that this is not a homework and didn't post my effort because it does not work and wanted to save space. It is a 50 line code. I think that this could be done straightforward somehow.
> >
> > Thanks again!
>
> Is it possible to have a =[1 1 1 2 2 3 3 1 1] ? If so, are the last two '1' forming a new block 2x2, or are they merged with the initial block of 3x3, hence having a 5x5 ?

You can see that the code I posted does do exactly this,
generating blocks of ones for each distinct block of
numbers in a.

The simplest way to convert those blocks to blocks of
non-unit values is a matrix multiply. Use spdiags to create
a (sparse) diagonal matrix, and then multiply it by the
block diagonal array created by my code.

John

Subject: block diagonal simple question

From: Jos (10584)

Date: 12 May, 2010 20:06:05

Message: 7 of 7

"leo nidas" <bleonidas25@yahoo.gr> wrote in message <hscmm3$cdj$1@fred.mathworks.com>...
>
>
> Hi there,
>
> Let the vector a=[1 1 1 2 2 3 3].
>
> Given the above vector I want to come up with the block diagonal matrix whose first block will be a 3 by 3 matrix of ones, the second a two by two matrix of twos, and the third a two by two matrix of threes.
>
> Well I think it is clear.. suppose that we have an extra four in "a" i.e. a=[1 1 1 2 2 3 3 4]. Then the fourth block of the wanted matrix will be an one by one matrix of 4 (i.e. one element). and so on...
>
> I played a bit with blkdiag and kron functions but I can't figure it out. I tried some for inside for loops but still could not make something that works generally...
>
> Thanx in advance for any answers!.
>
> P.S.1. The elements of vector "a" will be integers beginning from 1 with unknown maximum. Moreover, it will contain all integers from 1 to its maximum element at least once.
>
> P.S.2. I think this is obvious that this is not a homework and didn't post my effort because it does not work and wanted to save space. It is a 50 line code. I think that this could be done straightforward somehow.
>
> Thanks again!

Just for some indexing fun, here is one without blkdiag or intermeidate cell arrays. I have omitted the semi-colons so you can follow the flow. It can be done in a fewer lines if you like unreadable code ;-)

% data. with repetitions
  a = [1 1 4 3 3 3 4]
% engine
  tf = [true diff(a)~= 0]
  ua = a(tf)
  b = cumsum(tf)
  c = sqrt(b(:) * b)
  q = repmat(b,size(c,1),1) == c % or use bsxfun
  ix = ceil(c) % indices
  FM = ua(ix)
  FM(~q) = 0 % the desired block diagonal matrix

Jos

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us