{"id":390,"date":"2015-12-17T19:33:59","date_gmt":"2015-12-17T19:33:59","guid":{"rendered":"http:\/\/drsfenner.org\/blog\/?p=390"},"modified":"2016-02-05T16:28:51","modified_gmt":"2016-02-05T16:28:51","slug":"into-the-weeds-i-lapack-lapacke-and-three-paths","status":"publish","type":"post","link":"http:\/\/drsfenner.org\/blog\/2015\/12\/into-the-weeds-i-lapack-lapacke-and-three-paths\/","title":{"rendered":"Into the Weeds I &#8211; LAPACK, LAPACKE, and Three+ Paths"},"content":{"rendered":"<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<p>In the <a href=\"http:\/\/drsfenner.org\/blog\/2015\/12\/three-paths-to-least-squares-linear-regression\/\">last post<\/a>, we looked at three ways of solving the least-squares regression problem (Cholesky, QR, and SVD decompositions) using LAPACK routines in a round-about fashion. The different decompositions (i.e., factorizations) were performed by (1) calling a NumPy <code>np.linalg<\/code> routine that called (2) an LAPACK <a href=\"http:\/\/www.netlib.org\/lapack\/lug\/node25.html\">driver routine<\/a> for a &quot;bigger&quot; problem like <a href=\"http:\/\/www.netlib.org\/lapack\/lug\/node26.html\">linear equation solving<\/a> or <a href=\"http:\/\/www.netlib.org\/lapack\/lug\/node27.html\">least-squares<\/a>. The driver routine called one of the decompositions internally. <!--more--><\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"lapack-routines\">LAPACK Routines<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<p>Since the QR and SVD solutions both used a <em>copy<\/em> of our <span class=\"math inline\">\\(X\\)<\/span> matrix (or at least the memory used hinted at that), I want to dive into the lower level of LAPACK (avoiding NumPy) and call the driver routines directly. We&#8217;ll try to avoid doing the decompositions by hand, if we can!. The most immediate issue, in this series of experiments is: <em>how do we call the LAPACK routines?<\/em> Here is a table of the LAPACK routines used by the solver\/least squares routines in NumPy, SciPy, and cvxopt.<\/p>\n<table>\n<thead>\n<tr class=\"header\">\n<th align=\"left\">Python<br \/>Library<br \/>Routine<\/th>\n<th align=\"left\">Underlying<br \/>LAPACK<br \/>Routine<\/th>\n<th align=\"left\">Matrix Type<\/th>\n<th align=\"left\">Algorithm<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr class=\"odd\">\n<td align=\"left\"><code>sla.solve<\/code><br \/>w\/ <code>sym_pos=True<\/code><\/td>\n<td align=\"left\"><code>posv<\/code><\/td>\n<td align=\"left\">symmetric positive<br \/>definite matrix<\/td>\n<td align=\"left\">solve eqn using Cholesky<\/td>\n<\/tr>\n<tr class=\"even\">\n<td align=\"left\"><code>nla.solve<\/code><br \/><code>sla.solve<\/code><\/td>\n<td align=\"left\"><code>gesv<\/code><\/td>\n<td align=\"left\">square matrix<\/td>\n<td align=\"left\">solve eqn using LU<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td align=\"left\"><code>cla.solve<\/code><\/td>\n<td align=\"left\"><code>gels<\/code><\/td>\n<td align=\"left\">general matrix (full rank)<\/td>\n<td align=\"left\">least-squares via QR<\/td>\n<\/tr>\n<tr class=\"even\">\n<td align=\"left\"><code>sla.lstsq<\/code><\/td>\n<td align=\"left\"><code>gelss<\/code><\/td>\n<td align=\"left\">general matrix<\/td>\n<td align=\"left\">least-squares via SVD<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td align=\"left\"><code>nla.lstsq<\/code><\/td>\n<td align=\"left\"><code>gelsd<\/code><\/td>\n<td align=\"left\">general matrix<\/td>\n<td align=\"left\">least-squares via Divide-and-Conquer SVD<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The different libraries make use of different LAPACK routines. And, in general, the libraries only expose the LAPACK routines that they need. For example, <code>scipy.linalg<\/code> does not provide <code>dgels<\/code> (as of scipy-0.16.1) it is not listed in the <a href=\"http:\/\/docs.scipy.org\/doc\/scipy\/reference\/linalg.lapack.html#module-scipy.linalg.lapack\">scipy.linalg.lapack function list<\/a>. It is almost possible to pick and choose from each library to get the desired, underlying LAPACK routines, but I want to do something slightly different.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"lapack-fortran-to-c-sharksjets-montaguecapulet\">LAPACK: Fortran to C (Sharks\/Jets? Montague\/Capulet?)<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<p>One of the biggest obstacles to using LAPACK in Python is the fact that Python (at least CPython) and NumPy (and friends) are written in C. LAPACK is written in Fortran. This isn&#8217;t a show stopper. There are a number of interoperabiliity options out there: (1) converting Fortran to C (<code>f2c<\/code> program) and (2) linking Fortran binaries into a C program. The first is just a fancy pure-C program. The second generally requires declaring a C function prototype for the Fortran function you want to call (with something like: <code>extern &quot;C&quot; void dgels(arg1, arg2, etc.)<\/code>) and then simply calling the function. Here&#8217;s a <a href=\"http:\/\/nicolas.limare.net\/pro\/notes\/2014\/10\/31_cblas_clapack_lapacke\/\">quick overview<\/a>.<\/p>\n<p>Declaring your own prototypes is a real drag and it can also leave some holes in the conversion between C-land and Fortran-land. The biggest hole is the fact that Fortran stores data in <em>column-major<\/em> order, while C stores data in <em>row-major<\/em> order (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Row-major_order\">wikipedia:Row-major<\/a>). There are other issues as well and having a well-defined interface between the two layers is a really good idea. BLAS (lower level routines than LAPACK) has had one for years called <a href=\"http:\/\/www.netlib.org\/blas\/\">CBLAS<\/a>. However, it took significantly longer for LAPACK to get a standard C-interface: <a href=\"http:\/\/www.netlib.org\/lapack\/lapacke.html\">LAPACKE<\/a>. A quick side-note: <a href=\"http:\/\/www.netlib.org\/clapack\/\">CLAPACK<\/a> is a <code>f2c<\/code>&#8216;d version of LAPACK, so it provides similar functionality in a different way.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"lapacke-and-python\">LAPACKE and Python<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<p>After all that lead-in, my goal is to use LAPACKE to call LAPACK routines &#8212; from Python. It turns out that this is really easy. <a href=\"https:\/\/bitbucket.org\/mikefc\/py-liblapack\">py-liblapack<\/a> is a tiny shim built using <a href=\"http:\/\/cffi.readthedocs.org\/en\/latest\/\">a Python CFFI library called cffi<\/a>. Here, CFFI stands for <em>C foreign function interface<\/em> and that acronym shows up all over the place. One example is <a href=\"https:\/\/common-lisp.net\/project\/cffi\/\">LISP&#8217;s CFFI<\/a> where the C stands for <em>Common<\/em>. Anyway, <code>cffi<\/code> let&#8217;s us do some really cool things:<\/p>\n<ol style=\"list-style-type: decimal\">\n<li>Define and allocate C-level objects (variables). For example, <code>workspace = ffi.new(&quot;int[]&quot;, n)<\/code> creates a Python reference to a length-<code>n<\/code> <code>int<\/code> array<\/li>\n<li>Read in declarations from a <code>.h<\/code> file: <code>header_file = open(&quot;liblapack.h&quot;); ffi.cdef(header_file.read())<\/code><\/li>\n<li>Access functions defined in a C library. For example, <code>liblapack = ffi.dlopen(&quot;libreflapacke.so&quot;)<\/code> gives us dot-access (via Python attributes) to functions in <code>libreflapacke<\/code>. We can use <code>dgels<\/code> by coding: <code>liblapack.LAPACKE_dgels<\/code>.<\/li>\n<\/ol>\n<p>These three capabilities let <em>mikefc<\/em> write an ~10 line script that exposes LAPACKE for us in Python. Granted, more work went into making a <code>cffi<\/code>-compatible set of <code>.h<\/code> files for the LAPACKE routines, but that was done by another set of Python scripts. <code>py-liblapack<\/code> exposes all of the <code>single<\/code> and <code>double<\/code> (<code>s<\/code> and <code>d<\/code>) routines from LAPACKE; it would be straight-forward to also expose the <code>complex<\/code> and double-precision <code>complex<\/code> (<code>c<\/code> and <code>z<\/code>) routines.<\/p>\n<p>To use the <code>py-liblapack<\/code> code, all you need are two files from the source repository: <code>liblapack.py<\/code> and <code>liblapack.h<\/code>. Then, put the proper file names in <code>liblapack.py<\/code>:<\/p>\n<div class=\"sourceCode\">\n<pre class=\"sourceCode python\"><code class=\"sourceCode python\"><span class=\"im\">import<\/span> os\r\n<span class=\"im\">from<\/span> cffi <span class=\"im\">import<\/span> FFI\r\nffi <span class=\"op\">=<\/span> FFI()\r\n\r\nthis_dir <span class=\"op\">=<\/span> os.path.dirname(os.path.abspath(<span class=\"va\">__file__<\/span>)) <span class=\"op\">+<\/span> <span class=\"st\">&quot;\/&quot;<\/span>\r\n<span class=\"cf\">with<\/span> <span class=\"bu\">open<\/span>(this_dir <span class=\"op\">+<\/span> <span class=\"st\">&quot;liblapack.h&quot;<\/span>) <span class=\"im\">as<\/span> header_file:\r\n    ffi.cdef(header_file.read())\r\nliblapack <span class=\"op\">=<\/span> ffi.dlopen(<span class=\"st\">&quot;libreflapacke.so&quot;<\/span>)<\/code><\/pre>\n<\/div>\n<p>In the examples below, I&#8217;ll assume that <code>liblapack.py<\/code> lives in the same directory as my notebook and I&#8217;ll be <code>import<\/code>ing it, shortly.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"generic-setup-and-imports\">Generic Setup and Imports<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[1]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">operator<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">op<\/span>\r\n\r\n<span class=\"kn\">import<\/span> <span class=\"nn\">numpy<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">np<\/span>\r\n<span class=\"kn\">import<\/span> <span class=\"nn\">numpy.linalg<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">nla<\/span>\r\n<span class=\"kn\">import<\/span> <span class=\"nn\">scipy.linalg<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">sla<\/span>\r\n\r\n<span class=\"kn\">from<\/span> <span class=\"nn\">cvxopt<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">matrix<\/span> <span class=\"k\">as<\/span> <span class=\"n\">cvx_matrix<\/span>\r\n<span class=\"kn\">import<\/span> <span class=\"nn\">cvxopt.lapack<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">cla<\/span>\r\n\r\n<span class=\"o\">%<\/span><span class=\"k\">load_ext<\/span> memory_profiler\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[2]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"k\">def<\/span> <span class=\"nf\">create_data<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"o\">=<\/span><span class=\"mi\">5000<\/span><span class=\"p\">,<\/span> <span class=\"n\">p<\/span><span class=\"o\">=<\/span><span class=\"mi\">100<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"sd\">&#39;&#39;&#39; <\/span>\r\n<span class=\"sd\">        n is number cases\/observations\/examples<\/span>\r\n<span class=\"sd\">        p is number of features\/attributes\/variables<\/span>\r\n<span class=\"sd\">    &#39;&#39;&#39;<\/span>\r\n    <span class=\"n\">X<\/span>      <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">random<\/span><span class=\"o\">.<\/span><span class=\"n\">uniform<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">p<\/span><span class=\"p\">))<\/span>\r\n    <span class=\"n\">coeffs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">random<\/span><span class=\"o\">.<\/span><span class=\"n\">uniform<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"n\">p<\/span><span class=\"p\">)<\/span>\r\n    <span class=\"k\">def<\/span> <span class=\"nf\">f<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">):<\/span> <span class=\"k\">return<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">coeffs<\/span><span class=\"p\">)<\/span>\r\n\r\n    <span class=\"n\">noise<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">random<\/span><span class=\"o\">.<\/span><span class=\"n\">normal<\/span><span class=\"p\">(<\/span><span class=\"mf\">0.0<\/span><span class=\"p\">,<\/span> <span class=\"mf\">2.0<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">)<\/span>\r\n    <span class=\"n\">Y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">f<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"n\">noise<\/span>\r\n    <span class=\"n\">Y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">reshape<\/span><span class=\"p\">((<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"mi\">1<\/span><span class=\"p\">))<\/span>\r\n    \r\n    <span class=\"k\">return<\/span> <span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[3]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"n\">n_obs<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">16<\/span>\r\n<span class=\"n\">n_ftrs<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">10<\/span>\r\n<span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">create_data<\/span><span class=\"p\">(<\/span><span class=\"n\">n_obs<\/span><span class=\"p\">,<\/span><span class=\"n\">n_ftrs<\/span><span class=\"p\">)<\/span>\r\n<span class=\"k\">print<\/span> <span class=\"s\">&quot;about&quot;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">10<\/span><span class=\"o\">**<\/span><span class=\"nb\">int<\/span><span class=\"p\">(<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">log10<\/span><span class=\"p\">(<\/span><span class=\"n\">n_obs<\/span> <span class=\"o\">*<\/span> <span class=\"n\">n_ftrs<\/span><span class=\"p\">)),<\/span> <span class=\"s\">&quot;entries&quot;<\/span>\r\n<span class=\"k\">print<\/span> <span class=\"s\">&quot;about&quot;<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">itemsize<\/span> <span class=\"o\">*<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">size<\/span><span class=\"p\">)<\/span> <span class=\"o\">\/<\/span> <span class=\"nb\">float<\/span><span class=\"p\">(<\/span><span class=\"mi\">1024<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span><span class=\"p\">),<\/span> <span class=\"s\">&quot;MB&quot;<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"output_wrapper\">\n<div class=\"output\">\n<div class=\"output_area\">\n<div class=\"prompt\"><\/div>\n<div class=\"output_subarea output_stream output_stdout output_text\">\n<pre>about 10000000 entries\r\nabout 512.0 MB\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"liblapack-and-utilities\"><code>liblapack<\/code> and Utilities<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[4]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"kn\">from<\/span> <span class=\"nn\">liblapack<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">liblapack<\/span> <span class=\"k\">as<\/span> <span class=\"n\">lap<\/span>\r\n<span class=\"kn\">from<\/span> <span class=\"nn\">cffi<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FFI<\/span>\r\n<span class=\"n\">ffi<\/span> <span class=\"o\">=<\/span> <span class=\"n\">FFI<\/span><span class=\"p\">()<\/span>\r\n\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\"># numpy array to underlying C array<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">arr<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">ffi<\/span><span class=\"o\">.<\/span><span class=\"n\">cast<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;double *&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">arr<\/span><span class=\"o\">.<\/span><span class=\"n\">__array_interface__<\/span><span class=\"p\">[<\/span><span class=\"s\">&#39;data&#39;<\/span><span class=\"p\">][<\/span><span class=\"mi\">0<\/span><span class=\"p\">])<\/span>\r\n\r\n<span class=\"k\">def<\/span> <span class=\"nf\">get_iptr<\/span><span class=\"p\">(<\/span><span class=\"n\">arr<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">ffi<\/span><span class=\"o\">.<\/span><span class=\"n\">cast<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;int *&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">arr<\/span><span class=\"o\">.<\/span><span class=\"n\">__array_interface__<\/span><span class=\"p\">[<\/span><span class=\"s\">&#39;data&#39;<\/span><span class=\"p\">][<\/span><span class=\"mi\">0<\/span><span class=\"p\">])<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"cholesky-via-dposv\">Cholesky via <code>dposv<\/code><\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[5]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># posv<\/span>\r\n<span class=\"c\"># http:\/\/www.netlib.org\/lapack\/explore-html\/dc\/d7f\/lapacke__dposv_8c.html<\/span>\r\n<span class=\"c\"># https:\/\/software.intel.com\/en-us\/node\/520982<\/span>\r\n<span class=\"c\"># <\/span>\r\n<span class=\"c\"># lapack_int LAPACKE_dposv(int matrix_layout,<\/span>\r\n<span class=\"c\">#                          char uplo,<\/span>\r\n<span class=\"c\">#                          lapack_int n, lapack_int nrhs,<\/span>\r\n<span class=\"c\">#                          double *a, lapack_int lda,<\/span>\r\n<span class=\"c\">#                          double *b, lapack_int ldb)<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">sls_cholesky_orig<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span> <span class=\"n\">Y<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"n\">XtX<\/span> <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">T<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">)<\/span>\r\n    <span class=\"n\">XtY<\/span> <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">T<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">Y<\/span><span class=\"p\">)<\/span>\r\n\r\n    <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span> <span class=\"o\">=<\/span> <span class=\"n\">XtX<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span>\r\n    <span class=\"n\">nrhs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">XtY<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">if<\/span> <span class=\"n\">XtY<\/span><span class=\"o\">.<\/span><span class=\"n\">ndim<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">else<\/span> <span class=\"mi\">1<\/span>\r\n\r\n    <span class=\"n\">info<\/span> <span class=\"o\">=<\/span> <span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACKE_dposv<\/span><span class=\"p\">(<\/span><span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACK_ROW_MAJOR<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"s\">&quot;L&quot;<\/span><span class=\"p\">,<\/span> <span class=\"c\"># prefer L.dot(L.T) factorization<\/span>\r\n                             <span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">XtX<\/span><span class=\"p\">),<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span>    <span class=\"c\"># ldXtX = n<\/span>\r\n                             <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">XtY<\/span><span class=\"p\">),<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">)<\/span> <span class=\"c\"># ldXtY = nrhs<\/span>\r\n    <span class=\"k\">assert<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">info<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">XtY<\/span><span class=\"p\">[:<\/span><span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]]<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[6]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># %memit sls_cholesky_orig(X,Y)<\/span>\r\n<span class=\"c\"># peak memory: 581.86 MiB, increment: 11.87 MiB<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"lu-via-dgesv\">LU via <code>dgesv<\/code><\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[7]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># gesv<\/span>\r\n<span class=\"c\"># http:\/\/www.netlib.org\/lapack\/explore-html\/d6\/de8\/lapacke__dgesv_8c.html<\/span>\r\n<span class=\"c\"># https:\/\/software.intel.com\/en-us\/node\/520973<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#lapack_int LAPACKE_dgesv(int matrix_layout,<\/span>\r\n<span class=\"c\">#                         lapack_int n, lapack_int nrhs,<\/span>\r\n<span class=\"c\">#                         double *a, lapack_int lda,<\/span>\r\n<span class=\"c\">#                         lapack_int *ipiv,<\/span>\r\n<span class=\"c\">#                         double *b, lapack_int ldb)<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">sls_lu_orig<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span> <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span>\r\n    <span class=\"n\">nrhs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">if<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">ndim<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">else<\/span> <span class=\"mi\">1<\/span>\r\n\r\n    <span class=\"n\">workspace<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ffi<\/span><span class=\"o\">.<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;int[]&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">)<\/span> <span class=\"c\"># workspace array<\/span>\r\n\r\n    <span class=\"n\">info<\/span> <span class=\"o\">=<\/span> <span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACKE_dgesv<\/span><span class=\"p\">(<\/span><span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACK_ROW_MAJOR<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">),<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span>    <span class=\"c\"># ldX = n<\/span>\r\n                             <span class=\"n\">workspace<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">Y<\/span><span class=\"p\">),<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">)<\/span> <span class=\"c\"># ldY = nrhs<\/span>\r\n\r\n    <span class=\"k\">assert<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">info<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">Y<\/span><span class=\"p\">[:<\/span><span class=\"n\">n<\/span><span class=\"p\">]<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[8]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># %memit sls_orig(X,Y)<\/span>\r\n<span class=\"c\"># peak memory: 576.93 MiB, increment: 6.71 MiB<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"qr-via-dgels\">QR via <code>dgels<\/code><\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[9]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># gels<\/span>\r\n<span class=\"c\"># http:\/\/www.netlib.org\/lapack\/explore-html\/d9\/da2\/lapacke__dgels_8c.html<\/span>\r\n<span class=\"c\"># https:\/\/software.intel.com\/en-us\/node\/521112<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#lapack_int LAPACKE_dgels(int matrix_layout,<\/span>\r\n<span class=\"c\">#                         char trans,<\/span>\r\n<span class=\"c\">#                         lapack_int m, lapack_int n, lapack_int nrhs,<\/span>\r\n<span class=\"c\">#                         double* a, lapack_int lda,<\/span>\r\n<span class=\"c\">#                         double* b, lapack_int ldb);<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">sls_qr_orig<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span>  <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span>\r\n    <span class=\"n\">nrhs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">if<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">ndim<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">else<\/span> <span class=\"mi\">1<\/span>\r\n    <span class=\"n\">info<\/span> <span class=\"o\">=<\/span> <span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACKE_dgels<\/span><span class=\"p\">(<\/span><span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACK_ROW_MAJOR<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"s\">&quot;N&quot;<\/span><span class=\"p\">,<\/span> <span class=\"c\"># do not transpose<\/span>\r\n                             <span class=\"n\">m<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">),<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span>\r\n                             <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">Y<\/span><span class=\"p\">),<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">)<\/span>\r\n\r\n    <span class=\"k\">assert<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">info<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">Y<\/span><span class=\"p\">[:<\/span><span class=\"n\">n<\/span><span class=\"p\">]<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[10]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># %memit sls_qr_orig(X,Y)<\/span>\r\n<span class=\"c\"># peak memory: 1083.94 MiB, increment: 514.06 MiB<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"qr-via-dgels-take-two\">QR via <code>dgels<\/code>: Take Two<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[11]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"k\">def<\/span> <span class=\"nf\">sls_qr_minwork<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span>  <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span>\r\n    <span class=\"n\">nrhs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">if<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">ndim<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">else<\/span> <span class=\"mi\">1<\/span>\r\n    \r\n\r\n    <span class=\"c\"># http:\/\/www.netlib.org\/lapack\/explore-html\/d8\/dde\/dgels_8f_source.html<\/span>\r\n    <span class=\"c\"># min LWORK &gt;= max( 1, MN + max( MN, NRHS ) )<\/span>\r\n    <span class=\"n\">work_size<\/span> <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">size<\/span> <span class=\"o\">+<\/span> <span class=\"nb\">max<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">size<\/span><span class=\"p\">,<\/span><span class=\"n\">nrhs<\/span><span class=\"p\">)<\/span>\r\n    <span class=\"n\">work<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">zeros<\/span><span class=\"p\">(<\/span><span class=\"n\">work_size<\/span><span class=\"p\">)<\/span>\r\n    \r\n    <span class=\"n\">info<\/span> <span class=\"o\">=<\/span> <span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACKE_dgels_work<\/span><span class=\"p\">(<\/span><span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACK_ROW_MAJOR<\/span><span class=\"p\">,<\/span>\r\n                                 <span class=\"s\">&quot;N&quot;<\/span><span class=\"p\">,<\/span> <span class=\"c\"># do not transpose<\/span>\r\n                                 <span class=\"n\">m<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                                 <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">),<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span>\r\n                                 <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">Y<\/span><span class=\"p\">),<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                                 <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">work<\/span><span class=\"p\">),<\/span> <span class=\"n\">work_size<\/span><span class=\"p\">)<\/span>\r\n\r\n    <span class=\"k\">assert<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">info<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">Y<\/span><span class=\"p\">[:<\/span><span class=\"n\">n<\/span><span class=\"p\">]<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[12]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># %memit sls_qr_minwork(X,Y)<\/span>\r\n<span class=\"c\">#peak memory: 1084.91 MiB, increment: 517.84 MiB<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"svd-via-dgelss\">SVD via <code>dgelss<\/code><\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[13]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># gelss<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\"># http:\/\/www.netlib.org\/lapack\/explore-html\/db\/d77\/lapacke__dgelss_8c.html<\/span>\r\n<span class=\"c\"># https:\/\/software.intel.com\/en-us\/node\/521114<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#lapack_int LAPACKE_dgelss(int matrix_layout, <\/span>\r\n<span class=\"c\">#                          lapack_int m, lapack_int n, lapack_int nrhs, <\/span>\r\n<span class=\"c\">#                          double* a, lapack_int lda, <\/span>\r\n<span class=\"c\">#                          double* b, lapack_int ldb, <\/span>\r\n<span class=\"c\">#                          double* s, <\/span>\r\n<span class=\"c\">#                          double rcond, <\/span>\r\n<span class=\"c\">#                          lapack_int* rank )<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">sls_svd_dgelss<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span> <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span>\r\n    <span class=\"n\">nrhs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">if<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">ndim<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">else<\/span> <span class=\"mi\">1<\/span>\r\n\r\n    <span class=\"n\">singular_values<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">empty<\/span><span class=\"p\">(<\/span><span class=\"nb\">min<\/span><span class=\"p\">(<\/span><span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span><span class=\"p\">))<\/span>\r\n    <span class=\"n\">rank<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">zeros<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">dtype<\/span><span class=\"o\">=<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">int64<\/span><span class=\"p\">)<\/span>\r\n\r\n    <span class=\"n\">info<\/span> <span class=\"o\">=<\/span> <span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACKE_dgelss<\/span><span class=\"p\">(<\/span><span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACK_ROW_MAJOR<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">),<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">Y<\/span><span class=\"p\">),<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">singular_values<\/span><span class=\"p\">),<\/span>\r\n                              <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> \r\n                              <span class=\"n\">get_iptr<\/span><span class=\"p\">(<\/span><span class=\"n\">rank<\/span><span class=\"p\">))<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">Y<\/span><span class=\"p\">[:<\/span><span class=\"n\">n<\/span><span class=\"p\">]<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[14]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># %memit sls_svd_dgelss(X,Y)<\/span>\r\n<span class=\"c\"># peak memory: 1083.97 MiB, increment: 513.99 MiB<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"svd-via-dgelsd\">SVD via <code>dgelsd<\/code><\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[15]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># gelsd<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\"># http:\/\/www.netlib.org\/lapack\/explore-html\/df\/de3\/lapacke__dgelsd_8c.html<\/span>\r\n<span class=\"c\"># https:\/\/software.intel.com\/en-us\/node\/521115<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"c\">#lapack_int LAPACKE_dgelsd(int matrix_layout,<\/span>\r\n<span class=\"c\">#                          lapack_int m, lapack_int n, lapack_int nrhs,<\/span>\r\n<span class=\"c\">#                          double* a, lapack_int lda,<\/span>\r\n<span class=\"c\">#                          double* b, lapack_int ldb,<\/span>\r\n<span class=\"c\">#                          double* s,<\/span>\r\n<span class=\"c\">#                          double rcond,<\/span>\r\n<span class=\"c\">#                          lapack_int* rank );<\/span>\r\n<span class=\"c\">#<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">sls_svd_orig<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">):<\/span>\r\n    <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span> <span class=\"o\">=<\/span> <span class=\"n\">X<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span>\r\n    <span class=\"n\">nrhs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">if<\/span> <span class=\"n\">Y<\/span><span class=\"o\">.<\/span><span class=\"n\">ndim<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">else<\/span> <span class=\"mi\">1<\/span>\r\n\r\n    <span class=\"n\">singular_values<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">empty<\/span><span class=\"p\">(<\/span><span class=\"nb\">min<\/span><span class=\"p\">(<\/span><span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span><span class=\"p\">))<\/span>\r\n    <span class=\"n\">rank<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">zeros<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">dtype<\/span><span class=\"o\">=<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">int64<\/span><span class=\"p\">)<\/span>\r\n\r\n    <span class=\"n\">info<\/span> <span class=\"o\">=<\/span> <span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACKE_dgelsd<\/span><span class=\"p\">(<\/span><span class=\"n\">lap<\/span><span class=\"o\">.<\/span><span class=\"n\">LAPACK_ROW_MAJOR<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">m<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">),<\/span> <span class=\"n\">n<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">Y<\/span><span class=\"p\">),<\/span> <span class=\"n\">nrhs<\/span><span class=\"p\">,<\/span>\r\n                              <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">singular_values<\/span><span class=\"p\">),<\/span>\r\n                              <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> \r\n                              <span class=\"n\">get_iptr<\/span><span class=\"p\">(<\/span><span class=\"n\">rank<\/span><span class=\"p\">))<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"n\">Y<\/span><span class=\"p\">[:<\/span><span class=\"n\">n<\/span><span class=\"p\">]<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[16]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c\"># %memit sls_svd_orig(X,Y)<\/span>\r\n<span class=\"c\">#peak memory: 1084.62 MiB, increment: 514.18 MiB<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"check-for-correctness\">Check for Correctness<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<p>Here, we test the code to make sure they all give the same <span class=\"math inline\">\\(\\beta\\)<\/span>s. Note that we make a copy because most of these routines modify <code>X<\/code> adn <code>Y<\/code> in-place. This differs a bit from our semantics of early posts, but it isn&#8217;t terribly important because within <em>this<\/em> post, we are still comparing apples to apples. When we go back to the outside world, we may still need to make copies, depending on our use-cases for <code>X<\/code> and <code>Y<\/code>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[17]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"n\">_X<\/span><span class=\"p\">,<\/span><span class=\"n\">_Y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">create_data<\/span><span class=\"p\">(<\/span><span class=\"n\">n_obs<\/span><span class=\"p\">,<\/span><span class=\"n\">n_ftrs<\/span><span class=\"p\">)<\/span>\r\n\r\n<span class=\"n\">X<\/span><span class=\"p\">,<\/span> <span class=\"n\">Y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">copy<\/span><span class=\"p\">(<\/span><span class=\"n\">_X<\/span><span class=\"p\">),<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">copy<\/span><span class=\"p\">(<\/span><span class=\"n\">_Y<\/span><span class=\"p\">)<\/span>\r\n<span class=\"n\">betas_chol<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sls_cholesky_orig<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">)<\/span>\r\n\r\n<span class=\"n\">X<\/span><span class=\"p\">,<\/span> <span class=\"n\">Y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">copy<\/span><span class=\"p\">(<\/span><span class=\"n\">_X<\/span><span class=\"p\">),<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">copy<\/span><span class=\"p\">(<\/span><span class=\"n\">_Y<\/span><span class=\"p\">)<\/span>\r\n<span class=\"n\">betas_qr<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sls_qr_orig<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">)<\/span>\r\n\r\n<span class=\"n\">X<\/span><span class=\"p\">,<\/span> <span class=\"n\">Y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">copy<\/span><span class=\"p\">(<\/span><span class=\"n\">_X<\/span><span class=\"p\">),<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">copy<\/span><span class=\"p\">(<\/span><span class=\"n\">_Y<\/span><span class=\"p\">)<\/span>\r\n<span class=\"n\">betas_svd<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sls_svd_orig<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span><span class=\"n\">Y<\/span><span class=\"p\">)<\/span>\r\n\r\n<span class=\"n\">betas<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">betas_chol<\/span><span class=\"p\">,<\/span> <span class=\"n\">betas_qr<\/span><span class=\"p\">,<\/span> <span class=\"n\">betas_svd<\/span><span class=\"p\">]<\/span>\r\n<span class=\"k\">print<\/span> <span class=\"s\">&quot;All same betas?:&quot;<\/span><span class=\"p\">,<\/span> <span class=\"nb\">all<\/span><span class=\"p\">(<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">allclose<\/span><span class=\"p\">(<\/span><span class=\"n\">b1<\/span><span class=\"p\">,<\/span> <span class=\"n\">b2<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">b1<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">betas<\/span><span class=\"p\">[:<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">for<\/span> <span class=\"n\">b2<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">betas<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">:])<\/span>\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"output_wrapper\">\n<div class=\"output\">\n<div class=\"output_area\">\n<div class=\"prompt\"><\/div>\n<div class=\"output_subarea output_stream output_stdout output_text\">\n<pre>All same betas?: True\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"and-do-a-quick-timing-run\">And Do a Quick Timing Run<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing code_cell rendered\">\n<div class=\"input\">\n<div class=\"prompt input_prompt\">In&nbsp;[18]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"o\">%<\/span><span class=\"k\">timeit<\/span> sls_cholesky_orig(X,Y)\r\n<span class=\"o\">%<\/span><span class=\"k\">timeit<\/span> sls_lu_orig(X,Y)\r\n<span class=\"o\">%<\/span><span class=\"k\">timeit<\/span> sls_qr_orig(X,Y)\r\n<span class=\"o\">%<\/span><span class=\"k\">timeit<\/span> sls_qr_minwork(X,Y)\r\n<span class=\"o\">%<\/span><span class=\"k\">timeit<\/span> sls_svd_dgelss(X,Y)\r\n<span class=\"o\">%<\/span><span class=\"k\">timeit<\/span> sls_svd_orig(X,Y)\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"output_wrapper\">\n<div class=\"output\">\n<div class=\"output_area\">\n<div class=\"prompt\"><\/div>\n<div class=\"output_subarea output_stream output_stdout output_text\">\n<pre>1 loops, best of 3: 1.54 s per loop\r\n10 loops, best of 3: 32.6 ms per loop\r\n1 loops, best of 3: 8.99 s per loop\r\n1 loops, best of 3: 8.77 s per loop\r\n1 loops, best of 3: 9.17 s per loop\r\n1 loops, best of 3: 9.19 s per loop\r\n<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3 id=\"summary-results\">Summary Results<\/h3>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<table>\n<thead>\n<tr class=\"header\">\n<th align=\"left\">Algorithm<\/th>\n<th align=\"left\">Called Via<\/th>\n<th align=\"left\">Memory<br \/>Increment(MB)<\/th>\n<th align=\"left\">~Time(s)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr class=\"odd\">\n<td align=\"left\">Cholesky<\/td>\n<td align=\"left\"><code>dposv<\/code><\/td>\n<td align=\"left\">12<\/td>\n<td align=\"left\">1.5<\/td>\n<\/tr>\n<tr class=\"even\">\n<td align=\"left\">LU<\/td>\n<td align=\"left\"><code>dgesv<\/code><\/td>\n<td align=\"left\">7<\/td>\n<td align=\"left\">&gt;0.0<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td align=\"left\">QR<\/td>\n<td align=\"left\"><code>dgels<\/code><\/td>\n<td align=\"left\">514<\/td>\n<td align=\"left\">9<\/td>\n<\/tr>\n<tr class=\"even\">\n<td align=\"left\">QR (min LWORK)<\/td>\n<td align=\"left\"><code>dgels<\/code><\/td>\n<td align=\"left\">517<\/td>\n<td align=\"left\">9<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td align=\"left\">SVD<\/td>\n<td align=\"left\"><code>dgelss<\/code><\/td>\n<td align=\"left\">514<\/td>\n<td align=\"left\">9<\/td>\n<\/tr>\n<tr class=\"even\">\n<td align=\"left\">SVD<\/td>\n<td align=\"left\"><code>dgelsd<\/code><\/td>\n<td align=\"left\">514<\/td>\n<td align=\"left\">9<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<p>As you can see, things are still not &quot;right&quot;. And there are some hints running around in the code and discussion above as to what the remaining issue is. I won&#8217;t spill the beans, but stay tuned for next time.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"prompt input_prompt\">\n<\/div>\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<h3>\nAdditional Resources<br \/>\n<\/h3>\n<p>\nYou can grab a <a href=\"http:\/\/drsfenner.org\/public\/notebooks\/OLS_LAPACK_and_LAPACKE_1.ipynb\">copy of this notebook<\/a>.\n<\/p>\n<p>\nEven better, you can <a href=\"http:\/\/nbviewer.ipython.org\/url\/drsfenner.org\/public\/notebooks\/OLS_LAPACK_and_LAPACKE_1.ipynb\">view it using nbviewer<\/a>.\n<\/p>\n<h3>\nLicense<br \/>\n<\/h3>\n<p>\nUnless otherwise noted, the contents of this notebook are under the following license. The code in the notebook should be considered part of the text (i.e., licensed and treated as as follows).\n<\/p>\n<p><a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/\"><img decoding=\"async\" alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https:\/\/i.creativecommons.org\/l\/by-nc-sa\/4.0\/88x31.png\" \/><\/a><br \/><span xmlns:dct=\"http:\/\/purl.org\/dc\/terms\/\" property=\"dct:title\">DrsFenner.org Blog And Notebooks<\/span> by <a xmlns:cc=\"http:\/\/creativecommons.org\/ns#\" href=\"drsfenner.org\" property=\"cc:attributionName\" rel=\"cc:attributionURL\">Mark and Barbara Fenner<\/a> is licensed under a <a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/\">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License<\/a>.<br \/>Permissions beyond the scope of this license may be available at <a xmlns:cc=\"http:\/\/creativecommons.org\/ns#\" href=\"drsfenner.org\/blog\/about-and-contacts\" rel=\"cc:morePermissions\">drsfenner.org\/blog\/about-and-contacts<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In the last post, we looked at three ways of solving the least-squares regression problem (Cholesky, QR, and SVD decompositions) using LAPACK routines in a round-about fashion. The different decompositions (i.e., factorizations) were performed by (1) calling a NumPy np.linalg routine that called (2) an LAPACK driver routine for a &quot;bigger&quot; problem like linear equation [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,7],"tags":[],"class_list":["post-390","post","type-post","status-publish","format-standard","hentry","category-mrdr","category-sci-math-stat-python"],"_links":{"self":[{"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts\/390","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/comments?post=390"}],"version-history":[{"count":2,"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts\/390\/revisions"}],"predecessor-version":[{"id":427,"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts\/390\/revisions\/427"}],"wp:attachment":[{"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/media?parent=390"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/categories?post=390"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/tags?post=390"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}