{"id":1198,"date":"2015-05-04T12:00:54","date_gmt":"2015-05-04T17:00:54","guid":{"rendered":"https:\/\/blogs.mathworks.com\/cleve\/?p=1198"},"modified":"2015-05-03T19:46:55","modified_gmt":"2015-05-04T00:46:55","slug":"parallel-random-number-generators","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/cleve\/2015\/05\/04\/parallel-random-number-generators\/","title":{"rendered":"Parallel Random Number Generators"},"content":{"rendered":"<div class=\"content\"><!--introduction--><p>This is the second of a multi-part series about the MATLAB random number generators. If you ask for <tt>help rng<\/tt>, you will get lots of information, including the fact that there are three modern generators.<\/p><pre>'twister'              Mersenne Twister\r\n'combRecursive'        Combined Multiple Recursive\r\n'multFibonacci'        Multiplicative Lagged Fibonacci<\/pre><p>My <a href=\"https:\/\/blogs.mathworks.com\/cleve\/2015\/04\/17\/random-number-generator-mersenne-twister\/\">previous post<\/a> was about <tt>twister<\/tt>.  Today's post is about the other two, <tt>'combRecursive'<\/tt> and <tt>'multFibonacci'<\/tt>, which are designed for parallel computing.<\/p><!--\/introduction--><h3>Contents<\/h3><div><ul><li><a href=\"#cf5703d7-9a0f-40f1-9928-63d6e8369e79\">Parallel computing demo<\/a><\/li><li><a href=\"#3da37c24-033c-4859-9407-ad921f5280a5\">Parallel streams<\/a><\/li><li><a href=\"#65dcad46-23a2-4b15-bf79-ca9b99b8ff2a\">combRecursive<\/a><\/li><li><a href=\"#59bc3566-aa44-4dac-8935-1e82f0160b41\">multFibonacci<\/a><\/li><li><a href=\"#8ab0cbf9-c690-4c98-ac2e-2408e5f8ee14\">Which one?<\/a><\/li><li><a href=\"#9c82a652-1be3-4d30-a6ea-1e4d9acddf05\">Thanks<\/a><\/li><li><a href=\"#0a35b445-b563-4e0f-b9db-bc69f6ec79de\">References<\/a><\/li><\/ul><\/div><h4>Parallel computing demo<a name=\"cf5703d7-9a0f-40f1-9928-63d6e8369e79\"><\/a><\/h4><p>I frequently use the card game Blackjack to demonstrate parallel computing. At the same time I can demonstrate the random number generators. I regard Blackjack as a financial instrument, not unlike the stock of a publicly traded company.  Simulating the size of an investment as a function of time is a typical application of the Monte Carlo technique.<\/p><p>Begin by opening a pool of workers.<\/p><pre class=\"codeinput\">   parpool;\r\n<\/pre><pre class=\"codeoutput\">Starting parallel pool (parpool) using the 'local' profile ... connected to 2 workers.\r\n<\/pre><p>Four players each play twenty thousand hands of Blackjack.<\/p><pre class=\"codeinput\">   p = 4;\r\n   n = 20000;\r\n<\/pre><p>Collect the results in this array.<\/p><pre class=\"codeinput\">   B = zeros(n,p);\r\n<\/pre><p>A parallel <tt>for<\/tt> loop executes a Blackjack program that knows nothing about parallel computing.<\/p><pre class=\"codeinput\">   <span class=\"keyword\">parfor<\/span> k = 1:p\r\n      B(:,k) = cumsum(blackjacksim(n));\r\n   <span class=\"keyword\">end<\/span>\r\n<\/pre><p>Plot the results.<\/p><pre class=\"codeinput\">   plot(B)\r\n   title([<span class=\"string\">'Blackjack , $ '<\/span>, int2str(sum(B(end,:)))])\r\n   xlabel(<span class=\"string\">'Number of hands'<\/span>)\r\n   ylabel(<span class=\"string\">'Stake, ($)'<\/span>)\r\n   axis([0 n -2500 2500])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/cleve\/random_blog2_01.png\" alt=\"\"> <h4>Parallel streams<a name=\"3da37c24-033c-4859-9407-ad921f5280a5\"><\/a><\/h4><p>The card dealing calls the random number generator.  It is essential that the different parallel workers have different, independent streams of random numbers.  The default MATLAB generator <tt>twister<\/tt> does not offer this feature.  Simply starting <tt>twister<\/tt> with different seeds on different workers does not provide statistically independent streams. So we turn to the other generators.  To see which one is in use here, run a small <tt>spmd<\/tt>, \"single program, multiple data\" block.<\/p><pre class=\"codeinput\">   <span class=\"keyword\">spmd<\/span>\r\n      r = rng\r\n      s = r.State'\r\n      format <span class=\"string\">short<\/span>\r\n      x = rand(1,7)\r\n   <span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeoutput\">Lab 1: \r\n  r = \r\n       Type: 'combRecursive'\r\n       Seed: 0\r\n      State: [12x1 uint32]\r\n  s =\r\n    Columns 1 through 6\r\n    1720035765  2052922678  1637499698  3048064580  1173461082  2391850890\r\n    Columns 7 through 12\r\n    1862757735  2368998908  1385613640  1660833332   146924518  3104031825\r\n  x =\r\n      0.8789    0.6969    0.0409    0.4609    0.7528    0.2871    0.5241\r\nLab 2: \r\n  r = \r\n       Type: 'combRecursive'\r\n       Seed: 0\r\n      State: [12x1 uint32]\r\n  s =\r\n    Columns 1 through 6\r\n     323405913  3817048408  3712601073  1070773748  1552739185  3267875480\r\n    Columns 7 through 12\r\n    1594297407  2533167732  3377045245  3413340742  2651847732  1248925296\r\n  x =\r\n      0.1072    0.3194    0.1048    0.6623    0.0878    0.3692    0.8035\r\n<\/pre><p>We see that we have two workers, that they are both using the <tt>combRecursive<\/tt> generator, that they have the same <tt>seed<\/tt>, but different <tt>states<\/tt>, so they are generating different random numbers.<\/p><h4>combRecursive<a name=\"65dcad46-23a2-4b15-bf79-ca9b99b8ff2a\"><\/a><\/h4><p>Also known as <tt>mrg32k3a<\/tt>. A 32-bit combined multiple recursive generator (CMRG), due to Pierre L'Ecuyer, at the Universite de Montreal, and his colleagues, described in the papers referenced below. This generator is similar to the CMRG implemented in the RngStreams package. It has a period of $2^{127}$, and supports up to $2^{63}$ parallel streams, via sequence splitting, and $2^{51}$ substreams each of length $2^{76}$. Here is a link to the C source code. <a href=\"http:\/\/www.iro.umontreal.ca\/~lecuyer\/myftp\/papers\/combmrg2.c\">combmrg2.c<\/a><\/p><p>The state of the backbone generator is a 2-by-3 array S that evolves at each step according to the linear recurrence expressed succinctly in MATLAB by<\/p><pre class=\"language-matlab\">m1 = 2^32 - 209;\r\nm2 = 2^32 - 22853;\r\nx1 = mod(1403580*S(1,2)-810728*S(1,3),m1);\r\nx2 = mod(527612*S(2,1)-1370589*S(2,3),m2);\r\nS = [x1 S(1,1) S(1,2))\r\n     x2 <span class=\"string\">S(2,1)<\/span> <span class=\"string\">S(2,2)]<\/span>;\r\n<\/pre><p>A single precision random real <tt>u<\/tt> is then produced by<\/p><pre class=\"language-matlab\">z = mod(x1-x2,m1);\r\n<span class=\"keyword\">if<\/span> z &gt; 0, u = z\/(m1+1); <span class=\"keyword\">else<\/span>, u = m1\/(m1+1); <span class=\"keyword\">end<\/span>\r\n<\/pre><p>The important feature of this generator is that it is possible to create different initial states for each worker in a parallel pool so that the resulting streams of random numbers are statistically independent.<\/p><h4>multFibonacci<a name=\"59bc3566-aa44-4dac-8935-1e82f0160b41\"><\/a><\/h4><p>Also known as <tt>mlfg6331_64<\/tt>. A 64-bit multiplicative lagged Fibonacci generator (MLFG), developed by Michael Mascagni and Ashok Srinivasan at Florida State University. This generator, which has lags $l=63$ and $k=31$, is similar to the MLFG implemented in the SPRNG package.  It has a period of approximately $2^{124}$.  It supports up to $2^{61}$ parallel streams, via parameterization, and $2^{51}$ substreams each of length $2^{72}$.<\/p><p>The state of this generator is a length 63 vector of 64-bit integers S. The recurrence relation is<\/p><p>$$ x_n = x_{n-k} \\times x_{n-l} (mod 2^{64}) $$<\/p><p>Each random double precision value is created using one 64-bit integer from the generator; the possible values are all multiples of $2^{-53}$ strictly within the interval (0,1).<\/p><p>Again, the important feature of this generator is that it is possible to create different initial states for each worker in a parallel pool so that the resulting streams of random numbers are statistically independent.<\/p><h4>Which one?<a name=\"8ab0cbf9-c690-4c98-ac2e-2408e5f8ee14\"><\/a><\/h4><p>Which one should you use?  Most of the time, stick with the default and you'll be OK.  You will get <tt>'twister'<\/tt> in serial computations and <tt>'combRecursive'<\/tt> on the workers in a parallel pool.  You can use<\/p><pre>rng('shuffle')<\/pre><p>at the beginning of a session if you want different sequences of random numbers in different sessions.  Otherwise, don't worry about setting the generator or the seed.<\/p><p>If you want to experiment, you can use <tt>rng<\/tt> to try different generators and different starting seeds on your computation.  If you find a problem where it makes a significant difference, please let us know.<\/p><h4>Thanks<a name=\"9c82a652-1be3-4d30-a6ea-1e4d9acddf05\"><\/a><\/h4><p>Thanks again to Peter Perkins.<\/p><h4>References<a name=\"0a35b445-b563-4e0f-b9db-bc69f6ec79de\"><\/a><\/h4><p>Pierre L'Ecuyer, R. Simard, E. J. Chen, and W. D. Kelton. \"An Objected-Oriented Random-Number Package with Many Long Streams and Substreams.\" Operations Research, 50(6):1073-1075. 2002. <a href=\"http:\/\/www.iro.umontreal.ca\/~lecuyer\/myftp\/papers\/streams00.pdf\">&lt;http:\/\/www.iro.umontreal.ca\/~lecuyer\/myftp\/papers\/streams00.pdf<\/a>&gt;<\/p><p>Pierre L'Ecuyer.  \"Good Parameters and Implementations for Combined Multiple Recursive Random Number Generators.\" Operations Research 47(1):159-164. 1999. <a href=\"http:\/\/dx.doi.org\/10.1287\/opre.47.1.159\">&lt;http:\/\/dx.doi.org\/10.1287\/opre.47.1.159<\/a>&gt;<\/p><p>Michael Mascagni and Ashok Srinivasan. \"Parameterizing Parallel Multiplicative Lagged-Fibonacci Generators.\" Parallel Computing, 30: 899-916. 2004. <a href=\"http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/mlfg.ps\">&lt;http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/mlfg.ps<\/a>&gt;<\/p><p>Michael Mascagni and Ashok Srinivasan. \"SPRNG: A Scalable Library for Pseudorandom Number Generation.\" ACM Transactions on Mathematical Software, Vol 26 436-461. 2000. <a href=\"http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/sprngacm.ps\">&lt;http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/sprngacm.ps<\/a>&gt;<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_78d7420caec24600867e54276e49c2e7() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='78d7420caec24600867e54276e49c2e7 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 78d7420caec24600867e54276e49c2e7';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2015 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_78d7420caec24600867e54276e49c2e7()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2014b<br><\/p><\/div><!--\r\n78d7420caec24600867e54276e49c2e7 ##### SOURCE BEGIN #####\r\n%% Parallel Random Number Generators\r\n% This is the second of a multi-part series about the MATLAB random number\r\n% generators.\r\n% If you ask for |help rng|, you will get lots of information, including\r\n% the fact that there are three modern generators.\r\n%\r\n%  'twister'              Mersenne Twister\r\n%  'combRecursive'        Combined Multiple Recursive\r\n%  'multFibonacci'        Multiplicative Lagged Fibonacci\r\n% \r\n% My <https:\/\/blogs.mathworks.com\/cleve\/2015\/04\/17\/random-number-generator-mersenne-twister\/\r\n% previous post> was about |twister|.  Today's post is about the other two,\r\n% |'combRecursive'| and |'multFibonacci'|, which are designed for parallel\r\n% computing.\r\n\r\n%% Parallel computing demo\r\n% I frequently use the card game Blackjack to demonstrate parallel computing.\r\n% At the same time I can demonstrate the random number generators.\r\n% I regard Blackjack as a financial instrument, not unlike the stock of a \r\n% publicly traded company.  Simulating the size of an investment as a \r\n% function of time is a typical application of the Monte Carlo technique.\r\n\r\n%%\r\n% Begin by opening a pool of workers.\r\n\r\n   parpool;\r\n\r\n%%\r\n% Four players each play twenty thousand hands of Blackjack.\r\n\r\n   p = 4;\r\n   n = 20000;\r\n\r\n%%\r\n% Collect the results in this array.\r\n\r\n   B = zeros(n,p);\r\n\r\n%%\r\n% A parallel |for| loop executes a Blackjack program\r\n% that knows nothing about parallel computing.\r\n\r\n   parfor k = 1:p\r\n      B(:,k) = cumsum(blackjacksim(n));\r\n   end\r\n\r\n%%\r\n% Plot the results.\r\n\r\n   plot(B)\r\n   title(['Blackjack , $ ', int2str(sum(B(end,:)))])\r\n   xlabel('Number of hands')\r\n   ylabel('Stake, ($)')\r\n   axis([0 n -2500 2500])\r\n\r\n%% Parallel streams\r\n% The card dealing calls the random number generator.  It is essential\r\n% that the different parallel workers have different, independent streams\r\n% of random numbers.  The default MATLAB generator |twister| does not offer\r\n% this feature.  Simply starting |twister| with different seeds on different\r\n% workers does not provide statistically independent streams.\r\n% So we turn to the other generators.  To see which one is in use here, run\r\n% a small |spmd|, \"single program, multiple data\" block.\r\n\r\n\r\n   spmd\r\n      r = rng\r\n      s = r.State'\r\n      format short\r\n      x = rand(1,7)\r\n   end\r\n\r\n%%\r\n% We see that we have two workers, that they are both using the |combRecursive|\r\n% generator, that they have the same |seed|, but different |states|,\r\n% so they are generating different random numbers.\r\n\r\n%% combRecursive\r\n% Also known as |mrg32k3a|.\r\n% A 32-bit combined multiple recursive generator (CMRG), due to Pierre L'Ecuyer,\r\n% at the Universite de Montreal, and his colleagues, described in the\r\n% papers referenced below.\r\n% This generator is similar to the CMRG implemented in the RngStreams package.\r\n% It has a period of $2^{127}$, and supports up to $2^{63}$ parallel streams,\r\n% via sequence splitting, and $2^{51}$ substreams each of length $2^{76}$.\r\n% Here is a link to the C source code.\r\n% <http:\/\/www.iro.umontreal.ca\/~lecuyer\/myftp\/papers\/combmrg2.c combmrg2.c>\r\n\r\n%%\r\n% The state of the backbone generator is a 2-by-3 array S that evolves\r\n% at each step according to the linear recurrence expressed succinctly in\r\n% MATLAB by\r\n%\r\n%   m1 = 2^32 - 209;\r\n%   m2 = 2^32 - 22853;\r\n%   x1 = mod(1403580*S(1,2)-810728*S(1,3),m1);\r\n%   x2 = mod(527612*S(2,1)-1370589*S(2,3),m2);\r\n%   S = [x1 S(1,1) S(1,2))\r\n%        x2 S(2,1) S(2,2)];\r\n%\r\n% A single precision random real |u| is then produced by\r\n%\r\n%   z = mod(x1-x2,m1);\r\n%   if z > 0, u = z\/(m1+1); else, u = m1\/(m1+1); end\r\n\r\n%%\r\n% The important feature of this generator is that it is possible to create\r\n% different initial states for each worker in a parallel pool so that the\r\n% resulting streams of random numbers are statistically independent.\r\n\r\n\r\n%% multFibonacci\r\n% Also known as |mlfg6331_64|.\r\n% A 64-bit multiplicative lagged Fibonacci generator (MLFG), developed by\r\n% Michael Mascagni and Ashok Srinivasan at Florida State University.\r\n% This generator, which has lags $l=63$ and $k=31$, is similar to the MLFG\r\n% implemented in the SPRNG package.  It has a period of approximately\r\n% $2^{124}$.  It supports up to $2^{61}$ parallel streams, via parameterization,\r\n% and $2^{51}$ substreams each of length $2^{72}$.\r\n\r\n%%\r\n% The state of this generator is a length 63 vector of 64-bit integers S.\r\n% The recurrence relation is\r\n%\r\n% $$ x_n = x_{n-k} \\times x_{n-l} (mod 2^{64}) $$\r\n%\r\n% Each random double precision value is created using one 64-bit integer\r\n% from the generator; the possible values are all multiples of $2^{-53}$\r\n% strictly within the interval (0,1).\r\n\r\n%%\r\n% Again, the important feature of this generator is that it is possible to\r\n% create different initial states for each worker in a parallel pool so\r\n% that the resulting streams of random numbers are statistically independent.\r\n\r\n%% Which one?\r\n% Which one should you use?  Most of the time, stick with the default\r\n% and you'll be OK.  You will get |'twister'| in serial computations and\r\n% |'combRecursive'| on the workers in a parallel pool.  You can use\r\n%\r\n%  rng('shuffle')\r\n%\r\n% at the beginning of a session if you want different sequences of\r\n% random numbers in different sessions.  Otherwise, don't worry\r\n% about setting the generator or the seed.\r\n\r\n%%\r\n% If you want to experiment, you can use |rng| to try different generators\r\n% and different starting seeds on your computation.  If you find a problem\r\n% where it makes a significant difference, please let us know.\r\n\r\n%% Thanks\r\n% Thanks again to Peter Perkins.\r\n\r\n%% References\r\n% Pierre L'Ecuyer, R. Simard, E. J. Chen, and W. D. Kelton.\r\n% \"An Objected-Oriented Random-Number Package with Many Long Streams and\r\n% Substreams.\" Operations Research, 50(6):1073-1075. 2002.\r\n% <http:\/\/www.iro.umontreal.ca\/~lecuyer\/myftp\/papers\/streams00.pdf\r\n% http:\/\/www.iro.umontreal.ca\/~lecuyer\/myftp\/papers\/streams00.pdf>\r\n\r\n%%\r\n% Pierre L'Ecuyer.  \"Good Parameters and Implementations for Combined\r\n% Multiple Recursive Random Number Generators.\"\r\n% Operations Research 47(1):159-164. 1999.\r\n% <http:\/\/dx.doi.org\/10.1287\/opre.47.1.159\r\n% http:\/\/dx.doi.org\/10.1287\/opre.47.1.159>\r\n\r\n%%\r\n% Michael Mascagni and Ashok Srinivasan.\r\n% \"Parameterizing Parallel Multiplicative Lagged-Fibonacci Generators.\"\r\n% Parallel Computing, 30: 899-916. 2004.\r\n% <http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/mlfg.ps\r\n% http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/mlfg.ps>\r\n\r\n%%\r\n% Michael Mascagni and Ashok Srinivasan.\r\n% \"SPRNG: A Scalable Library for Pseudorandom Number Generation.\"\r\n% ACM Transactions on Mathematical Software, Vol 26 436-461. 2000.\r\n% <http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/sprngacm.ps\r\n% http:\/\/www.cs.fsu.edu\/~asriniva\/papers\/sprngacm.ps>\r\n\r\n##### SOURCE END ##### 78d7420caec24600867e54276e49c2e7\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/cleve\/random_blog2_01.png\" onError=\"this.style.display ='none';\" \/><\/div><!--introduction--><p>This is the second of a multi-part series about the MATLAB random number generators. If you ask for <tt>help rng<\/tt>, you will get lots of information, including the fact that there are three modern generators.... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/cleve\/2015\/05\/04\/parallel-random-number-generators\/\">read more >><\/a><\/p>","protected":false},"author":78,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[11,27,19],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/1198"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/users\/78"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/comments?post=1198"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/1198\/revisions"}],"predecessor-version":[{"id":1199,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/1198\/revisions\/1199"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/media?parent=1198"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/categories?post=1198"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/tags?post=1198"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}