Extending MATLAB With Numerical Recipes
Extending MATLAB With Numerical Recipes
ExtendingMATLABwithNumericalRecipes
ExtendingM
withNumericalRecipes
[DifficultyprintingthisdocumenthasbeenreportedforthebrowsersIE6andIE7.Ifyouencounterthis,youcanprintthedocumentfromthisPDFversion.]
NumericalRecipescode,orforthatmatteranyotherC++code,caneasilybeinvokedfromwithinMATLAB,from
theconsole,orfromMATLABfunctionswritteninmcode.Forsometasks,C++executeshugelyfasterthan
MATLABmcode,andyoucanalsoaccessfeaturesinNumericalRecipes(orelsewhere)thatarenotavailablein
MATLAB.YoucancodesomepartsofyourprojectinmcodeandotherpartsinC++,andcontrolthewhole
projectfromtheMATLABconsoleorcommandline.
Thisdocumentshowshowthisisdone,withexamplesoftwodifferentcodingmethodologies:(1)"API",using
theMATLABCAPIfunctioncalls,and(2)"NR3",usingthespecialNumericalRecipesincludefilenr3matlab.h.
Wethinkthat"NR3"isthebestchoice(it'ssimplertocode)butwealsoshow"API"examplessothatyoucan
understandtheunderlyingMATLABinterface.
Contents
ConventionsandOverview
"Hello,world!"UsingtheMatlabCAPI
DoJustOnce:IntroduceMatlabtoYourCompiler
TheNR3CodingMethod
"Hello,world!"Usingnr3matlab.h
AccessingMatlabVectorswithnr3matlab.h
LivingDangerously
LivingSafely
AccessingMatlabScalarswithnr3matlab.h
Matrices:"ThroughtheLookingGlass"(TTLG)
AccessingMatlabMatriceswithnr3matlab.h
WrapperFunctionsThatAccessMultipleMemberFunctionsinaClass
TheAPICodingMethod
TipsonMatlabCAPIProgramming
NumericalRecipesUsingtheMatlabCAPI
Appendix:UsingMicrosoftVisualStudio
ConventionsandOverview
MATLABmcode,ortextfromtheMATLABconsoleisshownonaredbackground:
% MATLAB code
[a b] = someroutine(c,d)
C++codeisshownonagreenbackground:
/* C++ code */
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
// don't worry yet about these weird types!
}
Acompiled,executablefilethatisinvokedbyaMATLABcommandiscalleda"mexfile".Mexfilesarewrittenas
sourcecodeoutsideoftheMATLABconsole,inatexteditorsuchasviorEmacsortheMATLABeditor,orinan
integrateddevelopmentenvironment(IDE)suchasMicrosoftVisualStudio.
Mexsourcecodefilesmustbecompiledandlinked.ThiscanbedoneeitherfromtheMATLABconsoleusingthe
command"mex",orelsefromtheIDE.Thefinalstepis,ifnecessary,tomovethecompiledmexfileintoyour
MATLABworkingdirectoryorpath.
Amexfile,asonecompilationunit,alwayscodesexactlyoneMATLABcallablefunction.Infact,thenameofthe
compiledmexfunctionistheMATLABfunctionnameusedtoaccessit.(Thatnametypicallydoesn'tevenappear
inthesourcecode,unlessyouhappentoincludeitinacomment!)
Ofcourse,withinyourmexfileyoucandoanynumberofC++functioncalls,memoryallocationsor
deallocations,inputoutput,andsoforth,beforereturningcontrol(eitherwithorwithoutreturnvalues)tothe
MATLABconsoleorcallingmfile.YoucanalsoaccessexistingorcreatenewnamedvariablesinMATLAB's
workspace,independentofwhethertheyareinputargumentstoyourmexfunction.
Hello,world!UsingtheM
http://numerical.recipes/nr3_matlab.html
CAPI
1/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
Hereissourcecodeforamexfunctionthatreceivesaninputarrayofarbitrarysizeandshapeandreturnsthe
squaresofeachofitselementsasarowvector.Oh,yes,italsoprints"Hello,world!"totheMATLABconsole.
/* helloworld.cpp */
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
int i, n = mxGetNumberOfElements(prhs[0]);
double *indata = (double *)mxGetData(prhs[0]);
plhs[0] = mxCreateNumericMatrix(1,n,mxDOUBLE_CLASS,mxREAL);
double *outdata = (double *)mxGetData(plhs[0]);
for (i=0;i<n;i++) outdata[i] = indata[i]*indata[i];
printf("Hello, world!\n");
}
WecompileitfromtheMATLABconsole,
>> mex helloworld.cpp
>>
Anexampleofusingournewmexfunctionis
>> b = [1 2 3; 4 5 6]
b =
1
2
3
4
5
6
>> a = helloworld(b)
Hello, world!
a =
1
16
4
25
>>
DoJustOnce:IntroduceM
36
toYourCompiler
YoumightwonderhowwegotthemexcommandtocompileC++source,sinceMATLABcomesonlywithabuilt
in,ratherbraindead,Ccompiler.TheansweristhatyouneedtohaveaC++compileralreadyonyourmachine
and,justonce,youneedtointroduceMATLABtoit.ForLinux,g++andIntelC++arelikelycompilersfor
WindowseitherMicrosoftVisualC++orIntelC++.
Tobindthe"mex"commandtoacompiler,dosomethinglikethefollowing:
>> mex -setup
Please choose your compiler for building external interface (MEX) files:
Would you like mex to locate installed compilers [y]/n? y
Select a compiler:
[1] Intel C++ 9.1 (with Microsoft Visual C++ 2005 linker)
in C:\Program Files\Intel\Compiler\C++\9.1
[2] Lcc-win32 C 2.4.1 in C:\PROGRA~1\MATLAB\R2007A~1\sys\lcc
[3] Microsoft Visual C++ 2005 in C:\Program Files\Microsoft Visual Studio 8
[4] Microsoft Visual C++ .NET 2003
in C:\Program Files\Microsoft Visual Studio .NET 2003
[5] Microsoft Visual C++ 6.0 in C:\Program Files\Microsoft Visual Studio
[0] None
Compiler: 3
Please verify your choices:
Compiler: Microsoft Visual C++ 2005
Location: C:\Program Files\Microsoft Visual Studio 8
Are these correct?([y]/n): y
Trying to update options file:
C:\Documents and Settings\...\MathWorks\MATLAB\R2007a\mexopts.bat
From template: C:\PROGRA~1\MATLAB\R2007A~1\bin\win32\mexopts\msvc80opts.bat
http://numerical.recipes/nr3_matlab.html
2/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
Done . . .
>>
TheaboveshowsaWindowsmachinewithseveralinstalledcompilers.Yourchoicesmaybefewer.Options1or
3abovewouldbegoodchoices.Option2,thebraindeadCcompiler,wouldnotbe.
TheNR3CodingMethod
TheNR3codingmethoduseswrapperfunctionsthatareintheincludefilenr3matlab.hinsteadoftheMATLAB
CAPI.Ofcourse,youcanalsouseanyoftheAPIfunctionsdirectly.Butyoushouldrarelyorneverneedto.
MexsourcefilesintheNR3codingmethodalwayshaveexactlytheframework
#include "nr3matlab.h"
/* you may put other stuff here */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
/* you must put something here */
}
ThevoidmexFunction(...)lineissomewhatequivalenttotheintmain(...)inordinaryC++
programming.(Youdon'tincludeamainroutineinmexfiles.)
Withinyourmexcode,youaregiventheintegernumberofarguments,nrhs,andtheexpectednumberof
returnedvaluesnlhs.Bothargumentsandreturnvaluesmayofcoursebearrays.Below,we'llseehowtouse
theinputargumentsplhsandprhswiththeNR3codingmethod.
Althoughtheorderofpresentationmightatfirstseemodd,we'lldiscussvectors,thenscalars,andfinally
matrices.But,beforeanyofthese,wemustofcourserepeatthe"Hello,world!"example,nowinNR3coding
style:
Hello,world!Usingnr3matlab.h
UsingtheNR3codingmethod,our"Hello,world!"mexfunctionisrathermorereadablethanbefore.
/* helloworld2.cpp */
#include "nr3matlab.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
MatDoub indata(prhs[0]);
Int i, j, k=0, m=indata.nrows(), n=indata.ncols();
VecDoub outdata(m*n,plhs[0]);
for (i=0;i<m;i++) for (j=0;j<n;j++) outdata[k++] = SQR(indata[i][j]);
printf("Hello, world!\n");
}
Executionisnodifferentfrombefore.
>> mex
>> b =
b =
1
4
>> a =
Hello,
a =
1
helloworld2.cpp
[1 2 3; 4 5 6]
2
3
5
6
helloworld2(b)
world!
16
AccessingM
25
36
Vectorswithnr3matlab.h
Theincludefilenr3matlab.hismostlythesameasthestandardNR3includefilenr3.h.Whatitaddsaresome
newvectorconstructorsandanewvectormemberfunction.ThesemakeiteasytointeractwithMATLABvectors
inanaturalway,withoutneedingtousetheAPImxfunctions.(Thatis,naturalforC++programmerswhohave
acopyofNumericalRecipes!)
Forreference,theadditionstothetemplatedclassNRvectorare:
template <class T> class NRvector {
/* ... */
NRvector(const mxArray *prhs);
// map Matlab rhs to vector
http://numerical.recipes/nr3_matlab.html
3/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
}
See,nomxfunctions!Except,ofcourse,mexFunctionitself,whichisalwaysrequired.Althoughtheabove
exampleshowsonlyVecDoubexemplars,everythingwouldworkfineforothertypesofvectors,e.g.,VecInt.The
constructorscheckfortypeconsistencyasnecessary,andreportanerrorifyouhavedonesomethingtype
inconsistent.Let'sseeitwork:
>> bb = [1 2 3]
bb =
1
2
3
>> dd = [4 5 6]
dd =
4
5
6
>> cc = NRvectorDemo(bb)
cc =
1
4
9
>> ee
ee =
4
4
5
5
>> bb
bb =
999
2
3
>> dd
dd =
999
5
6
>>
Thenr3matlab.hvectorconstructorscanaccessanynumericalMATLABarray,flatteningittoavectorinthe
MATLABstorageorder("bycolumns"or"Fortranlike"or"reverseofodometer").So,forexample,
>> bb = [1 2; 3 4]
bb =
1
2
3
4
>> dd = [5 6; 7 8]
dd =
http://numerical.recipes/nr3_matlab.html
4/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
5
7
>>
cc
>>
bb
>>
dd
6
8
cc = NRvectorDemo(bb)
=
1
9
4
16
bb
=
999
2
3
4
dd
=
999
6
7
8
>>
Noticethatthe"dangerous"operations,becausetheywritedirectlyintoMATLAB'sworkspace,don'tflattenthe
matricestovectors,sincethematricesstayinMATLABspace.
LivingDangerously
Officially,wehavetosay,"don'tdoit!".ButsincethereasonyouareprogammingC++withinMATLABis
probablyforperformanceonbigdatasets,youwillprobablywanttousetheoperationsthatwelabelaboveas
"dangerous".Weusethemallthetime.
WhatisdangerousabouttheseoperationsisnotthattheywillcrashMATLABorvoidyourwarranty(iftherewere
one,alwaysdoubtfulforsoftware).Thedangeristhattheycanhaveunintendedcomputationalsideeffects.If
youunderstandthese,youcanmanagethembutifyoudon't,youmightberathersurprised:
>> bb = [1 2 3]
bb =
1
2
3
>> bbsave = bb
bbsave =
1
2
3
>> dd = [4 5 6]
dd =
4
5
6
>> cc = NRvectorDemo(bb)
cc =
1
4
9
>> bb
bb =
999
2
3
>> bbsave
bbsave =
999
2
3
>>
KnowingthatbbwasgoingtobemodifiedbyNRvectorDemo,youcarefullysavedacopybbsave.Butlook:itgot
modifiedtoo.ThereasonisthatMATLAB'sclevermemorymanagementusesa"copyonmodify"strategy.Had
youmodifiedbbinsideMATLAB,itwouldhavecopiedbbsave'svaluesatthatpoint.Butsincewemodifieditwith
a"dangerous"method,undetectablebyMATLAB,thesavedcopynevergotmade.
Moral:Ifyouaregoingtousenr3matlab.h'sabilitytomodifyvaluesdirectlyinMATLABspace,besurethatthere
arenoexactcopiesofthevariablethatyoucareabout.Ifnecessary,youcanenforceuniquenessbytrickery,
suchas
bbsave = bb;
bb = bb .* 0.5; bb = bb .* 2;
butthisshouldalmostneverbenecessaryifyoujustkeepinmindthecopyhistoryofyourlargedatavariables.
So,shouldn'tthisscareyouawayfromlivingdangerously?Maybe.ButsupposeyouhaveaMATLABdatavectorof
length108,andyouintendtoapplyaseriesofC++mexfunctionstosomespecificcomponentsofthevector.
Youcanreadthosecomponentsusingnondangerousnr3matlab.hmethods.Buttheonlynondangerousway
towritethemisbythe.put()method,whichcopiesbackthewholevector.Ifthatisjusttooslow,thenthe
"dangerous"operationsarejustwhatyouneed.
LivingSafely
http://numerical.recipes/nr3_matlab.html
5/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
IfyouworrythatyoumightaccidentallywriteintoMATLABspace,youshoulddeclarevectorsderivedfromrhs
argumentsorMATLABnamedvariableswithconst.Then,thecompilerwillcatchanysuchaccidents.Changed
linesfromtheexampleaboveare:
const VecDoub b(prhs[0]);
// bind a rhs argument
const VecDoub d("dd");
// bind the variable dd
b[0] = 999.;
/* caught as compile time error */
d[0] = 999.;
/* caught as compile time error */
IfyoulaterdecidethatyoudowanttowriteintoMATLABspaceafterall,youcandosomethinglikethis:
VecDoub &bx = const_cast<VecDoub&>(b);
bx[0] = 999.;
// modifies b, no compile time error
AccessingM
Scalarswithnr3matlab.h
TurnnowtoMATLABscalars.
Sincescalarslikedoubleandintarefundamentaltypes,wecan'toverloadfunctionalityintotheirconstructors,
aswedidforvectors.Instead,withinnr3matlab.hseveraloverloadedversionsofatemplatedfunction
mxScalararedefined.(Notethat,despitethenamingconvention,thisisaNumericalRecipes,nota
MathWorks,function.)Thesefunctionsletyougrabscalarvalues,eitherfromyourmexfunction'sarguments,
orfromvariablesintheMATLABworkspace.TheyalsoletyoubindaC++variabletoanyofyourfunction'sreturn
values,andcopyscalarvaluesintonamedvariables(existingornew)inMATLAB'sworkspace.
Forreference,thefunctionsaredeclaredasfollows:
template
template
template
template
<class
<class
<class
<class
T>
T>
T>
T>
Easiertounderstandissamplecode.(NotethatwearenowprogramminginNR3style,usingtypedef'dtypes
likeDoub.Youdon'thavetodothisifyoudon'twantto.)
/* mxScalarDemo.cpp */
#include "nr3matlab.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
// normal usage of mxScalar:
// get a rhs argument by value
Doub a = mxScalar<Doub>(prhs[0]);
// bind a reference to a lhs returned value
Doub &b = mxScalar<Doub>(plhs[0]);
b = SQR(a); // set a return value, e.g.
// get a named variable in MATLAB space by value
Doub c = mxScalar<Doub>("cc");
// set a named variable in MATLAB space
Doub d = SQR(c); // e.g.
mxScalar<Doub>(d,"dd");
// abnormal usage (OK but dangerous! -- see "Living Dangerously")
// get a non-const reference to a rhs argument
Doub &e = const_cast<Doub&>( mxScalar<Doub>(prhs[1]) );
e = SQR(e); // overwrite its value in MATLAB space
// get a non-const reference to a variable by name
Doub &f = const_cast<Doub&>( mxScalar<Doub>("ff") );
f = SQR(f); // overwrite its value in MATLAB space
}
Theactionofthisfunctionistoreturnthesquareofitsfirstargumentandsetthenamedvariableddtobethe
squareofthenamedvariablecc.Itthendoestwo"dangerous"operations:Itchangesthevalueofitssecond
http://numerical.recipes/nr3_matlab.html
6/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
righthandsideargumenttoitssquare,anditoverwritesanonconstreferencetothenamedvariableffwith
itssquare.Let'swatchitgo:
>> aa=2; bb=3; cc=4; dd=5; ee=6; ff=7;
>> [aa bb cc dd ee ff]
ans =
2
3
4
5
6
7
>> bb = mxScalarDemo(aa,ee)
bb =
4
>> [aa bb cc dd ee ff]
ans =
2
4
4
16
36
49
>>
Youcanverifythatthe"after"valuesarewhatweexpect.
AlthoughtheaboveexampleshowsonlyDoubscalars,everythingwouldworkfineforothertypes(e.g.,Int).The
mxScalarfuctionscheckfortypeconsistencyasnecessary,andreportanerrorifyouhavedonesomethingtype
inconsistent.
NoticethatthemxScalarfuctionsaretemplated,andalwaysrequireanexplicittemplateargumentlike
mxScalar<double>()ormxScalar<int>().ThisissothattypecheckingagainstMATLAB'stypecanbemade
automatic,withanerrorthrownifyoutrytodosomethingbad.
AlsonotethatmostMATLABscalarsaredouble,eventhingslikearraysizesthataremorelogicallyaninteger.So
youwilloftenfindyourselfimportingargumentslikethis:
int n = int(mxScalar<Doub>(prhs[0]));
Matrices:ThroughtheLookingGlass(TTLG)
Matricesarehandledprettymuchlikevectors,above,exceptforoneflyintheointment,thefactthatMATLAB
andC++storetheelementsofamatrixindifferentorders.Youmustunderstandthisbeforeusing
nr3matlab.hwithNRmatrixdatatypes,oryouwillberatherunhappy:yourmatriceswillsometimesbethe
transposeofwhatyouexpected!NRmatrixdatatypesincludeNR3typeslikeMatDoub,MatInt,etc.
Thegoalisperformance:Wewanttobeabletoworkwithpotentiallylargeamountsofdatafromboththe
MATLABsideandtheNumericalRecipessideofthemexinterface.Whatwemustavoidisunnecessarycopying
backandforth,notonlybecauseoftheactualcopying,butalsobecauseoftheoverheadinvolvedinrapidly
allocatinganddeallocatinglargechunksofmemory(thuspossiblydrivingMATLAB'smemorymanagerintopoor
performance).
Therefore,wewanttopointdirectlyintoMATLAB'smemory,bothtoreaddataandalso(withsomerestrictions)
towriteit.Forscalarvaluesandvectors,wesawthatthisposednospecialproblemsexceptunderstandingthe
implicationsof"dangerous"operationsandavoidingthem,ornot,accordingtoyourtaste.Matriceshavethe
additionalproblemofstorageorder:MATLABishardwiredtostorebycolumns("Fortranorder"or"reverseof
odometer"),whileC++ishardwiredtostorebyrows("Corder"or"odometerorder").
Weadopta"ThroughtheLookingGlass"(TTLG)approach:Inourinterface,whenaMATLABmatrixcrossesthe
interfaceintoC++,whatappearsontheothersideasitstranspose.Whenit(oranyotherC++matrix)issent
backacrosstheinterfacetoMATLAB,whatappearsisalsothetransposeofwhatwassent.So,forexample,a
matrixthatmakesaroundtripintoC++andbackagain(withoutbeingmodifiedbyC++code)isunchanged.
ThegoodnewsabouttheTLGCapproachisthatitmakesforaverycleanandefficientinterface.Thebadnewsis
thatyouhavetorememberthatyoualwaysreceivethetransposeofwhatwassent.Usuallyyoucanjustcodefor
thisonthefly:Whereyoumighthavewrittenmymatrix[i][j],youinsteadwritemymatrix[j][i],andso
forth.Inmanycases,suchasdoingsomethinginparalleltoalltheelementsofamatrix,thereisnothingto
rememberatall.Occasionally,whenyouabsolutelyneedtoprocessanuntransposedmatrix,youhavetotake
anexplicittranspose.Thisofcoursewillusememoryallocationandaddoverhead.
ItisimportanttounderstandthateachsideoftheTTLGinterfaceisselfconsistentaccordingtoitsownusual
conventions,bothastosizeandastosubscriptnumbering(1basedinMATLABvs.0basedinC++).So,if
mymatrixis3x5inMATLAB(3rows,5columns),andthus5x3inC++(5rows,3columns),thenthefollowing
quantitiesarenumericallyequal:
size(mymatrix,1)=3=mymatrix.ncols()
size(mymatrix,2)=5=mymatrix.nrows()
mymatrix(1,1)=mymatrix[0][0]
mymatrix(2,4)=mymatrix[3][1]
http://numerical.recipes/nr3_matlab.html
7/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
AccessingM
Matriceswithnr3matlab.h
Forreference,theadditionstothetemplatedclassNRmatrixare:
template <class T> class NRmatrix {
/* ... */
NRmatrix(const mxArray *prhs); // map Matlab rhs to matrix
NRmatrix(int n, int m, mxArray* &plhs); // create Matlab lhs and map to matrix
NRmatrix(const char *varname); // import Matlab variable by name
void put(const char *varname); // copy NRmatrix to a named Matlab variable
}
Easiertounderstandaresomeusageexamples:
/* NRmatrixDemo.cpp */
#include "nr3matlab.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
Int i,j,m,n;
// matrix rhs arguments and lhs return values
MatDoub b(prhs[0]);
// bind a rhs argument
m = b.nrows();
// get shape
n = b.ncols();
MatDoub c(m,n,plhs[0]); // create a lhs return value of same shape
for (i=0;im;i++) for (j=0;jn;j++) c[i][j] = SQR(b[i][j]);
// get and put values for named variables in MATLAB space
MatDoub d("dd"); // bind the variable dd
m = b.nrows();
// get shape
n = b.ncols();
MatDoub e(m,2*n); // make a local vector with twice as many cols
// duplicate each value (duplicating cols in C++, rows in Matlab!)
for (i=0;im;i++) for (j=0;jn;j++) e[i][2*j] = e[i][2*j+1] = d[i][j];
e.put("ee");
// copy e to MATLAB variable ee
// advanced usage (OK, but dangerous! see section "Living Dangerously")
MatDoub
MatDoub
b[0][1]
d[1][0]
&bx = const_castMatDoub&>(b);
&dx = const_castMatDoub&>(d);
= 999.;
// modify a rhs argument in MATLAB space
= 999.;
// modify a named variable with no copying
}
FromtheMATLABside,wecanusethemexfunctionNRmatrixDemolikethis.
>> mex NRmatrixDemo.cpp
>> bb = [1 2 3; 4 5 6]
bb =
1
2
3
4
5
6
>> dd = [7 8 9; 10 11 12]
dd =
7
8
9
10
11
12
>> cc = NRmatrixDemo(bb)
cc =
1
4
9
16
25
36
>> ee
ee =
7
8
9
7
8
9
10
11
12
10
11
12
>> bb
bb =
1
2
3
999
5
6
http://numerical.recipes/nr3_matlab.html
8/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
>> dd
dd =
7
10
999
11
9
12
Noticethatthemodifiedelementisb[0][1]ontheC++side,butb(2,1)ontheMATLABside,becauseofthe
TTLGapproach.
WrapperFunctionsThatAccessMultipleMemberFunctionsinaClass
Ifyouwantasinglemexfiletoperformmultiplefunctions(forexample,calldifferentmemberfunctionswithin
asingleclass),you'llneedtofigureoutontheC++sidewhatisintendedfromthenumberandtypeofright
handsidearguments.Youcanalsoincludeargumentsofcharactertypethatcanfunctionaskeywords.
Forexample,asimplewrapperfortheNumericalRecipesclassGaumixmod(Gaussianmixturemodel)might
havethesepossiblecallsontheMATLABside:
>> gmm('construct',data,means)
>> [mean sig] = gmm(k) % return the mean and covariance of the kth component
>> resp = gmm('response') % return the response matrix
>> gmm('delete') % delete the model
ThecorrespondingC++lookslikethis.NotetheuseofthefunctionsmxT()andmxT<>()totestthetypeof
MATLABarguments.Thesefunctionsareinnr3matlab.h.
/* gmm.cpp */
#include "nr3matlab.h"
#include "cholesky.h"
#include "gaumixmod.h"
Gaumixmod *gmm = NULL;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
int i,j,nn,kk,mm;
if (gmm) {nn=gmm->nn; kk=gmm->kk; mm=gmm->mm;}
if (gmm && nrhs == 1 && mxT(prhs[0]) == mxT<Doub>()) {
// [mean sig] = gmm(k)
Int k = Int(mxScalar<Doub>(prhs[0]));
if (nlhs > 0) {
VecDoub mean(mm,plhs[0]);
for (i=0;i<mm;i++) mean[i] = gmm->means[k-1][i];
}
if (nlhs > 1) {
MatDoub sig(mm,mm,plhs[1]);
for (i=0;i<mm;i++) for (j=0;j<mm;j++) sig[i][j] = gmm->sig[k-1][i][j];
}
} else if (nrhs == 1 && mxScalar<char>(prhs[0]) == 'd') {
// gmm('delete')
delete gmm;
} else if (gmm && nrhs == 1 && mxScalar<char>(prhs[0]) == 'r') {
// gmm('response')
if (nlhs > 0) {
MatDoub resp(nn,kk,plhs[0]);
for (i=0;i<nn;i++) for (j=0;j<kk;j++) resp[i][j] = gmm->resp[i][j];
}
} else if (gmm && nrhs == 2 && mxT(prhs[1]) == mxT<Doub>()) {
// deltaloglike = gmm('step',nsteps)
Int nstep = Int(mxScalar<Doub>(prhs[1]));
Doub tmp;
for (i=0;i<nstep;i++) {
tmp = gmm->estep();
gmm->mstep();
}
if (nlhs > 0) {
Doub &deltaloglike = mxScalar<Doub>(plhs[0]);
deltaloglike = tmp;
}
http://numerical.recipes/nr3_matlab.html
9/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
TheAPICodingMethod
Youneedtoreadthefollowingsectionsonlyifyouwanttogobeyondthecapabilitiesprovidedbynr3matlab.h
anduseMATLABCAPIcallsdirectly.
TipsonM
CAPIProgramming
MexfileprogrammingusingtheCAPIinterfaceiswelldocumentedontheMathWorkswebsite.Agoodstarting
pageisthechapteronexternalinterfaces,aswellastheCAPIReferencepage.Nevertheless,wewillmakeafew
additionalpointshere.
Mexsourcefilesalwayshaveexactlytheframework
#include "mex.h"
/* you may put other stuff here */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
/* you must put something here */
}
ThevoidmexFunction(...)lineissomewhatequivalenttotheintmain(...)inordinaryC++
programming.(Youdon'tincludeamainroutineinmexfiles.)
Withinyourmexcode,youaregiventhenumberofarguments,nrhs,theexpectednumberofreturned
valuesnlhs,whichmayofcoursebearrays,anarrayofpointerstotheinputstructures(mxArrays),and
anarrayofpointersthatyoupopulatewithoutputmxArrays,asshownintheexample.
AlthoughdatainMATLABis(asthenameimplies)organizedintosubscriptedmatricesandarrays,theC
APIalwayspresentsMATLABdataasaonedimensionalarray(above,indata).Theorderingisalwaysby
columns,notrows,or,moregenerally,withthelastsubscriptchangingleastrapidly("reverseof
odometer"or"Fortranorder").ItiseasytofindoutMATLAB'sviewoftheinternalmatrixarrangementby
APIcallslikemxGetM,mxGetN,mxGetNumberOfDimensions,mxGetDimensions,andafewothers.But,
onceyoudothis,itisuptoyoutolocatebysubscript(s)anydesiredelements.(Thisisbasicallywhatthe
nr3matlabinterfaceisdesignedtomakeeasier.)MATLAB'sFortranstorageorderinghasotherimplications
thatarediscussedinthesectionMatrices:"ThroughtheLookingGlass",above.
ThemxGetDatafunctionreturnsavoidpointertothedata.ItisuptoyoutocastittotheintendedC++
type.Above,wetrustedtheusertosendusdoubledata,whichisMATLAB'sdefaulttype(evenforthings
thatyoumightotherwiseexpecttobeintegers).Thatis,ofcourse,badprogramming.Weshouldhave
usedAPIfunctionslikemxIsDoubleormxGetClassIDtogetMATLAB'sopinionastothedatatype,and
thenabortedwithmexErrMsgTxtifitisnottheexpectedenumvaluemxDOUBLE_CLASS.
IfyouplantousetheAPIinterface,youshouldperusethefilematrix.hlocatedinthe/extern/include
directoryofyourMATLABinstallation.Amongotherthings,thisfiledefinestheclassnameslike
mxDOUBLE_CLASS.
NumericalRecipesUsingtheM
CAPI
AlthoughweprefertousetheNR3codingmethod,above,youcanperfectlywelluseNumericalRecipesThird
Edition(NR3)code,andthestandardnr3.hincludefile,withtheMATLABCAPIinterface.
Forexample,hereisamexfilethatmakesNR3'sgeneralizedFermiDiracintegralroutineavailabletoMATLAB.
(TheNR3routinedoesafancyquadrature,usingtheDErule.)
http://numerical.recipes/nr3_matlab.html
10/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
/* fermidirac.cpp */
#include "mex.h"
#include
#include
#include
#include
http://numerical.recipes/nr3_matlab.html
11/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
Becausethisexamplepassesandreturnsscalarsonly,thefilefermidirac.cppwouldnotlooktoodifferentin
theNR3codingmethod:mxScalarwouldreplacemxGetScalar,throwwouldreplacemexErrMsgTxt,and
mxCreateDoubleScalarwoulddisappear(sincefcouldbedeclareddirectlyasthereturnvalueplhs[0]).
Appendix:UsingMicrosoftVisualStudio
Inallsectionsabovewe'vedonethecompilationandlinkingfromtheMATLABconsole,usingthemexcommand.
WesawinthesectionDoJustOnce:IntroduceMatlabtoYourCompilerthatwecouldcausethemexcommand
touseourfavoritecompiler.Butwewerenotgettingtheconvenienceofcompilingwithinanintegrated
developmentenvironment(IDE)suchasMicrosoftVisualStudio.Thissectionexplainshowtodothisfor
MATLAB7.1+andVisualStudio2005.Otherversionsshouldbesimilar.
Wefollowtheusefularticleby"abn9c".WesupposethatyourfunctioniscalledMyFunc(maketheobvious
changesbelowforwhateveritisactuallynamed).
Followthesesteps:
1.CreateanewC++Win32consoleapplicationnamedMyFunc.Ifyouareofferedachoiceofapplication
type,chooseDLL.
2.InthemenuProject/AddExistingItem...addthefilemexversion.rc,locatedinyourMatlabinstall
directory(e.g.,atC:\ProgramFiles\MATLAB\R2007b\extern\include).You'llneedtoshowfilesoftype
"ResourceFiles"toseethisfile.
3.Createa.deffilewiththistext
LIBRARY MyFunc.mexw32
EXPORTS mexFunction
andaddittotheSolution.YoucancreateitwiththemenuFile/New/File...,choosing"HeaderFile.h"
type.Butafteryouentertheabovetext,savethefileasMyFunc.def,notMyFunc.h.AddittotheSolution
viamenuProject/AddExistingItem...
NowgotothemenuProject/MyFuncPropertiesforthefollowingsteps:
4.SelectConfiguration:AllConfigurations
5.UnderConfigurationProperties/General/ConfigurationType,choose.dllifitisnotalreadyselected.
http://numerical.recipes/nr3_matlab.html
12/13
11/17/2016
ExtendingMATLABwithNumericalRecipes
6.UnderConfigurationProperties/C++/General/AdditionalIncludeDirectories,addtheMATLAB
extern\includedirectory(e.g.,C:\ProgramFiles\MATLAB\R2007b\extern\include).
7.UnderConfigurationProperties/C++/Preprocessor/PreprocessorDefinitions,addMATLAB_MEX_FILE
8.UnderConfigurationProperties/Linker/General/OutputFile,change.dllto.mexw32.Youcouldalsohere
change$(OutDir)tothefullpathofyourMATLABworkingdirectory.(Thiswillsaveyoufromhavingto
recopytheoutputfileeverytimeyourecompile.)
9.UnderConfigurationProperties/Linker/General/AdditionalLibraryDependencies,add
extern\lib\win32\microsoft(e.g.,C:\ProgramFiles\MATLAB\R2007b\extern\lib\win32\microsoft).
10.UnderConfigurationProperties/Linker/Input/AdditionalDependenciesaddlibmx.lib,libmex.lib,and
libmat.lib.Youdon'tneedpaths,justthenames.
11.UnderConfigurationProperties/Linker/Input/ModuleDefinitionFileaddMyFunc.def(thatis,the.def
filethatyoualreadycreated).Youdon'tneedapath,justthefilename.
Youcannow"OK"outof"MyFuncPropertyPages".
12.InthemainMyFunc.cppwindow,youcannowerasewhateveris"helpfully"provided,andenteryourmex
code.Aminimalskeletonis
#include "stdafx.h"
#include "nr3matlab.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
printf("Hello, world!\n"); // remove this line after testing
}
13.Besurethatnr3matlab.hisinyourprojectdirectoryorincludepath.
14.IfyounowdothemenuBuild/BuildSolution,yourfileshouldcompileandlink.Ifnecessary,movethefile
MyFunc.mexw32toyourMATLABworkingdirectory.TestfromMATLAB:
>> MyFunc()
Hello, world!
IfyouexecuteMyFuncfromwithinMATLABbetweencompilations,youmightneedtodo
>> clear MyFunc
beforethelinkercanoverwriteanewfile,orbeforeyournewexecutableisrecognizedbyMATLAB.
MicrosoftVisualStudiodoesn'tmakeiteasytocopyalltheabovesettingsfromoneprojecttoanother.There
arevariouscommercialtoolsforthis,sothatyoudon'thavetokeepgoingthroughalltheabovestepsforeach
newmexfunctionthatyouwrite.(WeuseonecalledCopyWiz.)
http://numerical.recipes/nr3_matlab.html
13/13