<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Working notes by Matthew Rocklin - SymPy </title>
        <description>Posts tagged as 'SymPy'</description>
        <link>http://matthewrocklin.com/blog/</link>
        <atom:link href="http://matthewrocklin.com/blog//feed.sympy.xml" rel="self" type="application/rss+xml" />
        
          
            <item>
                <title>SymPy and Theano -- Matrix Expressions</title>
                <description>&lt;h2 id='introduction'&gt;Introduction&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This post uses some LaTeX. You may want to read it on the &lt;a href='http://matthewrocklin.com/blog/work/2013/04/05/SymPy-Theano-part-3/'&gt;original site&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the last of a three part series connecting SymPy and Theano to transform mathematical expressions into efficient numeric code (see &lt;a href='http://matthewrocklin.com/blog/work/2013/03/19/SymPy-Theano-part-1/'&gt;part 1&lt;/a&gt; and &lt;a href='http://matthewrocklin.com/blog/work/2013/03/28/SymPy-Theano-part-2/'&gt;part 2&lt;/a&gt;). We have seen that it is simple and computationally profitable to combine the best parts of both projects.&lt;/p&gt;

&lt;p&gt;In this post we&amp;#8217;ll switch from computing scalar expressionss to computing matrix expressions. We&amp;#8217;ll define the Kalman filter in SymPy and send it to Theano for code generation. We&amp;#8217;ll then use SymPy to define a more performant blocked version of the same algorithm.&lt;/p&gt;

&lt;h2 id='kalman_filter'&gt;Kalman Filter&lt;/h2&gt;

&lt;p&gt;The &lt;a href='http://en.wikipedia.org/wiki/Kalman_filter'&gt;Kalman filter&lt;/a&gt; is an algorithm to compute the Bayesian update of a normal random variable given a linear observation with normal noise. It is commonly used when an uncertain quantity is updated with the results of noisy observations. For example it is used in weather forecasting after weather stations report in with new measurements, in aircraft/car control to automatically adjust for external conditions real-time, or even on your smartphone&amp;#8217;s GPS navigation as you update your position based on fuzzy GPS signals. It&amp;#8217;s everywhere, it&amp;#8217;s important, and it needs to be computed quickly and continuously. It suits our needs today because it can be completely defined with a pair of matrix expressions.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;sympy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;MatrixSymbol&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;
&lt;span class='n'&gt;n&lt;/span&gt;       &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;1000&lt;/span&gt;                          &lt;span class='c'&gt;# Number of variables in our system/current state&lt;/span&gt;
&lt;span class='n'&gt;k&lt;/span&gt;       &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;500&lt;/span&gt;                           &lt;span class='c'&gt;# Number of variables in the observation&lt;/span&gt;
&lt;span class='n'&gt;mu&lt;/span&gt;      &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;MatrixSymbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;mu&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;      &lt;span class='c'&gt;# Mean of current state&lt;/span&gt;
&lt;span class='n'&gt;Sigma&lt;/span&gt;   &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;MatrixSymbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Sigma&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;   &lt;span class='c'&gt;# Covariance of current state&lt;/span&gt;
&lt;span class='n'&gt;H&lt;/span&gt;       &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;MatrixSymbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;H&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;       &lt;span class='c'&gt;# A measurement operator on current state&lt;/span&gt;
&lt;span class='n'&gt;R&lt;/span&gt;       &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;MatrixSymbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;R&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;       &lt;span class='c'&gt;# Covariance of measurement noise&lt;/span&gt;
&lt;span class='n'&gt;data&lt;/span&gt;    &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;MatrixSymbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;    &lt;span class='c'&gt;# Observed measurement data&lt;/span&gt;

&lt;span class='n'&gt;newmu&lt;/span&gt;   &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;mu&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;Sigma&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;T&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;R&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;Sigma&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;T&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;I&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;mu&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;      &lt;span class='c'&gt;# Updated mean&lt;/span&gt;
&lt;span class='n'&gt;newSigma&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Sigma&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='n'&gt;Sigma&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;T&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;R&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;Sigma&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;T&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;I&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='n'&gt;H&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='n'&gt;Sigma&lt;/span&gt;       &lt;span class='c'&gt;# Updated covariance&lt;/span&gt;

&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;newmu&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;newSigma&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;$$ \Sigma H^T \left(H \Sigma H^T + R\right)^{-1} \left(-data + H \mu\right) + \mu $$ $$ - \Sigma H^T \left(H \Sigma H^T + R\right)^{-1} H \Sigma + \Sigma $$&lt;/p&gt;

&lt;h2 id='theano_execution'&gt;Theano Execution&lt;/h2&gt;

&lt;p&gt;The objects above are for symbolic mathematics, not for numeric computation. If we want to compute this expression we pass our expressions to Theano.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;inputs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;mu&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;Sigma&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;R&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;outputs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;newmu&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;newSigma&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;dtypes&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='n'&gt;inp&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;float64&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;inp&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;inputs&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;sympy.printing.theanocode&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;theano_function&lt;/span&gt;
&lt;span class='n'&gt;f&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;theano_function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;inputs&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;outputs&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;dtypes&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;dtypes&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Theano builds a Python function that calls down to a combination of low-level &lt;code&gt;C&lt;/code&gt; code, &lt;code&gt;scipy&lt;/code&gt; functions, and calls to the highly optimized &lt;code&gt;DGEMM&lt;/code&gt; routine for matrix multiplication. As input this function takes five numpy arrays corresponding to our five symbolic &lt;code&gt;inputs&lt;/code&gt; and produces two numpy arrays corresponding to our two symbolic &lt;code&gt;outputs&lt;/code&gt;. &lt;a href='https://github.com/sympy/sympy/pull/1965'&gt;Recent work&lt;/a&gt; allows &lt;em&gt;any&lt;/em&gt; SymPy matrix expression to be translated to and run by Theano.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='nn'&gt;numpy&lt;/span&gt;
&lt;span class='n'&gt;ninputs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;numpy&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;random&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rand&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;shape&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;astype&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;float64&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;i&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;inputs&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;nmu&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;nSigma&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;ninputs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id='blocked_execution'&gt;Blocked Execution&lt;/h2&gt;

&lt;p&gt;These arrays are too large to fit comfortably in the fastest parts of the memory hierarchy. As a result each sequential &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;scipy&lt;/code&gt;, or &lt;code&gt;DGEMM&lt;/code&gt; call needs to move big chunks of memory around while it computes. After one operation completes the next operation moves around the same memory while it performs its task. This repeated memory shuffling hurts performance.&lt;/p&gt;

&lt;p&gt;A common approach to reduce memory shuffling is to cut the computation into smaller blocks. We then perform as many computations as possible on a single block before moving on. This is a standard technique in matrix multiplication.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;sympy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;BlockMatrix&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;block_collapse&lt;/span&gt;
&lt;span class='n'&gt;A&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;B&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;C&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;D&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;E&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;F&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;G&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;K&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;MatrixSymbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;ABCDEFGK&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;X&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;BlockMatrix&lt;/span&gt;&lt;span class='p'&gt;([[&lt;/span&gt;&lt;span class='n'&gt;A&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;B&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
                 &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;C&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;D&lt;/span&gt;&lt;span class='p'&gt;]])&lt;/span&gt;
&lt;span class='n'&gt;Y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;BlockMatrix&lt;/span&gt;&lt;span class='p'&gt;([[&lt;/span&gt;&lt;span class='n'&gt;E&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;F&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
                 &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;G&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;K&lt;/span&gt;&lt;span class='p'&gt;]])&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;X&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;Y&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;$$ \begin{bmatrix} A &amp;amp; B \\ C &amp;amp; D \end{bmatrix} \begin{bmatrix} E &amp;amp; F \\ G &amp;amp; K \end{bmatrix}$$&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;block_collapse&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;X&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;Y&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;$$ \begin{bmatrix} A E + B G &amp;amp; A F + B K \\ C E + D G &amp;amp; C F + D K\end{bmatrix} $$&lt;/p&gt;

&lt;p&gt;We are now able to focus on substantially smaller chunks of the array. For example we can choose to keep &lt;code&gt;A&lt;/code&gt; in local memory and perform all computations that involve &lt;code&gt;A&lt;/code&gt;. We will still need to shuffle some memory around (this is inevitable) but by organizing with blocks we&amp;#8217;re able to shuffle less.&lt;/p&gt;

&lt;p&gt;This idea extends beyond matrix multiplication. For example, SymPy knows how to block a matrix inverse&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;block_collapse&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;X&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;I&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;$$ \begin{bmatrix} \left(- B D^{-1} C + A\right)^{-1} &amp;amp; - A^{-1} B \left(- C A^{-1} B + D\right)^{-1} \\ - \left(- C A^{-1} B + D\right)^{-1} C A^{-1} &amp;amp; \left(- C A^{-1} B + D\right)^{-1} \end{bmatrix} $$&lt;/p&gt;

&lt;p&gt;High performance dense linear algebra libraries hard-code all of these tricks into each individual routine. The call to the general matrix multiply routine &lt;code&gt;DGEMM&lt;/code&gt; performs blocked matrix multiply within the call. The call to the general matrix solve routine &lt;code&gt;DGESV&lt;/code&gt; can perform blocked matrix solve. Unfortunately these routines are unable to coordinate blocked computation &lt;em&gt;between&lt;/em&gt; calls.&lt;/p&gt;

&lt;p&gt;Fortunately, SymPy and Theano can.&lt;/p&gt;

&lt;p&gt;SymPy can define and reduce the blocked matrix expressions using relations like what are shown above.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;sympy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;blockcut&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;block_collapse&lt;/span&gt;
&lt;span class='n'&gt;blocksizes&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='n'&gt;Sigma&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;)],&lt;/span&gt;
        &lt;span class='n'&gt;H&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;     &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;)],&lt;/span&gt;
        &lt;span class='n'&gt;R&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;     &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;)],&lt;/span&gt;
        &lt;span class='n'&gt;mu&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;    &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,)],&lt;/span&gt;
        &lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;  &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,)]&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='n'&gt;blockinputs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;blockcut&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;blocksizes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;i&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;inputs&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;blockoutputs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;o&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;subs&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;dict&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;zip&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;inputs&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;blockinputs&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;o&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;outputs&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;collapsed_outputs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;map&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;block_collapse&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;blockoutputs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='n'&gt;fblocked&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;theano_function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;inputs&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;collapsed_outputs&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;dtypes&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;dtypes&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Theano is then able to coordinate this computation and compile it to low-level code. At this stage the expresssions/computations are fairly complex and difficult to present. Here is an image of the computation (click for zoomable PDF) as a directed acyclic graph.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://mrocklin.github.com/blog/images/fblocked.pdf'&gt;&lt;img src='http://mrocklin.github.com/blog/images/fblocked-small.png' alt='' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id='results'&gt;Results&lt;/h2&gt;

