Concrete Mathematics, Spiced with Sage, Part 1 Robert A. Beezer University of Puget Sound University of Victoria, CS 582/482 May 20, 2012

1. An open source system for advanced mathematics.
2. An open source mathematics distribution (like Linux) with Python as the glue.
3. A tool for learning and teaching mathematics.
4. A tool for mathematics research. Mission Statement
Create a viable free open source alternative to Magma, Maple, Mathematica, and Matlab.

• Created in 2005 by William Stein.
• Free and open, GPL license.
• Includes about 100 open source packages.
• Now has around 500,000 lines of new code, by several hundred mathematician-programmers.

Some of the 100 packages included:

• Groups, Algorithms, Programming (GAP) - group theory
• PARI - rings, finite fields, field extensions
• Singular - commutative algebra
• SciPy/NumPy - scientific computing, numerical linear algebra
• Integer Matrix Library (IML) - integer, rational matrices
• CVXOPT - linear programming, optimization
• NetworkX - graph theory
• Pynac - symbolic manipulation
• Maxima - calculus, differential equations

The Sage Notebook is a web application that provides a convenient interface to Sage commands, components and features.

A symbolic derivative (from Maxima).

f(x) = x^3*e^-x df = f.derivative() df

Derivative of a function is again a function, and can be evaluated.

slope = df(4) slope

Arbitrary precision numerical values on request (from MPmath).

N(slope, digits=20)

Can display plots in the notebook (matplotlib).

plot(df, 0, 10, color='red', thickness=5)

Study the multivariate integral $\displaystyle\int_{-4}^4\int_0^{x^2} y^2-10x^2\,dy\,dx$.

var('x y z') integral(integral(y^2-10*x^2, (y, 0, x^2)), (x, -4, 4)) surface = plot3d(y^2-10*x^2, (x, -4, 4), (y, 0, 16)) show(surface) region = implicit_plot3d(y-x^2, (x, -4, 4), (y, 0, 16), (z, 0, 98), color='red', opacity=0.20) show(surface+region)

Interactive demonstrations are easy to create with the interact decorator and modified function arguments.

@interact def plotter(maxdegree=range(2,40)): import sage.plot.colors colors = sage.plot.colors.rainbow(maxdegree+1) var('x') wholeplot = plot(x^1, (x, 0, 1), color=colors) for i in range(2, maxdegree+1): newplot = plot(x^i, (x, 0, 1), color=colors[i]) wholeplot = wholeplot + newplot show(wholeplot) @interact def taylor(order=slider(1, 12, 1, default=Integer(2), label="Degree of polynomial $\hat{f}$")): var('x') x0 = 0 f = sin(x)*e^(-x) p = plot(f, -1, 5, thickness=2) dot = point((x0,f(x=x0)), pointsize=80, rgbcolor=(1,0,0)) ft = f.taylor(x, x0 ,order) pt = plot(ft, -1, 5, color='green', thickness=2) html("Taylor series approximation to ${0}$ of degree {1} at $x={2}$".format(latex(f), Integer(order), x0) ) show(dot + p + pt, ymin = -0.5, ymax = 1)

Exclusive of combinatorics (see Part 2).

Prototypical use of Sage: permutation groups. Built from the mature open source package GAP (Groups, Algorithms, Programming).

G = DihedralGroup(8) G G.list() G.is_abelian() sg = G.subgroups() [H.order() for H in sg] H = sg H.list() H.is_normal(G)

Create graphs in a natural way:

harary = Graph([(0,1), (1,2), (2,3), (3,0), (1,3)]) harary harary.plot() harary.num_verts(), harary.num_edges() harary.is_planar() H = harary.hamiltonian_cycle() H.plot() harary.degree_sequence() sorted(harary.degree_sequence())

There are many pre-defined graphs (digraphs, too):

graphs.

Constant time generation of free trees, by B. Richmond, A. Odlyzko, B.D. McKay

trees_iterator = graphs.trees(8) T8 = list(trees_iterator) T8

From a path to a star:

[tree.diameter() for tree in T8] Visually: graphs_list.show_graphs(T8) • graphs.HanoiTowerGraph(n, d)
• Generalize to $n$ pegs and $d$ disks
• State graph: intermediate configurations, edges are one move
• Labels: $d$-tuple, large disk to small disk; entries are peg numbers
• Example: $n=3$, $d=4$: $(2,0,2,1)$

T = graphs.HanoiTowerGraph(3, 4, positions=True) T.show(figsize=12)

A solution is path between states all the disks on one peg'' and all the disks on another peg.''

solution=T.shortest_path((0,0,0,0), (1,1,1,1)) solution

Minimum number of moves:

len(solution) - 1 T.diameter()

More general:

T = graphs.HanoiTowerGraph(4, 3, positions=True) T.show(figsize=12) T = graphs.HanoiTowerGraph(4, 4, labels=False, positions=True) T.show(figsize=12)

