blog.angusgriffith.comhttps://blog.angusgriffith.com/2015-10-26T13:40:00+11:00Pontryagin duality2015-10-26T13:40:00+11:00Angus Griffithtag:blog.angusgriffith.com,2015-10-26:posts/2015/10/pontryagin-duality/<div class="section" id="topological-groups"> <h2>Topological groups</h2> <p>A topological group is what one might expect from the name, a group $G$ equipped with a topology. We ask that the topology is nice with respect to the group structure. Namely, we require that the binary operation on the group $G \times G \to G$, and the inverse $G \to G$ are continuous.</p> <p>One simple group is the circle group $\mathbb{T} = \{z \in \mathbb{C} : |z| &lt; 1\}$ equipped with multiplication. To make this a topological group this group can be equipped with the standard topology coming from $\mathbb{C}$. Complex multiplication and inverses are clearly continuous on $\mathbb{T}$. As we will soon see, this group turns out play a central role in Pontryagin duality.</p> <p>The next step is to define dual groups and state the Pontryagin duality theorem but first we define locally compact (abelian) groups.</p> </div> <div class="section" id="locally-compact-groups"> <h2>Locally compact groups</h2> <p>A topological group $G$ is called locally compact if and only if there is a compact neighbourhood containing the identity. That is, if there exists some open set $U \ni e$ whose closure is compact in the topology of $G$.</p> <p>For example, the circle group $\mathbb{T}$ is locally compact. Simply take $U = B_\epsilon(1) \cap \mathbb{T}$ for small $\epsilon &gt; 0$ such that $\bar{U}$ is just some closed connected piece of the circle.</p> <p>There are many more examples such as; $\mathbb{R}^n$ with addition and standard topology, and any finite abelian group equipped with the discrete topology.</p> </div> <div class="section" id="dual-group"> <h2>Dual group</h2> <p>The dual of a group is analogous to the dual of a vector space but there are some subtle differences.</p> <p>If $G$ is a locally compact abelian group then consider the set of continuous group homomorphisms $f : G \to \mathbb{T}$. Such functions are called characters of the group $G$ and collectively form a locally compact abelian group, called the dual group $G^\wedge$.</p> <p>For a finite dimensional vector space $V$ over a field $\mathbb{K}$ we usually define the dual space as $Hom(V, \mathbb{K})$. Likewise, for a locally compact abelian group the dual group is $Hom(G, \mathbb{T})$.</p> <p>For example, the integers with addition $(\mathbb{Z}, +)$ is isomorphic to the dual of the circle group $(\mathbb{T}, \cdot)$. Typically one proves this by showing that characters on $\mathbb{T}$ are of the form $z \mapsto z^n$ for some $n \in \mathbb{Z}$.</p> </div> <div class="section" id="pontryagin-duality-theorem"> <h2>Pontryagin duality theorem</h2> <p>The dual of $G^\wedge$ is canonically isomorphic to $G$.</p> <p>Canonical means that there is a natural isomorphism from $\phi: G \to (G^\wedge)^\wedge$. That is, $\phi(x) = \{\chi \mapsto \chi(x)\}$ for all $x \in G$, $\chi \in G^\wedge$.</p> </div> <script type= "text/javascript"> if (!document.getElementById('mathjaxscript_pelican')) { var s = document.createElement('script'); s.id = 'mathjaxscript_pelican'; s.type = 'text/javascript'; s.src = 'https:' == document.location.protocol ? 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' : 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'; s[(window.opera ? "innerHTML" : "text")] = "MathJax.Hub.Config({" + " config: ['MMLorHTML.js']," + " TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'AMS' } }," + " jax: ['input/TeX','input/MathML','output/HTML-CSS']," + " extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," + " displayAlign: 'center'," + " displayIndent: '0em'," + " showMathMenu: true," + " tex2jax: { " + " inlineMath: [ ['$','$'] ], " + " displayMath: [ ['$$','$$'] ]," + " processEscapes: true," + " preview: 'TeX'," + " }, " + " 'HTML-CSS': { " + " styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'black ! important'} }" + " } " + "}); "; (document.body || document.getElementsByTagName('head')).appendChild(s); } </script> Equivalent definitions for $BMO$2014-02-25T11:15:00+11:00Angus Griffithtag:blog.angusgriffith.com,2014-02-25:posts/2014/02/equivalent-definitions-for-bmo/<p>The space of functions of bounded mean oscillation $BMO$ is defined by the BMO norm \begin{equation} \label{norm} ||f||_{BMO} = \sup_{\text{cubes }Q} \frac{1}{|Q|} \int_Q |u(y) - u_Q| dy \end{equation}</p> <p>But an equivalent definition is to take the sup over balls instead of cubes. Previously I wondered what other shapes gave an equivalent norm.</p> <p><strong>Proposition:</strong> <em>Suppose $D \subset R^n$ is a open set such that there exists $0 &lt; r_1 &lt; r_2 &lt; \infty$ such that $$B(0, r_1) \subset D \subset B(0, r_2)$$ then the norm given by $$||f||_D := \sup_{E \in A_D} \frac{1}{|E|} \int_E |f(y) - f_E| dy$$ is equivalent to the BMO norm. The set $A_D$ is $D$ under any uniform scaling, rotations transtions or composition thereof.</em></p> <p>I have not yet proven this, but I think it should be possible by adapting ideas from Stein's Harmonic Analysis.</p> <script type= "text/javascript"> if (!document.getElementById('mathjaxscript_pelican')) { var s = document.createElement('script'); s.id = 'mathjaxscript_pelican'; s.type = 'text/javascript'; s.src = 'https:' == document.location.protocol ? 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' : 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'; s[(window.opera ? "innerHTML" : "text")] = "MathJax.Hub.Config({" + " config: ['MMLorHTML.js']," + " TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'AMS' } }," + " jax: ['input/TeX','input/MathML','output/HTML-CSS']," + " extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," + " displayAlign: 'center'," + " displayIndent: '0em'," + " showMathMenu: true," + " tex2jax: { " + " inlineMath: [ ['$','$'] ], " + " displayMath: [ ['$$','$$'] ]," + " processEscapes: true," + " preview: 'TeX'," + " }, " + " 'HTML-CSS': { " + " styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'black ! important'} }" + " } " + "}); "; (document.body || document.getElementsByTagName('head')).appendChild(s); } </script> The space $BMO$2014-02-21T11:31:00+11:00Angus Griffithtag:blog.angusgriffith.com,2014-02-21:posts/2014/02/the-space-bmo/<div class="section" id="introducing-bmo"> <h2>Introducing $BMO$</h2> <p>The space of functions of bounded mean oscillation or $BMO$ arises when studying the space of functions whos deviation from the mean over cubes is bounded. In ways $BMO$ is similar to $L^\infty$, and it is often used as a replacement, however functions in $BMO$ may be unbounded. The classic example of this is $\log(x)$.</p> <p>The space $BMO$ naturally arises in other situations too such as when studying singular integral operators, \begin{equation} f(x) \mapsto \int k(x,y) f(y)\, dy. \end{equation} These operators map $L^\infty$ to $BMO$.</p> <p>For a complex-valued locally integrable function on $\mathbb{R}^n$ we define $$||f||_{BMO} = \sup_Q \frac{1}{|Q|} \int_Q |f(x) - \text{Avg}_Q f| dx,$$ where the supremium is taken over all cubes $Q \subset \mathbb{R}^n$. This defines a norm when we take an equivalance class of functions that differ a.e. by a constant. We denote $BMO = \Big\lbrace f : \mathbb{R}^n \to \mathbb{C} \Big| ||f||_{BMO} &lt; \infty \Big\rbrace$. In fact, $BMO$ is a Banach space that contains $L^\infty$.</p> <p>Our definition for $BMO$ used cubes, but the definition using balls instead is equivalent. <strong>Question:</strong> What other shapes could we use? How about $L^p$ balls for $1 \le p \le \infty$?</p> </div> <script type= "text/javascript"> if (!document.getElementById('mathjaxscript_pelican')) { var s = document.createElement('script'); s.id = 'mathjaxscript_pelican'; s.type = 'text/javascript'; s.src = 'https:' == document.location.protocol ? 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' : 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'; s[(window.opera ? "innerHTML" : "text")] = "MathJax.Hub.Config({" + " config: ['MMLorHTML.js']," + " TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'AMS' } }," + " jax: ['input/TeX','input/MathML','output/HTML-CSS']," + " extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," + " displayAlign: 'center'," + " displayIndent: '0em'," + " showMathMenu: true," + " tex2jax: { " + " inlineMath: [ ['$','$'] ], " + " displayMath: [ ['$$','$$'] ]," + " processEscapes: true," + " preview: 'TeX'," + " }, " + " 'HTML-CSS': { " + " styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'black ! important'} }" + " } " + "}); "; (document.body || document.getElementsByTagName('head')).appendChild(s); } </script> GMPY_CFFI mpz speed2014-01-01T17:08:00+11:00Angus Griffithtag:blog.angusgriffith.com,2014-01-01:posts/2014/01/gmpy_cffi-mpz-speed/<div class="section" id="gmpy-cffi-is-slow"> <h2>gmpy_cffi is slow</h2> <p>Today I released version 0.1 of <a class="reference external" href="https://github.com/sn6uv/gmpy_cffi">gmpy_cffi</a>, a PyPy compatible implementation of <a class="reference external" href="https://github.com/sn6uv/gmpy_cffi">gmpy</a>. The problem is that my implementation is quite a bit slower.</p> <img alt="gmpy_mpz.png" src="/images/gmpy_mpz.png" style="width: 100%;" /> <p>As you can see, the time taken to initialize an mpz instance is about 10x slower under gmpy_cffi when compared to gmpy.</p> </div> <div class="section" id="explanation"> <h2>Explanation</h2> <p>The gmpy mpz initialisation code uses the CPython internals to access the raw bits storing the value of a python integer (or long). In comparison, gmpy_cffi converts the number to a hex string and then uses <cite>mpz_set_str</cite> with base 16 to set the GMP mpz value</p> <div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">_pyint_to_mpz</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">a</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Set a from n.</span> <span class="sd"> :type n: int,long</span> <span class="sd"> :type a: mpz_t</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">if</span> <span class="o">-</span><span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">&lt;=</span> <span class="n">n</span> <span class="o">&lt;=</span> <span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span><span class="p">:</span> <span class="n">gmp</span><span class="o">.</span><span class="n">mpz_set_si</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="k">elif</span> <span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">&lt;=</span> <span class="n">MAX_UI</span><span class="p">:</span> <span class="n">gmp</span><span class="o">.</span><span class="n">mpz_set_ui</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">gmp</span><span class="o">.</span><span class="n">mpz_set_str</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="nb">hex</span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">&#39;L&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;UTF-8&#39;</span><span class="p">),</span> <span class="mi">0</span><span class="p">)</span> </pre></div> <p>I've tried other methods such as using bit twiddling to break the python int into an array of C ints and then using mpz_import, but it was slower than using hex</p> <div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">_pyint_to_mpz</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">a</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Set a from n.</span> <span class="sd"> :type n: int,long</span> <span class="sd"> :type a: mpz_t</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="n">neg</span> <span class="o">=</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="n">n</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="s1">&#39;L&#39;</span><span class="p">)</span> <span class="n">size</span> <span class="o">=</span> <span class="n">tmp</span><span class="o">.</span><span class="n">itemsize</span> <span class="n">numb</span> <span class="o">=</span> <span class="p">(</span><span class="mi">8</span> <span class="o">*</span> <span class="n">size</span><span class="p">)</span> <span class="n">mask</span> <span class="o">=</span> <span class="o">~</span><span class="p">(</span><span class="o">~</span><span class="mi">0</span> <span class="o">&lt;&lt;</span> <span class="n">numb</span><span class="p">)</span> <span class="k">while</span> <span class="n">n</span><span class="p">:</span> <span class="n">v</span> <span class="o">=</span> <span class="n">n</span> <span class="o">&amp;</span> <span class="n">mask</span> <span class="n">n</span> <span class="o">=</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">numb</span> <span class="n">tmp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="n">addr</span><span class="p">,</span> <span class="n">count</span> <span class="o">=</span> <span class="n">tmp</span><span class="o">.</span><span class="n">buffer_info</span><span class="p">()</span> <span class="n">gmp</span><span class="o">.</span><span class="n">mpz_import</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ffi</span><span class="o">.</span><span class="n">cast</span><span class="p">(</span><span class="s1">&#39;void *&#39;</span><span class="p">,</span> <span class="n">addr</span><span class="p">))</span> <span class="k">if</span> <span class="n">neg</span><span class="p">:</span> <span class="n">gmp</span><span class="o">.</span><span class="n">mpz_neg</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> </pre></div> </div> <div class="section" id="conclusion"> <h2>Conclusion</h2> <p>The conversion from python long to gmp mpz is by far the main reason why initializing mpzs in gmpy_cffi is so slow, but there isn't really an obvious way to improve on this.</p> <p>Perhaps cffi could provide a fast method for converting python longs to an array of C ints, but I doubt there's a huge demand for that right now.</p> <p>We're within a factor of 10 of evil low level C hackery. For now that will have to do.</p> </div> Scoping in Python 32013-11-25T16:24:00+11:00Angus Griffithtag:blog.angusgriffith.com,2013-11-25:posts/2013/11/scoping-in-python-3/<div class="section" id="introduction"> <h2>Introduction</h2> <p>Recently I was working on porting my Python2 library <a class="reference external" href="https://github.com/sn6uv/gmpy_cffi">gmpy_cffi</a> to work under Python3 as well. I'm using <a class="reference external" href="http://pytest.org">py.test</a> to organise and run my tests. Each test module is in it's own class, and so we have code that looks something like this</p> <div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">pytest</span> <span class="kn">from</span> <span class="nn">gmpy_cffi</span> <span class="kn">import</span> <span class="n">mpq</span> <span class="k">class</span> <span class="nc">TestMPQ</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="n">ints</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="o">-</span><span class="mi">123</span><span class="p">,</span> <span class="mi">456</span><span class="p">,</span> <span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span><span class="p">,</span> <span class="o">-</span><span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span><span class="p">]</span> <span class="n">pairs</span> <span class="o">=</span> <span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ints</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">ints</span><span class="p">]</span> <span class="nd">@pytest.mark.parametrize</span><span class="p">((</span><span class="s1">&#39;n&#39;</span><span class="p">,</span> <span class="s1">&#39;d&#39;</span><span class="p">),</span> <span class="n">pairs</span><span class="p">)</span> <span class="k">def</span> <span class="nf">test_int</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span> <span class="nb">int</span><span class="p">(</span><span class="n">mpq</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">d</span><span class="p">))</span> <span class="o">==</span> <span class="n">n</span> <span class="o">//</span> <span class="n">d</span> <span class="kn">import</span> <span class="nn">pytest</span> <span class="kn">import</span> <span class="nn">sys</span> </pre></div> <p>Under Python2 this code behaves like you might expect, but under Python 3 we get the following traceback</p> <pre class="literal-block"> Traceback (most recent call last): File &quot;tests/test_example.py&quot;, line 6, in &lt;module&gt; class TestMPQ(object): File &quot;tests/test_example.py&quot;, line 8, in TestMPQ pairs = [(i, j) for i in ints for j in ints] File &quot;tests/test_example.py&quot;, line 8, in &lt;listcomp&gt; pairs = [(i, j) for i in ints for j in ints] NameError: global name 'ints' is not defined </pre> <p>But I defined ints just there! Even more strange, I made this minimal example:</p> <div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">A</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="n">integers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="n">singles</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">integers</span><span class="p">]</span> <span class="k">class</span> <span class="nc">B</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="n">integers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="n">pairs</span> <span class="o">=</span> <span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">integers</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">integers</span><span class="p">]</span> </pre></div> <p>Under Python2 this works fine, but under Python3 you get the same traceback as above but only for class B and not for class A. I looked up the Python3 documentation, <a class="reference external" href="http://docs.python.org/3.0/whatsnew/3.0.html">what's new in Python 3.0</a>, but all I found was</p> <blockquote> list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a list() constructor, and in particular the loop control variables are no longer leaked into the surrounding scope.</blockquote> <p>In Python 3 the iteration variables (<cite>i</cite> and <cite>j</cite> in the example) no longer leak out of the list comprehenion.</p> <div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="n">ints</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)]</span> </pre></div> <p>Under Python 2 we can access the iteration variable as a class variable</p> <blockquote> <pre class="doctest-block"> &gt;&gt;&gt; C().i 9 </pre> </blockquote> <p>but under Python 3:</p> <blockquote> <pre class="doctest-block"> &gt;&gt;&gt; C().i Traceback (most recent call last): File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt; AttributeError: 'C' object has no attribute 'i' </pre> </blockquote> <p>This isn't quite the same issue as we're trying to solve, but's it is related. I asked on <a class="reference external" href="http://stackoverflow.com/q/20136955/606640">stack overflow</a> if someone could explain my example. The first comments I recieved were &quot;Are you sure?&quot;, and that I should submit a bug against the implementation. I recieved an answer not soon after. The <a class="reference external" href="http://stackoverflow.com/a/20137069/606640">answer</a> by user Blckknght is excellent and worth a read, but to summarise:</p> <ul class="simple"> <li>List comprehensions were changed to prevent this leaking of iteration variables into the surrounding scope.</li> <li>They are now implemented with a function that is called to produce the lists.</li> </ul> <p>Just as class methods can't access class variables directly (you have to access them through <cite>self</cite>), these list comprehension functions also can't access the class variables. If the list comprehension isn't nested (as in class A), then it's okay because the list comprehension function is called with the class variable <cite>ints</cite> as an argument. When we nest list comprehensions however the body of the outer list comprehension, within which the inner list comprehension is called, doesn't know about the class variable <cite>ints</cite> and hence our NameError.</p> <p>The answer by Blckknght goes on in detail disasembling the python bytecode to show how exactly how this happens and is well worth a read. The change to prevent leaking scope make sense, and I think it's a good idea. You just have to remember that in Python 3 list comprehensions are functions, and in both Python 2 and 3 class scopes can be a little bit strange.</p> </div> Static site generation with pelican2013-11-21T16:24:00+11:00Angus Griffithtag:blog.angusgriffith.com,2013-11-21:posts/2013/11/static-site-generation-with-pelican/<div class="section" id="introduction"> <h2>Introduction</h2> <p>I'd like to start by talking about <a class="reference external" href="http://docs.getpelican.com/">pelican</a>, a neat python based static site generator. Pelican allows you to generate static content (HTML and CSS) from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> (RST) files.</p> </div> <div class="section" id="installing-pelican"> <h2>Installing Pelican</h2> <p>You can install pelican with pip:</p> <div class="highlight"><pre><span></span>$pip install pelican </pre></div> <p>The code is on <a class="reference external" href="https://github.com/getpelican/pelican/">github</a> if you're curious.</p> </div> <div class="section" id="creating-a-blog"> <h2>Creating a blog</h2> <p>Let's begin by creating a new directory</p> <div class="highlight"><pre><span></span>$ mkdir blog $<span class="nb">cd</span> blog/ </pre></div> <p>From here we need to add some config files so pelican knows how to generate the site. We can do this manually, but pelican includes this useful tool</p> <div class="highlight"><pre><span></span>$ pelican-quickstart </pre></div> <p>It will then ask you a series of questions, like where you want the website to be created:</p> <pre class="literal-block"> Welcome to pelican-quickstart v3.3.0. This script will help you create a new Pelican-based website. Please answer the following questions so this script can generate the files needed by Pelican. &gt; Where do you want to create your new web site? [.] &gt; What will be the title of this web site? my blog &gt; Who will be the author of this web site? me &gt; What will be the default language of this web site? [en] &gt; Do you want to specify a URL prefix? e.g., http://example.com (Y/n) n &gt; Do you want to enable article pagination? (Y/n) n &gt; Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n) &gt; Do you want an auto-reload &amp; simpleHTTP script to assist with theme and site development? (Y/n) &gt; Do you want to upload your website using FTP? (y/N) &gt; Do you want to upload your website using SSH? (y/N) &gt; Do you want to upload your website using Dropbox? (y/N) &gt; Do you want to upload your website using S3? (y/N) &gt; Do you want to upload your website using Rackspace Cloud Files? (y/N) Done. Your new project is available at /home/angus/blog </pre> <p>Lets test our new blog!</p> <div class="highlight"><pre><span></span>$fab build$ fab serve </pre></div> <p>and point your browser at <a class="reference external" href="http://localhost:8000/">http://localhost:8000/</a>.</p> <img alt="myblog.png" src="/images/myblog.png" style="width: 100%;" /> <p>Sucess!</p> <p>Tip: If <cite>python</cite> refers to Python 3 on your system you'll have to edit <cite>fabfile.py</cite> and the <cite>Makefile</cite> accordingly. E.g. Change</p> <div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">serve</span><span class="p">():</span> <span class="n">local</span><span class="p">(</span><span class="s1">&#39;cd {deploy_path} &amp;&amp; python -m SimpleHTTPServer&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">env</span><span class="p">))</span> </pre></div> <p>to either</p> <div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">serve</span><span class="p">():</span> <span class="n">local</span><span class="p">(</span><span class="s1">&#39;cd {deploy_path} &amp;&amp; python2 -m SimpleHTTPServer&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">env</span><span class="p">))</span> </pre></div> <p>or</p> <div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">serve</span><span class="p">():</span> <span class="n">local</span><span class="p">(</span><span class="s1">&#39;cd {deploy_path} &amp;&amp; python -m http.server&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">env</span><span class="p">))</span> </pre></div> <p>in <cite>fabfile.py</cite> depending on whether you want to test your blog with a Python 2 or Python 3 http server.</p> </div> <div class="section" id="adding-content"> <h2>Adding Content</h2> <p>We've got an empty blog working. Let's add some content</p> <div class="highlight"><pre><span></span>$vim content/firstpost.rst </pre></div> <p>and then add:</p> <div class="highlight"><pre><span></span><span class="gh">Firstpost</span> <span class="gh">#########</span> <span class="nc">:date:</span> <span class="nf">2012-03-30 23:47</span> <span class="nc">:category:</span> <span class="nf">programming</span> <span class="nc">:author:</span> <span class="nf">Angus Griffith</span> RST is cool! We can include code snippets like this <span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">python</span> <span class="k">def</span> <span class="nf">factorial</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="k">return</span> <span class="mi">1</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">n</span> <span class="o">*</span> <span class="n">factorial</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> and links like this Python_. <span class="p">..</span> <span class="nt">_Python:</span> http://python.org/ </pre></div> <p>rebuild the site</p> <div class="highlight"><pre><span></span>$ fab build </pre></div> <img alt="firstpost.png" src="/images/firstpost.png" style="width: 100%;" /> <p>Hooray!</p> <p>Obviously this is only a very short introduction to pelican. The <a class="reference external" href="http://docs.getpelican.com/en/3.3.0/getting_started.html">getting started</a> pelican documentation is excellent. It tells you how to add other pages, include images, link to internal content and much more.</p> </div> <script type= "text/javascript"> if (!document.getElementById('mathjaxscript_pelican')) { var s = document.createElement('script'); s.id = 'mathjaxscript_pelican'; s.type = 'text/javascript'; s.src = 'https:' == document.location.protocol ? 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' : 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'; s[(window.opera ? "innerHTML" : "text")] = "MathJax.Hub.Config({" + " config: ['MMLorHTML.js']," + " TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'AMS' } }," + " jax: ['input/TeX','input/MathML','output/HTML-CSS']," + " extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," + " displayAlign: 'center'," + " displayIndent: '0em'," + " showMathMenu: true," + " tex2jax: { " + " inlineMath: [ ['$','$'] ], " + " displayMath: [ ['$$','$$'] ]," + " processEscapes: true," + " preview: 'TeX'," + " }, " + " 'HTML-CSS': { " + " styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'black ! important'} }" + " } " + "}); "; (document.body || document.getElementsByTagName('head')).appendChild(s); } </script>