&lt;p&gt;Lets time each function on the same inputs and see which is faster&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;timeit&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;ninputs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='mi'&gt;1&lt;/span&gt; &lt;span class='n'&gt;loops&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;best&lt;/span&gt; &lt;span class='n'&gt;of&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='mf'&gt;2.69&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt; &lt;span class='n'&gt;per&lt;/span&gt; &lt;span class='n'&gt;loop&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;timeit&lt;/span&gt; &lt;span class='n'&gt;fblocked&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;ninputs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='mi'&gt;1&lt;/span&gt; &lt;span class='n'&gt;loops&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;best&lt;/span&gt; &lt;span class='n'&gt;of&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='mf'&gt;2.12&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt; &lt;span class='n'&gt;per&lt;/span&gt; &lt;span class='n'&gt;loop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&amp;#8217;s a 20% performance increase from just a few lines of high-level code.&lt;/p&gt;

&lt;p&gt;Blocked matrix multiply and blocked solve routines have long been established as &lt;em&gt;a good idea&lt;/em&gt;. High level mathematical and array programming libraries like SymPy and Theano allow us to extend this good idea to &lt;em&gt;arbitrary&lt;/em&gt; array computations.&lt;/p&gt;

&lt;h2 id='analysis'&gt;Analysis&lt;/h2&gt;

&lt;h3 id='good_things'&gt;Good Things&lt;/h3&gt;

&lt;p&gt;First, lets note that we&amp;#8217;re not introducing a new library for dense linear algebra. Instead we&amp;#8217;re noting that pre-existing general purpose high-level tools can be composed to that effect.&lt;/p&gt;

&lt;p&gt;Second, lets acknoledge that we could take this further. For example Theano seemlessly handles GPU interactions. We could take this same code to a GPU accelerated machine and it would just run faster without any action on our part.&lt;/p&gt;

&lt;h3 id='bad_things'&gt;Bad Things&lt;/h3&gt;

&lt;p&gt;However, there are some drawbacks.&lt;/p&gt;

&lt;p&gt;Frequent readers of my blog might recall a &lt;a href='http://matthewrocklin.com/blog/work/2012/11/24/Kalman-Filter/'&gt;previous post about the Kalman filter&lt;/a&gt;. In it I showed how we could use SymPy&amp;#8217;s inference engine to select appropriate BLAS/LAPACK calls. For example we could infer that because $ H \Sigma H^T + R $ was symmetric positive definite we could use the substantially more efficient &lt;code&gt;POSV&lt;/code&gt; routine for matrix solve rather than &lt;code&gt;GESV&lt;/code&gt; (&lt;code&gt;POSV&lt;/code&gt; uses the Cholesky algorithm for decomposition rather than straight LU). Theano doesn&amp;#8217;t support the specialized BLAS/LAPACK routines though, so we are unable to take advantage of this benefit. The lower-level interface (Theano) is not sufficiently rich to use all information captured in the higher-level (SymPy) representation.&lt;/p&gt;

&lt;p&gt;Also, I&amp;#8217;ve noticed that the blocked version of this computation experiences some significant roundoff errors (on the order of &lt;code&gt;1e-3&lt;/code&gt;). I&amp;#8217;m in the process of tracking this down. The problem must occur somewhere in the following tool-chain&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SymPy -&amp;gt; Blocking -&amp;gt; Theano -&amp;gt; SciPy -&amp;gt; C routines -&amp;gt; BLAS&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Debugging in this context can be wonderful if all elements are well unit-tested. If they&amp;#8217;re not (they&amp;#8217;re not) then tracking down errors like this requires an unfortunate breadth of expertise.&lt;/p&gt;

&lt;h2 id='references'&gt;References&lt;/h2&gt;

&lt;p&gt;Scripts&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://mrocklin.github.com/blog/scripts/kalman.py'&gt;Kalman example&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://mrocklin.github.com/blog/scripts/blocks.py'&gt;Block Matrix example&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://mrocklin.github.com/blog/scripts/kalman_blocked.py'&gt;Block Kalman&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
                <pubDate>Fri, 05 Apr 2013 00:00:00 -0700</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/04/05/SymPy-Theano-part-3</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/04/05/SymPy-Theano-part-3</guid>
            </item>
          
        
          
            <item>
                <title>SymPy and Theano -- Scalar Simplification</title>
                <description>&lt;h2 id='introduction'&gt;Introduction&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This post uses some LaTeX. You may want to read it on the original site.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my &lt;a href='http://matthewrocklin.com/blog/work/2013/03/19/SymPy-Theano-part-1/'&gt;last post&lt;/a&gt; I showed how SymPy can benefit from Theano. In particular Theano provided a mature platform for code generation that outperformed SymPy&amp;#8217;s attempt at the same problem. I argued that projects should stick to one specialty and depend on others for secondary concerns. Interfaces are better than add-ons.&lt;/p&gt;

&lt;p&gt;In this post I&amp;#8217;ll show how Theano can benefit from SymPy. In particular I&amp;#8217;ll demonstrate the practicality of SymPy&amp;#8217;s impressive scalar simplification routines for generating efficient programs.&lt;/p&gt;

&lt;p&gt;After re-reading over this post I realize that it&amp;#8217;s somewhat long. I&amp;#8217;ve decided to put the results first in hopes that it&amp;#8217;ll motivate you to keep reading.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Project&lt;/th&gt;&lt;th&gt;operation count&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;SymPy&lt;/td&gt;&lt;td style='text-align: center;'&gt;27&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;Theano&lt;/td&gt;&lt;td style='text-align: center;'&gt;24&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;SymPy+Theano&lt;/td&gt;&lt;td style='text-align: center;'&gt;17&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Now, lets find out what those numbers mean.&lt;/p&gt;

&lt;h2 id='example_problem'&gt;Example problem&lt;/h2&gt;

&lt;p&gt;We use a larger version of our problem from last time; a radial wavefunction corresponding to &lt;code&gt;n = 6&lt;/code&gt; and &lt;code&gt;l = 2&lt;/code&gt; for Carbon (&lt;code&gt;Z = 6&lt;/code&gt;)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from sympy.physics.hydrogen import R_nl
from sympy.abc import x
n, l, Z = 6, 2, 6
expr = R_nl(n, l, x, Z)
print latex(expr)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$\frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x}$$&lt;/p&gt;

&lt;p&gt;We want to generate code to compute both this expression and its derivative. Both SymPy and Theano can compute and simplify derivatives. In this post we&amp;#8217;ll measure the complexity of a computation that simultaneously computes both the above expression and its derivative. We&amp;#8217;ll arrive at this computation through a couple of different routes that use overlapping parts of SymPy and Theano. This will supply a couple of direct comparisons.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: I&amp;#8217;ve chosen a larger expression here to exaggerate results. Simpler expressions yield less impressive results.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id='simplification'&gt;Simplification&lt;/h2&gt;

