{"id":1201,"date":"2015-05-18T12:00:42","date_gmt":"2015-05-18T17:00:42","guid":{"rendered":"https:\/\/blogs.mathworks.com\/cleve\/?p=1201"},"modified":"2016-12-05T14:04:25","modified_gmt":"2016-12-05T19:04:25","slug":"the-ziggurat-random-normal-generator","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/cleve\/2015\/05\/18\/the-ziggurat-random-normal-generator\/","title":{"rendered":"The Ziggurat Random Normal Generator"},"content":{"rendered":"<div class=\"content\"><!--introduction-->This is the third in a multi-part series on the MATLAB random number generators. MATLAB has used variants of George Marsaglia's ziggurat algorithm to generate normally distributed random numbers for almost twenty years.\r\n\r\n<!--\/introduction-->\r\n<h3>Contents<\/h3>\r\n<div>\r\n<ul>\r\n \t<li><a href=\"#388a367b-f5ed-4df3-8a0a-af1e4b35aac0\">The Ziggurat<\/a><\/li>\r\n \t<li><a href=\"#8fbc76e7-00e2-44aa-b0c8-118845649585\">Initialization<\/a><\/li>\r\n \t<li><a href=\"#ba356625-3964-40db-8a10-db8c32daa44f\">Central algorithm<\/a><\/li>\r\n \t<li><a href=\"#bd56e1e6-a742-4926-9bc4-b57cf8c9afe9\">Accuracy<\/a><\/li>\r\n \t<li><a href=\"#dbbddbe7-fd74-43e1-a73d-65f5a650fff1\">Variations<\/a><\/li>\r\n \t<li><a href=\"#20b286bf-5a3e-4dbd-bb3e-338523b27716\">Underlying Uniform Generator<\/a><\/li>\r\n \t<li><a href=\"#639a8298-8c24-48a1-906d-5cc35a98cc95\">Acknowledgements<\/a><\/li>\r\n \t<li><a href=\"#c7b335a3-e2ac-4be3-83c7-c8d8da082714\">References<\/a><\/li>\r\n<\/ul>\r\n<\/div>\r\n<h4>The Ziggurat<a name=\"388a367b-f5ed-4df3-8a0a-af1e4b35aac0\"><\/a><\/h4>\r\nIt's important to have a memorable name for an algorithm. Ziggurats are ancient Mesopotamian terraced temple mounds that, mathematically, are two-dimensional step functions. A one-dimensional ziggurat underlies Marsaglia's algorithm. I'm not sure if we would still be using the algorithm today if Marsaglia had called it the \"step function algorithm\".\r\n\r\nThe probability density function, or <i>pdf<\/i>, of the normal distribution is the bell-shaped curve\r\n\r\n$$ f(x) = c e^{-x^2\/2} $$\r\n\r\nwhere $c = 1\/(2\\pi)^{1\/2}$ is a normalizing constant that we can ignore. If we were to generate random points $(x,y)$, uniformly distributed in the plane, and reject any of them that do not fall under this curve, the remaining $x$'s form our desired normal distribution. The ziggurat algorithm covers the area under the pdf by a slightly larger area with $n$ sections. The following figure has $n = 6$; the actual code we use today has $n = 256$. The choice of $n$ affects the speed, but not the accuracy of the code.\r\n<pre class=\"codeinput\">   z = zigplot(6)\r\n<\/pre>\r\n<pre class=\"codeoutput\">z =\r\n\r\n         0\r\n    0.8288\r\n    1.1713\r\n    1.4696\r\n    1.7819\r\n    2.1761\r\n\r\n<\/pre>\r\n<img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/cleve\/ziggurat_blog_01.png\" alt=\"\" hspace=\"5\" vspace=\"5\" \/>\r\n\r\nThe top $n-1$ sections of the ziggurat are rectangles. The bottom section is a rectangle together with an infinite tail under the graph of $f(x)$. The right-hand edges of the rectangles are at the points $z_k$ shown with circles in the figure. With $f(z_1) = 1$ and $f(z_{n+1}) = 0$, the height of the $k$ th section is $f(z_k) - f(z_{k+1})$. The key idea is to choose the $z_k$'s so that all $n$ sections, including the unbounded one on the bottom, have the same area.\r\n\r\nThere are other algorithms that approximate the area under the pdf with rectangles. The distinguishing features of Marsaglia's algorithm are the facts that the rectangles are horizontal and have equal areas.\r\n<h4>Initialization<a name=\"8fbc76e7-00e2-44aa-b0c8-118845649585\"><\/a><\/h4>\r\nFor a specified number, $n$, of sections, it is possible to solve a transcendental equation to find $z_n$, the point where the infinite tail meets the last rectangular section. In our picture with $n = 6$, it turns out that $z_n = 2.18$. In an actual code with $n = 256$, $z_n = 3.6542$. Once $z_n$ is known, it is easy to compute the common area of the sections and the other right-hand endpoints $z_k$. It is also possible to compute $\\sigma_k = z_{k-1}\/z_k$, which is the fraction of each section that lies underneath the section above it. Let's call these fractional sections the <i>core<\/i> of the ziggurat. The right-hand edge of the core is the dotted line in our figure. The remaining portions of the rectangles, to the right of the dotted lines in the area covered by the graph of $f(x)$, are the <i>tips<\/i>. The computation of the $z_k$ 's and $\\sigma_k$ 's is done only once and the values included in the header of the source code.\r\n<h4>Central algorithm<a name=\"ba356625-3964-40db-8a10-db8c32daa44f\"><\/a><\/h4>\r\nWith this initialization, normally distributed random numbers can be computed very quickly. The key portion of the code computes a single random integer, $j$, between $1$ and $n$ and a single uniformly distributed random number, $u$, between $-1$ and $1$. A check is then made to see if $u$ falls in the core of the $j$ th section. If it does, then we know that $u z_j$ is the $x$-coordinate of a point under the pdf and this value can be returned as one sample from the normal distribution. The code looks something like this.\r\n<pre>  j = randi(256);\r\n  u = 2*rand-1;\r\n  if abs(u) &lt; sigma(j)\r\n     r = u*z(j);\r\n  else\r\n     r = tip_computation\r\n  end<\/pre>\r\nMost of the $\\sigma_j$'s are greater than 0.98, and the test is true over 98.5% of the time. One normal random number can usually be computed from one random integer, one random uniform, an if-test, and a multiplication. The point determined by $j$ and $u$ will fall in a tip region less than 1.5% of the time. This happens if $j = 1$ because the top section has no core, if $j$ is between $2$ and $n-1$ and the random point is in one of the tips, or if $j = n$ and the point is in the infinite tail. In these cases, the more costly tip computation is required.\r\n<h4>Accuracy<a name=\"bd56e1e6-a742-4926-9bc4-b57cf8c9afe9\"><\/a><\/h4>\r\nIt is important to realize that, even though the ziggurat step function only approximates the probability density function, the resulting distribution is exactly normal. Decreasing $n$ decreases the amount of storage required for the tables and increases the fraction of time that extra computation is required, but does not affect the accuracy. Even with $n = 6$, we would have to do the more costly corrections over 25% of the time, instead of less than 1.5%, but we would still get an exact normal distribution.\r\n<h4>Variations<a name=\"dbbddbe7-fd74-43e1-a73d-65f5a650fff1\"><\/a><\/h4>\r\nDetails of the ziggurat implementation have varied over the years. The original 1984 paper by Marsaglia and Tsang included a fairly elaborate transformation algorithm for handling the tips. We used this algorithm for several releases of MATLAB and I reproduced its behavior in the program <tt>randntx<\/tt> in <i>Numerical Computing with MATLAB<\/i>. That method and that code are now obsolete.\r\n\r\nThe 2000 paper by Marsaglia and Tsang available at the <tt>jstatsoft<\/tt> link given below has a simpler rejection algorithm for use in the tips. We have been using this in more recent releases of MATLAB, including current ones.\r\n<h4>Underlying Uniform Generator<a name=\"20b286bf-5a3e-4dbd-bb3e-338523b27716\"><\/a><\/h4>\r\nMarsaglia and Tsang were anxious to make their normal generator as fast as their uniform generator. But they were a little too anxious. Their original code made one call to a 32-bit uniform generator. They used the high order 7 bits for the vertical index $j$ into the ziggurat and then reused all 32 bits to get the horizontal abscissa $u$. Later investigators, including Jurgen Doornik, found this correlation led to failures of certain statistical tests.\r\n\r\nWe now make two calls to the 32-bit Mersenne Twister generator (during sequential computation). We take 8 bits to get $j$ and then 52 of the remaining 56 bits to get a double precision $u$.\r\n\r\nHow does this affect the timing? Allocate a long vector.\r\n<pre class=\"codeinput\">   clear\r\n   m = 25e6\r\n   x = zeros(m,1);\r\n<\/pre>\r\n<pre class=\"codeoutput\">m =\r\n\r\n    25000000\r\n\r\n<\/pre>\r\nGenerate a random uniform vector and a random normal vector. Then compare the two execution times.\r\n<pre class=\"codeinput\">   tic, x = rand(m,1); tu = toc\r\n   tic, x = randn(m,1); tn = toc\r\n   ratio = tu\/tn\r\n<\/pre>\r\n<pre class=\"codeoutput\">tu =\r\n\r\n    0.3416\r\n\r\n\r\ntn =\r\n\r\n    0.4520\r\n\r\n\r\nratio =\r\n\r\n    0.7558\r\n\r\n<\/pre>\r\nSo, random uniform execution time is about three-quarters of the random normal execution time.\r\n<h4>Acknowledgements<a name=\"639a8298-8c24-48a1-906d-5cc35a98cc95\"><\/a><\/h4>\r\nThanks to Peter Perkins for his help on the entire series about the MATLAB random number generators.\r\n\r\nThis post on the ziggurat is adapted from section 9.3 of <i>Numerical Computing with MATLAB<\/i>.\r\n<h4>References<a name=\"c7b335a3-e2ac-4be3-83c7-c8d8da082714\"><\/a><\/h4>\r\nGeorge Marsaglia and W. W. Tsang, \"A fast, easily implemented method for sampling from decreasing or symmetric unimodal density functions.\" <i>SIAM Journal on Scientific and Statistical Computing<\/i> 5, 349-359, 1984. <a href=\"http:\/\/epubs.siam.org\/doi\/pdf\/10.1137\/0905026\">&lt;http:\/\/epubs.siam.org\/doi\/pdf\/10.1137\/0905026<\/a>&gt;\r\n\r\nGeorge Marsaglia and W. W. Tsang, \"The ziggurat method for generating random variables.\" <i>Journal of Statistical Software<\/i> 5, 1-7, 2000. <a href=\"http:\/\/www.jstatsoft.org\/v05\/i08\">&lt;http:\/\/www.jstatsoft.org\/v05\/i08<\/a>&gt;\r\n\r\nJurgen A. Doornik, \"An Improved Ziggurat Method to Generate Normal Random Samples.\" PDF, Nutfield College, Oxford, 2005. <a href=\"http:\/\/www.doornik.com\/research\/ziggurat.pdf\">&lt;http:\/\/www.doornik.com\/research\/ziggurat.pdf<\/a>&gt;\r\n\r\nCleve Moler, <i>Numerical Computing with MATLAB<\/i>, SIAM 2004, <a href=\"http:\/\/dx.doi.org\/10.1137\/1.9780898717952\">&lt;http:\/\/dx.doi.org\/10.1137\/1.9780898717952<\/a>&gt; Also available at: &lt;<a href=\"https:\/\/www.mathworks.com\/content\/dam\/mathworks\/mathworks-dot-com\/moler\/random.pdf\">https:\/\/www.mathworks.com\/content\/dam\/mathworks\/mathworks-dot-com\/moler\/random.pdf<\/a>&gt;\r\n\r\n<script>\/\/ <![CDATA[\r\nfunction grabCode_ea84ef676c06467981e06433f02f80b6() {\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='ea84ef676c06467981e06433f02f80b6 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' ea84ef676c06467981e06433f02f80b6';\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('\r\n\r\n<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>\r\n\r\n\r\n\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }\r\n\/\/ ]]><\/script>\r\n<p style=\"text-align: right; font-size: xx-small; font-weight: lighter; font-style: italic; color: gray;\">\r\n<a><span style=\"font-size: x-small; font-style: italic;\">Get\r\nthe MATLAB code<noscript>(requires JavaScript)<\/noscript><\/span><\/a>\r\n\r\nPublished with MATLAB\u00ae R2014a<\/p>\r\n\r\n<\/div>\r\n<!--\r\nea84ef676c06467981e06433f02f80b6 ##### SOURCE BEGIN #####\r\n%% The Ziggurat Random Normal Generator\r\n% This is the third in a multi-part series on the MATLAB random number\r\n% generators.  MATLAB has used variants of George Marsaglia's ziggurat\r\n% algorithm to generate normally distributed random numbers for almost\r\n% twenty years.\r\n\r\n%% The Ziggurat\r\n% It's important to have a memorable name for an algorithm.\r\n% Ziggurats are ancient Mesopotamian terraced temple mounds that,\r\n% mathematically, are two-dimensional step functions.\r\n% A one-dimensional ziggurat underlies Marsaglia's algorithm.\r\n% I'm not sure if we would still be using the algorithm today if\r\n% Marsaglia had called it the \"step function algorithm\".\r\n\r\n%%\r\n% The probability density function, or _pdf_, of the normal distribution\r\n% is the bell-shaped curve\r\n%\r\n% $$ f(x) = c e^{-x^2\/2} $$\r\n%\r\n% where $c = 1\/(2\\pi)^{1\/2}$ is a normalizing constant that we can ignore.\r\n% If we were to generate random points $(x,y)$, uniformly distributed in\r\n% the plane, and reject any of them that do not fall under this curve,\r\n% the remaining $x$'s form our desired normal distribution. The ziggurat\r\n% algorithm covers the area under the pdf by a slightly larger area with\r\n% $n$ sections.  The following figure has $n = 6$; the actual code we use\r\n% today has $n = 256$. The choice of $n$ affects the speed, but not the\r\n% accuracy of the code.\r\n%\r\nz = zigplot(6)\r\n\r\n%%\r\n% The top $n-1$ sections of the ziggurat are rectangles.  The bottom section\r\n% is a rectangle together with an infinite tail under the graph of $f(x)$.\r\n% The right-hand edges of the rectangles are at the points $z_k$ shown with\r\n% circles in the figure.  With $f(z_1) = 1$ and $f(z_{n+1}) = 0$,\r\n% the height of the $k$ th section is $f(z_k) - f(z_{k+1})$.\r\n% The key idea is to choose the $z_k$'s so that all $n$ sections,\r\n% including the unbounded one on the bottom, have the same area.\r\n\r\n%%\r\n% There are other algorithms that approximate the area under the pdf with\r\n% rectangles.  The distinguishing features of Marsaglia's algorithm are the\r\n% facts that the rectangles are horizontal and have equal areas.\r\n\r\n%% Initialization\r\n% For a specified number, $n$, of sections, it is possible to solve a\r\n% transcendental equation to find $z_n$, the point where the infinite tail\r\n% meets the last rectangular section.  In our picture with $n = 6$, it turns\r\n% out that $z_n = 2.18$.  In an actual code with $n = 256$, $z_n = 3.6542$.\r\n% Once $z_n$ is known, it is easy to compute the common area of the sections\r\n% and the other right-hand endpoints $z_k$.  It is also possible to compute\r\n% $\\sigma_k = z_{k-1}\/z_k$, which is the fraction of each section that lies\r\n% underneath the section above it.  Let's call these fractional sections the\r\n% _core_ of the ziggurat.\r\n% The right-hand edge of the core is the dotted line in our figure.\r\n% The remaining portions of the rectangles, to the right of the dotted lines\r\n% in the area covered by the graph of $f(x)$, are the _tips_.\r\n% The computation of the $z_k$ 's and $\\sigma_k$ 's is done only once and\r\n% the values included in the header of the source code.\r\n\r\n%% Central algorithm\r\n% With this initialization, normally distributed random numbers can be computed\r\n% very quickly.  The key portion of the code computes a single random integer,\r\n% $j$, between $1$ and $n$ and a single uniformly distributed random number,\r\n% $u$, between $-1$ and $1$.  A check is then made to see if $u$ falls in the\r\n% core of the $j$ th section.  If it does, then we know that $u z_j$ is the\r\n% $x$-coordinate of a point under the pdf and this value can be returned as one\r\n% sample from the normal distribution.  The code looks something like this.\r\n%\r\n%    j = randi(256);\r\n%    u = 2*rand-1;\r\n%    if abs(u) < sigma(j)\r\n%       r = u*z(j);\r\n%    else\r\n%       r = tip_computation\r\n%    end\r\n\r\n%%\r\n% Most of the $\\sigma_j$'s are greater than 0.98, and the test is true over\r\n% 98.5% of the time.  One normal random number can usually be computed from\r\n% one random integer, one random uniform, an if-test, and a multiplication.\r\n% The point determined by $j$ and $u$ will fall in a tip region less than\r\n% 1.5% of the time.  This happens if $j = 1$ because the top section has no\r\n% core, if $j$ is between $2$ and $n-1$ and the random point is in one of\r\n% the tips, or if $j = n$ and the point is in the infinite tail.  In these\r\n% cases, the more costly tip computation is required.\r\n\r\n%% Accuracy\r\n% It is important to realize that, even though the ziggurat step function\r\n% only approximates the probability density function, the resulting\r\n% distribution is exactly normal.  Decreasing $n$ decreases the amount of\r\n% storage required for the tables and increases the fraction of time that\r\n% extra computation is required, but does not affect the accuracy.\r\n% Even with $n = 6$, we would have to do the more costly corrections over\r\n% 25% of the time, instead of less than 1.5%, but we would still get an\r\n% exact normal distribution.\r\n\r\n%% Variations\r\n% Details of the ziggurat implementation have varied over the years.\r\n% The original 1984 paper by Marsaglia and Tsang included a fairly elaborate\r\n% transformation algorithm for handling the tips.  We used this algorithm\r\n% for several releases of MATLAB and I reproduced its behavior in the program\r\n% |randntx| in  _Numerical Computing with MATLAB_.  That method and that\r\n% code are now obsolete.\r\n\r\n%%\r\n% The 2000 paper by Marsaglia and Tsang available at the |jstatsoft|\r\n% link given below has a simpler rejection algorithm for use in the tips.\r\n% We have been using this in more recent releases of MATLAB, including\r\n% current ones.\r\n\r\n%% Underlying Uniform Generator\r\n% Marsaglia and Tsang were anxious to make their normal generator as\r\n% fast as their uniform generator.  But they were a little too anxious.\r\n% Their original code made one call to a 32-bit uniform generator.\r\n% They used the high order 7 bits for the vertical index $j$ into the\r\n% ziggurat and then reused all 32 bits to get the horizontal abscissa $u$.\r\n% Later investigators, including Jurgen Doornik, found this correlation\r\n% led to failures of certain statistical tests.\r\n\r\n%%\r\n% We now make two calls to the 32-bit Mersenne Twister generator\r\n% (during sequential computation).  We take 8 bits to get $j$ and then\r\n% 52 of the remaining 56 bits to get a double precision $u$.\r\n\r\n%%\r\n% How does this affect the timing?  Allocate a long vector.\r\n\r\nclear\r\nm = 25e6\r\nx = zeros(m,1);\r\n\r\n%%\r\n% Generate a random uniform vector and a random normal vector.\r\n% Then compare the two execution times.\r\n\r\ntic, x = rand(m,1); tu = toc\r\ntic, x = randn(m,1); tn = toc\r\nratio = tu\/tn\r\n\r\n%%\r\n% So, random uniform execution time is about three-quarters of the random\r\n% normal execution time.\r\n\r\n%% Acknowledgements\r\n% Thanks to Peter Perkins for his help on the entire series\r\n% about the MATLAB random number generators.\r\n\r\n%%\r\n% This post on the ziggurat is adapted from section 9.3 of\r\n%  _Numerical Computing with MATLAB_.\r\n\r\n%% References\r\n% George Marsaglia and W. W. Tsang,\r\n% \"A fast, easily implemented method for sampling from decreasing or\r\n% symmetric unimodal density functions.\"\r\n% _SIAM Journal on Scientific and Statistical Computing_ 5, 349-359, 1984.\r\n% <http:\/\/epubs.siam.org\/doi\/pdf\/10.1137\/0905026 % http:\/\/epubs.siam.org\/doi\/pdf\/10.1137\/0905026>\r\n\r\n%%\r\n% George Marsaglia and W. W. Tsang,\r\n% \"The ziggurat method for generating random variables.\"\r\n% _Journal of Statistical Software_ 5, 1-7, 2000.\r\n% <http:\/\/www.jstatsoft.org\/v05\/i08 % http:\/\/www.jstatsoft.org\/v05\/i08>\r\n\r\n%%\r\n% Jurgen A. Doornik,\r\n% \"An Improved Ziggurat Method to Generate Normal Random Samples.\"\r\n% PDF, Nutfield College, Oxford, 2005.\r\n% <http:\/\/www.doornik.com\/research\/ziggurat.pdf % http:\/\/www.doornik.com\/research\/ziggurat.pdf>\r\n\r\n%%\r\n% Cleve Moler,  _Numerical Computing with MATLAB_, SIAM 2004,\r\n% <http:\/\/dx.doi.org\/10.1137\/1.9780898717952 % http:\/\/dx.doi.org\/10.1137\/1.9780898717952>\r\n% Also available at:\r\n% <https:\/\/www.mathworks.com\/moler.htmlrandom.pdf % https:\/\/www.mathworks.com\/moler.htmlrandom.pdf>\r\n\r\n##### SOURCE END ##### ea84ef676c06467981e06433f02f80b6\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/cleve\/ziggurat_blog_01.png\" onError=\"this.style.display ='none';\" \/><\/div><!--introduction-->This is the third in a multi-part series on the MATLAB random number generators. MATLAB has used variants of George Marsaglia's ziggurat algorithm to generate normally distributed random numbers for almost twenty years.\r\n\r\n<!--\/introduction-->... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/cleve\/2015\/05\/18\/the-ziggurat-random-normal-generator\/\">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,4,8,14,26],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/1201"}],"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=1201"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/1201\/revisions"}],"predecessor-version":[{"id":2190,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/1201\/revisions\/2190"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/media?parent=1201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/categories?post=1201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/tags?post=1201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}