{"id":414,"date":"2016-02-05T16:06:07","date_gmt":"2016-02-05T16:06:07","guid":{"rendered":"http:\/\/drsfenner.org\/blog\/?p=414"},"modified":"2016-02-05T16:33:45","modified_gmt":"2016-02-05T16:33:45","slug":"testing-a-cholesky-implementation","status":"publish","type":"post","link":"https:\/\/drsfenner.org\/blog\/2016\/02\/testing-a-cholesky-implementation\/","title":{"rendered":"Testing a Cholesky Implementation"},"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 working through the Cholesky, QR, and SVD methods for solving the normal regression equations, I got curious about the underlying implementations of each. I did QR and Cholesky in grad school (a great Numerical Analysis sequence). I never got around to SVD (I think we did some variation of tridiagonalization). Anyway, Cholesky is so simple that I think <em>testing Cholesky<\/em> generated more interesting points for me. There were two big issues and the &quot;testing&quot; post is (I think) longer than the &quot;implementation&quot; post.<\/p>\n<p>Executing the tests brought up an interesting software engineering (code reuse) issue and creating good test inputs brought up an intersting mathematical issue. Read on! <!--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=\"some-testing-helpers\">Some Testing Helpers<\/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\">numpy<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">np<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">it<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">functools<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">ft<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">timeit<\/span>\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=\"c1\"># from python itertools docs:<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">pairwise<\/span><span class=\"p\">(<\/span><span class=\"n\">iterable<\/span><span class=\"p\">):<\/span>\n    <span class=\"s2\">&quot;s -&gt; (s0,s1), (s1,s2), (s2, s3), ...&quot;<\/span>\n    <span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span> <span class=\"o\">=<\/span> <span class=\"n\">it<\/span><span class=\"o\">.<\/span><span class=\"n\">tee<\/span><span class=\"p\">(<\/span><span class=\"n\">iterable<\/span><span class=\"p\">)<\/span>\n    <span class=\"nb\">next<\/span><span class=\"p\">(<\/span><span class=\"n\">b<\/span><span class=\"p\">,<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">it<\/span><span class=\"o\">.<\/span><span class=\"n\">izip<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">time_routines<\/span><span class=\"p\">(<\/span><span class=\"n\">routines<\/span><span class=\"p\">,<\/span> <span class=\"n\">inputs<\/span><span class=\"p\">,<\/span> <span class=\"n\">number<\/span><span class=\"o\">=<\/span><span class=\"mi\">10<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">name_len<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">max<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">r<\/span><span class=\"o\">.<\/span><span class=\"n\">__name__<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">r<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">routines<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">line_template<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;%&quot;<\/span> <span class=\"o\">+<\/span> <span class=\"nb\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">name_len<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot;s : <\/span><span class=\"si\">%6.4f<\/span><span class=\"s2\">&quot;<\/span>\n\n    <span class=\"n\">times<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">r<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">routines<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">call<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ft<\/span><span class=\"o\">.<\/span><span class=\"n\">partial<\/span><span class=\"p\">(<\/span><span class=\"n\">r<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">inputs<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">times<\/span><span class=\"p\">[<\/span><span class=\"n\">r<\/span><span class=\"o\">.<\/span><span class=\"n\">__name__<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">min<\/span><span class=\"p\">(<\/span><span class=\"n\">timeit<\/span><span class=\"o\">.<\/span><span class=\"n\">Timer<\/span><span class=\"p\">(<\/span><span class=\"n\">call<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">repeat<\/span><span class=\"p\">(<\/span><span class=\"n\">repeat<\/span><span class=\"o\">=<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"n\">number<\/span><span class=\"o\">=<\/span><span class=\"n\">number<\/span><span class=\"p\">))<\/span>\n    \n    <span class=\"k\">print<\/span> <span class=\"s2\">&quot;<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">&quot;<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"n\">line_template<\/span> <span class=\"o\">%<\/span> <span class=\"p\">(<\/span><span class=\"n\">k<\/span><span class=\"p\">,<\/span> <span class=\"n\">times<\/span><span class=\"p\">[<\/span><span class=\"n\">k<\/span><span class=\"p\">])<\/span> <span class=\"k\">for<\/span> <span class=\"n\">k<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">sorted<\/span><span class=\"p\">(<\/span><span class=\"n\">times<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"n\">times<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">))<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">same_results<\/span><span class=\"p\">(<\/span><span class=\"n\">routines<\/span><span class=\"p\">,<\/span> <span class=\"n\">inputs<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">results<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"n\">r<\/span><span class=\"o\">.<\/span><span class=\"n\">__name__<\/span><span class=\"p\">:<\/span><span class=\"n\">r<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">inputs<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">r<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">routines<\/span><span class=\"p\">}<\/span>\n        <span class=\"k\">return<\/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\">r1<\/span><span class=\"p\">,<\/span><span class=\"n\">r2<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">r1<\/span><span class=\"p\">,<\/span><span class=\"n\">r2<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">pairwise<\/span><span class=\"p\">(<\/span><span class=\"n\">results<\/span><span class=\"o\">.<\/span><span class=\"n\">values<\/span><span class=\"p\">()))<\/span>\n    <span class=\"k\">except<\/span><span class=\"p\">:<\/span> <span class=\"c1\"># quick-and-dirty<\/span>\n        <span class=\"k\">return<\/span> <span class=\"bp\">False<\/span>\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<p>So, with these helper routines, we can take several different implementations and compare them two ways: (1) do they all give the same answer (<code>same_results<\/code>) and (2) what are their run times (<code>time_routines<\/code>). Note that if the inputs are mutated in-place, we will be solving different problems in both of these. We&#8217;ll address that in a second. <code>same_results<\/code> plays a little fast-and-loose because, in general, floating-point closeness is <em>not transitive<\/em> &#8212; but closeness treats us <em>far<\/em> better than floating-point equality. However, we&#8217;ll be content enough check that if <code>close(a,b)<\/code> and <code>close(b,c)<\/code>, then we&#8217;re &quot;all close enough&quot;.<\/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=\"the-reuse-issue\">The Reuse Issue<\/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>Now, there are two problems that come up when we use this testing code. Since our implementations are not mutating, we don&#8217;t have to worry about that. However, we do have a similar issue. We have <em>two different data structures<\/em> being returned. Our &quot;naive&quot; method returns a full <code>NumPy<\/code> array; we also have &quot;packed&quot; versions that return a flat array that is a packed version of the triangular matrix being returned. So, to check for equality of results we would either (1) define a custom comparison routine or (2) provide a converter that will massage the packed versions into a full version. Here&#8217;s code that shows the issue:<\/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;[3]:<\/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\">makeFullLowerTri<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">X<\/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=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">X<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">triu_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">)]<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">0.0<\/span>\n    <span class=\"n\">X<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">tril_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">)]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">arange<\/span><span class=\"p\">((<\/span><span class=\"n\">n<\/span><span class=\"o\">*<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"o\">+<\/span><span class=\"mi\">1<\/span><span class=\"p\">))<\/span><span class=\"o\">\/<\/span><span class=\"mf\">2.0<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">X<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">makeFullLowerTri<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">makePackedLowerTri<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">arange<\/span><span class=\"p\">((<\/span><span class=\"n\">n<\/span><span class=\"o\">*<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"o\">+<\/span><span class=\"mi\">1<\/span><span class=\"p\">))<\/span><span class=\"o\">\/<\/span><span class=\"mf\">2.0<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">makePackedLowerTri<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">print<\/span> <span class=\"n\">same_results<\/span><span class=\"p\">([<\/span><span class=\"n\">makeFullLowerTri<\/span><span class=\"p\">,<\/span> <span class=\"n\">makePackedLowerTri<\/span><span class=\"p\">],<\/span> <span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,))<\/span>\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>[[ 0.  0.  0.]\n [ 1.  2.  0.]\n [ 3.  4.  5.]]\n[ 0.  1.  2.  3.  4.  5.]\nFalse\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<p>BTW, you might see the <code>2.0<\/code> in the <code>np.arange<\/code> expression. If <code>arange<\/code> takes a <code>float<\/code> as its input, it produces an array of <code>np.float64<\/code> (more technically, <code>np.float_<\/code> &#8230; &quot;machine floating point size&quot;). If the input is an <code>int<\/code>, the <code>dtype<\/code> is also <code>np.int_<\/code>. Anyway, it&#8217;s just a trick to get the <code>dtype<\/code> squared away nicely.<\/p>\n<p>So, here&#8217;s a quick &quot;expander&quot; which turns packed triangular into full.<\/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;[4]:<\/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\">expand<\/span><span class=\"p\">(<\/span><span class=\"n\">packedTri<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">X<\/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=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">n<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">X<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">triu_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">)]<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">0.0<\/span>\n    <span class=\"n\">X<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">tril_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">)]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">packedTri<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">X<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">allclose<\/span><span class=\"p\">(<\/span><span class=\"n\">expand<\/span><span class=\"p\">(<\/span><span class=\"n\">makePackedLowerTri<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">),<\/span> <span class=\"mi\">3<\/span><span class=\"p\">),<\/span> <span class=\"n\">makeFullLowerTri<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">))<\/span>\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>True\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<p>But, our <code>same_results<\/code> routine take one function to apply (not nested applications). That process of nesting applications of a function has a name: <em>function composition<\/em>. And, you might remember it from studying such wonders as the chain rule of derivatives. But, unless you are into functional programming and languages, you might not have played around with it much from a software engineering perspective. What we need is (1) a single function that is the result of (2) applying <code>expand<\/code> on <code>makePackedLowerTri<\/code>. Fortunately, Python makes it relatively easy to create such a critter.<\/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;[5]:<\/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\">helper<\/span><span class=\"p\">(<\/span><span class=\"n\">main<\/span><span class=\"p\">,<\/span> <span class=\"n\">post<\/span><span class=\"p\">):<\/span>\n    <span class=\"sd\">&#39;&#39;&#39; help out by creating\/returning a process that calls *main* to do the &quot;work&quot;<\/span>\n<span class=\"sd\">        and then *post* to do the &quot;post-processing&quot;&#39;&#39;&#39;<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">inner<\/span><span class=\"p\">(<\/span><span class=\"n\">A<\/span><span class=\"p\">):<\/span>\n        <span class=\"sd\">&#39;&#39;&#39; compute the composition of two functions on A&#39;&#39;&#39;<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">post<\/span><span class=\"p\">(<\/span><span class=\"n\">main<\/span><span class=\"p\">(<\/span><span class=\"n\">A<\/span><span class=\"p\">))<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">inner<\/span>\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<p>Now, the next issue is that we don&#8217;t want to modify <code>main<\/code> &#8211; which will be our <code>makePackedLowerTri<\/code>. In particular, it returns one array and we want to keep it that way. That means that <code>post<\/code> (<code>expand<\/code>) is going to be missing an argument &#8211; the <code>n<\/code> value. If only there were a way to &quot;partially&quot; apply a function to some arguments and leave the rest &quot;to be filled in later&quot;. But wait! There is:<\/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;[6]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c1\"># above, we did:  import functools as ft <\/span>\n<span class=\"n\">expand3<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ft<\/span><span class=\"o\">.<\/span><span class=\"n\">partial<\/span><span class=\"p\">(<\/span><span class=\"n\">expand<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"o\">=<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\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<p><code>expand3<\/code> is a function of <em>one<\/em> argument that has its <code>n<\/code> argument fixed at <code>3<\/code>. It is as if we had typed (without the typing and with many more resuse possibilities):<\/p>\n<div class=\"sourceCode\">\n<pre class=\"sourceCode python\"><code class=\"sourceCode python\"><span class=\"kw\">def<\/span> expand3(packedTri):\n    X <span class=\"op\">=<\/span> np.empty((<span class=\"dv\">3<\/span>,<span class=\"dv\">3<\/span>))\n    X[np.triu_indices(<span class=\"dv\">3<\/span>)] <span class=\"op\">=<\/span> <span class=\"fl\">0.0<\/span>\n    X[np.tril_indices(<span class=\"dv\">3<\/span>)] <span class=\"op\">=<\/span> packedTri\n    <span class=\"cf\">return<\/span> X<\/code><\/pre>\n<\/div>\n<p>A couple of quick notes. (1) We&#8217;ll see that we don&#8217;t <em>have<\/em> to lock down the value of <code>n<\/code>. We could compute it inside of <code>expand<\/code> or we could hack on <code>helper<\/code> or <code>makePackedLowerTri<\/code>. (2) Adding compositions is a problem, if we want to <em>directly compare the work<\/em> (memory, time, etc.) of the base functions. We&#8217;ll ignore that for now because we are comparing correctness.<\/p>\n<p>Here&#8217;s how the pieces work together. <code>makeFullLowerTri<\/code> <em>is<\/em> a &quot;direct&quot; function that we give an arg to and get our usable result. For the packed version, we do a bit more work. We call <code>helper<\/code> and it <em>makes a function for us<\/em>. That function that it creates is the one we want to call. So, we have two calls: (1) we call <code>helper<\/code> and (2) we call the returned value (from <code>helper<\/code>). The second call gives us a comparable result. Here they are:<\/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;[7]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"c1\"># simple case<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">makeFullLowerTri<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># complex case<\/span>\n<span class=\"n\">r<\/span> <span class=\"o\">=<\/span> <span class=\"n\">helper<\/span><span class=\"p\">(<\/span><span class=\"n\">makePackedLowerTri<\/span><span class=\"p\">,<\/span> <span class=\"n\">expand3<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">r<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\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>[[ 0.  0.  0.]\n [ 1.  2.  0.]\n [ 3.  4.  5.]]\n[[ 0.  0.  0.]\n [ 1.  2.  0.]\n [ 3.  4.  5.]]\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<p>And here&#8217;s how we use it in <code>same_results<\/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;[8]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"n\">routines<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">makeFullLowerTri<\/span><span class=\"p\">,<\/span> <span class=\"n\">helper<\/span><span class=\"p\">(<\/span><span class=\"n\">makePackedLowerTri<\/span><span class=\"p\">,<\/span> <span class=\"n\">expand3<\/span><span class=\"p\">)]<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">same_results<\/span><span class=\"p\">(<\/span><span class=\"n\">routines<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,))<\/span>\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>True\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=\"generalizing\">Generalizing<\/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>The process of composing functions &#8211; and composing more than two functions &#8211; seems like a nicely repeatable process. Can we make the above more general than just <code>helper<\/code>? The answer is &quot;yes!&quot;. There used to be a python module (third-party) called <code>functional<\/code> that had a <code>compose<\/code> routine. However, I can&#8217;t find it anymore (it is reference in the python 3.1 functional HOWTO document). But, a little hacking and Googling found some resources and resulted in the following code:<\/p>\n<ul>\n<li><a href=\"https:\/\/mathieularose.com\/function-composition-in-python\/#solution\">A single arg solution<\/a><\/li>\n<li><a href=\"https:\/\/joshbohde.com\/blog\/functional-python\">A *arg and **kwarg solution<\/a><\/li>\n<li><a href=\"https:\/\/www.ics.uci.edu\/~pattis\/ICS-33\/lectures\/functionalprogramming.txt\">A nice Python+functional writeup<\/a> (although it doesn&#8217;t talk about composition explicitly)<\/li>\n<\/ul>\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=\"k\">def<\/span> <span class=\"nf\">compose<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">functions<\/span><span class=\"p\">):<\/span>\n    <span class=\"sd\">&#39;&#39;&#39; compose functions left-to-right being outer-to-inner <\/span>\n<span class=\"sd\">            NOTE: algebrists rejoice that I specified that to prevent headaches &#39;&#39;&#39;<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">identity<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">):<\/span> \n        <span class=\"sd\">&#39;&#39;&#39; just bulletproofing b\/c we won&#39;t have empty compose() call<\/span>\n<span class=\"sd\">            NOTE:  it works like identity(composedFuncs()) <\/span>\n<span class=\"sd\">                   not the equiv. composedFuncs(identity())&#39;&#39;&#39;<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">x<\/span> \n    <span class=\"k\">def<\/span> <span class=\"nf\">applyTwo<\/span><span class=\"p\">(<\/span><span class=\"n\">remainder<\/span><span class=\"p\">,<\/span> <span class=\"n\">current<\/span><span class=\"p\">):<\/span>\n        <span class=\"sd\">&#39;&#39;&#39; remainder1(remainder2(remainder3(current(finished)))) <\/span>\n<span class=\"sd\">            finished is done<\/span>\n<span class=\"sd\">            remainder represents composition of remainder_1 .... remainder_n&#39;&#39;&#39;<\/span>\n        <span class=\"k\">def<\/span> <span class=\"nf\">helper<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">finished<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">remainder<\/span><span class=\"p\">(<\/span><span class=\"n\">current<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">finished<\/span><span class=\"p\">))<\/span>\n        <span class=\"c1\"># helper.__name__ = &quot;helper(%s)&quot; % current.__name__<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">helper<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">ft<\/span><span class=\"o\">.<\/span><span class=\"n\">reduce<\/span><span class=\"p\">(<\/span><span class=\"n\">applyTwo<\/span><span class=\"p\">,<\/span> <span class=\"n\">functions<\/span><span class=\"p\">,<\/span> <span class=\"n\">identity<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">foo<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">return<\/span> <span class=\"s2\">&quot;outer(&quot;<\/span> <span class=\"o\">+<\/span> <span class=\"n\">x<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot;)&quot;<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">bar<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">return<\/span> <span class=\"s2\">&quot;inner(&quot;<\/span> <span class=\"o\">+<\/span> <span class=\"n\">x<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot;)&quot;<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">foo<\/span><span class=\"p\">(<\/span><span class=\"n\">bar<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;mark&quot;<\/span><span class=\"p\">))<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">compose<\/span><span class=\"p\">(<\/span><span class=\"n\">foo<\/span><span class=\"p\">,<\/span> <span class=\"n\">bar<\/span><span class=\"p\">)(<\/span><span class=\"s2\">&quot;mark&quot;<\/span><span class=\"p\">)<\/span>\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>outer(inner(mark))\nouter(inner(mark))\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<p>Basically, we call <code>applyTwo<\/code> many times (on each function we are composing) and we get back a <code>helper<\/code> (uncomment the <code>helper<\/code> name assignment and print it out to see how it progresses) that interlocks the inner result to the outer composition.<\/p>\n<p>I&#8217;ll give bonus points for someone that can show a way to pass <code>keywordable<\/code> arguments back from the inner function calls without <em>requiring<\/em> modifications to the <code>return<\/code> statements. It&#8217;s &quot;easy&quot; to either return &quot;the usual&quot; or a tuple that will be detupled by the next layer out. But, sending something that can be <code>**kwarg<\/code>-ed seems a bit more messy.<\/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=\"the-testcase-issue\">The Testcase Issue<\/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>To test Cholesky, we need &quot;symmetric, postitive-definite&quot; (SPD) matrices. Since Cholesky is a version of a &quot;matrix square root&quot;, you can think about this as &quot;we can only take the square root of a postive number&quot; (ignoring <span class=\"math inline\">\\(i\\)<\/span>\/complex-values). I was inspired by a <a href=\"http:\/\/scicomp.stackexchange.com\/a\/1793\">stack overflow thread<\/a> to use the following method. In particular, Arnold Neumaier had a nice answer that I wanted to dig into (prove to myself that it worked and see the mathematics behind it). Here is what I came up with.<\/p>\n<p>I&#8217;ll start with a few facts that you can gather from a linear algebra or numerical methods textbook (and\/or the Web).<\/p>\n<ul>\n<li>The eigenvalues of a matrix are postive if, and only if, the matrix is SPD.<\/li>\n<li>The eigenvalues of a diagonal matrix are the values of the diagonal.<\/li>\n<li>The matrices <span class=\"math inline\">\\(A\\)<\/span> and <span class=\"math inline\">\\(B\\)<\/span> are called <em>similar matrices<\/em> if we can write <span class=\"math inline\">\\(A=P^{-1}BP\\)<\/span> for some invertible <span class=\"math inline\">\\(P\\)<\/span>.<\/li>\n<li>Similar matrices have the same characteristic polynomial, and hence, the same eigenvalues.<\/li>\n<li>Orthogonal matrices have <span class=\"math inline\">\\(A^T=A^{-1}\\)<\/span><\/li>\n<li>There is a special type of orthogonal matrix called a Householder matrix. It has the form: <span class=\"math inline\">\\(H = I &#8211; 2vv^T\\)<\/span> for <span class=\"math inline\">\\(v\\)<\/span> an <span class=\"math inline\">\\(n\\)<\/span>-element column-vector (<span class=\"math inline\">\\(H\\)<\/span> is <span class=\"math inline\">\\(n \\times n\\)<\/span>).<\/li>\n<li>Since Householder matrices are made up of <span class=\"math inline\">\\(I\\)<\/span> and <span class=\"math inline\">\\(vv^T\\)<\/span>, we can see quickly that they must be <em>symmetric<\/em> <span class=\"math inline\">\\(H=H^T\\)<\/span>.<\/li>\n<\/ul>\n<p>One corollary: since <span class=\"math inline\">\\(H=H^{T}=H^{-1}\\)<\/span>, we have that <span class=\"math inline\">\\(A=HBH=H^{T}BH=H^{-1}BH\\)<\/span> means that applying a Householder matrix on the left and right of <span class=\"math inline\">\\(B\\)<\/span> creates an <span class=\"math inline\">\\(A\\)<\/span> that is <em>similar<\/em> to <span class=\"math inline\">\\(B\\)<\/span>. That&#8217;s exactly what we will do to a diagonal matrix with positive entries on the diagonal. Thus, we start with a (simple) SPD matrix and create a <em>similar<\/em> matrix that is more interesting. Incidentally, one other fact:<\/p>\n<ul>\n<li>The condition number of a matrix <span class=\"math inline\">\\(A\\)<\/span> is equal to the (absolute value of the) ratio of the biggest to the smallest eigenvalues of <span class=\"math inline\">\\(A\\)<\/span>. That is, <span class=\"math inline\">\\(cond(A)=\\left| \\frac{max(eigval(A))}{min(eigval(A))} \\right|\\)<\/span>.<\/li>\n<\/ul>\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=\"creating-an-spd-matrix-from-random-vectors\">Creating an SPD Matrix from Random Vectors<\/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>So, if we set the eigenvalues appropriately, we can control the condition number to make a particular well-behaved or ill-behaved matrix. We can create a SPD test matrix <span class=\"math inline\">\\(T_{spd}\\)<\/span>, with condition number <span class=\"math inline\">\\(C\\)<\/span>, with the following steps:<\/p>\n<ol style=\"list-style-type: decimal\">\n<li><span class=\"math inline\">\\(d=[1\\ uniform(1,C)\\ C]\\)<\/span>, with <span class=\"math inline\">\\(n-2\\)<\/span> elements being sampled by the uniform distribution.<\/li>\n<li><span class=\"math inline\">\\(D_+ = diag(d)\\)<\/span> be a <span class=\"math inline\">\\(n \\times n\\)<\/span> matrix with diagonal <span class=\"math inline\">\\(d\\)<\/span><\/li>\n<li><span class=\"math inline\">\\(w=[uniform(0,1)]\\)<\/span> with <span class=\"math inline\">\\(n\\)<\/span> elements<\/li>\n<li><span class=\"math inline\">\\(H=I-2ww^{T}\\)<\/span><\/li>\n<li><span class=\"math inline\">\\(T_{spd}=HD_{+}H\\)<\/span><\/li>\n<\/ol>\n<p>Note, I didn&#8217;t title this &quot;Generating a Random SPD Matrix&quot; (if I say it elsewhere, I deserve a slap on the wrist). I have no clue what the sampling properties of the matrices we are making are.<\/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=\"applying-householder-matrices\">Applying Householder Matrices<\/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>A quick reminder about some matrix transpose rules: <span class=\"math inline\">\\((A+B)^T=A^T+B^T\\)<\/span> and <span class=\"math inline\">\\((AB)^T=B^TA^T\\)<\/span>. Also, if <span class=\"math inline\">\\(D\\)<\/span> is diagonal (and square), then <span class=\"math inline\">\\(D=D^T\\)<\/span>.<\/p>\n<p>There are two interesting facts about Householder matrices. From above, <span class=\"math inline\">\\(H = I &#8211; 2ww^T\\)<\/span>. (1) Householder matrices are completely defined by the underlying vector used to create them (i.e., the <span class=\"math inline\">\\(w\\)<\/span> vector). (2) To multiply (or &quot;apply&quot;) a Householder matrix <span class=\"math inline\">\\(H\\)<\/span> to <span class=\"math inline\">\\(A\\)<\/span> on the left or right <span class=\"math inline\">\\(HA\\)<\/span> or <span class=\"math inline\">\\(AH\\)<\/span>, we don&#8217;t need to make the full <span class=\"math inline\">\\(n \\times n\\)<\/span> matrix of <span class=\"math inline\">\\(H\\)<\/span>. We can just use the <span class=\"math inline\">\\(w\\)<\/span> vector. Golub and VanLoan (3rd, page 211) point out that (and you can derive in about two lines):<\/p>\n<ul>\n<li><span class=\"math inline\">\\(HA=(I-{\\beta}vv^t)=A-vw^T_L\\)<\/span> with <span class=\"math inline\">\\(w_L={\\beta}A^Tv\\)<\/span>, and,<\/li>\n<li><span class=\"math inline\">\\(AH=A(I-{\\beta}vv^T)=A-w_Rv^T\\)<\/span> with <span class=\"math inline\">\\(w_R={\\beta}Av\\)<\/span><\/li>\n<\/ul>\n<p>Further, we&#8217;re going to be working with a diagonal matrix filling in for <span class=\"math inline\">\\(A\\)<\/span>. This means that for our <span class=\"math inline\">\\(HDH\\)<\/span>, we have:<\/p>\n<p><span class=\"math display\">\\[HDH = (HD)H = \\color{red}{(D-vw^T_L)}H = \\color{red}{(D-vw^T_L)} &#8211; w_Rv^T = {\\star}_1\\]<\/span><\/p>\n<p>In this case, <span class=\"math inline\">\\(w^T_L=({\\beta}D^Tv)^T=({\\beta}Dv)^T={\\beta}v^TD\\)<\/span> and <span class=\"math inline\">\\(w_R={\\beta}\\color{red}{(D-vw^T_L)}v\\)<\/span>. The red is meant to highlight the fact that the first multiplication\/expansion plays an important role in the second multiplication\/expansion.<\/p>\n<p>Substituting in:<\/p>\n<p><span class=\"math display\">\\[{\\star}_1 = (D-{\\beta}vv^TD) &#8211; {\\beta}(D-vw^T_L)vv^T = {\\star}_2\\]<\/span><\/p>\n<p>The second term is a bit tricky:<\/p>\n<p><span class=\"math display\">\\[\\begin{align}<br \/>\n{\\beta}(D-vw^T_L)vv^T&amp;=&amp;{\\beta}(D-v({\\beta}v^TD))vv^T            \\\\<br \/>\n                     &amp;=&amp;{\\beta}Dvv^T-{\\beta}v{\\beta}v^TDvv^T     \\\\<br \/>\n                     &amp;=&amp;{\\beta}Dvv^T-{\\beta}^2vv^TDvv^T          \\\\<br \/>\n\\end{align}<br \/>\n\\]<\/span><\/p>\n<p>So, we have: <span class=\"math display\">\\[{\\star}_2 = (D-{\\beta}vv^TD) &#8211; {\\beta}Dvv^T \\color{red}{+} {\\beta}^2vv^TDvv^T = D &#8211; {\\beta}vv^TD &#8211; {\\beta}Dvv^T \\color{red}{+} {\\beta}^2vv^TDvv^T\\]<\/span><\/p>\n<p>I highlighted the two pluses because, in a first draft, I missed them and had some flipped signs running around the end of my equations. When we expanded the second term, it had a minus in front of it. Can&#8217;t lose the negatives!<\/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=\"a-nicer-form\">A Nicer Form?<\/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>At this point, you might be <em>stuck<\/em>. You might try some various factorizations, completing-the-squares, consulting algebra books for quadratic forms, etc. Not that <em>I&#8217;d<\/em> ever do that. However, you might wonder if the simple <span class=\"math inline\">\\(HA=A-vw^T\\)<\/span> form can be carried out for <em>two<\/em> applications of <span class=\"math inline\">\\(H\\)<\/span> (one left and one right). That is, can we say something like: <span class=\"math inline\">\\(HAH = A &#8211; dot(\\cdot,\\cdot) &#8211; dot(\\cdot,\\cdot)\\)<\/span>, for some appropriate arguments to <span class=\"math inline\">\\(dot\\)<\/span>. Looking at <span class=\"math inline\">\\({\\star}_2\\)<\/span>, we might have the brilliant idea that <span class=\"math inline\">\\(v\\)<\/span>s should stay the same. If it ain&#8217;t broke, don&#8217;t fix it. Then, let&#8217;s rearrange the scalars (they are push overs). We may get to this form:<\/p>\n<p><span class=\"math display\">\\[D &#8211; v\\boxed{{\\beta}v^TD} &#8211; \\boxed{{\\beta}Dv}v^T + {\\beta}^2vv^TDvv^T\\]<\/span><\/p>\n<p>Things are looking hopeful. But! What do we do with the last term (the first term, <span class=\"math inline\">\\(D\\)<\/span>, is a standalone in the single multiplication rules from G&amp;VL). It has a <span class=\"math inline\">\\(v\\)<\/span> on the left and a <span class=\"math inline\">\\(v^T\\)<\/span> on the right. We want one or the other, not both! What do we do? We split the difference. Or, more to the point we split it into two equal pieces (halve it) and use both! Also, <span class=\"math inline\">\\(v^TDv\\)<\/span> is a scalar (check the dimensions if you don&#8217;t believe me). I&#8217;ll rename it <span class=\"math inline\">\\(\\alpha\\)<\/span>.<\/p>\n<p><span class=\"math display\">\\[<br \/>\nD &#8211; v\\color{green}{\\boxed{{\\beta}v^TD}} &#8211; \\color{red}{\\boxed{{\\beta}Dv}}v^T<br \/>\n    + \\color{red}{\\boxed{\\frac{1}{2}{\\beta}^2{\\alpha}v}}v^T<br \/>\n    + v\\color{green}{\\boxed{\\frac{1}{2}{\\beta}^2{\\alpha}v^T}}<br \/>\n\\]<\/span><\/p>\n<p>Now, look at the <span class=\"math inline\">\\(v\\color{green}{\\square}\\)<\/span> terms. If we factor out <span class=\"math inline\">\\(-v\\)<\/span> and call the result <span class=\"math inline\">\\(w_\\star\\)<\/span>, we have <span class=\"math inline\">\\(w_{\\star} = \\color{green}{{\\beta}v^TD &#8211; \\frac{1}{2}{\\beta}^2{\\alpha}v^T}\\)<\/span>.<\/p>\n<p>Can we come up with something for <span class=\"math inline\">\\(\\color{red}{\\square}v^T\\)<\/span>? Let&#8217;s see what <span class=\"math inline\">\\(w^T_\\star\\)<\/span> is: <span class=\"math inline\">\\(w^T_{\\star} = ({\\beta}v^TD)^T &#8211; (\\frac{1}{2}{\\beta}^2{\\alpha}v^T)^T = \\color{red}{{\\beta}Dv &#8211; \\frac{1}{2}{\\beta}^2{\\alpha}v}\\)<\/span>. Does it look familiar? (The color might help!) Fortunately, the answer is yes! And I&#8217;ll take serendipity in my mathematics any day. <span class=\"math inline\">\\(w^T_{\\star}\\)<\/span> is the sum of the coefficients on the <span class=\"math inline\">\\(v^T\\)<\/span> terms. So, with all that, we have:<\/p>\n<p><span class=\"math display\">\\[HDH = D &#8211; vw_{\\star} &#8211; w^T_{\\star}v^T\\]<\/span><\/p>\n<p>Lastly (really!), <span class=\"math inline\">\\(v\\)<\/span> is a column-vector, so by inference <span class=\"math inline\">\\(w_\\star\\)<\/span> must be a row-vector. You can also see this because <span class=\"math inline\">\\(w_\\star\\)<\/span> is made from <span class=\"math inline\">\\(v^T\\)<\/span>. Good. Now, in NumPy, if we mutiply two vectors, we get the element-wise result between the two. We want the <code>np.outer<\/code> product between the two vectors (<code>np.dot<\/code> would be great if we had multi-dimensional critters). We also don&#8217;t have to worry about the transposes in the last term when we use <code>np.outer<\/code> (the 1-D arrays are effectively &quot;unoriented&quot; vectors).<\/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=\"some-code\">Some Code<\/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 simply have basic code to either give us a fixed pair of vectors (for testing the tester &#8211; sort of like guarding the guardians) or to give us two random vectors with some conditioning constraints (for the generated matrix).<\/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;[10]:<\/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\">make_random_vecs_with_cond<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">C<\/span><span class=\"p\">,<\/span> <span class=\"n\">repeatable<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">if<\/span> <span class=\"n\">repeatable<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">d<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">linspace<\/span><span class=\"p\">(<\/span><span class=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"n\">C<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">v<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">arange<\/span><span class=\"p\">(<\/span><span class=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"o\">+<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"o\">+<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">d<\/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=\"n\">n<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">1.0<\/span><span class=\"p\">;<\/span> <span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">n<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">C<\/span>\n        <span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">:<\/span><span class=\"n\">n<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/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=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"n\">C<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"o\">-<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">v<\/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=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"mf\">100.0<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">d<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span>\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=\"dead-simple-implementation\">Dead Simple Implementation<\/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 is the super-simple-visually-verify implementation. We actually ignore all the hard work above and explicitly construct the Householder matrix &#8230; so that we can verify that our &quot;clever&quot; method produces the same numerical result. <em>Always<\/em> test yourself. Incidentally, to test the &quot;gold standard&quot;, we&#8217;ll compute the eigenvalues of the result and make sure they are the ones we initually used above (the <code>np.linspace<\/code> call will produce a diagonal of <code>[1, 5.5, 10]<\/code> for the call below.<\/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;[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\">make_spd_explicit<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">C<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">d<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_random_vecs_with_cond<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">C<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">v<\/span> <span class=\"o\">=<\/span> <span class=\"n\">v<\/span><span class=\"p\">[:,<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">newaxis<\/span><span class=\"p\">]<\/span> <span class=\"c1\"># explicitly convert to column vector<\/span>\n    <span class=\"n\">nrm<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"mf\">2.0<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"n\">v<\/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\">v<\/span><span class=\"p\">)))<\/span><span class=\"o\">.<\/span><span class=\"n\">reshape<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># explicitly create house for testing purposes<\/span>\n    <span class=\"n\">house<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">eye<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"n\">nrm<\/span><span class=\"o\">*<\/span><span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">T<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">D<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">diag<\/span><span class=\"p\">(<\/span><span class=\"n\">d<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">direct<\/span> <span class=\"o\">=<\/span> <span class=\"n\">house<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">D<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">house<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">direct<\/span>\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=\"n\">expected<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_spd_explicit<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">expected<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">linalg<\/span><span class=\"o\">.<\/span><span class=\"n\">eig<\/span><span class=\"p\">(<\/span><span class=\"n\">expected<\/span><span class=\"p\">)[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\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>[[ 3.02040816  2.75510204  2.20408163]\n [ 2.75510204  8.43877551  0.55102041]\n [ 2.20408163  0.55102041  5.04081633]]\n[  1.   10.    5.5]\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=\"better-method-using-our-hard-work\">Better Method Using Our Hard Work<\/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=\"k\">def<\/span> <span class=\"nf\">make_spd<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">C<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">d<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_random_vecs_with_cond<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">C<\/span><span class=\"p\">)<\/span>\n    \n    <span class=\"c1\"># each of these should be O(n) steps<\/span>\n    <span class=\"n\">beta<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"mf\">2.0<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"n\">v<\/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\">v<\/span><span class=\"p\">)))<\/span>\n    <span class=\"n\">dv<\/span> <span class=\"o\">=<\/span> <span class=\"n\">d<\/span><span class=\"o\">*<\/span><span class=\"n\">v<\/span> <span class=\"c1\"># elem-wise version of Dv and v^TD<\/span>\n    <span class=\"n\">alpha<\/span> <span class=\"o\">=<\/span>  <span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">dv<\/span><span class=\"p\">)<\/span>    \n    <span class=\"n\">w_star<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">beta<\/span> <span class=\"o\">*<\/span> <span class=\"n\">dv<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"p\">(<\/span><span class=\"o\">.<\/span><span class=\"mi\">5<\/span> <span class=\"o\">*<\/span> <span class=\"n\">beta<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span> <span class=\"o\">*<\/span> <span class=\"n\">alpha<\/span> <span class=\"o\">*<\/span> <span class=\"n\">v<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># not TOO clever, is we really want to avoid extra memory layouts<\/span>\n    <span class=\"c1\"># we could either a call to BLAS dger to update <\/span>\n    <span class=\"c1\"># outer products in place (i.e., A -+ outer(v,w))<\/span>\n    <span class=\"n\">clever<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">diag<\/span><span class=\"p\">(<\/span><span class=\"n\">d<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">outer<\/span><span class=\"p\">(<\/span><span class=\"n\">v<\/span><span class=\"p\">,<\/span><span class=\"n\">w_star<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">outer<\/span><span class=\"p\">(<\/span><span class=\"n\">w_star<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span><span class=\"p\">)<\/span>\n    \n    <span class=\"k\">return<\/span> <span class=\"n\">clever<\/span>\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=\"n\">actual<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_spd<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span><span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">allclose<\/span><span class=\"p\">(<\/span><span class=\"n\">expected<\/span><span class=\"p\">,<\/span> <span class=\"n\">actual<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">linalg<\/span><span class=\"o\">.<\/span><span class=\"n\">eig<\/span><span class=\"p\">(<\/span><span class=\"n\">actual<\/span><span class=\"p\">)[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\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>True\n[  1.   10.    5.5]\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<p>And if you stuck with me through all of that, go have a beer, take a walk, or something relaxing!<\/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=\"addendum-even-more-clever-er-er\">Addendum: Even More Clever-er-er<\/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=\"kn\">import<\/span> <span class=\"nn\">scipy.linalg.blas<\/span> <span class=\"kn\">as<\/span> <span class=\"nn\">slab<\/span>\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=\"n\">w<\/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=\"mf\">0.0<\/span><span class=\"p\">,<\/span> <span class=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">v<\/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=\"mf\">0.0<\/span><span class=\"p\">,<\/span> <span class=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">W<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">arange<\/span><span class=\"p\">(<\/span><span class=\"mf\">9.0<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">reshape<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">print<\/span> <span class=\"n\">W<\/span> <span class=\"o\">-<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">outer<\/span><span class=\"p\">(<\/span><span class=\"n\">v<\/span><span class=\"p\">,<\/span><span class=\"n\">w<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">outer<\/span><span class=\"p\">(<\/span><span class=\"n\">w<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># FAILS to update in place:  <\/span>\n<span class=\"c1\"># see https:\/\/github.com\/scipy\/scipy\/issues\/5738<\/span>\n<span class=\"n\">f<\/span> <span class=\"o\">=<\/span> <span class=\"n\">slab<\/span><span class=\"o\">.<\/span><span class=\"n\">get_blas_funcs<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;syr2&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">W<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span><span class=\"p\">,<\/span><span class=\"n\">w<\/span><span class=\"p\">))<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">f<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span><span class=\"n\">w<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span><span class=\"p\">,<\/span><span class=\"n\">a<\/span><span class=\"o\">=<\/span><span class=\"n\">W<\/span><span class=\"p\">,<\/span><span class=\"n\">overwrite_a<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">print<\/span> <span class=\"n\">W<\/span>\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>[[-0.0129077   0.74418334  1.45810324]\n [ 2.74418334  3.54239773  4.44051274]\n [ 5.45810324  6.44051274  7.71944681]]\n[[-0.0129077   0.74418334  1.45810324]\n [ 3.          3.54239773  4.44051274]\n [ 6.          7.          7.71944681]]\n[[ 0.  1.  2.]\n [ 3.  4.  5.]\n [ 6.  7.  8.]]\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=\"so-back-to-a-custom-solution\">So, back to a &quot;custom&quot; solution:<\/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;[17]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"o\">!<\/span>cat myheader.h\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>typedef enum CBLAS_ORDER     {CblasRowMajor=101, CblasColMajor=102} CBLAS_ORDER;\ntypedef enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113, CblasConjNoTrans=114} CBLAS_TRANSPOSE;\ntypedef enum CBLAS_UPLO      {CblasUpper=121, CblasLower=122} CBLAS_UPLO;\ntypedef enum CBLAS_DIAG      {CblasNonUnit=131, CblasUnit=132} CBLAS_DIAG;\ntypedef enum CBLAS_SIDE      {CblasLeft=141, CblasRight=142} CBLAS_SIDE;\n\nvoid cblas_dsyr2(const enum CBLAS_ORDER order, \n                 const enum CBLAS_UPLO Uplo, \n                 const int N, \n                 const double alpha, \n                 const double *X, const int incX, \n                 const double *Y, const int incY, \n                 double *A, \n                 const int lda);\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;[18]:<\/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\">cffi<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FFI<\/span>\n<span class=\"n\">ffi<\/span> <span class=\"o\">=<\/span> <span class=\"n\">FFI<\/span><span class=\"p\">()<\/span>\n\n<span class=\"k\">with<\/span> <span class=\"nb\">open<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;.\/myheader.h&quot;<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">header_file<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">ffi<\/span><span class=\"o\">.<\/span><span class=\"n\">cdef<\/span><span class=\"p\">(<\/span><span class=\"n\">header_file<\/span><span class=\"o\">.<\/span><span class=\"n\">read<\/span><span class=\"p\">())<\/span>\n<span class=\"n\">libblas<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ffi<\/span><span class=\"o\">.<\/span><span class=\"n\">dlopen<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;\/usr\/lib64\/libopenblas_openmp.so&quot;<\/span><span class=\"p\">)<\/span>\n\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>\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=\"s2\">&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=\"s1\">&#39;data&#39;<\/span><span class=\"p\">][<\/span><span class=\"mi\">0<\/span><span class=\"p\">])<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">my_syr2<\/span><span class=\"p\">(<\/span><span class=\"n\">A<\/span><span class=\"p\">,<\/span><span class=\"n\">alpha<\/span><span class=\"p\">,<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span><span class=\"n\">y<\/span><span class=\"p\">):<\/span>\n    <span class=\"c1\"># A &lt;- A + alpha x y.T + alpha y x.T (A is updated in place)<\/span>\n    <span class=\"c1\"># this is a special case that will only work correctly for A is diagonal<\/span>\n    <span class=\"c1\"># b\/c of the the lower to upper triangle copy<\/span>\n    <span class=\"n\">N<\/span> <span class=\"o\">=<\/span> <span class=\"n\">A<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n    <span class=\"k\">assert<\/span> <span class=\"n\">N<\/span> <span class=\"o\">==<\/span> <span class=\"n\">A<\/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=\"ow\">and<\/span> <span class=\"n\">N<\/span> <span class=\"o\">==<\/span> <span class=\"n\">x<\/span><span class=\"o\">.<\/span><span class=\"n\">size<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">N<\/span> <span class=\"o\">==<\/span> <span class=\"n\">y<\/span><span class=\"o\">.<\/span><span class=\"n\">size<\/span>\n    \n    <span class=\"n\">libblas<\/span><span class=\"o\">.<\/span><span class=\"n\">cblas_dsyr2<\/span><span class=\"p\">(<\/span><span class=\"mi\">101<\/span><span class=\"p\">,<\/span> <span class=\"mi\">122<\/span><span class=\"p\">,<\/span> <span class=\"c1\"># RowMajor, LowerTriangular<\/span>\n                        <span class=\"n\">N<\/span><span class=\"p\">,<\/span> <span class=\"n\">alpha<\/span><span class=\"p\">,<\/span> <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">),<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">y<\/span><span class=\"p\">),<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n                        <span class=\"n\">get_dptr<\/span><span class=\"p\">(<\/span><span class=\"n\">A<\/span><span class=\"p\">),<\/span> <span class=\"n\">N<\/span><span class=\"p\">)<\/span>\n    <span class=\"c1\"># propogate lower triangle to upper triangle<\/span>\n    <span class=\"n\">A<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">triu_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">N<\/span><span class=\"p\">,<\/span><span class=\"mi\">1<\/span><span class=\"p\">)]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">A<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">tril_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">N<\/span><span class=\"p\">,<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">)]<\/span> <span class=\"c1\"># only works b\/c off diag are zero<\/span>\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;[19]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"n\">w<\/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=\"mf\">0.0<\/span><span class=\"p\">,<\/span> <span class=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">v<\/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=\"mf\">0.0<\/span><span class=\"p\">,<\/span> <span class=\"mf\">1.0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">W<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">arange<\/span><span class=\"p\">(<\/span><span class=\"mf\">9.0<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">reshape<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">expected<\/span> <span class=\"o\">=<\/span> <span class=\"n\">W<\/span> <span class=\"o\">-<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">outer<\/span><span class=\"p\">(<\/span><span class=\"n\">v<\/span><span class=\"p\">,<\/span><span class=\"n\">w<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">outer<\/span><span class=\"p\">(<\/span><span class=\"n\">w<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"s2\">&quot;expected:<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">expected<\/span>\n\n<span class=\"c1\"># FAILS to update in place:  <\/span>\n<span class=\"c1\"># see https:\/\/github.com\/scipy\/scipy\/issues\/5738<\/span>\n<span class=\"n\">my_syr2<\/span><span class=\"p\">(<\/span><span class=\"n\">W<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">w<\/span><span class=\"p\">,<\/span> <span class=\"n\">v<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">W<\/span>\n\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">allclose<\/span><span class=\"p\">(<\/span><span class=\"n\">expected<\/span><span class=\"p\">,<\/span><span class=\"n\">W<\/span><span class=\"p\">)<\/span>\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>expected:\n[[-0.09167778  0.79466529  1.51937221]\n [ 2.79466529  3.73716468  4.59675651]\n [ 5.51937221  6.59675651  7.78031939]]\n[[-0.09167778  2.79466529  5.51937221]\n [ 2.79466529  3.73716468  6.59675651]\n [ 5.51937221  6.59675651  7.78031939]]\nFalse\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;[20]:<\/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\">make_spd_opt<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">C<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">d<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_random_vecs_with_cond<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">C<\/span><span class=\"p\">)<\/span>\n    \n    <span class=\"c1\"># each of these should be O(n) steps<\/span>\n    <span class=\"n\">beta<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"mf\">2.0<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"n\">v<\/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\">v<\/span><span class=\"p\">)))<\/span>\n    <span class=\"n\">dv<\/span> <span class=\"o\">=<\/span> <span class=\"n\">d<\/span><span class=\"o\">*<\/span><span class=\"n\">v<\/span> <span class=\"c1\"># elem-wise version of Dv and v^TD<\/span>\n    <span class=\"n\">alpha<\/span> <span class=\"o\">=<\/span>  <span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">dv<\/span><span class=\"p\">)<\/span>    \n    <span class=\"n\">w_star<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">beta<\/span> <span class=\"o\">*<\/span> <span class=\"n\">dv<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"p\">(<\/span><span class=\"o\">.<\/span><span class=\"mi\">5<\/span> <span class=\"o\">*<\/span> <span class=\"n\">beta<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span> <span class=\"o\">*<\/span> <span class=\"n\">alpha<\/span> <span class=\"o\">*<\/span> <span class=\"n\">v<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">clever<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">diag<\/span><span class=\"p\">(<\/span><span class=\"n\">d<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">my_syr2<\/span><span class=\"p\">(<\/span><span class=\"n\">clever<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">v<\/span><span class=\"p\">,<\/span> <span class=\"n\">w_star<\/span><span class=\"p\">)<\/span>   \n    <span class=\"k\">return<\/span> <span class=\"n\">clever<\/span>\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;[21]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"n\">expected<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_spd_explicit<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">actual<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_spd_opt<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span><span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">actual<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">allclose<\/span><span class=\"p\">(<\/span><span class=\"n\">expected<\/span><span class=\"p\">,<\/span> <span class=\"n\">actual<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">linalg<\/span><span class=\"o\">.<\/span><span class=\"n\">eig<\/span><span class=\"p\">(<\/span><span class=\"n\">actual<\/span><span class=\"p\">)[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\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>[[ 3.02040816  2.75510204  2.20408163]\n [ 2.75510204  8.43877551  0.55102041]\n [ 2.20408163  0.55102041  5.04081633]]\nTrue\n[  1.   10.    5.5]\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<p>However, since <span class=\"math inline\">\\(D=D^T\\)<\/span>, it isn&#8217;t too confusing to <em>hack<\/em> the <code>scipy.linalg.blas.dsyr2<\/code> call to work correctly. The call will only honor <code>overwrite_a<\/code> if the <code>a<\/code> is in Fortran order &#8211; which <code>a.T<\/code> will be:<\/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;[22]:<\/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\">make_spd_opt2<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">C<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">d<\/span><span class=\"p\">,<\/span><span class=\"n\">v<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_random_vecs_with_cond<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">,<\/span><span class=\"n\">C<\/span><span class=\"p\">)<\/span>\n    \n    <span class=\"c1\"># each of these should be O(n) steps<\/span>\n    <span class=\"n\">beta<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"mf\">2.0<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"n\">v<\/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\">v<\/span><span class=\"p\">)))<\/span>\n    <span class=\"n\">dv<\/span> <span class=\"o\">=<\/span> <span class=\"n\">d<\/span><span class=\"o\">*<\/span><span class=\"n\">v<\/span> <span class=\"c1\"># elem-wise version of Dv and v^TD<\/span>\n    <span class=\"n\">alpha<\/span> <span class=\"o\">=<\/span>  <span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">dot<\/span><span class=\"p\">(<\/span><span class=\"n\">dv<\/span><span class=\"p\">)<\/span>    \n    <span class=\"n\">w_star<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">beta<\/span> <span class=\"o\">*<\/span> <span class=\"n\">dv<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"p\">(<\/span><span class=\"o\">.<\/span><span class=\"mi\">5<\/span> <span class=\"o\">*<\/span> <span class=\"n\">beta<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span> <span class=\"o\">*<\/span> <span class=\"n\">alpha<\/span> <span class=\"o\">*<\/span> <span class=\"n\">v<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">clever<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">diag<\/span><span class=\"p\">(<\/span><span class=\"n\">d<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">slab<\/span><span class=\"o\">.<\/span><span class=\"n\">dsyr2<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">w_star<\/span><span class=\"p\">,<\/span> <span class=\"n\">v<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"o\">=<\/span><span class=\"n\">clever<\/span><span class=\"o\">.<\/span><span class=\"n\">T<\/span><span class=\"p\">,<\/span> <span class=\"n\">overwrite_a<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    \n    <span class=\"c1\"># have to propogate (unless we wanted to just use a packed rep.)<\/span>\n    <span class=\"n\">N<\/span> <span class=\"o\">=<\/span> <span class=\"n\">clever<\/span><span class=\"o\">.<\/span><span class=\"n\">shape<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">clever<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">triu_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">N<\/span><span class=\"p\">,<\/span><span class=\"mi\">1<\/span><span class=\"p\">)]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">clever<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">tril_indices<\/span><span class=\"p\">(<\/span><span class=\"n\">N<\/span><span class=\"p\">,<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">)]<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">clever<\/span>\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;[23]:<\/div>\n<div class=\"inner_cell\">\n<div class=\"input_area\">\n<div class=\" highlight hl-ipython2\">\n<pre><span class=\"n\">expected<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_spd_explicit<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">actual<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_spd_opt2<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span><span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">print<\/span> <span class=\"n\">np<\/span><span class=\"o\">.<\/span><span class=\"n\">allclose<\/span><span class=\"p\">(<\/span><span class=\"n\">expected<\/span><span class=\"p\">,<\/span> <span class=\"n\">actual<\/span><span class=\"p\">)<\/span>\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>True\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>\nAdditional Resources<br \/>\n<\/h3>\n<p>\nYou can grab a <a href=\"http:\/\/drsfenner.org\/public\/notebooks\/ImplementingCholeskyTesting.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\/ImplementingCholeskyTesting.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 working through the Cholesky, QR, and SVD methods for solving the normal regression equations, I got curious about the underlying implementations of each. I did QR and Cholesky in grad school (a great Numerical Analysis sequence). I never got around to SVD (I think we did some variation of tridiagonalization). Anyway, Cholesky is so [&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-414","post","type-post","status-publish","format-standard","hentry","category-mrdr","category-sci-math-stat-python"],"_links":{"self":[{"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts\/414","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/comments?post=414"}],"version-history":[{"count":1,"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts\/414\/revisions"}],"predecessor-version":[{"id":415,"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/posts\/414\/revisions\/415"}],"wp:attachment":[{"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/media?parent=414"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/categories?post=414"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/drsfenner.org\/blog\/wp-json\/wp\/v2\/tags?post=414"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}