&lt;p&gt;We show the expression, it&amp;#8217;s derivative, and SymPy&amp;#8217;s simplification of that derivative. In each case we quantify the complexity of the expression by the number of algebraic operations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The target expression:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;print latex(expr)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$\frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x}$$&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;print &amp;quot;Operations: &amp;quot;, count_ops(expr)
Operations:  17&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;It&amp;#8217;s derivative&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;print latex(expr.diff(x))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$ \frac{1}{210} \sqrt{70} x^{2} \left(- 4 x^{2} + 32 x - 56\right) e^{- x} - \frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x} + \frac{1}{105} \sqrt{70} x \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x} $$&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;print &amp;quot;Operations: &amp;quot;, count_ops(expr.diff(x))
Operations:  48&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;The result of &lt;code&gt;simplify&lt;/code&gt;&lt;/strong&gt; on the derivative. Note the significant cancellation of the above expression.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;print latex(simplify(expr.diff(x)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$ \frac{2}{315} \sqrt{70} x \left(x^{4} - 17 x^{3} + 90 x^{2} - 168 x + 84\right) e^{- x} $$&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;print &amp;quot;Operations: &amp;quot;, count_ops(simplify(expr.diff(x)))
Operations:  18&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;An unevaluated derivative object&lt;/strong&gt;. We&amp;#8217;ll end up passing this to Theano so that it computes the derivative on its own.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;print latex(Derivative(expr, x))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$ \frac{\partial}{\partial x}\left(\frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x}\right) $$&lt;/p&gt;

&lt;h2 id='bounds_on_the_cost_of_differentiation'&gt;Bounds on the cost of Differentiation&lt;/h2&gt;

&lt;p&gt;Scalar differentiation is actually a very simple transformation.&lt;/p&gt;

&lt;p&gt;You need to know how to transform all of the elementary functions (&lt;code&gt;exp, log, sin, cos, polynomials, etc...&lt;/code&gt;), the chain rule, and that&amp;#8217;s it. Theorems behind automatic differentiation state that the cost of a derivative will be at most five times the cost of the original. In this case we&amp;#8217;re guaranteed to have at most &lt;code&gt;17*5 == 85&lt;/code&gt; operations in the derivative computation; this holds in our case because &lt;code&gt;48 &amp;lt; 85&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However derivatives are often far simpler than this upper bound. We see that after simplification the operation count of the derivative is &lt;code&gt;18&lt;/code&gt;, only one more than the original. This is common in practice.&lt;/p&gt;

&lt;h2 id='theano_simplification'&gt;Theano Simplification&lt;/h2&gt;

&lt;p&gt;Like SymPy, Theano transforms graphs to mathematically equivalent but computationally more efficient representations. It provides standard compiler optimizations like constant folding, and common sub-expressions as well as array specific optimizations like the element-wise operation fusion.&lt;/p&gt;

&lt;p&gt;Because users regularly handle mathematical terms Theano also provides a set of optimizations to simplify some common scalar expressions. For example Theano will convert expressions like &lt;code&gt;x*y/x&lt;/code&gt; to &lt;code&gt;y&lt;/code&gt;. In this sense it overlaps with SymPy&amp;#8217;s &lt;code&gt;simplify&lt;/code&gt; functions. This post is largely a demonstration that SymPy&amp;#8217;s scalar simplifications are far more powerful than Theano&amp;#8217;s and that their use can result in significant improvements. This shouldn&amp;#8217;t be surprising. Sympians are devoted to scalar simplification to a degree that far exceeds the Theano community&amp;#8217;s devotion to this topic.&lt;/p&gt;

&lt;h2 id='experiment'&gt;Experiment&lt;/h2&gt;

&lt;p&gt;We&amp;#8217;ll compute the derivative of our radial wavefunction and then simplify the result. We&amp;#8217;ll do this using both SymPy&amp;#8217;s derivative and simplify routines and using Theano&amp;#8217;s derivative and simplify routines. We&amp;#8217;ll then compare the two results by counting the number of required operations.&lt;/p&gt;

&lt;p&gt;Here is some setup code that you can safely ignore:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;fgraph_of&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;exprs&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='sd'&gt;&amp;quot;&amp;quot;&amp;quot; Transform SymPy expressions into Theano Computation &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class='n'&gt;outs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;map&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;theano_code&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;exprs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;ins&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;theano&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gof&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;graph&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inputs&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;outs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;ins&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;outs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;theano&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gof&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;graph&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;clone&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ins&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;outs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;theano&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gof&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;FunctionGraph&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ins&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;outs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;theano_simplify&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='sd'&gt;&amp;quot;&amp;quot;&amp;quot; Simplify a Theano Computation &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class='n'&gt;mode&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;theano&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;compile&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get_default_mode&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;excluding&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;fusion&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;fgraph&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;clone&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='n'&gt;mode&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;optimizer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;optimize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;fgraph&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;theano_count_ops&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='sd'&gt;&amp;quot;&amp;quot;&amp;quot; Count the number of Scalar operations in a Theano Computation &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;len&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;filter&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;lambda&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='nb'&gt;isinstance&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;op&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;theano&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;tensor&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;Elemwise&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
                      &lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;apply_nodes&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In SymPy we create both an unevaluated derivative and a fully evaluated and sympy-simplified version. We translate each to Theano, simplify within Theano, and then count the number of operations both before and after simplification. In this way we can see the value added by both SymPy&amp;#8217;s and Theano&amp;#8217;s optimizations.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;exprs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;Derivative&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;    &lt;span class='c'&gt;# derivative computed in Theano&lt;/span&gt;
         &lt;span class='n'&gt;simplify&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;diff&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))]&lt;/span&gt; &lt;span class='c'&gt;# derivative computed in SymPy, also sympy-simplified&lt;/span&gt;

&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;expr&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;exprs&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
    &lt;span class='n'&gt;fgraph&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;fgraph_of&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;simp_fgraph&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;theano_simplify&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Operations:                             &amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;theano_count_ops&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Operations after Theano Simplification: &amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;theano_count_ops&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;simp_fgraph&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Theano Only&lt;/p&gt;

&lt;p&gt;$$ \frac{\partial}{\partial x}\left(\frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x}\right) $$&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Operations:                              40
Operations after Theano Simplification:  21&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;SymPy + Theano&lt;/p&gt;

&lt;p&gt;$$ \frac{2}{315} \sqrt{70} x \left(x^{4} - 17 x^{3} + 90 x^{2} - 168 x + 84\right) e^{- x} $$&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Operations:                              13
Operations after Theano Simplification:  10&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='analysis'&gt;Analysis&lt;/h2&gt;

&lt;p&gt;On its own Theano produces a derivative expression that is about as complex as the unsimplified SymPy version. Theano simplification then does a surprisingly good job, roughly halving the amount of work needed (&lt;code&gt;40 -&amp;gt; 21&lt;/code&gt;) to compute the result. If you dig deeper however you find that this isn&amp;#8217;t because it was able to algebraically simplify the computation (it wasn&amp;#8217;t) but rather because the computation contained several common sub-expressions. The Theano version looks a lot like the unsimplified SymPy version. Note the common sub-expressions like &lt;code&gt;56*x&lt;/code&gt; below.&lt;/p&gt;

&lt;p&gt;$$ \frac{1}{210} \sqrt{70} x^{2} \left(- 4 x^{2} + 32 x - 56\right) e^{- x} - \frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x} + \frac{1}{105} \sqrt{70} x \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x} $$&lt;/p&gt;

&lt;p&gt;The pure-SymPy simplified result is again substantially more efficient (&lt;code&gt;13&lt;/code&gt; operations). Interestingly Theano is still able to improve on this, again not because of additional algebraic simplification but rather due to constant folding. The two projects simplify in orthogonal ways.&lt;/p&gt;

&lt;h2 id='simultaneous_computation'&gt;Simultaneous Computation&lt;/h2&gt;

&lt;p&gt;When we compute both the expression and its derivative simultaneously we find substantial benefits from using the two projects together.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;orig_expr&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;R_nl&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;l&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;Z&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;expr&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;exprs&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
    &lt;span class='n'&gt;fgraph&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;fgraph_of&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;orig_expr&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;simp_fgraph&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;theano_simplify&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;orig_expr&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
    &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Operations:                             &amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;len&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fgraph&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;apply_nodes&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Operations after Theano Simplification: &amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;len&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;simp_fgraph&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;apply_nodes&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;$$ \begin{pmatrix}\frac{\partial}{\partial x}\left(\frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x}\right), &amp;amp; \frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x}\end{pmatrix} $$&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Operations:                              57
Operations after Theano Simplification:  24&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$ \begin{pmatrix}\frac{2}{315} \sqrt{70} x \left(x^{4} - 17 x^{3} + 90 x^{2} - 168 x + 84\right) e^{- x}, &amp;amp; \frac{1}{210} \sqrt{70} x^{2} \left(- \frac{4}{3} x^{3} + 16 x^{2} - 56 x + 56\right) e^{- x}\end{pmatrix} $$&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Operations:                              27
Operations after Theano Simplification:  17&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The combination of SymPy&amp;#8217;s scalar simplification and Theano&amp;#8217;s common sub-expression optimization yields a significantly simpler computation than either project could do independently.&lt;/p&gt;

&lt;p&gt;To summarize&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Project&lt;/th&gt;&lt;th&gt;operation count&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;SymPy&lt;/td&gt;&lt;td style='text-align: center;'&gt;27&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;Theano&lt;/td&gt;&lt;td style='text-align: center;'&gt;24&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;SymPy+Theano&lt;/td&gt;&lt;td style='text-align: center;'&gt;17&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id='references'&gt;References&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://mrocklin.github.com/blog/scripts/sympy_theano_simplification.py'&gt;A script of this session&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
                <pubDate>Thu, 28 Mar 2013 00:00:00 -0700</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/03/28/SymPy-Theano-part-2</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/03/28/SymPy-Theano-part-2</guid>
            </item>
          
        
          
            <item>
                <title>SymPy and Theano -- Code Generation</title>
                <description>&lt;p&gt;No one is good at everything, that&amp;#8217;s why we have society.&lt;/p&gt;

&lt;p&gt;No project is good at everything, that&amp;#8217;s why we have interfaces.&lt;/p&gt;

&lt;p&gt;This is the first of three posts that join &lt;code&gt;SymPy&lt;/code&gt;, a library for symbolic mathematics, and &lt;code&gt;Theano&lt;/code&gt;, a library for mathematical compilation to numeric code. Each library does a few things really well. Each library also over-reaches bit and does a few things not-as-well. Fortunately the two libraries have clear and simple data structures and so can be used together effectively.&lt;/p&gt;

&lt;p&gt;In this post I&amp;#8217;ll focus on how SymPy can use Theano to generate efficient code.&lt;/p&gt;

&lt;h2 id='physics'&gt;Physics&lt;/h2&gt;

&lt;p&gt;SymPy knows Physics. For example, here is the radial wavefunction corresponding to &lt;code&gt;n = 3&lt;/code&gt; and &lt;code&gt;l = 1&lt;/code&gt; for Carbon (&lt;code&gt;Z = 6&lt;/code&gt;)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from sympy.physics.hydrogen import R_nl
from sympy.abc import x
expr = R_nl(3, 1, x, 6)
print latex(expr)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$\frac{8}{3} x \left(- 4 x + 4\right) e^{- 2 x}$$&lt;/p&gt;

&lt;p&gt;SymPy is great at this. It can manipulate high level mathematical expressions very naturally. When it comes to numeric computation it is less effective.&lt;/p&gt;

&lt;h2 id='numerics'&gt;Numerics&lt;/h2&gt;

