Intro to Sage - SD 60 Chennai
system:sage


<h1 style="text-align: left;">Introduction to <em>Sage</em>:</h1>
<h1 style="text-align: left;">Mathematics Software for All</h1>
<h2 style="text-align: left;"><a href="http://wiki.sagemath.org/days60" target="_blank">Sage Days 60</a>, <a href="http://www.imsc.res.in/" target="_blank">IMSc</a>, Chennai</h2>
<h2 style="text-align: left;">Speaker: <a href="http://www.math-cs.gordon.edu/~kcrisman/" target="_blank">Karl-Dieter Crisman</a>, <a href="http://www.gordon.edu/" target="_blank">Gordon College</a></h2>
<p style="text-align: left;">Thank you to the organizers for the invitation to come and introduce you all to Sage.</p>
<h2>Just the Basics</h2>
<p>Let's get started. Hopefully by now you and I don't need help with the following computations:</p>

{{{id=0|
2+2
///
4
}}}

{{{id=2|
integrate(x^3,x)
///
1/4*x^4
}}}

{{{id=48|
3*vector([1,2,3])
///
(3, 6, 9)
}}}

On the other hand, if I needed one of the following as an intermediate step, I might appreciate some assistance:

{{{id=33|
factorial(100)
///
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
}}}

{{{id=49|
matrix([[1,2,3],[4,5,7],[6,8,9]])^-1
///
[-11/7   6/7  -1/7]
[  6/7  -9/7   5/7]
[  2/7   4/7  -3/7]
}}}

<p>What if someone sends me a possible counterexample to FLT?</p>

{{{id=57|
27784^3 + 35385^3 - 40362^3
///
1
}}}

<p>Good thing we checked. &nbsp;Now let's do an integral.</p>

{{{id=9|
integral(3*x^2/sqrt(25*x^2-3), x)
///
3/50*sqrt(25*x^2 - 3)*x + 9/250*log(50*x + 10*sqrt(25*x^2 - 3))
}}}

Hmm, the antiderivative looks kind of ugly. &nbsp;Let me try to simplify it and typeset it nicely.

