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

Simple Question about Optimization of Nested IF-FOR loops

Asked by Mohsen on 17 Jun 2013

Does any one know how to optimize this code so that it runs faster:

    for i=1:iNZ;
        if iPointsinSlice>0;
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m+(l-1)*iNX+i*iNX*iNY)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
        end
    end

Your help is much appreciated! Thanks a lot!

0 Comments

Mohsen

Products

5 Answers

Answer by Roger Stafford on 17 Jun 2013

Is 'iPointsinSlice' a scalar? If so and if it is not positive, nothing will happen here.

Next, don't you mean "m+(l-1)*iNX+(i-1)*iNX*iNY" as the index to 'DoseCubeU'? As it stands it will vary from 1+iNX*iNY to iNX*iNY*iNZ+iNX*iNY. Assuming my guess is correct, do this:

 if iPointsinSlice > 0
   t = repmat(SliceMaskUr==1,1,1,iNZ);
   DoseCubeU(t) = (100/RX_Dose)*SumDose(t);
 end

In case 'iPointsinSlice' is not a scalar you will have to correct your code before we can see how to handle it.

1 Comment

Mohsen on 17 Jun 2013

'iPointsinSlice' is a scalar. "m+(l-1)*iNX+(i-1)*iNX*iNY" is used as the index to 'DoseCubeU. But your code gives the error that REPMAT has too many arguments. How should I fix it?

Roger Stafford
Answer by Roger Stafford on 17 Jun 2013

Sorry! It should have been:

 t = repmat(SliceMaskUr==1,[1,1,iNZ]);

1 Comment

Mohsen on 18 Jun 2013

I changed

DoseCubeU(m+(l-1)*iNX+i*iNY*iNX)=100*SumDose(m,l,i)/RX_Dose;

to

DoseCubeU(double(m)+double((l-1))*double(iNX)+double((i-1))*double(iNY)*double(iNX))=100*SumDose(m,l,i)/RX_Dose;

Otherwise the indexing will not be correct. For example, iNX*iNY*iNZ (which is 120*120*11) becomes equal to 65535 (which is wrong). We should write it as double(iNX)*double(iNY)*double(iNZ) in order to get the correct results (ie. 158400).

By making this change, both the indexing (the initial) method and the subscription method (below) give the same results. But these results are different than any of the other proposed methods.

So, how can I optimize:

    for i=1:iNZ;
        if iPointsinSlice>0;
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m,l,i)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
        end
    end
Roger Stafford
Answer by Mohsen on 17 Jun 2013

This code doesn't give me the same result as my initial code. Please note that the purpose of "m+(l-1)*iNX+i*iNX*iNY" is to reshape the SumDose array which is (iNX by iNY by iNZ) to a one dimensional array (1 by iNX*iNY*iNZ).

I tried also

                    if SliceMaskUr==1;
                        DoseCubeU= reshape(SumDose,1,[iNX iNY iNZ])*(100/RX_Dose);
                    end

but it didn't work neither...

Any insight?

4 Comments

Mohsen on 18 Jun 2013

Thank you for your reply. In my original code, I changed "m+(l-1)*iNX+i*iNX*iNY" to "m+(l-1)*iNX+(i-1)*iNX*iNY" so that the index of DoseCubeU is from 1 to iNX*iNY*iNZ.

Both DoseCubeU and SumDose are of sizes iNX-by-iNY-by-iNZ.

However, your code still gives me a different answer than my original code.

As a test, in order to use the subscription notation instead of indexing, I just modified my code to the following and surprisingly the results are again different from the two previous methods:

    for i=1:iNZ;
        if iPointsinSlice>0;
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m,l,i)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
        end
    end

This is confusing!!

Mohsen on 18 Jun 2013

I think that the function poly2mask is in charge of these discrepancies. Any idea why? Here is the entire code:

iNNX=double(iNX);

iNNY=double(iNY);

    for i=1:iNZ;
        iPointsinSlice=1;
        for j=1:iNCUr;
            if UrContourZ(j)==ZSlice(i);
                iPointsinSlice = iPointsinSlice+1;
                UrPointX(iPointsinSlice-1)=1 + (UrContourX(j)-Offset(1,1));
                UrPointY(iPointsinSlice-1)=1 + (UrContourY(j)-Offset(2,1));
            end
        end
        if iPointsinSlice>0;
            indx=round(iPointsinSlice);
            indy=round(iPointsinSlice);
            indx(1:iPointsinSlice-1)=UrPointX(1:iPointsinSlice-1)/DresX;
            indy(1:iPointsinSlice-1)=UrPointY(1:iPointsinSlice-1)/DresY;
            SliceMaskUr = poly2mask(indx,indy,iNNX,iNNY);
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m+(l-1)*iNX+(i-1)*iNY*iNX)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
       end
    end

Your help is much appreciated! :)

Mohsen on 18 Jun 2013

I changed

DoseCubeU(m+(l-1)*iNX+i*iNY*iNX)=100*SumDose(m,l,i)/RX_Dose;