&lt;p&gt;Fortunately there are methods to offload the work to numerical projects like &lt;code&gt;numpy&lt;/code&gt; or to generate and compile straight &lt;code&gt;Fortran&lt;/code&gt; code. Here we use two existing methods to create two identical vectorized functions to compute the above expression.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from sympy.utilities.autowrap import ufuncify
from sympy.utilities.lambdify import lambdify
fn_numpy   = lambdify(x, expr, &amp;#39;numpy&amp;#39;)
fn_fortran = ufuncify([x], expr)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fn_numpy&lt;/code&gt; replaces each of the SymPy operations with the equivalent function from the popular NumPy package. &lt;code&gt;fn_fortran&lt;/code&gt; generates and compiles low-level Fortran code and uses &lt;code&gt;f2py&lt;/code&gt; to bind it to a Python function. They each use &lt;code&gt;numpy&lt;/code&gt; arrays as common data structures, supporting broad interoperability with the rest of the Scientific Python ecosystem. They both work well and produce identical results.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from numpy import linspace
&amp;gt;&amp;gt;&amp;gt; xx = linspace(0, 1, 5)
&amp;gt;&amp;gt;&amp;gt; fn_numpy(xx)
[ 0.          1.21306132  0.98101184  0.44626032  0.        ]
&amp;gt;&amp;gt;&amp;gt; fn_fortran(xx)
[ 0.          1.21306132  0.98101184  0.44626032  0.        ]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use these functions and &lt;code&gt;matplotlib&lt;/code&gt; to plot the original equation&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from pylab import plot, show, legend
xx = linspace(0, 5, 50000)
plot(xx, fn_numpy(xx))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src='http://mrocklin.github.com/blog/images/R_31.png' alt='' /&gt;&lt;/p&gt;

&lt;h2 id='performance'&gt;Performance&lt;/h2&gt;

&lt;p&gt;When we profile these functions we find that the &lt;code&gt;Fortran&lt;/code&gt; solution runs a bit faster. This is because it is able to fuse all of the scalar operations into one loop while the &lt;code&gt;numpy&lt;/code&gt; solution walks over memory several times, performing each operation individually. Jensen wrote a more thorough &lt;a href='http://ojensen.wordpress.com/2010/08/10/fast-ufunc-ish-hydrogen-solutions/'&gt;blogpost about this&lt;/a&gt; when he worked on code generation. He shows substantial performance increases as the complexity of the mathematical expression increases.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; timeit fn_numpy(xx)
1000 loops, best of 3: 1.4 ms per loop
&amp;gt;&amp;gt;&amp;gt; timeit fn_fortran(xx)
1000 loops, best of 3: 884 us per loop&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This weekend I built up a translation from SymPy expressions to Theano computations. This builds off of &lt;a href='http://github.com/nouiz/theano_sympy/'&gt;old work&lt;/a&gt; done with &lt;a href='http://github.com/nouiz'&gt;Frederic Bastien&lt;/a&gt; at SciPy2012.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from sympy.printing.theanocode import theano_function
&amp;gt;&amp;gt;&amp;gt; fn_theano  = theano_function([x], [expr], dims={x: 1}, dtypes={x: &amp;#39;float64&amp;#39;})
&amp;gt;&amp;gt;&amp;gt; timeit fn_theano(xx)
1000 loops, best of 3: 1.04 ms per loop&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Theano generates &lt;code&gt;C&lt;/code&gt; code that performs the same loop fusion done in &lt;code&gt;Fortran&lt;/code&gt; but it incurs a bit more startup time. It performs somewhere between the &lt;code&gt;numpy&lt;/code&gt; and &lt;code&gt;Fortran&lt;/code&gt; solutions.&lt;/p&gt;

&lt;p&gt;However, the &lt;code&gt;SymPy to Theano&lt;/code&gt; translation interface only takes up about a page of code while the &lt;code&gt;lambdify&lt;/code&gt; and &lt;code&gt;autowrap&lt;/code&gt; modules are substantially more complex. Additionally, Theano is actively developed and is sure to improve and track changes in hardware well into the future. &lt;code&gt;lambdify&lt;/code&gt; and &lt;code&gt;autowrap&lt;/code&gt; have been relatively untouched over the past year. For example Theano is able to seemlessly compile these computations to the GPU.&lt;/p&gt;

&lt;h2 id='leveraging_theano'&gt;Leveraging Theano&lt;/h2&gt;

&lt;p&gt;In the above example we used Theano to copy the behavior of SymPy&amp;#8217;s existing &lt;code&gt;numpy&lt;/code&gt; and &lt;code&gt;Fortran&lt;/code&gt; numeric solutions. Theano is capable of substantially more than this. To show a simple example we&amp;#8217;ll compute both our original output and the derivative simultaneously.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;outputs = expr, simplify(expr.diff(x))
print latex(outputs)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$$ \begin{pmatrix}\frac{8}{3} x \left(- 4 x + 4\right) e^{- 2 x}, &amp;amp; \frac{32}{3} \left(2 x^{2} - 4 x + 1\right) e^{- 2 x}\end{pmatrix} $$&lt;/p&gt;

&lt;p&gt;We redefine our functions to produce both outputs, instead of just &lt;code&gt;expr&lt;/code&gt; alone&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fn_numpy  = lambdify([x], outputs, &amp;#39;numpy&amp;#39;)
fn_theano = theano_function([x], outputs, dims={x: 1}, dtypes={x: &amp;#39;float64&amp;#39;})

fns_fortran = [ufuncify([x], output) for output in outputs]
fn_fortran  = lambda xx: [fn_fortran(xx) for fn_fortran in fns_fortran]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The expression and its derivative look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for y in fn_theano(xx):
    plot(xx, y)
legend([&amp;#39;$R_{31}$&amp;#39;, &amp;quot;$R&amp;#39;_{31}$&amp;quot;])&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src='http://mrocklin.github.com/blog/images/R_31_prime.png' alt='' /&gt;&lt;/p&gt;

&lt;p&gt;Because Theano handles common subexpressions well it is able to perform the extra computation with only a very slight increase in runtime, easily eclipsing either of the other two options.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; timeit fn_numpy(xx)
100 loops, best of 3: 2.85 ms per loop
&amp;gt;&amp;gt;&amp;gt; timeit fn_fortran(xx)
1000 loops, best of 3: 1.8 ms per loop
&amp;gt;&amp;gt;&amp;gt; timeit fn_theano(xx)
1000 loops, best of 3: 1.16 ms per loop&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we extend this experiment and vary the number of simultaneous derivatives we observe the following runtimes&lt;/p&gt;

&lt;p&gt;&lt;img src='http://mrocklin.github.com/blog/images/profile-theano-fortran-numpy.png' alt='' /&gt;&lt;/p&gt;

&lt;p&gt;In the case of highly structured computation Theano is able to scale very favorably.&lt;/p&gt;

&lt;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The Theano project is devoted to code generation at a level that exceeds the devotion of SymPy to this same topic. This is natural and prevalent. When we combine the good parts of both projects we often achieve a better result than with an in-house solution&lt;/p&gt;

&lt;p&gt;In-house solutions to foreign problems lack persistence. As programmers within an ecosystem we should make projects that do one thing well and provide clean interfaces and simple data structures to encourage inter-project communication.&lt;/p&gt;

&lt;h2 id='references'&gt;References&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://sympy.org/'&gt;SymPy&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://deeplearning.net/software/theano'&gt;Theano&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://ojensen.wordpress.com/2010/08/10/fast-ufunc-ish-hydrogen-solutions/'&gt;Jensen&amp;#8217;s Blogpost&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/mrocklin/sympy/tree/theano-print'&gt;Development git repository&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://mrocklin.github.com/blog/scripts/sympy_theano_printing.ipynb'&gt;IPython notebook of this work&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
                <pubDate>Tue, 19 Mar 2013 00:00:00 -0700</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/03/19/SymPy-Theano-part-1</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/03/19/SymPy-Theano-part-1</guid>
            </item>
          
        
          
            <item>
                <title>Maximum a Posteriori Estimation</title>
                <description>&lt;p&gt;&lt;em&gt;Disclaimer: I know relatively little about this application. Corrections welcome.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post we see how SymPy can simplify common numeric calculations, particularly in Bayesian inference problems.&lt;/p&gt;

&lt;p&gt;Imagine you are a scientist studying some &lt;a href='http://en.wikipedia.org/wiki/Poisson_process'&gt;counting process&lt;/a&gt; (like radioactive decay or the number of page requests on a web server). You describe this process with a &lt;a href='http://en.wikipedia.org/wiki/Poisson_distribution'&gt;Poisson random variable&lt;/a&gt; and try to learn the rate parameter of this distribution by observing some random samples.&lt;/p&gt;

&lt;p&gt;If you have no preconceptions about the rate then this problem is easy. You just divide total counts by total time and you&amp;#8217;re done.&lt;/p&gt;

&lt;p&gt;A more complex problem arises when external theory provides prior information about your rate parameter (for example physics might impose rules on the rate of radioactive decay). Lets model this problem in SymPy. For the sake of concreteness lets arbitrarily assume that $\lambda$, the rate parameter, follows a Beta distribution with parameters &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;symbols&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;a,b&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;lam&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Symbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;lambda&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;rate&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Beta&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;lam&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;count&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Poisson&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;X&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;rate&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the lab we observe many samples $x_i$ taken from &lt;code&gt;count&lt;/code&gt;. From these we wish to find the most likely value of &lt;code&gt;rate&lt;/code&gt;. The probability of any single value of &lt;code&gt;rate&lt;/code&gt; given our data can be rewritten with Bayes&amp;#8217; rule.&lt;/p&gt;

&lt;p&gt;$$ p(\lambda \vert x_i) \propto \prod_i p(x_i \vert \lambda) \cdot p(\lambda) $$&lt;/p&gt;

&lt;p&gt;In this case the distributions are given by&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;pdf&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;density&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;rate&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;  &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;pdf&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;  &lt;span class='c'&gt;# density of count, given rate&lt;/span&gt;
&lt;span class='n'&gt;pdf&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;density&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;rate&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;         &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;pdf&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;lam&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;$$ p(x_i \vert \lambda) = \frac{\lambda^{x}}{e^{\lambda} x!} \;\;\;\; p(\lambda) = \frac{\lambda^{a - 1} \left(- \lambda + 1\right)^{b - 1} \Gamma\left(a + b\right)}{\Gamma\left(a\right) \Gamma\left(b\right)}$$&lt;/p&gt;

&lt;p&gt;To find the maximizer of $p(\lambda \vert x_i)$ we set the derivative equal to zero. We simplify the computation by taking the &lt;code&gt;log&lt;/code&gt;. Because &lt;code&gt;log&lt;/code&gt; is monotonic this does not change the solution.&lt;/p&gt;

&lt;p&gt;$$ 0 = \frac{d}{d\lambda} \log\left( \prod_i p(x_i \vert \lambda) \cdot p(\lambda)\right) = \frac{d}{d\lambda} \sum_i \log(p(x_i \vert \lambda) \cdot p(\lambda)) $$&lt;/p&gt;

&lt;p&gt;We can accomplish this in SymPy with the following code&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='c'&gt;# Model `n` observations with a function `data` indexed by integer `i`&lt;/span&gt;
&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;symbols&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;i,n&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;integer&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;data&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='c'&gt;# Compute log likelihood&lt;/span&gt;
&lt;span class='n'&gt;loglikelihood&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;log&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Product&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;density&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;rate&lt;/span&gt;&lt;span class='p'&gt;)(&lt;/span&gt;&lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='n'&gt;density&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;rate&lt;/span&gt;&lt;span class='p'&gt;)(&lt;/span&gt;&lt;span class='n'&gt;lam&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
&lt;span class='n'&gt;Eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;simplify&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;loglikeihood&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;diff&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;lam&lt;/span&gt;&lt;span class='p'&gt;)),&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;$$ \sum_{i=1}^{n} \frac{a \left(\lambda - 1\right) + b \lambda - \lambda \left(\lambda - 1\right) - 2 \lambda + \left(\lambda - 1\right) \operatorname{data}{\left[i \right]} + 1}{\lambda \left(\lambda - 1\right)} = 0 $$&lt;/p&gt;

&lt;h2 id='discussion'&gt;Discussion&lt;/h2&gt;

&lt;p&gt;SymPy reduces this Bayesian inference problem to finding roots of the above equation. I suspect that many prevalent numeric problems could be similarly accelerated through a symbolic preprocessing step.&lt;/p&gt;

&lt;p&gt;Looking at the equation above it&amp;#8217;s clear that this problem can be simplified further. However I like the existing solution because it does not depend on the user possessing any mathematical expertise beyond the ability to describe their mathematical model (the derivatives, log, etc&amp;#8230; are generally applicable to this problem). In what other automated ways can SymPy further process computations like this? What are other ways that aren&amp;#8217;t in SymPy but could be developed in the future?&lt;/p&gt;

&lt;p&gt;I suspect that the problem given here is analytically solvable. To the extent possible SymPy should try to solve these problems. However for the vast number of problems without analytic solutions I suspect there is still a great deal we can do, either by reducing the problem as above or through the mathematically informed selection of numeric algorithms.&lt;/p&gt;

&lt;p&gt;Various root finding algorithms are appropriate in different cases. Wikipedia suggests &lt;a href='http://en.wikipedia.org/wiki/Householder%27s_method'&gt;Householder&amp;#8217;s Method&lt;/a&gt;, a generalization on Newton&amp;#8217;s method for scalar systems with known derivatives. Perhaps in cases where SymPy is unable to solve the problem analytically it could select the correct numeric algorithm. Is this a reasonable use case for SymPy?&lt;/p&gt;

&lt;h2 id='references'&gt;References&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://en.wikipedia.org/wiki/Maximum_a_posteriori_estimation'&gt;Maximum A Posteriori Estimation&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://en.wikipedia.org/wiki/Poisson_process'&gt;Poisson process&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://en.wikipedia.org/wiki/Householder%27s_method'&gt;Householder&amp;#8217;s Method&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
                <pubDate>Mon, 25 Feb 2013 00:00:00 -0800</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/02/25/MaximumAposteriori</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/02/25/MaximumAposteriori</guid>
            </item>
          
        
          
            <item>
                <title>Assuming assumptions</title>
                <description>&lt;p&gt;SymPy has two assumptions systems called (unimaginatively) &amp;#8220;old assumptions&amp;#8221; and &amp;#8220;new assumptions.&amp;#8221; They differ in how they manage mathematical attributes.&lt;/p&gt;

&lt;h3 id='old_assumptions'&gt;Old Assumptions&lt;/h3&gt;

&lt;p&gt;In old assumptions attributes are bound to variables&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Symbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Symbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These are then composed into expressions.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;expr&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we query these expressions directly&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;is_positive&lt;/span&gt;
&lt;span class='bp'&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The expression and the attributes are woven into the same object.&lt;/p&gt;

&lt;h3 id='new_assumptions'&gt;New Assumptions&lt;/h3&gt;

&lt;p&gt;In new assumptions variables and attributes are maintained separately.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Symbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Symbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;facts&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&lt;/span&gt; &lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The construction of mathematical expressions remains unchanged&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;expr&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But querying now requires two inputs, both the expression and the facts.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;ask&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;facts&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='bp'&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The separation of facts from expressions enables rich logical inference but it requires the management of two separate variables, &lt;code&gt;expr&lt;/code&gt; and &lt;code&gt;facts&lt;/code&gt;, rather than just one, &lt;code&gt;expr&lt;/code&gt;. It is difficult to consistently pass the extra variable through all relevant function calls.&lt;/p&gt;

&lt;h3 id='global_assumptions'&gt;Global assumptions&lt;/h3&gt;

&lt;p&gt;One solution to the management problem is to keep all facts in a globally accessible collection. This removes the need to pass an extra argument between function calls.&lt;/p&gt;

&lt;p&gt;This little known feature is already accessible in SymPy&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='c'&gt;# Setup&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;global_assumptions&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;global_assumptions&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='c'&gt;# Compute in this context&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;ask&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='bp'&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately global variables often cause confusion. We will invariably add an experimental fact to the global collection and then forget to clean up, polluting future computations. In this case we need to always remember to clean up after we&amp;#8217;re done.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='c'&gt;# Cleanup&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;global_assumptions&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;remove&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;global_assumptions&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;remove&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This cleanup step is both crucial and forgettable. We can not trust ourselves to remember it.&lt;/p&gt;

&lt;h2 id='introducing_'&gt;Introducing &lt;code&gt;assuming&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Context managers provide the convenience of global variables with side-effect free security. This is accomplished through consistent cleanup.&lt;/p&gt;

&lt;p&gt;SymPy now includes, &lt;code&gt;assuming&lt;/code&gt;, a context manager for mathematical assumptions. Here is an example&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;facts&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;with&lt;/span&gt; &lt;span class='n'&gt;assuming&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;facts&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;     &lt;span class='n'&gt;ask&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Q&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='bp'&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All &lt;code&gt;ask&lt;/code&gt; calls within this block have global-like access to the knowledge &lt;code&gt;Q.positive(x)&lt;/code&gt; and &lt;code&gt;Q.positive(y)&lt;/code&gt;. These calls may be at top level as in the example above or buried deeply within function calls. This arrangement is convenient because we do not need to pass down &lt;code&gt;facts&lt;/code&gt; through all function calls. This knowledge is pervasive like a global variable but contained within the &lt;code&gt;with assuming&lt;/code&gt; clause.&lt;/p&gt;</description>
                <pubDate>Tue, 05 Feb 2013 00:00:00 -0800</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/02/05/Assuming</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/02/05/Assuming</guid>
            </item>
          
        
          
            <item>
                <title>Commutative Unification</title>
                <description>&lt;p&gt;LogPy now supports commutative and associative pattern matching on expression trees. This is a standard requirement for computer algebra systems like SymPy but not a traditional feature of logic programming systems.&lt;/p&gt;

&lt;p&gt;Pattern-matching in LogPy is expressed by the &lt;code&gt;eq&lt;/code&gt; goal. This goal relies on unification to match trees of tuples. Unification is a computational cornerstone of LogPy. Traditionally &lt;code&gt;eq&lt;/code&gt; performs exact structural pattern matching. For example&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(1, x, (5, y, 7))  matches  (1, (2, 3, 4), (5, 6, 7))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;with the following substitution&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{x: (2, 3, 4), y: 6}&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='expression_trees'&gt;Expression Trees&lt;/h2&gt;

&lt;p&gt;We traditionally represent both mathematical expressions and computer programs with expression trees. For example \(y * (1 + x)\) can be visualized as follows&lt;/p&gt;

&lt;p&gt;&lt;img src='http://mrocklin.github.com/blog/images/arith-expr.png' alt='' /&gt;&lt;/p&gt;

&lt;p&gt;We represent this expression in LogPy with tuples. The head/first element of each tuple is an operation like &lt;code&gt;add&lt;/code&gt; or &lt;code&gt;mul&lt;/code&gt;. All subsequent elements (the tail) are the arguments/children of that expression.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;y * (x + 1) -&amp;gt; (mul, y, (add, x, 1))&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='matching_expression_trees'&gt;Matching Expression Trees&lt;/h2&gt;

&lt;p&gt;This form is exactly what we use for unification. We could match this pattern against the following expression, treating &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; as wildcard logic variables&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(mul, y, (add, x, 1))  matches  (mul, (pow, 2, 10), (add, 3, 1))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;with the following substitution&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{x: 3, y: (pow, 2, 10)}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But what about the following?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(add, x, 1)  matches?  (add, 1, 3)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This doesn&amp;#8217;t unify. While the first (&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;) and second (&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;) elements can match (if &lt;code&gt;{x: 1}&lt;/code&gt;) the third elements (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;) will not.&lt;/p&gt;

&lt;p&gt;As mathematicians however we know that because &lt;code&gt;add&lt;/code&gt; is commutative these expressions should match if we are allowed to rearrange the terms in the tail and match &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; to &lt;code&gt;3&lt;/code&gt;. LogPy doesn&amp;#8217;t know this by default. LogPy is not a math library.&lt;/p&gt;

&lt;h2 id='building_commutative_equality'&gt;Building Commutative Equality&lt;/h2&gt;

&lt;p&gt;Given the goal &lt;code&gt;seteq&lt;/code&gt; for set unification and a goal &lt;code&gt;conso&lt;/code&gt; for head-tail pattern matching we build &lt;code&gt;eq_commutative&lt;/code&gt; for commutative matching.&lt;/p&gt;

&lt;p&gt;Example of &lt;code&gt;seteq&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;run(0, x, seteq((1, 2, x), (3, 1, 2)))  # seteq matches within sets
(3,)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Example of &lt;code&gt;conso&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;run(0, head,  conso(head, tail, (1, 2, 3, 4)))
(1,)
run(0, tail,  conso(head, tail, (1, 2, 3, 4)))
((2, 3, 4),)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Given these two it is easy to build &lt;code&gt;eq_commutative&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;eq_commutative&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;u&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;v&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='n'&gt;operation&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;utail&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;vtail&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;lall&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;conso&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;operation&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;utail&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;u&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
                &lt;span class='n'&gt;conso&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;operation&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;vtail&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;v&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
                &lt;span class='n'&gt;commutative&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;operation&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
                &lt;span class='n'&gt;seteq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;utail&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;vtail&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That is we require all of the following (&lt;code&gt;lall&lt;/code&gt; is logical all).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;u&lt;/code&gt; must be of the form &lt;code&gt;(operation, utail....)&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;v&lt;/code&gt; must be of the form &lt;code&gt;(operation, vtail....)&lt;/code&gt;. Note that the same variable &lt;code&gt;operation&lt;/code&gt; must be the same in both expressions.&lt;/li&gt;

&lt;li&gt;The operation must be commutative (operations register themselves beforehand, see example below)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;utail&lt;/code&gt; and &lt;code&gt;vtail&lt;/code&gt; must unify under set equality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am glossing over some details here, like &amp;#8220;what about associative matching&amp;#8221; and &amp;#8220;how does &lt;code&gt;seteq&lt;/code&gt; work?&amp;#8221; but this should give a high-level view of how logic programs are made. Lets see an example of associative/commutative matching&lt;/p&gt;

&lt;h2 id='example'&gt;Example&lt;/h2&gt;

&lt;p&gt;This is the &lt;a href='https://github.com/logpy/logpy/blob/master/examples/commutative.py'&gt;standard example&lt;/a&gt; for commutative matching found in the &lt;a href='https://github.com/logpy/logpy'&gt;repository&lt;/a&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;fact&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy.assoccomm&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;eq_assoccomm&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;
&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy.assoccomm&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;commutative&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;associative&lt;/span&gt;

&lt;span class='c'&gt;# Define some dummy Operationss&lt;/span&gt;
&lt;span class='n'&gt;add&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;add&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;mul&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;mul&amp;#39;&lt;/span&gt;

&lt;span class='c'&gt;# Register that these ops are commutative using the facts system&lt;/span&gt;
&lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;commutative&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;mul&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;commutative&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;add&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;associative&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;mul&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;associative&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;add&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='c'&gt;# Define some wild variables&lt;/span&gt;
&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='c'&gt;# Two expressions to match&lt;/span&gt;
&lt;span class='n'&gt;pattern&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;mul&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;add&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;                &lt;span class='c'&gt;# (1 + x) * y&lt;/span&gt;
&lt;span class='n'&gt;expr&lt;/span&gt;    &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;mul&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;add&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;                &lt;span class='c'&gt;# 2 * (3 + 1)&lt;/span&gt;
&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;pattern&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;expr&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;         
&lt;span class='c'&gt;# ((3, 2),) #  meaning one result with x matches to 3 and y matches to 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;With this LogPy contains all of the functionality of SymPy&amp;#8217;s old &lt;code&gt;unify&lt;/code&gt; module but in a cleaner and much more extensible form.&lt;/p&gt;</description>
                <pubDate>Fri, 25 Jan 2013 00:00:00 -0800</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/01/25/Commutative-Unification</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/01/25/Commutative-Unification</guid>
            </item>
          
        
          
            <item>
                <title>LogPy - Facts and Relations</title>
                <description>&lt;p&gt;In &lt;a href='http://mrocklin.github.com/blog/work/2013/01/14/LogPy-Introduction/'&gt;my last post&lt;/a&gt; I introduced &lt;a href='http://github.com/logpy/logpy'&gt;LogPy&lt;/a&gt;, a library for logic and relational programming in Python. In this post I show how LogPy can be used as a quick and dirty in-memory database.&lt;/p&gt;

&lt;h2 id='data'&gt;Data&lt;/h2&gt;

&lt;p&gt;As an example we&amp;#8217;ll look at the 50 states in the US. We know two things about each state.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is it coastal? For example California (CA) is coastal because it is next to the Pacific Ocean, Arizona (AZ) is not.&lt;/li&gt;

&lt;li&gt;To which other states is it adjacent? For example California (CA) is adjacent to Oregon (OR), Arizona (AZ) and Nevada (NV).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We express data in LogPy using relations and facts&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;Relation&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;facts&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;coastal&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Relation&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;coastal&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;CA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;here we have asserted the fact that &lt;code&gt;&amp;#39;CA&amp;#39;&lt;/code&gt; is coastal. Lets quickly do this for all of the coastal states&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;coastal_states&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;WA,OR,CA,TX,LA,MS,AL,GA,FL,SC,NC,VA,MD,DE,NJ,NY,CT,RI,MA,ME,NH,AK,HI&amp;#39;&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;state&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;coastal_states&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;split&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;     &lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;coastal&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;state&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Adjacency is only slightly more complex to express. The following code asserts that California (CA) is adjacent to Arizona (AZ) and that California (CA) is adjacent to Oregon (OR).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;adjacent&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Relation&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;CA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;AZ&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;CA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;OR&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we need a list of all adjacent pairs of states. Fortunately &lt;a href='http://writeonly.wordpress.com/2009/03/20/adjacency-list-of-states-of-the-united-states-us/'&gt;someone else&lt;/a&gt; has already compiled such a list. His data looks like this&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;AK
AL,MS,TN,GA,FL
AR,MO,TN,MS,LA,TX,OK
AZ,CA,NV,UT,CO,NM
CA,OR,NV,AZ
CO,WY,NE,KS,OK,NM,AZ,UT
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each line says that the first element is adjacent to the following ones. So for example Alaska (AK) is adjacent to no states and California (CA) is adjacent to Oregon (OR), Nevada (NV) and Arizona (AZ). We can parse this file and assert the relevant facts with fairly standard Python code&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;f&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;open&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;examples/data/adjacent-states.txt&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;  &lt;span class='c'&gt;# lines like &amp;#39;CA,OR,NV,AZ&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;adjlist&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;line&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strip&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;split&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;line&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;close&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;

&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;L&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;adjlist&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;                   &lt;span class='c'&gt;# [&amp;#39;CA&amp;#39;, &amp;#39;OR&amp;#39;, &amp;#39;NV&amp;#39;, &amp;#39;AZ&amp;#39;]&lt;/span&gt;
    &lt;span class='n'&gt;head&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;tail&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;L&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt; &lt;span class='n'&gt;L&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;:]&lt;/span&gt;        &lt;span class='c'&gt;# &amp;#39;CA&amp;#39;, [&amp;#39;OR&amp;#39;, &amp;#39;NV&amp;#39;, &amp;#39;AZ&amp;#39;]&lt;/span&gt;
    &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;state&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;tail&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
        &lt;span class='n'&gt;fact&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;head&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;state&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='c'&gt;# e.g. &amp;#39;CA&amp;#39; is adjacent to &amp;#39;OR&amp;#39;,&lt;/span&gt;
                                    &lt;span class='c'&gt;#      &amp;#39;CA&amp;#39; is adjacent to &amp;#39;NV&amp;#39;, etc...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id='queries'&gt;Queries&lt;/h2&gt;

&lt;p&gt;Once have asserted the relevant facts we can run queries with the logical expressions of LogPy. Recall from the &lt;a href='http://mrocklin.github.com/blog/work/2013/01/14/LogPy-Introduction/'&gt;last post&lt;/a&gt; that we can use relations to express logical goals and use &lt;code&gt;run&lt;/code&gt; to search for cases that satisfy those goals. Here are two simple queries&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;CA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;NY&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='c'&gt;# is California adjacent to New York?&lt;/span&gt;
&lt;span class='p'&gt;()&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;CA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;    &lt;span class='c'&gt;# all states next to California&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;OR&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;NV&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;AZ&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can construct more complex queries with multiple goals. In SQL the following queries would require a &lt;code&gt;JOIN&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;  &lt;span class='c'&gt;# create second variable for complex queries&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;TX&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;    &lt;span class='c'&gt;# all coastal states next to Texas&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;                 &lt;span class='n'&gt;coastal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;LA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,)&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;coastal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;           &lt;span class='c'&gt;# five states that border a coastal state&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;                 &lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;VT&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;AL&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;WV&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;DE&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;MA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;TN&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;    &lt;span class='c'&gt;# all states adjacent to Tennessee&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;                 &lt;span class='n'&gt;adjacent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;FL&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;    &lt;span class='c'&gt;#        and adjacent to Florida&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;GA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;AL&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Facts and relations are currently indexed by default, yielding relatively fast query times.&lt;/p&gt;

&lt;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;LogPy provides a declarative interface to query complex data. Data is stored as facts/tuples and queries are expressed as logical goals. This system is expressive and can match SQL in many respects. The use of Logic programming languages for database queries has roots in &lt;a href='http://en.wikipedia.org/wiki/Datalog'&gt;Datalog&lt;/a&gt; a subset of Prolog designed for databases.&lt;/p&gt;</description>
                <pubDate>Thu, 17 Jan 2013 00:00:00 -0800</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/01/17/LogPy-Facts-Relations</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/01/17/LogPy-Facts-Relations</guid>
            </item>
          
        
          
            <item>
                <title>Introducing LogPy</title>
                <description>&lt;p&gt;&lt;a href='http://github.com/logpy/logpy'&gt;LogPy&lt;/a&gt; is a library for logic and relational programming in Python. This post contains some introductory examples.&lt;/p&gt;

&lt;h2 id='informative_examples'&gt;Informative Examples&lt;/h2&gt;

&lt;p&gt;LogPy enables the expression of relations and the search for values which satisfy them. The following code is the &amp;#8220;Hello, world!&amp;#8221; of logic programming. It asks for &lt;code&gt;1&lt;/code&gt; number, &lt;code&gt;x&lt;/code&gt;, such that &lt;code&gt;x == 5&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;membero&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;conde&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Multiple variables and multiple goals can be used simultaneously. The following code asks for a number x such that &lt;code&gt;x == z&lt;/code&gt; and &lt;code&gt;z == 3&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;z&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;z&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
              &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;z&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;LogPy uses &lt;a href='http://en.wikipedia.org/wiki/Unification_%28computer_science%29'&gt;unification&lt;/a&gt;, an advanced form of pattern matching, to match within expression trees. The following code asks for a number, x, such that &lt;code&gt;(1, 2) == (1, x)&lt;/code&gt; holds.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above examples use &lt;code&gt;eq&lt;/code&gt;, a &lt;em&gt;goal&lt;/em&gt; to state that two expressions are equal. Other goals exist. &lt;code&gt;membero(item, coll)&lt;/code&gt;, a goal, states that &lt;code&gt;item&lt;/code&gt; is a member of &lt;code&gt;coll&lt;/code&gt;, a collection.&lt;/p&gt;

&lt;p&gt;The following example uses &lt;code&gt;membero&lt;/code&gt; twice to ask for 2 values of x, such that x is a member of &lt;code&gt;(1, 2, 3)&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; that x is a member of &lt;code&gt;(2, 3, 4)&lt;/code&gt;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;membero&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;)),&lt;/span&gt;  &lt;span class='c'&gt;# x is a member of (1, 2, 3)&lt;/span&gt;
              &lt;span class='n'&gt;membero&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;  &lt;span class='c'&gt;# x is a member of (2, 3, 4)&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can write other fancier goals too. Here is a list of all prime numbers within &lt;code&gt;1..10&lt;/code&gt;. &lt;code&gt;primo&lt;/code&gt; depends on the traditional &lt;code&gt;prime&lt;/code&gt; and &lt;code&gt;isprime&lt;/code&gt; functions found in &lt;code&gt;sympy&lt;/code&gt;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy.math&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;primo&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;membero&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;6&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;7&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;8&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;9&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='mi'&gt;10&lt;/span&gt;&lt;span class='p'&gt;)),&lt;/span&gt;
              &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;primo&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;7&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Want just a few primes? Here are five numbers that satisfy the &lt;code&gt;primo&lt;/code&gt; goal&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;primo&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;7&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;11&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id='relations'&gt;Relations&lt;/h2&gt;

&lt;p&gt;We often want to state and then query data. Logic programming represents data a set of facts and represents queries with logical goals. In the following examples we assert some facts about the Simpsons family, construct queries through logical goals and then run the queries to obtain results.&lt;/p&gt;

&lt;p&gt;The following code defines a &lt;code&gt;parent&lt;/code&gt; relation and uses it to state who fathered whom.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;logpy&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;Relation&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;facts&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;parent&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Relation&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;facts&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Homer&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;Bart&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;               &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Homer&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;Lisa&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;               &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Abe&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;  &lt;span class='s'&gt;&amp;#39;Homer&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We ask some questions using the &lt;code&gt;parent&lt;/code&gt; relation as a goal constructor. Who is Bart&amp;#8217;s father?&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;Bart&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;  &lt;span class='c'&gt;# one x such that x is a parent of Bart&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Homer&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,)&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Homer&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='c'&gt;# two xs such that Homer is a parent of x&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Lisa&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;Bart&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can use intermediate variables for more complex queries. Who is Bart&amp;#8217;s grandfather?&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; 
              &lt;span class='n'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;Bart&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;  
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Abe&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can express the grandfather relationship separately. In this example we use &lt;code&gt;conde&lt;/code&gt;, a goal constructor for logical &lt;em&gt;and&lt;/em&gt; and &lt;em&gt;or&lt;/em&gt;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;grandparent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;z&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;     &lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;var&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;...&lt;/span&gt;     &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;conde&lt;/span&gt;&lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='n'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;z&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;run&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;grandparent&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;Bart&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;Abe,&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;grandparent&lt;/code&gt; demonstrates that we can construct complex relations programmatically. How would you define sibling? How about uncle or aunt? How about descendant?&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;d like to play with LogPy you can install it with pip or easy_install using&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pip install logic&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or clone it directly from github&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone git@github.com:logpy/logpy.git&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Source is available at &lt;a href='http://github.com/logpy/logpy/'&gt;http://github.com/logpy/logpy/&lt;/a&gt;, design input and contributions are much appreciated.&lt;/p&gt;

&lt;h2 id='logic_programming_in_general'&gt;Logic Programming in General&lt;/h2&gt;

&lt;p&gt;Logic and relational programming are making a comeback. They were popular in the 80s, died during the AI dark ages, and have recently begun a resurgence in the functional programming community. Logic programs write music, search databases, write numeric algorithms, and build testing frameworks. It is expressive for a wide class of problems.&lt;/p&gt;

&lt;p&gt;The design of LogPy is based off of &lt;code&gt;miniKanren&lt;/code&gt;, a simple and powerful implementation in Scheme popularized through the &lt;code&gt;core.logic&lt;/code&gt; Clojure library.&lt;/p&gt;

&lt;h2 id='references'&gt;References&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href='http://kanren.sourceforge.net/'&gt;miniKanren&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/clojure/core.logic'&gt;core.logic&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://en.wikipedia.org/wiki/Logic_programming'&gt;Wikipedia article on Logic Programming&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/clojure/core.logic/wiki/A-Core.logic-Primer'&gt;core.logic primer&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
                <pubDate>Mon, 14 Jan 2013 00:00:00 -0800</pubDate>
                <link>http://matthewrocklin.com/blog//work/2013/01/14/LogPy-Introduction</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2013/01/14/LogPy-Introduction</guid>
            </item>
          
        
          
            <item>
                <title>Statistical Simplification</title>
                <description>&lt;p&gt;&lt;a href=''&gt;Lawrence Leemis&lt;/a&gt;, a statistician at Williams and Mary, recently published &lt;a href='http://www.math.wm.edu/~leemis/chart/UDR/UDR.html'&gt;a wonderful interactive visualization&lt;/a&gt; on the reduction relationships of statistical distributions. (found via &lt;a href='http://www.johndcook.com/blog/2012/12/10/extended-distribution-chart/'&gt;John Cook&amp;#8217;s blog&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.math.wm.edu/~leemis/chart/UDR/UDR.html'&gt;&lt;img src='http://www.johndcook.com/leemis.png' alt='' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This excites me because it touches on one of my favorite topics&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How do we reusably encode expert knowledge into computational systems?&lt;/em&gt;&lt;/p&gt;

&lt;h2 id='the_big_challenge'&gt;The Big Challenge&lt;/h2&gt;

&lt;p&gt;Correct use of mathematical information can accelerate important computations by several orders of magnitude. Unfortunately the people who know the mathematics are not always the ones doing the computation. This results in substantial waste.&lt;/p&gt;

&lt;p&gt;How do we integrate expert mathematical knowledge everywhere? One solution is to collaborate more. While collaboration is generally good it doesn&amp;#8217;t scale well. As problems become more complex it is more difficult to find all of the necessary experts, especially for smaller relatively unimportant projects. Also, collaboration rarely results in reusable infrastructure. Statistical chemistry projects are rarely applicable to statistical biology problems despite their shared interest in statistics.&lt;/p&gt;

&lt;h2 id='one_solution__multistage_compilation'&gt;One Solution - Multi-Stage Compilation&lt;/h2&gt;

&lt;p&gt;We could write each expert&amp;#8217;s knowledge into a single project and then connect many such projects into a multi-stage compiler. At each each stage we simplify the expression with the knowledge relevant at that stage. We must create a transformation between each pair of connecting stages. Ideally the conceptual distance between connected stages is small and so these transformations are easy.&lt;/p&gt;

&lt;p&gt;This isn&amp;#8217;t clearly the right solution. It is difficult to chain many small projects together and end up with efficient code. You need to find the right sequence of intermediate layers that are able to communicate mathematical information down to the lowest-level of computational code.&lt;/p&gt;

&lt;h2 id='relevance_to_sympystats'&gt;Relevance to SymPy.stats&lt;/h2&gt;

&lt;p&gt;SymPy.stats endeavors to be a transformation in such a toolchain. It converts stochastic expressions into integral expressions.&lt;/p&gt;

&lt;p&gt;The surrounding infrastructure looks like this&lt;/p&gt;

&lt;p&gt;&lt;img src='http://mrocklin.github.com/blog/images/stats-simp.png' alt='' /&gt;&lt;/p&gt;

&lt;p&gt;When SymPy expressions are imbued with random variables they form stochastic expressions. Sympy.stats transforms these into integral expressions which are then again converted through a variety of methods, either numeric (like Monte Carlo) or again symbolic.&lt;/p&gt;

&lt;p&gt;Each stage within this pipeline presents us with the opportunity to simplify the expression with knowledge relevant to that stage. For example at the input and output SymPy Expr layers we make algebraic and trigonometric simplifications like the following&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;X + X -&amp;gt; 2*X
sin(x)**2 + cos(x)**2 -&amp;gt; 1 &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At the integration stage we might separate multivariate integrals if possible or use integration by parts.&lt;/p&gt;

&lt;p&gt;Notice that there is no such simplification self-loop at the &lt;code&gt;Stochastic Expr&lt;/code&gt; node. This is where the information in Leemis&amp;#8217; chart would fit.&lt;/p&gt;

&lt;h3 id='a_failing_of_sympystats'&gt;A Failing of sympy.stats&lt;/h3&gt;

&lt;p&gt;Currently sympy.stats does not simplify stochastic expressions with expert knowledge; it converts directly from stochastic expressions to integral expressions without first applying known simplifications like what is encoded in Leemis&amp;#8217; chart. This causes some fairly embarassing failures&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;In&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;]:&lt;/span&gt; &lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;sympy.stats&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;

&lt;span class='n'&gt;In&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;]:&lt;/span&gt; &lt;span class='n'&gt;X&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Normal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;X&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;  &lt;span class='c'&gt;# A standard normal random variable&lt;/span&gt;

&lt;span class='n'&gt;In&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;]:&lt;/span&gt; &lt;span class='n'&gt;density&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;X&lt;/span&gt;&lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;  
&lt;span class='n'&gt;Out&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;]:&lt;/span&gt; 
&lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;failure&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='n'&gt;unevaluated&lt;/span&gt; &lt;span class='n'&gt;integral&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Any statistician could tell you that the expression &lt;code&gt;X**2&lt;/code&gt; has a Chi Squared distribution which has a simple and well understood density. This relation is commonly known and commonly occurs in practice.&lt;/p&gt;

&lt;p&gt;Because sympy.stats doesn&amp;#8217;t know this it blindly takes the expression &lt;code&gt;density(X**2)&lt;/code&gt; and converts it directly into an integral. The resulting integral is difficult and stumps the integration routines.* In this case knowing basic statistics would have turned an impossible problem into a trivial one.&lt;/p&gt;

&lt;h3 id='future_work'&gt;Future work&lt;/h3&gt;

&lt;p&gt;We should encode relations on distributions into SymPy. The knowledge in Leemis&amp;#8217;s chart could be written down as a knowledgebase of known transformations. Transformations like the following could solve our immediate problem.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;Normal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;StandardNormal&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;span class='n'&gt;StandardNormal&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt; &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;ChiSquared&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;StandardNormal&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;ChiSquared&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;ChiSquared&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each stage in the compilation pipeline presents us with an opportunity to apply expert knowledge. The &lt;code&gt;Stochastic Expr&lt;/code&gt; stage is such an opportunity of which we are not currently taking advantage.&lt;/p&gt;

&lt;p&gt;Leemis&amp;#8217;s chart is written declaratively, highlighting which logical transformations are possible under which conditions. The new modules on &lt;a href='http://mrocklin.github.com/blog/work/2012/11/01/Unification/'&gt;unification&lt;/a&gt; and &lt;a href='http://mrocklin.github.com/blog/work/2012/11/07/Strategies/'&gt;strategies&lt;/a&gt; should provide all of the necessary infrastructure to translate Leemis&amp;#8217; chart to functioning code. Writing a minimal simpliication scheme for the above problem might be as simple as&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='c'&gt;#    rewriterule(from-pattern, to-pattern, wilds)&lt;/span&gt;
&lt;span class='n'&gt;p1&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;rewriterule&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Normal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;StandardNormal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;wilds&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,))&lt;/span&gt;
&lt;span class='n'&gt;p2&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;rewriterule&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;StandardNormal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;ChiSquared&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;wilds&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,))&lt;/span&gt;
&lt;span class='n'&gt;p3&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;rewriterule&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;StandardNormal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;ChiSquared&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; 
                 &lt;span class='n'&gt;ChiSquared&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;wilds&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;

