{"id":3535,"date":"2011-05-18T17:56:13","date_gmt":"2011-05-18T16:56:13","guid":{"rendered":"http:\/\/www.walkingrandomly.com\/?p=3535"},"modified":"2011-05-18T17:56:13","modified_gmt":"2011-05-18T16:56:13","slug":"a-faster-version-of-matlabs-lsqcurvefit-using-the-nag-toolbox-for-matlab","status":"publish","type":"post","link":"https:\/\/walkingrandomly.com\/?p=3535","title":{"rendered":"A faster version of MATLAB&#8217;s lsqcurvefit using the NAG Toolbox for MATLAB"},"content":{"rendered":"<p>MATLAB&#8217;s <a href=\"http:\/\/www.mathworks.com\/help\/toolbox\/optim\/ug\/lsqcurvefit.html\">lsqcurvefit<\/a> function is a very useful piece of code that will help you solve non-linear least squares curve fitting problems and it is used a lot by researchers at my workplace, <a href=\"http:\/\/www.manchester.ac.uk\/\">The University of Manchester<\/a>.\u00a0 As far as we are concerned it has two problems:<\/p>\n<ul>\n<li>lsqcurvefit is part of the Optimisation toolbox and, since we only have a limited number of licenses for that toolbox, the function is sometimes inaccessible.\u00a0 When we run out of licenses on campus users get the following error message<\/li>\n<\/ul>\n<pre>??? License checkout failed.\r\nLicense Manager Error -4\r\nMaximum number of users for Optimization_Toolbox reached.\r\nTry again later.\r\nTo see a list of current users use the lmstat utility or contact your License Administrator.<\/pre>\n<ul>\n<li>lsqcurvefit is written as an .m file and so isn&#8217;t as fast as it could be.<\/li>\n<\/ul>\n<p>One solution to these problems is to switch to the <a href=\"http:\/\/www.nag.co.uk\/numeric\/MB\/start.asp\">NAG Toolbox for MATLAB<\/a>.\u00a0 Since we have a full site license for this product, we never run out of licenses and, since it is written in compiled Fortran, it is sometimes a lot faster than MATLAB itself.\u00a0 However, the current version of the NAG Toolbox (Mark 22 at the time of writing) isn&#8217;t without its issues either:<\/p>\n<ul>\n<li>There is no direct equivalent to lsqcurvefit in the NAG toolbox.\u00a0 You have to use NAG&#8217;s equivalent of lsqnonlin instead (which NAG call e04fy)<\/li>\n<li>The current version of the NAG Toolbox, Mark 22, doesn&#8217;t support function handles.<\/li>\n<li>The NAG toolbox requires the use of the datatypes <strong>int32<\/strong> and <strong>int64<\/strong> depending on the architecture of your machine.\u00a0 The practical upshot of this is that your MATLAB code is suddenly a lot less portable.\u00a0 If you develop on a 64 bit machine then it will need modifying to run on a 32 bit machine and vice-versa.<\/li>\n<\/ul>\n<p>While working on optimising someone&#8217;s code a few months ago I put together a couple of .m files in an attempt to address these issues.\u00a0 My intent was to improve the functionality of these files and eventually publish them but I never seemed to find the time.\u00a0 However, they have turned out to be a minor hit and I&#8217;ve sent them out to researcher after researcher with the caveat <strong>&#8220;These are a first draft, I need to tidy them up sometime&#8221;<\/strong> only to get the reply &#8220;Thanks for that, I no longer have any license problems and my code is executing more quickly.&#8221;\u00a0 They may be simple but it seems that they are useful.<\/p>\n<p>So, until I find the time to add more functionality, here are my little wrappers that allow you to do non linear least squares fitting using the NAG Toolbox for MATLAB.\u00a0 They are about as minimal as you can get but they work and have proven to be useful time and time again.\u00a0 They also solve all 3 of the NAG issues mentioned above.<\/p>\n<ul>\n<li><a href=\"https:\/\/www.walkingrandomly.com\/images\/NAG\/MATLAB\/lsqcurvefit\/1\/nag_lsqcurvefit.m\">nag_lsqcurvefit.m<\/a><\/li>\n<li><a href=\"https:\/\/www.walkingrandomly.com\/images\/NAG\/MATLAB\/lsqcurvefit\/1\/nag_lsqcurvefit_aux.m\">nag_lsqcurvefit_aux.m<\/a><\/li>\n<\/ul>\n<p>To use them just put them <strong>both<\/strong> somewhere on your MATLAB path.\u00a0 The syntax is identical to lsqcurvefit but this first version of my wrapper doesn&#8217;t do anything more complicated than the following<\/p>\n<p>MATLAB:<\/p>\n<pre>[x,resnorm] = lsqcurvefit(@myfun,x0,xdata,ydata);<\/pre>\n<p>NAG with my wrapper:<\/p>\n<pre>[x,resnorm] = nag_lsqcurvefit(@myfun,x0,xdata,ydata);\r\n<\/pre>\n<p>I may add extra functionality in the future but it depends upon demand.<br \/>\n<strong> <\/strong><\/p>\n<p><strong>Performance<\/strong><\/p>\n<p>Let&#8217;s look at the example given on the <a href=\"http:\/\/www.mathworks.com\/help\/toolbox\/optim\/ug\/lsqcurvefit.html\">MATLAB help page for lsqcurvefit<\/a> and compare it to the NAG version.\u00a0 First create a file called myfun.m as follows<\/p>\n<pre>function F = myfun(x,xdata)\r\nF = x(1)*exp(x(2)*xdata);<\/pre>\n<p>Now create the data and call the MATLAB fitting function<\/p>\n<pre>% Assume you determined xdata and ydata experimentally\r\nxdata = [0.9 1.5 13.8 19.8 24.1 28.2 35.2 60.3 74.6 81.3];\r\nydata = [455.2 428.6 124.1 67.3 43.2 28.1 13.1 -0.4 -1.3 -1.5];\r\nx0 = [100; -1] % Starting guess\r\n[x,resnorm] = lsqcurvefit(@myfun,x0,xdata,ydata);<\/pre>\n<p>On my system I get the following timing for MATLAB (typical over around 10 runs)<\/p>\n<pre>tic;[x,resnorm] = lsqcurvefit(@myfun,x0,xdata,ydata); toc\r\nElapsed time is 0.075685 seconds.\r\n<\/pre>\n<p>with the following results<\/p>\n<pre>x =\r\n   1.0e+02 *\r\n   4.988308584891165\r\n  -0.001012568612537\r\n&gt;&gt; resnorm\r\nresnorm =\r\n   9.504886892389219\r\n<\/pre>\n<p>and for NAG using my wrapper function I get the following timing (typical over around 10 runs)<\/p>\n<pre>tic;[x,resnorm] = nag_lsqcurvefit(@myfun,x0,xdata,ydata); toc\r\nElapsed time is 0.008163 seconds.\r\n<\/pre>\n<p>So, for this example, <strong>NAG is around 9 times faster!<\/strong> The results agree with MATLAB to several decimal places<\/p>\n<pre>x =\r\n   1.0e+02 *\r\n   4.988308605396028\r\n  -0.001012568632465\r\n&gt;&gt; resnorm\r\nresnorm =\r\n   9.504886892366873\r\n<\/pre>\n<p>In the real world I find that the relative timings vary enormously and have seen speed-ups that range from a factor of 14 down to none at all.\u00a0 Whenever I am optimisng MATLAB code and see a lsqcurvefit function I always give the NAG version a quick try and am often impressed with the results.<\/p>\n<p>My system specs if you want to compare results: 64bit Linux on a Intel Core 2 Quad Q9650\u00a0 @ 3.00GHz running MATLAB 2010b and NAG Toolbox version MBL6A22DJL<\/p>\n<p><strong>More articles about NAG<br \/>\n<\/strong><\/p>\n<ul>\n<li><a href=\"https:\/\/www.walkingrandomly.com\/?p=1488\">A faster version of MATLAB&#8217;s fsolve using the NAG Toolbox for MATLAB<\/a><\/li>\n<li><a href=\"https:\/\/www.walkingrandomly.com\/?p=2782\">An alternative to the ranksum function using the NAG Toolbox for MATLAB<\/a><\/li>\n<li><a href=\"https:\/\/www.walkingrandomly.com\/?p=2475\">Playing with NAG\u2019s Library for SMP &amp; multicore (Or parallel programming made easy)<\/a><\/li>\n<li><a href=\"https:\/\/www.walkingrandomly.com\/?page_id=1662\">PyNAG &#8211; Calling the NAG C library from Python<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>MATLAB&#8217;s lsqcurvefit function is a very useful piece of code that will help you solve non-linear least squares curve fitting problems and it is used a lot by researchers at my workplace, The University of Manchester.\u00a0 As far as we are concerned it has two problems: lsqcurvefit is part of the Optimisation toolbox and, since [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[11,28,7],"tags":[],"class_list":["post-3535","post","type-post","status-publish","format-standard","hentry","category-matlab","category-nag-library","category-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3swhs-V1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=\/wp\/v2\/posts\/3535","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3535"}],"version-history":[{"count":8,"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=\/wp\/v2\/posts\/3535\/revisions"}],"predecessor-version":[{"id":3545,"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=\/wp\/v2\/posts\/3535\/revisions\/3545"}],"wp:attachment":[{"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3535"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3535"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/walkingrandomly.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3535"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}