to

DoseCubeU(double(m)+double((l-1))*double(iNX)+double((i-1))*double(iNY)*double(iNX))=100*SumDose(m,l,i)/RX_Dose;

Otherwise the indexing will not be correct. For example, iNX*iNY*iNZ (which is 120*120*11) becomes equal to 65535 (which is wrong). We should write it as double(iNX)*double(iNY)*double(iNZ) in order to get the correct results (ie. 158400).

By making this change, both the indexing (the initial) method and the subscription method (below) give the same results. But these results are different than any of the other proposed methods.

So, how can I optimize:

    for i=1:iNZ;
        if iPointsinSlice>0;
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m,l,i)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
        end
    end
Mohsen
Answer by Andrei Bobrov on 18 Jun 2013
Edited by Andrei Bobrov on 19 Jun 2013
DoseCubeU = bsxfun(@times,100*SumDose/RX,SliceMaskUr==1);

ADD

s = SliceMaskUr(end:-1:1,end:-1:1);
tt = cumsum(cumsum(s),2);
t1 = flipud(any(tt,2));
t2 = fliplr(any(tt));
DoseCubeU = bsxfun(@times,100*SumDose(t1,t2,:)/RX_Dose,SliceMaskUr(t1,t2));

4 Comments

Mohsen on 18 Jun 2013

I think that the function poly2mask is in charge of these discrepancies. Any idea why? Here is the entire code:

iNNX=double(iNX);

iNNY=double(iNY);

    for i=1:iNZ;
        iPointsinSlice=1;
        for j=1:iNCUr;
            if UrContourZ(j)==ZSlice(i);
                iPointsinSlice = iPointsinSlice+1;
                UrPointX(iPointsinSlice-1)=1 + (UrContourX(j)-Offset(1,1));
                UrPointY(iPointsinSlice-1)=1 + (UrContourY(j)-Offset(2,1));
            end
        end
        if iPointsinSlice>0;
            indx=round(iPointsinSlice);
            indy=round(iPointsinSlice);
            indx(1:iPointsinSlice-1)=UrPointX(1:iPointsinSlice-1)/DresX;
            indy(1:iPointsinSlice-1)=UrPointY(1:iPointsinSlice-1)/DresY;
            SliceMaskUr = poly2mask(indx,indy,iNNX,iNNY);
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m+(l-1)*iNX+(i-1)*iNY*iNX)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
       end
    end

Your help is much appreciated! :)

Mohsen on 18 Jun 2013

I changed

DoseCubeU(m+(l-1)*iNX+i*iNY*iNX)=100*SumDose(m,l,i)/RX_Dose;

to

DoseCubeU(double(m)+double((l-1))*double(iNX)+double((i-1))*double(iNY)*double(iNX))=100*SumDose(m,l,i)/RX_Dose;

Otherwise the indexing will not be correct. For example, iNX*iNY*iNZ (which is 120*120*11) becomes equal to 65535 (which is wrong). We should write it as double(iNX)*double(iNY)*double(iNZ) in order to get the correct results (ie. 158400).

By making this change, both the indexing (the initial) method and the subscription method (below) give the same results. But these results are different than any of the other proposed methods.

So, how can I optimize:

    for i=1:iNZ;
        if iPointsinSlice>0;
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m,l,i)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
        end
    end
Andrei Bobrov on 19 Jun 2013

Corrected. See ADD part in my answer.

Andrei Bobrov
Answer by Iain on 18 Jun 2013

Try:

 DoseCubeU(NY,NX,NZ) = 0; % or any suitable initialisation
 if iPointsinSlice>0;
  DoseCubeU(SliceMaskUr(m,l)==1,:) = 100*SumDose(SliceMaskUr(m,l)==1,:);
 end

2 Comments

Mohsen on 18 Jun 2013

This gives me a different answer than all the other four methods!

Mohsen on 18 Jun 2013

I changed

DoseCubeU(m+(l-1)*iNX+i*iNY*iNX)=100*SumDose(m,l,i)/RX_Dose;

to

DoseCubeU(double(m)+double((l-1))*double(iNX)+double((i-1))*double(iNY)*double(iNX))=100*SumDose(m,l,i)/RX_Dose;

Otherwise the indexing will not be correct. For example, iNX*iNY*iNZ (which is 120*120*11) becomes equal to 65535 (which is wrong). We should write it as double(iNX)*double(iNY)*double(iNZ) in order to get the correct results (ie. 158400).

By making this change, both the indexing (the initial) method and the subscription method (below) give the same results. But these results are different than any of the other proposed methods.

So, how can I optimize:

    for i=1:iNZ;
        if iPointsinSlice>0;
            for m=1:iNX;
                for l=1:iNY;
                    if SliceMaskUr(m,l)==1;
                        DoseCubeU(m,l,i)=100*SumDose(m,l,i)/RX_Dose;
                    end
                end
            end
        end
    end
Iain

Contact us