&lt;span class='n'&gt;statsimp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;exhaust&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;bottom_up&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;multiplex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;p1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;p2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;p3&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If anyone is interested in this I&amp;#8217;d be happy to help out. This is the sort of project that really excites me but that I can&amp;#8217;t currently justify time-wise.&lt;/p&gt;</description>
                <pubDate>Tue, 11 Dec 2012 00:00:00 -0800</pubDate>
                <link>http://matthewrocklin.com/blog//work/2012/12/11/Statistical-Simplification</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2012/12/11/Statistical-Simplification</guid>
            </item>
          
        
          
            <item>
                <title>Characteristic Functions</title>
                <description>&lt;p&gt;In a recent post, &lt;a href='http://jpktd.blogspot.com/2012/12/characteristic-functions-and-scipystats.html'&gt;Characteristic Functions and scipy.stats&lt;/a&gt;, &lt;a href='https://github.com/josef-pkt'&gt;Josef Perktold&lt;/a&gt; created functions for the &lt;a href='http://en.wikipedia.org/wiki/Characteristic_function'&gt;characteristic functions&lt;/a&gt; of the &lt;a href='http://en.wikipedia.org/wiki/Normal_distribution'&gt;Normal&lt;/a&gt; (easy) and &lt;a href='http://en.wikipedia.org/wiki/Student%27s_t-distribution'&gt;t&lt;/a&gt; (hard) distributions. The t-distribution is challenging because the solution involves special functions and has numerically challenging behavior around 0 for high degrees of freedom. Some quotes&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The characteristic function for the normal distribution is easy, but looking at the characteristic function of the t-distribution, I wish someone had translated it into code already&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Since I haven&amp;#8217;t seen it yet, I sat down and tried it myself. I managed to code the characteristic function of the t-distribution, but it returns NaNs when it is evaluated close to zero for large df. I didn&amp;#8217;t find a Bessel &amp;#8220;k&amp;#8221; function that works in this case&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;He then includes his code and discusses a particular application of the characteristic function which I won&amp;#8217;t discuss here.&lt;/p&gt;

