{"id":655,"date":"2015-08-23T20:28:12","date_gmt":"2015-08-23T19:28:12","guid":{"rendered":"http:\/\/numbercrunch.de\/blog\/?p=655"},"modified":"2023-01-18T22:09:04","modified_gmt":"2023-01-18T21:09:04","slug":"mpl-a-message-passing-library","status":"publish","type":"post","link":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/","title":{"rendered":"MPL &#8211; A message passing library"},"content":{"rendered":"<p style=\"text-align: justify;\">The <a href=\"https:\/\/en.wikipedia.org\/wiki\/Message_Passing_Interface\" target=\"_blank\" rel=\"noopener noreferrer\">Message Passing Interface<\/a> (MPI) Standard defines a message passing library, which serves as the basis for many high-performance computing applications today. It provides portable scalable functions for data exchange in parallel computations for various parallel computing architectures. Originally application programing interfaces had been defined for C and Fortran as well as for C++. In the 2008 update, known as MPI-3, however, the C++ bindings have been removed from the MPI standard. During the various revisions the MPI standard became quite complex and dropping one of the three language bindings may have helped to keep the standard maintainable as a whole. Furthermore, the C++ bindings were not very well designed. Although object orientated techniques had been applied, the MPI C++ bindings did not come close to a well designed C++ library by today&#8217;s standards. <span class=\"kindle_author\"><a title=\"Posts by Jeff Squyres\" href=\"http:\/\/blogs.cisco.com\/author\/JeffSquyres\" rel=\"author\">Jeff Squyres<\/a><\/span> explains in more detail, what happened to the C++ bindings in his <a href=\"https:\/\/web.archive.org\/web\/20170421220544\/http:\/\/blogs.cisco.com\/performance\/the-mpi-c-bindings-what-happened-and-why\/\" target=\"_blank\" rel=\"noopener noreferrer\">blog<\/a>.<\/p>\n<p style=\"text-align: justify;\">Alternative C++ bindings to the MPI Standard are provided by <a href=\"http:\/\/www.boost.org\/doc\/libs\/1_59_0\/doc\/html\/mpi.html\" target=\"_blank\" rel=\"noopener noreferrer\">Boost MPI<\/a> and <a href=\"https:\/\/www.osl.iu.edu\/research\/oompi\/software.php\" target=\"_blank\" rel=\"noopener noreferrer\">OOMPI<\/a>, which was an early attempt to bring MPI 1 functionality to C++ in an object orientated way. Boost MPI uses rather modern C++ programing techniques to provide a very nice interface to the MPI standard&#8217;s core functionality. With Boost MPI programs become more type save (When sending data of a particular C++ type, the corresponding MPI data type is deduced by the compiler.) and sending data given by user defined structures or classes becomes much more easy than with the MPI standard&#8217;s C or C++ bindings. Although Boost MPI is a huge improvement over the <span class=\"st\">deprecated<\/span> C++ bindings of the MPI standard it has also its limitations.<\/p>\n<ul>\n<li style=\"text-align: justify;\">It is no longer actively maintained.<\/li>\n<li style=\"text-align: justify;\">Sending data of complex classes and structures is based on Boost serialization, which may cause performance reductions and does not work in heterogeneous environments (different endians etc.).<\/li>\n<li style=\"text-align: justify;\">Boost MPI provides no equivalent to derived MPI data types (strided vectors, sub matrices, etc.).<\/li>\n<li style=\"text-align: justify;\">Although Boost MPI supports the more general graph communicators, there are no functions for Cartesian communicators.<\/li>\n<li style=\"text-align: justify;\">Boost MPI is based on C++03, it does not benefit from new C++11 features.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Because C++ was dropped from the MPI standard and because Boost MPI does not fulfill all my needs for a flexible easy-to-use C++ message passing library I started to write my own massage passing library on top of MPI, just called MPL (Message Passing Library), see my <a href=\"https:\/\/github.com\/rabauke\/mpl\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub<\/a> account. Note that MPL will neither bring all functions of the C language API to C++ nor provide a direct mapping of the C API to some C++ functions and classes. Its focus is on the MPI core functions, ease of use, type safety, and elegance. It uses C++11 features, wherever reasonable, e.g., lambda functions as custom reduction operations.<\/p>\n<p style=\"text-align: justify;\">MPL relies heavily on templates and template meta programming and it comes just as a bunch of header files. Documentation is still missing and only available in form as the source code and a few sample programs. If you are familiar with MPI, however, the transition to MPL will not be difficult. Let us start with a hello-world type program:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">#include &lt;cstdlib&gt;\n#include &lt;iostream&gt;\n#include &lt;mpl\/mpl.hpp&gt;\n\nint main() {\n  const mpl::communicator &amp; comm_world(mpl::environment::comm_world());\n  std::cout &lt;&lt; \"Hello world! I am running on \\\"\" \n   \t    &lt;&lt; mpl::environment::processor_name() \n   \t    &lt;&lt; \"\\\". My rank is \"\n  \t    &lt;&lt; comm_world.rank()\n  \t    &lt;&lt; \" out of \" \n   \t    &lt;&lt; comm_world.size() &lt;&lt; \" processes.\\n\";\n  return EXIT_SUCCESS;\n}\n<\/pre>\n<p style=\"text-align: justify;\">Similar to <code>MPI_COMM_WORLD<\/code> in MPI, MPL has a global communicator that contains all processes, which belong to a parallel computation. Each communicator has a rank (the number of the process within a communicator) and a size (the total number of processes). The program shown above just prints for each process its rank, the size of the world communicator and the computer&#8217;s name, where the process runs. Note that with MPL it is not required to initialize or to finalize the massage passing library (<code>MPI_Init<\/code> and <code>MPI_Finalize<\/code> are called implicitly by some compiler magic.).<\/p>\n<p style=\"text-align: justify;\">Let us look at a less trivial example and see how messages are send and received. A very elementary example using the C language bindings of MPI and C++11 may look like this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">#include &lt;cstdlib&gt;\n#include &lt;complex&gt;\n#include &lt;iostream&gt;\n#include &lt;mpi.h&gt;\n\nint main(int argc, char *argv[]) {\n  MPI_Init(&amp;argc, &amp;argv);\n  int c_size, c_rank;\n  MPI_Comm_rank(MPI_COMM_WORLD, &amp;c_rank);\n  MPI_Comm_size(MPI_COMM_WORLD, &amp;c_size);\n  if (c_size&lt;2) {\n    MPI_Finalize();\n    return EXIT_FAILURE;\n  }\n  \/\/ send and receive a single floating point number\n  if (c_rank==0) {\n    double pi=3.14;\n    MPI_Send(&amp;pi, \/\/ pointer to memory\n         1, \/\/ number of data items\n         MPI_DOUBLE, \/\/ data type\n         1, \/\/ destination\n         0, \/\/ tag\n         MPI_COMM_WORLD \/\/ communicator\n         );\n    std::cout &lt;&lt; \"sent: \" &lt;&lt; pi &lt;&lt; '\\n';\n  } else if (c_rank==1) {\n    double pi=0;\n    MPI_Recv(&amp;pi, \/\/ pointer to memory\n         1, \/\/ number of data items\n         MPI_DOUBLE, \/\/ data type\n         0, \/\/ source\n         0, \/\/ tag\n         MPI_COMM_WORLD, \/\/ communicator\n         MPI_STATUS_IGNORE \/\/ ignore the receive status\n         );\n    std::cout &lt;&lt; \"got : \" &lt;&lt; pi &lt;&lt; '\\n';\n  }\n  MPI_Finalize();\n  return EXIT_SUCCESS;\n}\n<\/pre>\n<p style=\"text-align: justify;\">Here the standard MPI functions <code>MPI_Send<\/code> and <code>MPI_Recv<\/code> are employed. The function signature requires a lot of parameters: a pointer to a buffer, the number of items to be send or received, the data type, a source or destination, a tag, and finally the communicator. With MPL this simplifies a lot. MPL assumes that only one data item is send or received at a time, thus the number of data items is not needed to be specified. Furthermore, the underling MPI datatype will be deduced automatically at compile time by the compiler. This eliminates a typical error of MPI programs, e.g., passing a pointer to a do an integer by specifying <code>MPI_DOUBLE<\/code> as the data type. The tag, which may be used to distinguish between different kind of messages, becomes in MPL an argument with a default value, so it is optional. Thus, in MPL only the communicator, a reference to the data and a source or destination has to be given to the send and receive functions. The MPL equivalent to the MPI program shown above may look as:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">#include &lt;cstdlib&gt;\n#include &lt;complex&gt;\n#include &lt;iostream&gt;\n#include &lt;mpl\/mpl.hpp&gt;\n\nint main() {\n\u00a0 const mpl::communicator &amp;comm_world=mpl::environment::comm_world();\n\u00a0 if (comm_world.size()&lt;2)\n\u00a0\u00a0\u00a0 return EXIT_FAILURE;\n\u00a0 \/\/ send and recieve a single floating point number\n\u00a0 if (comm_world.rank()==0) {\n\u00a0\u00a0\u00a0 double pi=3.14;\n\u00a0\u00a0\u00a0 comm_world.send(pi, 1);\u00a0 \/\/ send to rank 1\n\u00a0\u00a0\u00a0 std::cout &lt;&lt; \"sent: \" &lt;&lt; pi &lt;&lt; '\\n';\n\u00a0 } else if (comm_world.rank()==1) {\n\u00a0\u00a0\u00a0 double pi=0;\n\u00a0\u00a0\u00a0 comm_world.recv(pi, 0);\u00a0 \/\/ receive from rank 0\n\u00a0\u00a0\u00a0 std::cout &lt;&lt; \"got : \" &lt;&lt; pi &lt;&lt; '\\n';\n\u00a0 }\n\u00a0 return EXIT_SUCCESS;\n}\n<\/pre>\n<p>Of course sending and receiving single data items will not be sufficient for a message passing library. This is why MPL introduces the concept of data layouts. Data layouts specify the memory layout of a set of data to be sent or received (similar to derived data types in MPI). The layout may be continuous, a strided vector etc. The data layout is provided as an additional parameter to sending or receiving functions and, in contrast to the case of single data items, data is passed via a pointer. The following example may give an idea how data layouts are used with MPL:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">#include &lt;cstdlib&gt;\n#include &lt;complex&gt;\n#include &lt;iostream&gt;\n#include &lt;vector&gt;\n#include &lt;mpl\/mpl.hpp&gt;\n\nint main() {\n  const mpl::communicator &amp;comm_world=mpl::environment::comm_world();\n  if (comm_world.size()&lt;2)\n    return EXIT_FAILURE;\n  std::vector&lt;double&gt; v(8);\n  mpl::contiguous_layout&lt;double&gt; v_layout(v.size());\n  \/\/ send and recieve a vector of floating point numbers\n  if (comm_world.rank()==0) {\n    double init=0;\n    for (double &amp;x : v) {\n      x=init;\n      ++init;\n    }\n    comm_world.send(v.data(), v_layout, 1);  \/\/ send to rank 1\n    std::cout &lt;&lt; \"sent: \";\n    for (double &amp;x : v) \n      std::cout &lt;&lt; x &lt;&lt; ' ';\n    std::cout &lt;&lt; '\\n';\n  } else if (comm_world.rank()==1) {\n    comm_world.recv(v.data(), v_layout, 0);  \/\/ receive from rank 0\n    std::cout &lt;&lt; \"got : \";\n    for (double &amp;x : v) \n      std::cout &lt;&lt; x &lt;&lt; ' ';\n    std::cout &lt;&lt; '\\n';\n  }\n  return EXIT_SUCCESS;\n}\n<\/pre>\n<p style=\"text-align: justify;\">Addendum: Besides MPL, Boost MPI and OOMPI there is <a href=\"https:\/\/github.com\/motonacciu\/mpp\/\" target=\"_blank\" rel=\"noopener noreferrer\">MPP<\/a>, which is a further library that attempts to bring MPI to modern C++.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Message Passing Interface (MPI) Standard defines a message passing library, which serves as the basis for many high-performance computing applications today. It provides portable scalable functions for data exchange in parallel computations for various parallel computing architectures. Originally application programing interfaces had been defined for C and Fortran as well as for C++. In&hellip; <a href=\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">MPL &#8211; A message passing library<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16,9,8],"tags":[],"class_list":["post-655","post","type-post","status-publish","format-standard","hentry","category-c","category-mpi","category-parallel-computing"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v25.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>MPL - A message passing library - Number Crunch<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"MPL - A message passing library - Number Crunch\" \/>\n<meta property=\"og:description\" content=\"The Message Passing Interface (MPI) Standard defines a message passing library, which serves as the basis for many high-performance computing applications today. It provides portable scalable functions for data exchange in parallel computations for various parallel computing architectures. Originally application programing interfaces had been defined for C and Fortran as well as for C++. In&hellip; Continue reading MPL &#8211; A message passing library\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\" \/>\n<meta property=\"og:site_name\" content=\"Number Crunch\" \/>\n<meta property=\"article:published_time\" content=\"2015-08-23T19:28:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-18T21:09:04+00:00\" \/>\n<meta name=\"author\" content=\"Heiko Bauke\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Heiko Bauke\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\"},\"author\":{\"name\":\"Heiko Bauke\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\"},\"headline\":\"MPL &#8211; A message passing library\",\"datePublished\":\"2015-08-23T19:28:12+00:00\",\"dateModified\":\"2023-01-18T21:09:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\"},\"wordCount\":951,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\"},\"articleSection\":[\"C++\",\"MPI\",\"parallel computing\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\",\"url\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\",\"name\":\"MPL - A message passing library - Number Crunch\",\"isPartOf\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#website\"},\"datePublished\":\"2015-08-23T19:28:12+00:00\",\"dateModified\":\"2023-01-18T21:09:04+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.numbercrunch.de\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"MPL &#8211; A message passing library\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#website\",\"url\":\"https:\/\/www.numbercrunch.de\/blog\/\",\"name\":\"Number Crunch\",\"description\":\"A computational science blog.\",\"publisher\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.numbercrunch.de\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\",\"name\":\"Heiko Bauke\",\"logo\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/image\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"MPL - A message passing library - Number Crunch","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/","og_locale":"en_US","og_type":"article","og_title":"MPL - A message passing library - Number Crunch","og_description":"The Message Passing Interface (MPI) Standard defines a message passing library, which serves as the basis for many high-performance computing applications today. It provides portable scalable functions for data exchange in parallel computations for various parallel computing architectures. Originally application programing interfaces had been defined for C and Fortran as well as for C++. In&hellip; Continue reading MPL &#8211; A message passing library","og_url":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/","og_site_name":"Number Crunch","article_published_time":"2015-08-23T19:28:12+00:00","article_modified_time":"2023-01-18T21:09:04+00:00","author":"Heiko Bauke","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Heiko Bauke","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#article","isPartOf":{"@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/"},"author":{"name":"Heiko Bauke","@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413"},"headline":"MPL &#8211; A message passing library","datePublished":"2015-08-23T19:28:12+00:00","dateModified":"2023-01-18T21:09:04+00:00","mainEntityOfPage":{"@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/"},"wordCount":951,"commentCount":1,"publisher":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413"},"articleSection":["C++","MPI","parallel computing"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/","url":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/","name":"MPL - A message passing library - Number Crunch","isPartOf":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#website"},"datePublished":"2015-08-23T19:28:12+00:00","dateModified":"2023-01-18T21:09:04+00:00","breadcrumb":{"@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/08\/mpl-a-message-passing-library\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.numbercrunch.de\/blog\/"},{"@type":"ListItem","position":2,"name":"MPL &#8211; A message passing library"}]},{"@type":"WebSite","@id":"https:\/\/www.numbercrunch.de\/blog\/#website","url":"https:\/\/www.numbercrunch.de\/blog\/","name":"Number Crunch","description":"A computational science blog.","publisher":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.numbercrunch.de\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413","name":"Heiko Bauke","logo":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts\/655"}],"collection":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/comments?post=655"}],"version-history":[{"count":26,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts\/655\/revisions"}],"predecessor-version":[{"id":962,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts\/655\/revisions\/962"}],"wp:attachment":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/media?parent=655"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/categories?post=655"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/tags?post=655"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}