{{{id=7|
show(expand(integral(3*x^2/sqrt(25*x^2-3),x)))
///
<html><script type="math/tex; mode=display">\newcommand{\Bold}[1]{\mathbf{#1}}\frac{3}{50} \, \sqrt{25 \, x^{2} - 3} x + \frac{9}{250} \, \log\left(50 \, x + 10 \, \sqrt{25 \, x^{2} - 3}\right)</script></html>
}}}

That's better. &nbsp;Well, maybe I should just type it in my notes, so I don't forget. &nbsp;$$\frac{3}{50}\sqrt{25x^2-3x}+\frac{9}{250}\log\left(50x+10\sqrt{25x^2-3}\right)$$ 
Of course, maybe I needed a <em>definite</em> integral.</p>

{{{id=51|
show(integral(3*x^2/sqrt(25*x^2-3),x,1,2))
///
<html><script type="math/tex; mode=display">\newcommand{\Bold}[1]{\mathbf{#1}}\frac{3}{25} \, \sqrt{97} - \frac{3}{50} \, \sqrt{22} + \frac{9}{250} \, \log\left(10 \, \sqrt{97} + 100\right) - \frac{9}{250} \, \log\left(10 \, \sqrt{22} + 50\right)</script></html>
}}}

And maybe I needed it numerically approximated, with a built-in error bound computed.

{{{id=50|
numerical_integral(3*x^2/sqrt(25*x^2-3),1,2)
///
(0.9262503194124578, 1.0283444311781162e-14)
}}}

And maybe I need to visualize that as well...

{{{id=53|
show(plot(3*x^2/sqrt(25*x^2-3),(x,1,2),fill=True)+plot(3*x^2/sqrt(25*x^2-3),(x,.5,3)),figsize=3)
html("This shows $\int_1^2 \\frac{3x^2}{\sqrt{25x^2-3}}\; dx$")
///
<html><font color='black'><img src='cell://sage0.png'></font></html>
<html><font color='black'>This shows <script type="math/tex">\int_1^2 \frac{3x^2}{\sqrt{25x^2-3}}\; dx</script></font></html>
}}}

Even if you haven't done these sorts of things yourself, you know you can do so with computer help, and possibly have something in a lab or on your laptop which can do them - or you use some <a href="http://www.wolframalpha.com/" target="_blank">web app or other</a>.

But creating something like this takes just a bit more time.

{{{id=35|
%hide
def Newton_Iterates(a_function, guess, iterations = 5):
    ''' 
    Returns a list of the iterations of the Newton-Raphson method approximations to a zero of a_function.

    INPUT:
        a_function: a function of one variable
        start: the starting value of the iteration
        iterations: (optional) the number of iterations to draw
    '''
    f(x)=a_function(x)
    deriv=f.derivative()
    approx(x)=x-f(x)/deriv(x)
    input = guess
    iter_list = [input]
    for i in range(iterations):
        input = approx(input).n()
        iter_list.append(input)
    return iter_list

def Newton_Graph(a_function, guess, iterations = 5):
    '''
    Returns a graphics object of a plot of a_function and Newton-Raphson method tangent lines.

    INPUT:
        a_function: a function of one variable
        start: the starting value of the iteration
        iterations: (optional) the number of iterations to draw
        xmin: (optional) the lower end of the plotted interval
        xmax: (optional) the upper end of the plotted interval
    
    EXAMPLES:
        sage: f = lambda x: x^3-3*x^2+2*x
        sage: show(Newton_Graph(f,.5))
    
    Note: This is very slow with symbolic functions.
    '''
    iter_list = [[guess,0]]
    f(x)=a_function(x)
    deriv=f.derivative()
    approx(x)=x-f(x)/deriv(x)
    input = guess
    for i in range(iterations):
        iter_list.append([input,f(input)])
        input=approx(input).n()
        iter_list.append([input,0])
    approx_tangents = line(iter_list,rgbcolor=(1,0,0))
    xmin=min([point[0] for point in iter_list])-1
    xmax=max([point[0] for point in iter_list])+1
    ymin=min([point[1] for point in iter_list])-.5
    ymax=max([point[1] for point in iter_list])+.5
    basic_plot = plot(a_function, xmin, xmax, color='blue')
    P=basic_plot + approx_tangents
    P.show(ymin=ymin,ymax=ymax)

def cubic_approx(guess, intercept=0, iterations = 5):
    f(x)=x^3-3*x^2+2*x+intercept
    return Newton_Graph(f,guess,iterations=iterations)

def cubic_iterate(guess, intercept=0, iterations = 5):
    f(x)=x^3-3*x^2+2*x+intercept
    return Newton_Iterates(f,guess,iterations=iterations)

@interact
def _(guess=RR(.5),intercept=slider(-2,2,.5,0),iterations=slider(1,20,1,5)):
    root = cubic_iterate(guess,intercept=intercept,iterations=iterations)[-1]
    print 'start guess=', guess
    print 'intercept=', intercept
    print 'iterations =', iterations
    print 'root approximation =', root 
    cubic_approx(guess,intercept=intercept,iterations=iterations)
///
<html><!--notruncate-->
        <div padding=6 id="div-interact-35">
          <table width=800px height=20px bgcolor="#c5c5c5" cellpadding=15>
            <tr>
              <td bgcolor="#f9f9f9" valign=top align=left>
            <table>
              <tr><td colspan=3><table><tr><td align=right><font color="black">guess&nbsp;</font></td><td><input type="text" value="0.500000000000000" size=80 onchange="interact(35, {variable: 'guess', adapt_number: 1, value: encode64(this.value)}, 1)"></input></td>
</tr><tr><td align=right><font color="black">intercept&nbsp;</font></td><td>
        <table>
          <tr>
            <td>
              <div id="slider-intercept-35" style="margin:0px; margin-left: 1.0em; margin-right: 1.0em; width: 15.0em;"></div>
            </td>
            
            <td>
              <font color="black" id="slider-intercept-35-lbl"></font>
            </td>
          </tr>
        </table><script>
    (function() {
        var values = ["-2.00000000000000","-1.50000000000000","-1.00000000000000","-0.500000000000000","0.000000000000000","0.500000000000000","1.00000000000000","1.50000000000000","2.00000000000000"];
        setTimeout(function() {
            $('#slider-intercept-35').slider({
                step: 1,
                min: 0,
                max: 8,
                value: 4,
                change: function (e, ui) {
                    var position = ui.value;
                    if (values != null) {
                        $('#slider-intercept-35-lbl').text(values[position]);
                        interact(35, {variable: 'intercept', adapt_number: 2, value: encode64(position)}, 1);
                    }
                },
                slide: function (e, ui) {
                    if (values != null) {
                        $('#slider-intercept-35-lbl').text(values[ui.value]);
                    }
                }
            });
            if (values != null) {
                $('#slider-intercept-35-lbl').text(values[$('#slider-intercept-35').slider('value')]);
            }
        }, 1);
    })();
    </script></td>
</tr><tr><td align=right><font color="black">iterations&nbsp;</font></td><td>
        <table>
          <tr>
            <td>
              <div id="slider-iterations-35" style="margin:0px; margin-left: 1.0em; margin-right: 1.0em; width: 15.0em;"></div>
            </td>
            
            <td>
              <font color="black" id="slider-iterations-35-lbl"></font>
            </td>
          </tr>
        </table><script>
    (function() {
        var values = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"];
        setTimeout(function() {
            $('#slider-iterations-35').slider({
                step: 1,
                min: 0,
                max: 19,
                value: 4,
                change: function (e, ui) {
                    var position = ui.value;
                    if (values != null) {
                        $('#slider-iterations-35-lbl').text(values[position]);
                        interact(35, {variable: 'iterations', adapt_number: 3, value: encode64(position)}, 1);
                    }
                },
                slide: function (e, ui) {
                    if (values != null) {
                        $('#slider-iterations-35-lbl').text(values[ui.value]);
                    }
                }
            });
            if (values != null) {
                $('#slider-iterations-35-lbl').text(values[$('#slider-iterations-35').slider('value')]);
            }
        }, 1);
    })();
    </script></td>
</tr></table></td></tr>
              <tr><td></td><td style='width: 100%;'>
        <div id="cell-interact-35"><?__SAGE__START>
          <table border=0 bgcolor="white" width=100%>
            <tr>
              <td bgcolor="white" align=left valign=top>
                <pre><?__SAGE__TEXT></pre>
              </td>
            </tr>
            <tr>
              <td align=left valign=top><?__SAGE__HTML></td>
            </tr>
          </table><?__SAGE__END>
        </div></td><td></td></tr>
              <tr><td colspan=3></td></tr>
            </table></td>
            </tr>
          </table>
        </div></html>
}}}

Or maybe it was something that you really need to see from more than one viewpoint.

{{{id=55|
u, v = var('u,v')
f1 = (4+(3+cos(v))*sin(u), 4+(3+cos(v))*cos(u), 4+sin(v))
f2 = (8+(3+cos(v))*cos(u), 3+sin(v), 4+(3+cos(v))*sin(u))
p1 = parametric_plot3d(f1, (u,0,2*pi), (v,0,2*pi), texture="red")
p2 = parametric_plot3d(f2, (u,0,2*pi), (v,0,2*pi), texture="blue")
show(p1 + p2)
///
}}}

<h2>So What?</h2>
<p>It's so great to have this computational and visualization power. Unfortunately, with some such software, you may have run into one of the following three barriers to using it more widely.</p>
<ul>
<li>You used wonderful (free!) applets and demonstrations (e.g. for fractals, modular arithmetic), which handle <strong>only one narrow piece of mathematics</strong>.</li>
<li>You were asked to use a powerful and impressive comprehensive software package, but it is <strong>very&nbsp;expensive</strong>, especially depending on how often you use it.</li>
<li>You might have needed to use a computer lab whose <strong>hours are inconvenient and might be distant</strong>&nbsp;(certainly not useful at home).</li>
</ul>
<p><a href="http://sagemath.org/" target="_blank"><em>Sage</em></a>, the software I am currently using in this talk, is a<strong> free, powerful option</strong> which avoids all these issues. &nbsp; You can download it freely, <em>OR</em>&nbsp;you can run it off a server for interface <strong>in your web browser</strong>- just as I am doing right now! &nbsp;Indeed, there are four interfaces:</p>
<ul>
<li>Command line interface</li>
<li>This notebook interface</li>
<li>Cloud.sagemath.com, a next-gen web app</li>
<li>Sage cell server
<ul>
<li>(There are also apps for Android and iPhone/iPad which use the cell server technology.)</li>
</ul>
</li>
</ul>
<p>Let me demonstrate each of these for you briefly. &nbsp;</p>
<p>(Demo Interlude)</p>
<p>However, we'll stick with the notebook here.</p>
<h2>More Basics</h2>
<p>Sage handles other topics in undergraduate mathematics&nbsp;with aplomb, such as vector calculus, number theory, applied linear algebra, differential equations, statistics...</p>

{{{id=36|
x,y,z=var('x y z')
plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors=['red','green','blue'])
///
}}}

This one is best viewed using 3D glasses, of course.

The following one shows many theorems about numbers, color-encoded!

{{{id=37|
@interact
def power_table_plot(p=(7,prime_range(50))):
    P=matrix_plot(matrix(p-1,[mod(a,p)^b for a in range(1,p) for b in srange(p)]),cmap='jet')
    show(P)
///
<html><!--notruncate-->
        <div padding=6 id="div-interact-37">
          <table width=800px height=20px bgcolor="#c5c5c5" cellpadding=15>
            <tr>
              <td bgcolor="#f9f9f9" valign=top align=left>
            <table>
              <tr><td colspan=3><table><tr><td align=right><font color="black">p&nbsp;</font></td><td><select onchange="interact(37, {variable: 'p', adapt_number: 4, value: encode64(this.options[this.selectedIndex].value)}, 1);"><option value="0" >2</option>
<option value="1" >3</option>
<option value="2" >5</option>
<option value="3" selected>7</option>
<option value="4" >11</option>
<option value="5" >13</option>
<option value="6" >17</option>
<option value="7" >19</option>
<option value="8" >23</option>
<option value="9" >29</option>
<option value="10" >31</option>
<option value="11" >37</option>
<option value="12" >41</option>
<option value="13" >43</option>
<option value="14" >47</option>
</select></td>
</tr></table></td></tr>
              <tr><td></td><td style='width: 100%;'>
        <div id="cell-interact-37"><?__SAGE__START>
          <table border=0 bgcolor="white" width=100%>
            <tr>
              <td bgcolor="white" align=left valign=top>
                <pre><?__SAGE__TEXT></pre>
              </td>
            </tr>
            <tr>
              <td align=left valign=top><?__SAGE__HTML></td>
            </tr>
          </table><?__SAGE__END>
        </div></td><td></td></tr>
              <tr><td colspan=3></td></tr>
            </table></td>
            </tr>
          </table>
        </div></html>
}}}

<p>If you like numerical methods, these come built-in as well. &nbsp;Note the interactivity Sage can provide.</p>

{{{id=56|
%hide
import pylab
A_image = pylab.mean(pylab.imread(DATA + 'san_thome.png'), 2)
B_image = pylab.mean(pylab.imread(DATA + 'imsc_night.png'), 2)
@interact
def svd_image(i=(5,(1..50))):
    u,s,v = pylab.linalg.svd(A_image)
    A = sum(s[j]*pylab.outer(u[0:,j],v[j,0:]) for j in range(i))
    u1,s1,v1 = pylab.linalg.svd(B_image)
    B = sum(s1[j]*pylab.outer(u1[0:,j],v1[j,0:]) for j in range(i))
    g = graphics_array([[matrix_plot(A),matrix_plot(B)],[matrix_plot(A_image),matrix_plot(B_image)]])
    show(g,axes=False, figsize=6)
    html('<h2>Compressed using %s eigenvalues</h2>'%i)
///
<html><!--notruncate-->
        <div padding=6 id="div-interact-56">
          <table width=800px height=20px bgcolor="#c5c5c5" cellpadding=15>
            <tr>
              <td bgcolor="#f9f9f9" valign=top align=left>
            <table>
              <tr><td colspan=3><table><tr><td align=right><font color="black">i&nbsp;</font></td><td>
        <table>
          <tr>
            <td>
              <div id="slider-i-56" style="margin:0px; margin-left: 1.0em; margin-right: 1.0em; width: 15.0em;"></div>
            </td>
            
            <td>
              <font color="black" id="slider-i-56-lbl"></font>
            </td>
          </tr>
        </table><script>
    (function() {
        var values = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50"];
        setTimeout(function() {
            $('#slider-i-56').slider({
                step: 1,
                min: 0,
                max: 49,
                value: 4,
                change: function (e, ui) {
                    var position = ui.value;
                    if (values != null) {
                        $('#slider-i-56-lbl').text(values[position]);
                        interact(56, {variable: 'i', adapt_number: 5, value: encode64(position)}, 1);
                    }
                },
                slide: function (e, ui) {
                    if (values != null) {
                        $('#slider-i-56-lbl').text(values[ui.value]);
                    }
                }
            });
            if (values != null) {
                $('#slider-i-56-lbl').text(values[$('#slider-i-56').slider('value')]);
            }
        }, 1);
    })();
    </script></td>
</tr></table></td></tr>
              <tr><td></td><td style='width: 100%;'>
        <div id="cell-interact-56"><?__SAGE__START>
          <table border=0 bgcolor="white" width=100%>
            <tr>
              <td bgcolor="white" align=left valign=top>
                <pre><?__SAGE__TEXT></pre>
              </td>
            </tr>
            <tr>
              <td align=left valign=top><?__SAGE__HTML></td>
            </tr>
          </table><?__SAGE__END>
        </div></td><td></td></tr>
              <tr><td colspan=3></td></tr>
            </table></td>
            </tr>
          </table>
        </div></html>
}}}

{{{id=43|
%hide
y = var('y') 
@interact 
def _(g=input_box(default = 1-y),a=2,b=2,auto_update=False): 
     yfun = function('yfun',x) 
     f = desolve(diff(yfun,x) - g(y=yfun), yfun, ics=[a,b]) 
     Q=plot(f,0,3) 
     q = Q[0].get_minmax_data()
     P=plot_slope_field(g,(x,q['xmin'],q['xmax']),(y,q['ymin'],q['ymax'])) 
     html('$f(x)=%s$'%(latex(f),))
     show(P+Q)
///
<html><!--notruncate-->
        <div padding=6 id="div-interact-43">
          <table width=800px height=20px bgcolor="#c5c5c5" cellpadding=15>
            <tr>
              <td bgcolor="#f9f9f9" valign=top align=left>
            <table>
              <tr><td colspan=3><table><tr><td align=right><font color="black">g&nbsp;</font></td><td><input type="text" value="-y + 1" size=80 onchange="interact(43, {variable: 'g', adapt_number: 6, value: encode64(this.value)}, 0)"></input></td>
</tr><tr><td align=right><font color="black">a&nbsp;</font></td><td><input type="text" value="2" size=80 onchange="interact(43, {variable: 'a', adapt_number: 7, value: encode64(this.value)}, 0)"></input></td>
</tr><tr><td align=right><font color="black">b&nbsp;</font></td><td><input type="text" value="2" size=80 onchange="interact(43, {variable: 'b', adapt_number: 8, value: encode64(this.value)}, 0)"></input></td>
</tr><tr><td colspan=2><input type="button" value="Update" onclick="interact(43, {}, 1)">
</td>
</tr></table></td></tr>
              <tr><td></td><td style='width: 100%;'>
        <div id="cell-interact-43"><?__SAGE__START>
          <table border=0 bgcolor="white" width=100%>
            <tr>
              <td bgcolor="white" align=left valign=top>
                <pre><?__SAGE__TEXT></pre>
              </td>
            </tr>
            <tr>
              <td align=left valign=top><?__SAGE__HTML></td>
            </tr>
          </table><?__SAGE__END>
        </div></td><td></td></tr>
              <tr><td colspan=3></td></tr>
            </table></td>
            </tr>
          </table>
        </div></html>
}}}

In the previous example, notice that it's possible to join several different types of computations together. In this example, we calculate a symbolic solution to a differential equation, but plot the slope field and solution numerically. &nbsp;Sage tries to be unified as much as possible.

<p>Statistics are possible via some very basic native Sage functionality, or via several very powerful components of Sage that are primarily statistical/numerical. &nbsp;By far the most powerful of these is R.</p>

{{{id=44|
%r
library("MASS")
data(Cars93)
mean(Cars93$MPG.city)
xtabs( ~ Origin + MPG.city, data=Cars93)
///
[1] 22.36559
         MPG.city
Origin    15 16 17 18 19 20 21 22 23 24 25 26 28 29 30 31 32 33 39 42 46
  USA      2  3  4  5  8  3  3  4  7  2  2  0  1  2  0  2  0  0  0  0  0
  non-USA  0  0  4  7  2  5  3  3  1  3  4  2  1  4  1  0  1  1  1  1  1
}}}

<p>Of course, one reason <em>I</em> like Sage is not all these 'useful' things, but producing eye candy:</p>

{{{id=47|
plot([x^i for i in [1..12]],(x,0,1),fill = dict((i,[i+1]) for i in [0..11]))
///
<html><font color='black'><img src='cell://sage0.png'></font></html>
}}}

<h2>Can it help with Research?</h2>



But can you do research-level mathematics in Sage? &nbsp;In fact, it started as purely a research tool nearly a decade ago. &nbsp;Just because it quickly became the comprehensive software you see today doesn't mean it isn't full of cutting-edge mathematics.

First, let's see a small example that doesn't use too much high-powered stuff. &nbsp;It's a tiny piece of what a student of mine used to disprove a conjecture of one of my colleagues - and to come up with another conjecture, which she proved. &nbsp;(It's since appeared in <em>Mathematical Social Sciences.</em>)

{{{id=16|
%hide
def get_correct_perms_generator(n):
    r"""
    Creates a generator to make every non-parametric data set
    with 3 candidates and n rows, in the normal form with each
    column ordered down and the top row ordered left to right.

    There are (3n!)/(n!^3*6) of these - found by using Sloane 
    online encyclopedia because I was lazy, but this is obvious
    in hindsight.
    """
    from copy import copy
    firstcolumniter=Combinations(range(1,3*n),n-1)    
    for combo1 in firstcolumniter:
        output1=[3*n]
        data1=range(1,3*n)
        combo1.sort()
        combo1.reverse()
        for item1 in combo1:
            output1.append(item1)
            data1.remove(item1)
        data1.sort()
        biggestleft=data1.pop()
        output1.append(biggestleft)
        secondcolumniter=Combinations(data1,n-1)
        for combo2 in secondcolumniter:
            output2=copy(output1)
            data2=copy(data1)
            combo2.sort()
            combo2.reverse()
            for item2 in combo2:
                output2.append(item2)
                data2.remove(item2)
            data2.sort()
            data2.reverse()
            for item3 in data2:
                output2.append(item3)
            yield output2

def get_profile(mylist,n):
    r"""
    Takes a non-parametric data set with 3 candidates
    and n rows and yields the voting profile associated
    to it.
    """
    import sage.combinat.permutation as permutation
    profile=[0,0,0,0,0,0]
    rawpref=[]
    standardrawpref=[]
    for i in mylist[0:n]:
        for j in mylist[n:2*n]:
            for k in mylist[2*n:]:
                rawpref=[i,j,k]
                standardrawpref=list(permutation.to_standard(rawpref))
                if standardrawpref==[3,2,1]:
                    profile[0]+=1
                elif standardrawpref==[3,1,2]:
                    profile[1]+=1
                elif standardrawpref==[2,1,3]:
                    profile[2]+=1
                elif standardrawpref==[1,2,3]:
                    profile[3]+=1
                elif standardrawpref==[1,3,2]:
                    profile[4]+=1
                elif standardrawpref==[2,3,1]:
                    profile[5]+=1
    return(profile)

def get_decomposition(myprofile):
    r"""
    Takes a voting profile with three candidates
    and yields the standard (Saari) decomposition 
    into Basic (A and B), Reversal (A and B), 
    Condorcet and Kernel components.
    """
    ProfileMatrix=(1/6)*matrix([[2,1,-1,-2,-1,1],[1,-1,-2,-1,1,2],[0,1,-1,0,1,-1],[-1,1,0,-1,1,0],[1,-1,1,-1,1,-1],[1,1,1,1,1,1]])
    return (ProfileMatrix*matrix(6,myprofile)).transpose()
///
}}}

{{{id=39|
G = get_correct_perms_generator(2)
p = G.next()
p;get_profile(p,2);get_decomposition(get_profile(p,2))
///
[6, 1, 5, 2, 4, 3]
[2, 2, 0, 2, 2, 0]
[  0   0 2/3   0   0 4/3]
}}}

<h2>Graphs, Groups, and More</h2>

Okay, let's look at some topics I have heard the attendees at this talk might be interested in.  To start off, let's make a graph.  Any old graph.

{{{id=15|
G = Graph({0:[1,2],1:[0,2,3],2:[0,1,3],3:[1,2,5,6],4:[5],5:[3,4],6:[3,7],7:[6]}); G.set_pos({0:[315,315],1:[35,35],2:[275,160.99999999999997],3:[165,243],4:[228,44],5:[76,296],6:[211,301],7:[298,104]});  graph_editor(G);
///
<html><font color='black'><div id="graph_editor_15"><table><tbody>
      <tr><td><iframe style="width: 800px; height: 400px; border: 0;" id="iframe_graph_editor_15" src="/javascript/graph_editor/graph_editor.html?cell_id=15"></iframe><input type="hidden" id="graph_data_15" value="num_vertices=8;edges=[[0,1],[0,2],[1,2],[1,3],[2,3],[3,5],[3,6],[4,5],[6,7]];pos=[[1.0,0.0],[0.0,1.0],[0.8571428571428571,0.55],[0.4642857142857143,0.2571428571428571],[0.6892857142857143,0.9678571428571429],[0.14642857142857144,0.06785714285714284],[0.6285714285714286,0.050000000000000044],[0.9392857142857143,0.7535714285714286]];"><input type="hidden" id="graph_name_15" value="G"></td></tr>
      <tr><td><button onclick="
    var f, g, saved_input;
    g = $('#iframe_graph_editor_15')[0].contentWindow.update_sage();

    if (g[2] === '') {
        alert('You need to give a Sage variable name to the graph, before saving it.');
        return;
    }
    f = g[2] + ' = Graph(' + g[0] + '); ' + g[2] + '.set_pos(' + g[1] + '); '
    
    f += ' graph_editor(' + g[2] + ');'
    $('#cell_input_15').val(f);
    cell_input_resize(15);
    evaluate_cell(15, false);

">Save</button><button onclick="cell_delete_output(15);">Close</button></td></tr>
</tbody></table></div></font></html>
}}}

{{{id=59|
G.chromatic_polynomial()
///
x^8 - 9*x^7 + 34*x^6 - 70*x^5 + 85*x^4 - 61*x^3 + 24*x^2 - 4*x
}}}

<p>Note that this means any computation you want to do that Sage can do with graphs, you can in principle do by just "drawing" the graph.</p>

<p>Sage consists of many separate components, each of which is an open-source standard in its field.  Let's see a nice example of all these things working together.</p>

{{{id=31|
H = graphs.TetrahedralGraph() # Takes NetworkX graph
///
}}}

{{{id=38|
H = H.cartesian_product(H) # Uses Sage functionality
///
}}}

{{{id=40|
show(H) # uses matplotlib
///
<html><font color='black'><img src='cell://sage0.png'></font></html>
}}}

{{{id=24|
Sym = H.automorphism_group() # Native Sage Code using C backend for graphs
///
}}}

{{{id=25|
len( Sym.list() )  # Needs GAP to calculate
///
1152
}}}

{{{id=26|
Sym._gap_().ComputedPCentralSeriess()  # Directly within GAP
///
[  ]
}}}

{{{id=60|
poly = H.chromatic_polynomial() # Uses compiled C code from Cython in Sage
///
}}}

{{{id=61|
deriv = derivative(poly,x) # Uses Ginac/Pynac for symbolics
///
}}}

{{{id=63|
deriv.subs(x=0)
///
-188580960
}}}

<p>And yes, this graph is connected.</p>

{{{id=65|
integral(poly,x) # Uses Maxima for integration, symbolic summation, etc.
///
1/17*x^17 - 3*x^16 + 1096/15*x^15 - 7902/7*x^14 + 161032/13*x^13 - 102358*x^12 + 7242454/11*x^11 - 16789056/5*x^10 + 123182360/9*x^9 - 89140779/2*x^8 + 114946568*x^7 - 230543668*x^6 + 1742815741/5*x^5 - 376891986*x^4 + 264255876*x^3 - 94290480*x^2
}}}

<p>The book "Quo Vadis, Graph Theory?: A Source Book for Challenges and Directions" asks for interpretations of such things.</p>

{{{id=30|

///
}}}

<h2>Non-mathematical fun</h2>
<p>There are many other great aspects of Sage I haven't mentioned yet. &nbsp;Let's see how each of these works.</p>
<ul>
<li>Tab-Completion for instant, contextual help</li>
<li>It's <em>Open Source</em> - so fast bug fixes or enhancements happen as a matter of course - and <em>you</em> can contribute!</li>
<li>It's a combination of research-level quality new code and well-regarded programs such as Maxima, GAP, PARI, R, ... so a&nbsp;<strong>gigantic</strong>&nbsp;range of functionality comes "out of the box"</li>
<li>It's integrated - you can use the Python language, LaTeX, proprietary programs, command-line interface...</li>
</ul>
<p>But the best thing to do is to try it out or download it!</p>
<ul>
<li><a href="http://www.sagemath.org">http://www.sagemath.org</a>&nbsp;- the Sage website</li>
<li><a href="http://cloud.sagemath.com">http://cloud.sagemath.com</a></li>
<li>While on campus at SD 60,&nbsp;<a href="http://citron:8080/">http://citron:8080/</a></li>
</ul>
<h2>More Math</h2>
<p>Here is a gallery of other research-level things. But to really explore, one needs to peruse the <a href="http://www.sagemath.org/doc/reference/" target="_blank">gargantuan reference manual</a>.</p>
<h3>Analytic Number Theory</h3>
<p>I like this example, as it shows that Riemann's exact formula for $\pi(x)$, the prime counting function, is completely different in nature than other approximations.</p>

{{{id=29|
import mpmath
var('y')
L = lcalc.zeros_in_interval(10,50,0.1)
@interact
def _(n=(100,(60,10^3))):
   P = plot(prime_pi,n-50,n,color='black',legend_label='$\pi(x)$')
   P += plot(Li,n-50,n,color='green',legend_label='$Li(x)$')
   G = lambda x: sum([mpmath.li(x^(1/j))*moebius(j)/j for j in [1..3]])
   P += plot(G,n-50,n,color='red',legend_label='$\sum_{j=1}^{%s}\\frac{\mu(j)}{j}Li(x^{1/j})$'%3)
   F = lambda x: sum([(mpmath.li(x^(1/j))-log(2)+numerical_integral(1/(y*(y^2-1)*log(y)),x^(1/j),oo)[0])*moebius(j)/j for j in [1..3]])-sum([(mpmath.ei(log(x)*((0.5+l[0]*i)/j))+mpmath.ei(log(x)*((0.5-l[0]*i)/j))).real for l in L for j in [1..3]])
   P += plot(F,n-50,n,color='blue',legend_label='Really good estimate',plot_points=50)
   show(P)
///
<html><!--notruncate-->
        <div padding=6 id="div-interact-29">
          <table width=800px height=20px bgcolor="#c5c5c5" cellpadding=15>
            <tr>
              <td bgcolor="#f9f9f9" valign=top align=left>
            <table>
              <tr><td colspan=3><table><tr><td align=right><font color="black">n&nbsp;</font></td><td>
        <table>
          <tr>
            <td>
              <div id="slider-n-29" style="margin:0px; margin-left: 1.0em; margin-right: 1.0em; width: 15.0em;"></div>
            </td>
            
            <td>
              <font color="black" id="slider-n-29-lbl"></font>
            </td>
          </tr>
        </table><script>
    (function() {
        var values = ["60.0","61.88376753507014","63.76753507014028","65.65130260521042","67.53507014028055","69.41883767535069","71.30260521042082","73.18637274549096","75.07014028056109","76.95390781563123","78.83767535070136","80.7214428857715","82.60521042084163","84.48897795591176","86.3727454909819","88.25651302605203","90.14028056112217","92.0240480961923","93.90781563126244","95.79158316633257","97.6753507014027","99.55911823647284","101.44288577154298","103.32665330661311","105.21042084168324","107.09418837675338","108.97795591182351","110.86172344689365","112.74549098196378","114.62925851703392","116.51302605210405","118.39679358717419","120.28056112224432","122.16432865731446","124.04809619238459","125.93186372745473","127.81563126252486","129.699398797595","131.58316633266514","133.4669338677353","135.35070140280544","137.2344689378756","139.11823647294574","141.0020040080159","142.88577154308604","144.76953907815619","146.65330661322633","148.53707414829648","150.42084168336663","152.30460921843678","154.18837675350693","156.07214428857708","157.95591182364723","159.83967935871738","161.72344689378752","163.60721442885767","165.49098196392782","167.37474949899797","169.25851703406812","171.14228456913827","173.02605210420842","174.90981963927857","176.79358717434872","178.67735470941886","180.561122244489","182.44488977955916","184.3286573146293","186.21242484969946","188.0961923847696","189.97995991983976","191.8637274549099","193.74749498998005","195.6312625250502","197.51503006012035","199.3987975951905","201.28256513026065","203.1663326653308","205.05010020040095","206.9338677354711","208.81763527054125","210.7014028056114","212.58517034068154","214.4689378757517","216.35270541082184","218.236472945892","220.12024048096214","222.0040080160323","223.88777555110244","225.77154308617258","227.65531062124273","229.53907815631288","231.42284569138303","233.30661322645318","235.19038076152333","237.07414829659348","238.95791583166363","240.84168336673378","242.72545090180392","244.60921843687407","246.49298597194422","248.37675350701437","250.26052104208452","252.14428857715467","254.02805611222482","255.91182364729497","257.7955911823651","259.67935871743526","261.5631262525054","263.44689378757556","265.3306613226457","267.21442885771586","269.098196392786","270.98196392785616","272.8657314629263","274.74949899799645","276.6332665330666","278.51703406813675","280.4008016032069","282.28456913827705","284.1683366733472","286.05210420841735","287.9358717434875","289.81963927855764","291.7034068136278","293.58717434869794","295.4709418837681","297.35470941883824","299.2384769539084","301.12224448897854","303.0060120240487","304.88977955911884","306.773547094189","308.65731462925913","310.5410821643293","312.42484969939943","314.3086172344696","316.19238476953973","318.0761523046099","319.95991983968","321.8436873747502","323.7274549098203","325.6112224448905","327.4949899799606","329.37875751503077","331.2625250501009","333.14629258517107","335.0300601202412","336.91382765531137","338.7975951903815","340.68136272545166","342.5651302605218","344.44889779559196","346.3326653306621","348.21643286573226","350.1002004008024","351.98396793587256","353.8677354709427","355.75150300601285","357.635270541083","359.51903807615315","361.4028056112233","363.28657314629345","365.1703406813636","367.05410821643375","368.9378757515039","370.82164328657404","372.7054108216442","374.58917835671434","376.4729458917845","378.35671342685464","380.2404809619248","382.12424849699494","384.0080160320651","385.89178356713523","387.7755511022054","389.65931863727553","391.5430861723457","393.42685370741583","395.310621242486","397.1943887775561","399.0781563126263","400.9619238476964","402.8456913827666","404.7294589178367","406.6132264529069","408.496993987977","410.38076152304717","412.2645290581173","414.14829659318747","416.0320641282576","417.91583166332776","419.7995991983979","421.68336673346806","423.5671342685382","425.45090180360836","427.3346693386785","429.21843687374866","431.1022044088188","432.98597194388896","434.8697394789591","436.75350701402925","438.6372745490994","440.52104208416955","442.4048096192397","444.28857715430985","446.17234468938","448.05611222445015","449.9398797595203","451.82364729459044","453.7074148296606","455.59118236473074","457.4749498998009","459.35871743487104","461.2424849699412","463.12625250501134","465.0100200400815","466.89378757515163","468.7775551102218","470.66132264529193","472.5450901803621","474.42885771543223","476.3126252505024","478.1963927855725","480.0801603206427","481.9639278557128","483.847695390783","485.7314629258531","487.61523046092327","489.4989979959934","491.38276553106357","493.2665330661337","495.15030060120387","497.034068136274","498.91783567134416","500.8016032064143","502.68537074148446","504.5691382765546","506.45290581162476","508.3366733466949","510.22044088176506","512.1042084168351","513.9879759519052","515.8717434869753","517.7555110220454","519.6392785571155","521.5230460921856","523.4068136272557","525.2905811623258","527.1743486973959","529.058116232466","530.9418837675361","532.8256513026062","534.7094188376763","536.5931863727463","538.4769539078164","540.3607214428865","542.2444889779566","544.1282565130267","546.0120240480968","547.8957915831669","549.779559118237","551.6633266533071","553.5470941883772","555.4308617234473","557.3146292585174","559.1983967935874","561.0821643286575","562.9659318637276","564.8496993987977","566.7334669338678","568.6172344689379","570.501002004008","572.3847695390781","574.2685370741482","576.1523046092183","578.0360721442884","579.9198396793585","581.8036072144286","583.6873747494986","585.5711422845687","587.4549098196388","589.3386773547089","591.222444889779","593.1062124248491","594.9899799599192","596.8737474949893","598.7575150300594","600.6412825651295","602.5250501001996","604.4088176352697","606.2925851703397","608.1763527054098","610.0601202404799","611.94388777555","613.8276553106201","615.7114228456902","617.5951903807603","619.4789579158304","621.3627254509005","623.2464929859706","625.1302605210407","627.0140280561108","628.8977955911809","630.781563126251","632.665330661321","634.5490981963911","636.4328657314612","638.3166332665313","640.2004008016014","642.0841683366715","643.9679358717416","645.8517034068117","647.7354709418818","649.6192384769519","651.503006012022","653.386773547092","655.2705410821621","657.1543086172322","659.0380761523023","660.9218436873724","662.8056112224425","664.6893787575126","666.5731462925827","668.4569138276528","670.3406813627229","672.224448897793","674.1082164328631","675.9919839679332","677.8757515030032","679.7595190380733","681.6432865731434","683.5270541082135","685.4108216432836","687.2945891783537","689.1783567134238","691.0621242484939","692.945891783564","694.8296593186341","696.7134268537042","698.5971943887743","700.4809619238443","702.3647294589144","704.2484969939845","706.1322645290546","708.0160320641247","709.8997995991948","711.7835671342649","713.667334669335","715.5511022044051","717.4348697394752","719.3186372745453","721.2024048096154","723.0861723446855","724.9699398797555","726.8537074148256","728.7374749498957","730.6212424849658","732.5050100200359","734.388777555106","736.2725450901761","738.1563126252462","740.0400801603163","741.9238476953864","743.8076152304565","745.6913827655266","747.5751503005966","749.4589178356667","751.3426853707368","753.2264529058069","755.110220440877","756.9939879759471","758.8777555110172","760.7615230460873","762.6452905811574","764.5290581162275","766.4128256512976","768.2965931863677","770.1803607214378","772.0641282565078","773.9478957915779","775.831663326648","777.7154308617181","779.5991983967882","781.4829659318583","783.3667334669284","785.2505010019985","787.1342685370686","789.0180360721387","790.9018036072088","792.7855711422789","794.669338677349","796.553106212419","798.4368737474891","800.3206412825592","802.2044088176293","804.0881763526994","805.9719438877695","807.8557114228396","809.7394789579097","811.6232464929798","813.5070140280499","815.39078156312","817.27454909819","819.1583166332601","821.0420841683302","822.9258517034003","824.8096192384704","826.6933867735405","828.5771543086106","830.4609218436807","832.3446893787508","834.2284569138209","836.112224448891","837.9959919839611","839.8797595190312","841.7635270541012","843.6472945891713","845.5310621242414","847.4148296593115","849.2985971943816","851.1823647294517","853.0661322645218","854.9498997995919","856.833667334662","858.7174348697321","860.6012024048022","862.4849699398723","864.3687374749423","866.2525050100124","868.1362725450825","870.0200400801526","871.9038076152227","873.7875751502928","875.6713426853629","877.555110220433","879.4388777555031","881.3226452905732","883.2064128256433","885.0901803607134","886.9739478957835","888.8577154308535","890.7414829659236","892.6252505009937","894.5090180360638","896.3927855711339","898.276553106204","900.1603206412741","902.0440881763442","903.9278557114143","905.8116232464844","907.6953907815545","909.5791583166246","911.4629258516946","913.3466933867647","915.2304609218348","917.1142284569049","918.997995991975","920.8817635270451","922.7655310621152","924.6492985971853","926.5330661322554","928.4168336673255","930.3006012023956","932.1843687374657","934.0681362725358","935.9519038076058","937.8356713426759","939.719438877746","941.6032064128161","943.4869739478862","945.3707414829563","947.2545090180264","949.1382765530965","951.0220440881666","952.9058116232367","954.7895791583068","956.6733466933769","958.557114228447","960.440881763517","962.3246492985871","964.2084168336572","966.0921843687273","967.9759519037974","969.8597194388675","971.7434869739376","973.6272545090077","975.5110220440778","977.3947895791479","979.278557114218","981.162324649288","983.0460921843581","984.9298597194282","986.8136272544983","988.6973947895684","990.5811623246385","992.4649298597086","994.3486973947787","996.2324649298488","998.1162324649189","1000.0"];
        setTimeout(function() {
            $('#slider-n-29').slider({
                step: 1,
                min: 0,
                max: 499,
                value: 21,
                change: function (e, ui) {
                    var position = ui.value;
                    if (values != null) {
                        $('#slider-n-29-lbl').text(values[position]);
                        interact(29, {variable: 'n', adapt_number: 11, value: encode64(position)}, 1);
                    }
                },
                slide: function (e, ui) {
                    if (values != null) {
                        $('#slider-n-29-lbl').text(values[ui.value]);
                    }
                }
            });
            if (values != null) {
                $('#slider-n-29-lbl').text(values[$('#slider-n-29').slider('value')]);
            }
        }, 1);
    })();
    </script></td>
</tr></table></td></tr>
              <tr><td></td><td style='width: 100%;'>
        <div id="cell-interact-29"><?__SAGE__START>
          <table border=0 bgcolor="white" width=100%>
            <tr>
              <td bgcolor="white" align=left valign=top>
                <pre><?__SAGE__TEXT></pre>
              </td>
            </tr>
            <tr>
              <td align=left valign=top><?__SAGE__HTML></td>
            </tr>
          </table><?__SAGE__END>
        </div></td><td></td></tr>
              <tr><td colspan=3></td></tr>
            </table></td>
            </tr>
          </table>
        </div></html>
}}}

<p>Here's a result from the last couple years connected to work the founder of Sage, William Stein, is doing, as well as to Ramanujan (some of you will know <a href="http://www.math.tifr.res.in/~eghate/tau.pdf" target="_blank">the connection</a>).</p>
<p><strong>Theorem</strong>:</p>
<p>Let $r_{12}(n)$ denote the number of ways to write $n$ as a sum of&nbsp;<em>twelve</em>&nbsp;squares (where order and sign both matter, so $(1,2)$ and $(2,1)$ and $(-2,1)$ are all different).&nbsp;As we let $p$ go through the set of all prime numbers, the distribution of the fraction $$\frac{r_{12}(p)-8(p^5+1)}{32p^{5/2}}$$ is asymptotic to $$\frac{2}{\pi}\sqrt{1-t^2}\; .$$&nbsp;</p>

{{{id=66|
def dist(v, b, left=float(0), right=float(pi)):
    """
    We divide the interval between left (default: 0) and
    right (default: pi) up into b bins.

    For each number in v (which must left and right),
    we find which bin it lies in and add this to a counter.
    This function then returns the bins and the number of
    elements of v that lie in each one.

    ALGORITHM: To find the index of the bin that a given
    number x lies in, we multiply x by b/length and take the
    floor.
    """
    length = right - left
    normalize = float(b/length)
    vals = {}
    d = dict([(i,0) for i in range(b)])
    for x in v:
        n = int(normalize*(float(x)-left))
        d[n] += 1
    return d, len(v)

def graph(d, b, num=5000, left=float(0), right=float(pi)):
    s = Graphics()
    left = float(left); right = float(right)
    length = right - left
    w = length/b
    k = 0
    for i, n in d.iteritems():
        k += n
        # ith bin has n objects in it.
        s += polygon([(w*i+left,0), (w*(i+1)+left,0), \
                     (w*(i+1)+left, n/(num*w)), (w*i+left, n/(num*w))],\
                     rgbcolor=(0,0,0.5))
    return s

def sqrt2():
    PI = float(pi)
    return plot(lambda x: (2/PI)*math.sqrt(1-x^2), -1,1, plot_points=200,
              rgbcolor=(0.3,0.1,0.1), thickness=2)

delta = delta_qexp(10^5)

@interact
def delta_dist(b=(20,(10..150)), number = (500,1000,..,delta.prec())):
    D = delta[:number]
    w = [float(D[p])/(2*float(p)^(5.5)) for p in prime_range(number + 1)]
    d, total_number_of_points = dist(w,b,float(-1),float(1))
    show(graph(d, b, total_number_of_points,-1,1) + sqrt2(), frame=True, gridlines=True)
///
<html><!--notruncate-->
        <div padding=6 id="div-interact-66">
          <table width=800px height=20px bgcolor="#c5c5c5" cellpadding=15>
            <tr>
              <td bgcolor="#f9f9f9" valign=top align=left>
            <table>
              <tr><td colspan=3><table><tr><td align=right><font color="black">b&nbsp;</font></td><td>
        <table>
          <tr>
            <td>
              <div id="slider-b-66" style="margin:0px; margin-left: 1.0em; margin-right: 1.0em; width: 15.0em;"></div>
            </td>
            
            <td>
              <font color="black" id="slider-b-66-lbl"></font>
            </td>
          </tr>
        </table><script>
    (function() {
        var values = ["10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72","73","74","75","76","77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98","99","100","101","102","103","104","105","106","107","108","109","110","111","112","113","114","115","116","117","118","119","120","121","122","123","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","144","145","146","147","148","149","150"];
        setTimeout(function() {
            $('#slider-b-66').slider({
                step: 1,
                min: 0,
                max: 140,
                value: 10,
                change: function (e, ui) {
                    var position = ui.value;
                    if (values != null) {
                        $('#slider-b-66-lbl').text(values[position]);
                        interact(66, {variable: 'b', adapt_number: 12, value: encode64(position)}, 1);
                    }
                },
                slide: function (e, ui) {
                    if (values != null) {
                        $('#slider-b-66-lbl').text(values[ui.value]);
                    }
                }
            });
            if (values != null) {
                $('#slider-b-66-lbl').text(values[$('#slider-b-66').slider('value')]);
            }
        }, 1);
    })();
    </script></td>
</tr><tr><td align=right><font color="black">number&nbsp;</font></td><td>
        <table>
          <tr>
            <td>
              <div id="slider-number-66" style="margin:0px; margin-left: 1.0em; margin-right: 1.0em; width: 15.0em;"></div>
            </td>
            
            <td>
              <font color="black" id="slider-number-66-lbl"></font>
            </td>
          </tr>
        </table><script>
    (function() {
        var values = ["500","1000","1500","2000","2500","3000","3500","4000","4500","5000","5500","6000","6500","7000","7500","8000","8500","9000","9500","10000","10500","11000","11500","12000","12500","13000","13500","14000","14500","15000","15500","16000","16500","17000","17500","18000","18500","19000","19500","20000","20500","21000","21500","22000","22500","23000","23500","24000","24500","25000","25500","26000","26500","27000","27500","28000","28500","29000","29500","30000","30500","31000","31500","32000","32500","33000","33500","34000","34500","35000","35500","36000","36500","37000","37500","38000","38500","39000","39500","40000","40500","41000","41500","42000","42500","43000","43500","44000","44500","45000","45500","46000","46500","47000","47500","48000","48500","49000","49500","50000","50500","51000","51500","52000","52500","53000","53500","54000","54500","55000","55500","56000","56500","57000","57500","58000","58500","59000","59500","60000","60500","61000","61500","62000","62500","63000","63500","64000","64500","65000","65500","66000","66500","67000","67500","68000","68500","69000","69500","70000","70500","71000","71500","72000","72500","73000","73500","74000","74500","75000","75500","76000","76500","77000","77500","78000","78500","79000","79500","80000","80500","81000","81500","82000","82500","83000","83500","84000","84500","85000","85500","86000","86500","87000","87500","88000","88500","89000","89500","90000","90500","91000","91500","92000","92500","93000","93500","94000","94500","95000","95500","96000","96500","97000","97500","98000","98500","99000","99500","100000"];
        setTimeout(function() {
            $('#slider-number-66').slider({
                step: 1,
                min: 0,
                max: 199,
                value: 0,
                change: function (e, ui) {
                    var position = ui.value;
                    if (values != null) {
                        $('#slider-number-66-lbl').text(values[position]);
                        interact(66, {variable: 'number', adapt_number: 13, value: encode64(position)}, 1);
                    }
                },
                slide: function (e, ui) {
                    if (values != null) {
                        $('#slider-number-66-lbl').text(values[ui.value]);
                    }
                }
            });
            if (values != null) {
                $('#slider-number-66-lbl').text(values[$('#slider-number-66').slider('value')]);
            }
        }, 1);
    })();
    </script></td>
</tr></table></td></tr>
              <tr><td></td><td style='width: 100%;'>
        <div id="cell-interact-66"><?__SAGE__START>
          <table border=0 bgcolor="white" width=100%>
            <tr>
              <td bgcolor="white" align=left valign=top>
                <pre><?__SAGE__TEXT></pre>
              </td>
            </tr>
            <tr>
              <td align=left valign=top><?__SAGE__HTML></td>
            </tr>
          </table><?__SAGE__END>
        </div></td><td></td></tr>
              <tr><td colspan=3></td></tr>
            </table></td>
            </tr>
          </table>
        </div></html>
}}}

<h3>Cython</h3>
<p>The Sage-combinat crew has a huge number of good tutorials that are not (yet) in the official Sage documentation. &nbsp;While we're on the subject of prime numbers, <a href="http://combinat.sagemath.org/doc/thematic_tutorials/siena_tutorials/Worksheet10-IntroductionToCython.html" target="_blank">here is one</a> which shows how Cython can be used to speed up calculations of interest.</p>

{{{id=67|
sage: def first_primes_python(m):
...       primes_list = []
...       n = 2
...       while len(primes_list) < m:
...           n_is_prime = True
...           for p in primes_list:
...               if n % p == 0:
...                   n_is_prime = False
...                   break
...           if n_is_prime == True:
...               primes_list.append(n)
...           n = n + 1
...       return primes_list
///
}}}

{{{id=69|
%cython
def first_primes_cython_v1(m):
      primes_list = []
      n = 2
      while len(primes_list) < m:
          n_is_prime = True
          for p in primes_list:
              if n % p == 0:
                  n_is_prime = False
                  break
          if n_is_prime == True:
              primes_list.append(n)
          n = n + 1
      return primes_list
///
}}}

{{{id=70|
time p = first_primes_python(5000)
///
Time: CPU 1.82 s, Wall: 1.82 s
}}}

{{{id=71|
time p = first_primes_cython_v1(5000)
///
Time: CPU 0.45 s, Wall: 0.45 s
}}}

<h3>Formal Power Series in Combinatorics</h3>
<p>It turns out that one can do quite complicated things combining combinatorics and power series within Sage. &nbsp;This example is too long for me to include directly, so let's go to the <a href="../../../doc/live/reference/combinat/sage/combinat/tutorial.html#enumeration-of-trees-using-generating-functions" target="_blank">link</a>! (A world-readable link to a non-live version is <a href="http://www.sagemath.org/doc/reference/combinat/sage/combinat/tutorial.html#enumeration-of-trees-using-generating-functions" target="_blank">here</a>.) &nbsp;</p>
<p>As it says, "Therefore, instead of solving the equation, we look for the equation describing the object which is best suited to the problem we want to solve."</p>

{{{id=72|

///
}}}

<h3>Random Self-Promotion</h3>
<p>I don't have a heading for this, but it just shows that you can do a lot in Sage. &nbsp;This actually has applications in social choice theory, usually considered as a subbranch of economics.</p>

{{{id=74|
d5 = {12345:[12354,12435,13245,15234,13452],12354:[12534,13254,14235,13542],12435:[15243,12453,14352,14235],13245:[15324,12453,13254,13425],15234:[14523,15243,12534,15324],13452:[13425,13542,14523,14352],15432:[15423,15342,14532,14325,12543],12543:[13254,15243,12534,12453],14325:[14352,14235,13254,13425],14532:[15324,14352,12453,14523],15342:[13425,15324,12534,13542],15423:[15243,14235,14523,13542],13524:[13542,15243,13254,14352,15324],14253:[12534,12453,14523,14235,13425]}
G5 = Graph(d5)
///
}}}

{{{id=75|
plot(G5,figsize=4)
///
<html><font color='black'><img src='cell://sage0.png'></font></html>
}}}

{{{id=76|
Gp5 = G5.automorphism_group()
print Gp5.order()
///
480
}}}

{{{id=77|
Gp5.character_table()
///
[                         1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1                          1]
[                         1                         -1                          1                          1                         -1                          1                         -1                         -1                          1                          1                          1                          1                         -1                         -1                          1                          1                          1                          1                          1]
[                         1                         -1                          1                          1                          1                         -1                          1                          1                         -1                         -1                          1                          1                         -1                         -1                          1                          1                         -1                         -1                          1]
[                         1                          1                          1                          1                         -1                         -1                         -1                         -1                         -1                         -1                          1                          1                          1                          1                          1                          1                         -1                         -1                          1]
[                         2                          0                         -2                          2                          0                          0                          0                          0                          0                          0                          2                         -2                          0                          0                         -2                          2                          0                          0                         -2]
[                         4                          0                          0                         -1                         -2                          0                          1                          0                         -1                          1                          1                          1                          2                         -1                         -1                          0                          1                         -4                          4]
[                         4                          0                          0                         -1                         -2                          0                          1                          0                          1                         -1                          1                          1                         -2                          1                         -1                          0                         -1                          4                          4]
[                         4                          0                          0                         -1                          2                          0                         -1                          0                         -1                          1                          1                          1                         -2                          1                         -1                          0                          1                         -4                          4]
[                         4                          0                          0                         -1                          2                          0                         -1                          0                          1                         -1                          1                          1                          2                         -1                         -1                          0                         -1                          4                          4]
[                         5                         -1                          1                          0                         -1                         -1                         -1                          1                          1                          0                         -1                         -1                          1                          1                          0                          1                          0                         -5                          5]
[                         5                         -1                          1                          0                          1                          1                          1                         -1                         -1                          0                         -1                         -1                          1                          1                          0                          1                          0                          5                          5]
[                         5                          1                          1                          0                         -1                          1                         -1                          1                         -1                          0                         -1                         -1                         -1                         -1                          0                          1                          0                          5                          5]
[                         5                          1                          1                          0                          1                         -1                          1                         -1                          1                          0                         -1                         -1                         -1                         -1                          0                          1                          0                         -5                          5]
[                         6                          0                         -2                          1                          0                         -2                          0                          0                          0                          1                          0                          0                          0                          0                          1                         -2                          1                          6                          6]
[                         6                          0                         -2                          1                          0                          2                          0                          0                          0                         -1                          0                          0                          0                          0                          1                         -2                         -1                         -6                          6]
[                         6                          0                          2                          1                          0                          0                          0                          0                          0  2*zeta5^3 + 2*zeta5^2 + 1                          0                          0                          0                          0                         -1                         -2 -2*zeta5^3 - 2*zeta5^2 - 1                          0                         -6]
[                         6                          0                          2                          1                          0                          0                          0                          0                          0 -2*zeta5^3 - 2*zeta5^2 - 1                          0                          0                          0                          0                         -1                         -2  2*zeta5^3 + 2*zeta5^2 + 1                          0                         -6]
[                         8                          0                          0                         -2                          0                          0                          0                          0                          0                          0                          2                         -2                          0                          0                          2                          0                          0                          0                         -8]
[                        10                          0                         -2                          0                          0                          0                          0                          0                          0                          0                         -2                          2                          0                          0                          0                          2                          0                          0                        -10]
}}}

{{{id=78|
Chars5 = Gp5.irreducible_characters()
CCRs5 = Gp5.conjugacy_classes_representatives()
P5 = [sum([len(z) for z in x.cycle_tuples(True) if len(z)==1]) for x in CCRs5]
for ch in Chars5:
    mysum = 0
    for i in range(19):
        mysum += P5[i]*ch.values()[i] * 480 / Gp5.centralizer(CCRs5[i]).order()
    print mysum/480
///
1
0
0
1
0
0
0
0
0
0
0
1
1
0
0
1
1
0
0
}}}

<p>To me, this is basically magic. &nbsp;I hope you will enjoy similar magical experiences with Sage!</p>

{{{id=79|

///
}}}