Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

PostedbyLorenShure,March1,2007
I'mpleasedtointroduceTimDavisasthisweek'sguestblogger.TimisaprofessorattheUniversityofFlorida,andistheauthororcoauthorofmany
ofoursparsematrixfunctions(lu,chol,muchofsparsebackslash,orderingmethodssuchasamdandcolamd,andotherfunctionssuchasetree
andsymbfact).Heisalsotheauthorofarecentbook,DirectMethodsforSparseLinearSystems,publishedbySIAM,wheremoredetailsofMATLAB
sparsematricesarediscussed(http://www.cise.ufl.edu/~davis).

Contents

MATLABisSlow?OnlyIfYouUseItIncorrectly

HowNottoCreateaFiniteElementMatrix

What'sWrongwithIt?

HowMATLABStoresSparseMatrices

ABetterWaytoCreateaFiniteElementMatrix

Moral:DoNotAbuseA(i,j)=...forSparseAUsesparseInstead

TryaFasterSparseFunction

WhenFastisNotFastEnough...

MATLABisSlow?OnlyIfYouUseItIncorrectly
Fromtimetotime,Ihearcommentssuchas"MATLABisslowforlargefiniteelementproblems."WhenIlookatthedetails,theproblemistypically
duetoanoveruseofA(i,j)= ...whencreatingthesparsematrix(assemblingthefiniteelements).Thiscanbeseenintypicaluser'scode,
MATLABcodeinbooksonthetopic,andeveninMATLABitself.Theproblemiswidespread.MATLABcanbeveryfastforfiniteelementproblems,
butnotifit'susedincorrectly.

HowNottoCreateaFiniteElementMatrix
Agoodexampleofwhatnottodocanbefoundinthewathen.mfunction,inMATLAB.A=gallery('wathen',200,200)takesahugeamountof
timeaveryminormodificationcutstheruntimedrastically.I'mnotintendingtosingleoutthisonefunctionforcritiquethisisaverycommonissue
thatIseeoverandoveragain.ThisfunctionisbuiltintoMATLAB,whichmakesitanaccessibleexample.ItwasfirstwrittenwhenMATLABdidnot
supportsparsematrices,andwasmodifiedonlyslightlytoexploitsparsity.Itwasnevermeantforgeneratinglargesparsefiniteelementmatrices.
Youcanseetheentirefunctionwiththecommand:

typeprivate/wathen.m
Belowisanexcerptoftherelevantpartsofwathen.m.Thefunctionwathen1.mcreatesafiniteelementmatrixofannxbynymesh.Eachiloop
createsasingle8by8finiteelementmatrix,andaddsitintoA.

typewathen1
tic
A=wathen1(200,200)
toc

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

1/8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

functionA=wathen1(nx,ny)
rand('state',0)
e1=[66286326202666820632]
e2=[38268168202838620816]
e=[e1e2e2'e1]/45
n=3*nx*ny+2*nx+2*ny+1
A=sparse(n,n)
RHO=100*rand(nx,ny)
nn=zeros(8,1)
forj=1:ny
fori=1:nx
nn(1)=3*j*nx+2*i+2*j+1
nn(2)=nn(1)1
nn(3)=nn(2)1
nn(4)=(3*j1)*nx+2*j+i1
nn(5)=3*(j1)*nx+2*i+2*j3
nn(6)=nn(5)+1
nn(7)=nn(6)+1
nn(8)=nn(4)+1
em=e*RHO(i,j)
forkrow=1:8
forkcol=1:8
A(nn(krow),nn(kcol))=A(nn(krow),nn(kcol))+em(krow,kcol)
end
end
end
end
Elapsedtimeis305.832709seconds.

What'sWrongwithIt?
Theabovecodeisfineforgeneratingamodestsizedmatrix,buttheA(i,j) = ...statementisquiteslowwhenAislargeandsparse,particularly
wheniandjarealsoscalars.Theinnertwoforloopscanbevectorizedsothatiandjarevectorsoflength8.EachA(i,j) = ...statementis
assemblinganentirefiniteelementmatrixintoA.However,thisleadstoveryminimalimprovementinruntime.

typewathen1b
tic
A1b=wathen1b(200,200)
toc

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

2/8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

functionA=wathen1b(nx,ny)
rand('state',0)
e1=[66286326202666820632]
e2=[38268168202838620816]
e=[e1e2e2'e1]/45
n=3*nx*ny+2*nx+2*ny+1
A=sparse(n,n)
RHO=100*rand(nx,ny)
nn=zeros(8,1)
forj=1:ny
fori=1:nx
nn(1)=3*j*nx+2*i+2*j+1
nn(2)=nn(1)1
nn(3)=nn(2)1
nn(4)=(3*j1)*nx+2*j+i1
nn(5)=3*(j1)*nx+2*i+2*j3
nn(6)=nn(5)+1
nn(7)=nn(6)+1
nn(8)=nn(4)+1
em=e*RHO(i,j)
A(nn,nn)=A(nn,nn)+em
end
end
Elapsedtimeis282.945593seconds.

disp(norm(AA1b,1))

HowMATLABStoresSparseMatrices
Tounderstandwhytheaboveexamplesaresoslow,youneedtounderstandhowMATLABstoresitssparsematrices.AnnbynMATLABsparse
matrixisstoredasthreearraysI'llcallthemp,i,andx.ThesethreearraysarenotdirectlyaccessiblefromM,buttheycanbeaccessedbya
mexFunction.Thenonzeroentriesincolumnjarestoredini(p(j):p(j+1)-1)andx(p(j):p(j+1)-1),wherexholdsthenumericalvaluesand
iholdsthecorrespondingrowindices.Belowisaverysmallexample.First,Icreateafullmatrixandconvertitintoasparseone.Thisisonlysothat
youcaneasilyseethematrixCandhowit'sstoredinsparseform.Youshouldnevercreateasparsematrixthisway,exceptfortinyexamples.

C=[
4.50.03.20.0
3.12.90.00.9
0.01.73.00.0
3.50.40.01.0]
C=sparse(C)

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

3/8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

C=
(1,1)4.5000
(2,1)3.1000
(4,1)3.5000
(2,2)2.9000
(3,2)1.7000
(4,2)0.4000
(1,3)3.2000
(3,3)3.0000
(2,4)0.9000
(4,4)1.0000
NoticethatthenonzeroentriesinCarestoredincolumnorder,withsortedrowindices.Theinternalp,i,andxarrayscanbereconstructedas
follows.Thefind(C)statementreturnsalistof"triplets,"wherethekthtripletisi(k),j(k),andx(k).ThisspecifiesthatC(i(k),j(k))isequalto
x(k).Next,find(diff(...))constructsthecolumnpointerarrayp(thisonlyworksiftherearenoallzerocolumnsinthematrix).

[ijx]=find(C)
n=size(C,2)
p=find(diff([0jn+1]))
forcol=1:n
fprintf('column%d:\nkrowindexvalue\n',col)
disp([(p(col):p(col+1)1)'i(p(col):p(col+1)1)x(p(col):p(col+1)1)])
end

column1:
krowindexvalue
1.00001.00004.5000
2.00002.00003.1000
3.00004.00003.5000
column2:
krowindexvalue
4.00002.00002.9000
5.00003.00001.7000
6.00004.00000.4000
column3:
krowindexvalue
7.00001.00003.2000
8.00003.00003.0000
column4:
krowindexvalue
9.00002.00000.9000
10.00004.00001.0000
NowconsiderwhathappenswhenoneentryisaddedtoC:

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

4/8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

C(3,1)=42
[ijx]=find(C)
n=size(C,2)
p=find(diff([0jn+1]))
forcol=1:n
fprintf('column%d:\nkrowindexvalue\n',col)
disp([(p(col):p(col+1)1)'i(p(col):p(col+1)1)x(p(col):p(col+1)1)])
end

column1:
krowindexvalue
1.00001.00004.5000
2.00002.00003.1000
3.00003.000042.0000
4.00004.00003.5000
column2:
krowindexvalue
5.00002.00002.9000
6.00003.00001.7000
7.00004.00000.4000
column3:
krowindexvalue
8.00001.00003.2000
9.00003.00003.0000
column4:
krowindexvalue
10.00002.00000.9000
11.00004.00001.0000
andyoucanseethatnearlyeveryentryinChasbeenmoveddownbyoneintheiandxarrays.Ingeneral,thesinglestatementC(3,1)=42takes
timeproportionaltothenumberofentriesinmatrix.Thus,loopingnnz(A)timesoverthestatementA(i,j)=A(i,j)+...takestimeproportionalto
nnz(A)^2.

ABetterWaytoCreateaFiniteElementMatrix
Theversionbelowisonlyslightlydifferent.Itcouldbeimproved,butIleftitnearlythesametoillustratehowsimpleitistowritefastMATLABcodeto
solvethisproblem,viaaminortweak.Theideaistocreatealistoftriplets,andletMATLABconvertthemintoasparsematrixallatonce.Ifthereare
duplicates(whichafiniteelementmatrixalwayshas)theduplicatesaresummed,whichisexactlywhatyouwantwhenassemblingafiniteelement
matrix.InMATLAB7.3(R2006b),sparseusesquicksort,whichtakesnnz(A)*log(nnz(A))time.Thisisslowerthanitcouldbe(alineartime
bucketsortcanbeused,takingessentiallynnz(A)time).However,it'sstillmuchfasterthannnz(A)^2.Forthismatrix,nnz(A)isabout1.9million.

typewathen2.m
tic
A2=wathen2(200,200)
toc

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

5/8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

functionA=wathen2(nx,ny)
rand('state',0)
e1=[66286326202666820632]
e2=[38268168202838620816]
e=[e1e2e2'e1]/45
n=3*nx*ny+2*nx+2*ny+1
ntriplets=nx*ny*64
I=zeros(ntriplets,1)
J=zeros(ntriplets,1)
X=zeros(ntriplets,1)
ntriplets=0
RHO=100*rand(nx,ny)
nn=zeros(8,1)
forj=1:ny
fori=1:nx
nn(1)=3*j*nx+2*i+2*j+1
nn(2)=nn(1)1
nn(3)=nn(2)1
nn(4)=(3*j1)*nx+2*j+i1
nn(5)=3*(j1)*nx+2*i+2*j3
nn(6)=nn(5)+1
nn(7)=nn(6)+1
nn(8)=nn(4)+1
em=e*RHO(i,j)
forkrow=1:8
forkcol=1:8
ntriplets=ntriplets+1
I(ntriplets)=nn(krow)
J(ntriplets)=nn(kcol)
X(ntriplets)=em(krow,kcol)
end
end
end
end
A=sparse(I,J,X,n,n)
Elapsedtimeis1.594073seconds.

disp(norm(AA2,1))

1.4211e014
Ifyoudonotknowhowmanyentriesyourmatrixwillhave,youmaynotbeabletopreallocatetheI,J,andXarrays,asdoneinwathen2.m.Inthat
case,startthematareasonablesize(anythinglargerthanzerowilldo)andaddthiscodetotheinnermostloop,justafterntripletsis
incremented:

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

6/8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

len=length(X)
if(ntriplets>len)
I(2*len)=0
J(2*len)=0
X(2*len)=0
end
andwhendone,usesparse(I(1:ntriplets),J(1:ntriplets),X(1:ntriplets),n,n).

Moral:DoNotAbuseA(i,j)=...forSparseAUsesparseInstead
Avoidstatementssuchas

C(4,2)=C(4,2)+42
inaloop.Createalistoftriplets(i,j,x)andusesparseinstead.Thisadviceholdsforanysparsematrix,notjustfiniteelementones.

TryaFasterSparseFunction
CHOLMODincludesasparse2mexFunctionwhichisareplacementforsparse.Itusesalineartimebucketsort.TheMATLAB7.3(R2006b)
sparseaccountsforabout3/4thsthetotalruntimeofwathen2.m.Forthismatrixsparse2inCHOLMODisabout10timesfasterthantheMATLAB
sparse.CHOLMODcanbefoundintheSuiteSparsepackage,inMATLABCentral.
IfyouwouldliketoseeashortandconciseCmexFunctionimplementationofthemethodusedbysparse2,takealookatCSparse,whichwas
writtenforaconcisetextbookstylepresentation.Thecs_sparsemexFunctionusescs_compress.c,toconvertthetripletstoacompressedcolumn
formofA',cs_dupl.ctosumupduplicateentries,andthencs_transpose.ctotransposetheresult(whichalsosortsthecolumns).

WhenFastisNotFastEnough...
EvenwiththisdramaticimprovementinconstructingthematrixA,MATLABcouldstilluseadditionalfeaturesforfasterconstructionofsparsefinite
elementmatrices.Constructingthematrixshouldbemuchfasterthanx=A\b,sincecholisdoingabout700timesmoreworkassparseforthis
matrix(1.3billionflops,vs1.9millionnonzerosinA).Theruntimesarenotthatdifferent,however:

tic
A=wathen2(200,200)
toc
b=rand(size(A,1),1)
tic
x=A\b
toc

Elapsedtimeis1.720397seconds.
Elapsedtimeis3.125791seconds.

GettheMATLABcode
PublishedwithMATLAB7.4

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

7/8

7/1/2016

CreatingSparseFiniteElementMatricesinMATLABLorenontheArtofMATLAB

http://blogs.mathworks.com/loren/2007/03/01/creatingsparsefiniteelementmatricesinmatlab/

8/8

You might also like