Forget about graphics, work with graph itself.

T = graphs.HanoiTowerGraph(4, 8, labels=False, positions=False) T.num_verts()

Code vertices to integers: $d$-tuples, base $n$. All disks on peg 0, move to all disks on peg 3.

solution = T.shortest_path(0, 4^8-1) solution len(solution)-1

Theorem: automorphisms of the state graph are just the obvious ones (renumber pegs)

T = graphs.HanoiTowerGraph(4, 6, labels=False, positions=False) A = T.automorphism_group() A.order() S4 = SymmetricGroup(4) S4.is_isomorphic(A)

Automorphisms are computed via Brendan McKay's nauty algorithm, re-implemented as NICE.

Many possible fields and rings: finite fields, field extensions, algebraic numbers.

A = matrix(QQ, [[1, -2, 3, 2, -1, -4, -3, 4], [3, -2, 2, 5, 0, 6, -5, -5], [0, -1, 2, 1, -2, -4, -1, 4], [-3, 2, -1, -1, -6, -3, 5, 3], [3, -4, 4, 0, 7, -7, -7, 6]]) A A.rref() b = vector(QQ, [2, -1, 3, 4, -3]) A.solve_right(b)

And it is fast.

A = random_matrix(ZZ, 1000, 1000) time A.determinant()

We can combine linear algebra with graph theory (aka algebraic graph theory).

A small singular graph. (I. Sciriha, 2007)

Notice this is the kernel over the integers, and is computed as a module. It is easy to upgrade to the rationals.

A matrix kernel (null space) is a vector space, and has all the attendant properties.

kerQ.dimension() kerQ.basis()

Numerical linear algebra is supplied by SciPy, through to LAPACK, ATLAS, BLAS.

A matrix of double-floating point real numbers (RDF).

B = matrix(RDF, [[0.4706, 0.3436, 0.7156, 0.1706, 0.3863, 0.222, -0.9673], [0.9433, -0.7333, -0.2906, -0.5203, 0.3548, 0.7577, 0.3936], [-0.8998, 0.9269, -0.9646, -0.2294, -0.8171, 0.4568, 0.5949], [0.8814, 0.89, -0.2059, 0.7434, -0.1642, 0.6918, 0.7113], [-0.0034, -0.9842, 0.7213, -0.7196, -0.7422, 0.3335, 0.5829], [-0.5676, 0.6433, -0.2296, 0.2681, 0.2992, 0.6988, 0.3332], [0.0366, -0.5788, 0.5882, 0.1559, -0.6434, 0.871, -0.6518]]) B

And the QR decomposition of B.

Q, R = B.QR() Q (Q.conjugate_transpose()*Q).round(4) R.round(4) (Q*R-B).round(4)
import pylab A_image = pylab.mean(pylab.imread(DATA + 'mystery.png'), 2) @interact def svd_image(i=(1,(1..50)), display_axes=True): 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)) # g = graphics_array([matrix_plot(A),matrix_plot(A_image)]) show(matrix_plot(A), axes=display_axes, figsize=(6,8)) html('

## Compressed using %s singular values

'%i)

$\dots$is superb.

latex(integrate(sec(x), x)) A = random_matrix(QQ, 6, num_bound=9, den_bound=9) latex(A)

With "typeset" button checked.

A = random_matrix(QQ, 6, num_bound=9, den_bound=9) A

Note to self: un-check "typeset" button.

P = graphs.PetersenGraph() P.set_latex_options(vertex_shape='diamond', vertex_color='red', vertex_label_color='gold', edge_color='blue') latex(P)

Shift-Click on blue bar to activate. TeX-aware.

We can add text to our notebooks using TeX syntax and dollar signs. Previous multivariate integral:

\int_0^4\int_0^{x^2} y^2-10x^2\,dy\,dx

Can embed images this way also.

SageTeX allows you to call Sage to compute values, expressions or plots for automatic inclusion in your LaTeX document. (And will write your papers for you!)

LaTeX source: Today's date, 2012-05-22 = 20120522, factors as \sage{factor(20110212)}.

Final Document: Today's date, 2012-05-22 = 20120522, factors as $2 \cdot 338 \cdot 26267$.

Can author in the worksheet or in LaTeX, ReStructured Text, XML to produce worksheets (this is an example).

A huge number of examples are provided for (a) learning to use Sage commands, and (b) to test Sage commands. We call these doctests.''

M = matrix(QQ, [[1, -2, 2], [-4, 5, 6], [1, 2, 4]]) M

Illustrate tab-completion (rational form), help (doctests, zig-zag form), source code.

M.

A Sage-inspired project to convert Python to C, then compile.

Factorial, Python-style.

def py_fact(n): fact = 1 for i in range(n): fact = fact*(i+1) return fact py_fact(12) timeit('py_fact(12)')