&lt;h2 id='symbolic_solution'&gt;Symbolic Solution&lt;/h2&gt;

&lt;p&gt;Josef wished that this code had been written already. Characteristic functions aren&amp;#8217;t built into SymPy but we may be able to derive them automatically.&lt;/p&gt;

&lt;p&gt;Wikipedia says that the characteristic function \(\phi(t)\) of a random variable &lt;code&gt;X&lt;/code&gt; is defined as follows&lt;/p&gt;

&lt;p&gt;$$ \phi_X(t) = E(e^{itX}) $$&lt;/p&gt;

&lt;p&gt;It equal to the expectation of &lt;code&gt;exp(i*t*X)&lt;/code&gt;. Lets do this in SymPy&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from sympy.stats import *
&amp;gt;&amp;gt;&amp;gt; mu = Symbol(&amp;#39;mu&amp;#39;, bounded=True)
&amp;gt;&amp;gt;&amp;gt; sigma = Symbol(&amp;#39;sigma&amp;#39;, positive=True, bounded=True)
&amp;gt;&amp;gt;&amp;gt; t = Symbol(&amp;#39;t&amp;#39;, positive=True)

&amp;gt;&amp;gt;&amp;gt; X = Normal(&amp;#39;X&amp;#39;, mu, sigma)  # Normal random variable
&amp;gt;&amp;gt;&amp;gt; simplify(E(exp(I*t*X)))     # Expectation of exp(I*t*X)
              2  2
             σ ⋅t 
     ⅈ⋅μ⋅t - ─────
               2  
   ℯ             &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I was actually pretty surprised that this worked as smoothly as it did. SymPy stats wasn&amp;#8217;t designed for this.&lt;/p&gt;

&lt;p&gt;Here are some gists for the &lt;a href='https://gist.github.com/4186685'&gt;Cauchy&lt;/a&gt; and &lt;a href='https://gist.github.com/4186709'&gt;Student-T&lt;/a&gt; distributions. Cauchy simplifies down pretty well but the Student-T characteristic function has a few special functions included.&lt;/p&gt;

&lt;h2 id='behavior_near_zero'&gt;Behavior near zero&lt;/h2&gt;

&lt;p&gt;Josef says that the behavior of the characteristic function of the t distribution near zero for high degrees of freedom (the nu parameter) is challenging to compute numerically. Can SymPy handle this symbolically?&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;nu&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Symbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;nu&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;integer&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;t&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Symbol&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;t&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;positive&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='bp'&gt;True&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;X&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;StudentT&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;X&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;nu&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;simplify&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;E&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;exp&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;I&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;X&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src='http://goo.gl/a6xcw' alt='' /&gt;&lt;/p&gt;

&lt;p&gt;The bold scripted I&amp;#8217;s are besseli functions. We restrict this expression to a specific number of degrees of freedom, setting &lt;code&gt;nu = 50&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; simplify(E(exp(I*t*X))).subs(nu, 50)  # replace nu with 50
         ⎛         ___  ⎞            ⎛        ___  ⎞
∞⋅besseli⎝-25, 5⋅╲╱ 2 ⋅t⎠ - ∞⋅besseli⎝25, 5⋅╲╱ 2 ⋅t⎠&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whoops, simple substitution at that number of degrees of freedom fails, giving us infinities. What if we build the expression with &lt;code&gt;50&lt;/code&gt; from the beginning? This gives the integration routines more information when they compute the expectation.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; X = StudentT(&amp;#39;X&amp;#39;, 50)
&amp;gt;&amp;gt;&amp;gt; simplify(E(exp(I*t*X)))
        ⎛              │     2  -ⅈ⋅π⎞           ⎛              │     2  ⅈ⋅π⎞
╭─╮3, 1 ⎜   1/2        │ 25⋅t ⋅ℯ    ⎟   ╭─╮3, 1 ⎜   1/2        │ 25⋅t ⋅ℯ   ⎟
│╶┐     ⎜              │ ───────────⎟ + │╶┐     ⎜              │ ──────────⎟
╰─╯1, 3 ⎝25, 0, 1/2    │      2     ⎠   ╰─╯1, 3 ⎝25, 0, 1/2    │     2     ⎠
────────────────────────────────────────────────────────────────────────────
                        1240896803466478878720000⋅π                         &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The solution is in terms of &lt;a href='http://en.wikipedia.org/wiki/Meijer-G'&gt;Meijer-G&lt;/a&gt; functions. Can we evaluate this close to &lt;code&gt;t = 0&lt;/code&gt;?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; simplify(E(exp(I*t*X))).subs(t, 1e-6).evalf()
0.999999999999479 + 1.56564942264937e-29⋅ⅈ

&amp;gt;&amp;gt;&amp;gt; simplify(E(exp(I*t*X))).subs(t, 1e-30).evalf()  
1.0 - 1.2950748484704e-53⋅ⅈ&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is where scipy&amp;#8217;s special functions failed in Josef&amp;#8217;s post, yielding infinity instead of 1.&lt;/p&gt;

&lt;p&gt;And finally we plot the behavior around 0.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; plot(re(simplify(E(exp(I*t*X)))), (t, 1e-7, 1e-1))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src='http://mrocklin.github.com/blog/images/student-t-characteristic-near-zero.png' alt='' /&gt;&lt;/p&gt;

&lt;h2 id='closing_notes'&gt;Closing Notes&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;sympy.stats&lt;/code&gt; module was not designed with characteristic functions in mind. I was pleasantly surprised when I entered code almost identical to the mathematical definition&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;X = Normal(&amp;#39;X&amp;#39;, mu, sigma)
E(exp(I*t*X))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and received the correct answer. I am always happy when projects work on problems for which they were not originally designed. The fact that this works is largely due to SymPy&amp;#8217;s excellent handling of integrals of special functions, due largely to &lt;a href='https://github.com/ness01'&gt;Tom Bachmann&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you do complex work on statistical functions I recommend you take a look at &lt;code&gt;sympy.stats&lt;/code&gt;. It&amp;#8217;s able to perform some interesting high level transformations. Thanks to recent work by &lt;a href='https://github.com/raoulb'&gt;Raoul Bourquin&lt;/a&gt; many of the common distributions found in &lt;code&gt;scipy.stats&lt;/code&gt; are now available (with even more in a &lt;a href='https://github.com/sympy/sympy/pull/1413'&gt;pull request&lt;/a&gt;).&lt;/p&gt;</description>
                <pubDate>Mon, 03 Dec 2012 00:00:00 -0800</pubDate>
                <link>http://matthewrocklin.com/blog//work/2012/12/03/Characteristic-Functions</link>
                <guid isPermaLink="true">http://matthewrocklin.com/blog//work/2012/12/03/Characteristic-Functions</guid>
            </item>
          
        
    </channel>
</rss>
