Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Project: SageDays78
Views: 431

Sage Beginner's Workshop

This is an introduction to the basic functionality of Sage, with an emphasis on seeing how to handle a worksheet and how to get more detailed help. We will point out a little bit of the power that Sage has hiding in it, but this is not a full-fledged tutorial. Down at the bottom of the page you will find links to some more resources.


Note that this worksheet is based upon an earlier one by Theron Hitchman. That worksheet, available here, was designed for the Sage Notebook interface. This one is written with the SageMathCloud worksheet style in mind. Other contributors include: Harald Schilly, Gustav Delius.

Worksheet Basics

The first thing to note is that a worksheet is made up of "cells." These are where you will do your programming. To evaluate a cell, you press [Shift]+[Enter]. Try it now in the cell below. Add 5 and 4.
5+4
9

Note that the output is marked by a grey parenthesis on the left near the line numbers, and the inputs are separated by thin, grey horizontal rulings. Also, the active cell has a light grey background cell.

Another way to evaluate a cell is to use the "run" button at the top of the worksheet. Depending on the width of your display, this button may or may not have the word "run" on it. If not, just look for the triangle pointing to the right.

Try that version now with the simple computation below.

67-5
62

To keep things rolling, you will often need to create new cells. At the end of a worksheet this is done automatically: there is always a set of blank lines at the bottom of a .sagews file. If you somehow manage to evaluate the last line, the page should refresh with a new blank line below the output.

The other way to make a new cell also works in the middle of a worksheet. Use your mouse or trackpad to hover over one of the thin grey horizontal rulings which separate cells. The ruling should get highlighted in blue. At this point, clicking the highlighted ruling will create a new cell directly below that ruling.

Try it now. Make a new cell between the ones below.

print('Do not touch this cell. Make a new one just below it!')
Do not touch this cell. Make a new one just below it!
print("Hello Sage Days!")
Hello Sage Days!

It is possible to delete input cells, too. To do so, simply empty the cell and press [Backspace] or [Delete] in the active, empty cell. Try deleting a one or two of the cells just below.

Note that pressing [Backspace] at the beginning of a cell will also remove the horizontal bar between cells. This joins the two input cells into a single one. That trick might be useful to you at some point.

"not empty, empty me first to delete me"

It is useful to annotate your work by typing text right into the page. To do this, you can use two methods.

  • HTML: If you open a cell with the “decorator” as the first line, the worksheet will evaluate the rest of the cell by parsing it as html.

  • Markdown: If you open a cell with the “decorator” as the first line, the worksheet will evaluate that cell by interpreting the input following the Markdown specification, converting it to html, and displaying the html as output.

If you don’t know either, basic Markdown is easy to learn. Even if you don’t learn it, paragraphs typed in markdown will display roughly how you want them on this page.

After evaluation, the input for a Markdown or html cell will automatically hide. To reopen the input for editing, simply double click the displayed output. The text in this page has been generated with a mix of these two approaches, so you can double click them to see some examples of how this works.

Sage as a Calculator

Arithmetic works just as you would expect. The basic operations are + for addition, - for subtraction, * for multiplication, / for division, and ^ for exponentiation. Try that out now. Make some cells and evaluate some basic arithmetic operations.

Note that sage tries to remember what kind of object you are working with, so 4/5 is kept as a rational number in that form: 4/5. But if you give it a decimal expression, Sage will use finite precision arithmetic.

If you want to get a numerical (decimal) approximation to a number that is expressed differently, you can use the .n() method. This method has an option to change how many digits you want displayed. Here are some examples, all in a line. [This demonstrates how to get one compute cell to display several computations—separate them by semicolons.]

4/5; .75; (4/5).n(); pi.n(digits=300)
4/5 0.750000000000000 0.800000000000000 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127

Sage can also be used as a symbolic calculator. (It is a computer algebra system, after all.) For this to work, you have to tell Sage the names of things it should consider as symbolic variables. After that, you can create an manipulate expressions in a variety of ways.

x = var('x') expr = 1 / (1-x^2) show(expr)
1x21\displaystyle -\frac{1}{x^{2} - 1}

In this case, the method tells Sage to display the output nicely using LaTeX\LaTeX{}.

expr2 = - expr + expr^3 show(expr2)
1x211(x21)3\displaystyle \frac{1}{x^{2} - 1} - \frac{1}{{\left(x^{2} - 1\right)}^{3}}

An important part of Sage’s capabilities for symbolic expressions is the ability to simplify.

show(expr2.simplify_rational())
x42x2x63x4+3x21\displaystyle \frac{x^{4} - 2 \, x^{2}}{x^{6} - 3 \, x^{4} + 3 \, x^{2} - 1}

Of course, you can evaluate an expression by making a substitution of particular values for a variable, too.

expr2.subs(x = pi); expr2.subs(x = pi).n()
1/(pi^2 - 1) - 1/(pi^2 - 1)^3 0.111311464472836

How do I get help?

There are several methods for getting help while using a Sage worksheet. The most obvious one is to click the Help icon in the top left corner of the page. This takes you to the Sage documentation. Almost everything you want to know can be found there in one way or another. I say almost because Sage is an open-source project maintained by a community of mathematicians across teh world. Some people are better than others at writing documentation. Also, it is a bit intimidating that "Almost everything you ever need to know" is there! Sage is a large project with a lot of power and functionality. It can be difficult to find the thing you need unless you know how to look for it.

Thankfully, the Sage Developers have incorporated other ways to get help. The first option is called "Tab Completion." You can type part of a command and then hit the [Tab] key to get a menu of possible commands that start that way. Let's try it. In the next cell, type

then hit the [Tab] key. After you are done looking, press [Escape] to leave the pop-up menu.

A = macaulay2

Notice that there are quite a few commands that start with “ma”. We want the one for a matrix. Can you find it?

Define a matrix called A by typing the following in the next cell, and then evaluating it.

A = matrix([[1,2],[3,4]])
A
[1 2] [3 4]
A.dense_rows??
File: /projects/sage/sage-6.10/src/sage/matrix/matrix1.pyx Source: def dense_rows(self, copy=True): """ Return list of the dense rows of self. INPUT: - ``copy`` - (default: True) if True, return a copy so you can modify it safely (note that the individual vectors in the copy should not be modified since they are mutable!) EXAMPLES:: sage: m = matrix(3, range(9)); m [0 1 2] [3 4 5] [6 7 8] sage: v = m.dense_rows(); v [(0, 1, 2), (3, 4, 5), (6, 7, 8)] sage: v is m.dense_rows() False sage: m.dense_rows(copy=False) is m.dense_rows(copy=False) True sage: m[0,0] = 10 sage: m.dense_rows() [(10, 1, 2), (3, 4, 5), (6, 7, 8)] TESTS: Check that the returned rows are immutable as per :trac:`14874`:: sage: m = Mat(ZZ,3,3)(range(9)) sage: v = m.dense_rows() sage: map(lambda x: x.is_mutable(), v) [False, False, False] """ x = self.fetch('dense_rows') if not x is None: if copy: return list(x) return x cdef Py_ssize_t i A = self if self.is_dense() else self.dense_matrix() R = [A.row(i) for i in range(self._nrows)] # Make the vectors immutable since we are caching them map(lambda x: x.set_immutable(), R) # cache result self.cache('dense_rows', R) if copy: return list(R) else: return R
%md Nothing seems to happen. Sage made the matrix and put it in memory, but did not print it out. To see it, simply type A in a cell and evaluate.

Nothing seems to happen. Sage made the matrix and put it in memory, but did not print it out. To see it, simply type A in a cell and evaluate.

There is a fundamental number attached to each matrix called its “rank.” Sage has a way to compute the rank built in. Like most built-in methods, you can access this function in two ways. First type

and evaluate. Then make a new cell and type

and evaluate. Both times you should get the number 2 as output.

What else can you do with a matrix? Sage thinks like a mathematician! In particular, it attaches “methods” to “objects” depending on their “type.”

To see all of the methods attached to an object, you can use the “dot-[Tab]” approach. Type (notice the period!) then press [Tab] to get a list of all the methods attached to the matrix A. Sage knows a lot of linear algebra, so the menu will be very big.

The other ways to get help involve using the question mark key. First, a command name followed by a question mark will evaluate to the documentation for that command.

I left the matrix command a little mysterious above. To see why I had you type it like that, evaluate this in the next cell.

To get more information, you can use the double question mark. When you evaluate the command “matrix??” you will get the Sage source code for how the matrix command works! I don’t use this very often, but if you think you find a bug in Sage, this is the place to start looking. Try it tnow to see what it looks like. Evaluate

matrix??
File: /projects/sage/sage-6.10/local/lib/python2.7/site-packages/sage/matrix/constructor.py Source: def _matrix_constructor(*args, **kwds): """ Create a matrix. This implements the ``matrix`` constructor:: sage: matrix([[1,2],[3,4]]) [1 2] [3 4] It also contains methods to create special types of matrices, see ``matrix.[tab]`` for more options. For example:: sage: matrix.identity(2) [1 0] [0 1] INPUT: The matrix command takes the entries of a matrix, optionally preceded by a ring and the dimensions of the matrix, and returns a matrix. The entries of a matrix can be specified as a flat list of elements, a list of lists (i.e., a list of rows), a list of Sage vectors, a callable object, or a dictionary having positions as keys and matrix entries as values (see the examples). If you pass in a callable object, then you must specify the number of rows and columns. You can create a matrix of zeros by passing an empty list or the integer zero for the entries. To construct a multiple of the identity (`cI`), you can specify square dimensions and pass in `c`. Calling matrix() with a Sage object may return something that makes sense. Calling matrix() with a NumPy array will convert the array to a matrix. The ring, number of rows, and number of columns of the matrix can be specified by setting the ring, nrows, or ncols parameters or by passing them as the first arguments to the function in the order ring, nrows, ncols. The ring defaults to ZZ if it is not specified or cannot be determined from the entries. If the numbers of rows and columns are not specified and cannot be determined, then an empty 0x0 matrix is returned. - ``ring`` - the base ring for the entries of the matrix. - ``nrows`` - the number of rows in the matrix. - ``ncols`` - the number of columns in the matrix. - ``sparse`` - create a sparse matrix. This defaults to True when the entries are given as a dictionary, otherwise defaults to False. OUTPUT: a matrix EXAMPLES:: sage: m=matrix(2); m; m.parent() [0 0] [0 0] Full MatrixSpace of 2 by 2 dense matrices over Integer Ring :: sage: m=matrix(2,3); m; m.parent() [0 0 0] [0 0 0] Full MatrixSpace of 2 by 3 dense matrices over Integer Ring :: sage: m=matrix(QQ,[[1,2,3],[4,5,6]]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Rational Field :: sage: m = matrix(QQ, 3, 3, lambda i, j: i+j); m [0 1 2] [1 2 3] [2 3 4] sage: m = matrix(3, lambda i,j: i-j); m [ 0 -1 -2] [ 1 0 -1] [ 2 1 0] :: sage: matrix(QQ,2,3,lambda x, y: x+y) [0 1 2] [1 2 3] sage: matrix(QQ,3,2,lambda x, y: x+y) [0 1] [1 2] [2 3] :: sage: v1=vector((1,2,3)) sage: v2=vector((4,5,6)) sage: m=matrix([v1,v2]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Integer Ring :: sage: m=matrix(QQ,2,[1,2,3,4,5,6]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Rational Field :: sage: m=matrix(QQ,2,3,[1,2,3,4,5,6]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Rational Field :: sage: m=matrix({(0,1): 2, (1,1):2/5}); m; m.parent() [ 0 2] [ 0 2/5] Full MatrixSpace of 2 by 2 sparse matrices over Rational Field :: sage: m=matrix(QQ,2,3,{(1,1): 2}); m; m.parent() [0 0 0] [0 2 0] Full MatrixSpace of 2 by 3 sparse matrices over Rational Field :: sage: import numpy sage: n=numpy.array([[1,2],[3,4]],float) sage: m=matrix(n); m; m.parent() [1.0 2.0] [3.0 4.0] Full MatrixSpace of 2 by 2 dense matrices over Real Double Field :: sage: v = vector(ZZ, [1, 10, 100]) sage: m=matrix(v); m; m.parent() [ 1 10 100] Full MatrixSpace of 1 by 3 dense matrices over Integer Ring sage: m=matrix(GF(7), v); m; m.parent() [1 3 2] Full MatrixSpace of 1 by 3 dense matrices over Finite Field of size 7 :: sage: g = graphs.PetersenGraph() sage: m = matrix(g); m; m.parent() [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] [0 0 1 0 1 0 0 0 1 0] [1 0 0 1 0 0 0 0 0 1] [1 0 0 0 0 0 0 1 1 0] [0 1 0 0 0 0 0 0 1 1] [0 0 1 0 0 1 0 0 0 1] [0 0 0 1 0 1 1 0 0 0] [0 0 0 0 1 0 1 1 0 0] Full MatrixSpace of 10 by 10 dense matrices over Integer Ring :: sage: matrix(ZZ, 10, 10, range(100), sparse=True).parent() Full MatrixSpace of 10 by 10 sparse matrices over Integer Ring :: sage: R = PolynomialRing(QQ, 9, 'x') sage: A = matrix(R, 3, 3, R.gens()); A [x0 x1 x2] [x3 x4 x5] [x6 x7 x8] sage: det(A) -x2*x4*x6 + x1*x5*x6 + x2*x3*x7 - x0*x5*x7 - x1*x3*x8 + x0*x4*x8 TESTS:: sage: m=matrix(); m; m.parent() [] Full MatrixSpace of 0 by 0 dense matrices over Integer Ring sage: m=matrix(QQ); m; m.parent() [] Full MatrixSpace of 0 by 0 dense matrices over Rational Field sage: m=matrix(QQ,2); m; m.parent() [0 0] [0 0] Full MatrixSpace of 2 by 2 dense matrices over Rational Field sage: m=matrix(QQ,2,3); m; m.parent() [0 0 0] [0 0 0] Full MatrixSpace of 2 by 3 dense matrices over Rational Field sage: m=matrix([]); m; m.parent() [] Full MatrixSpace of 0 by 0 dense matrices over Integer Ring sage: m=matrix(QQ,[]); m; m.parent() [] Full MatrixSpace of 0 by 0 dense matrices over Rational Field sage: m=matrix(2,2,1); m; m.parent() [1 0] [0 1] Full MatrixSpace of 2 by 2 dense matrices over Integer Ring sage: m=matrix(QQ,2,2,1); m; m.parent() [1 0] [0 1] Full MatrixSpace of 2 by 2 dense matrices over Rational Field sage: m=matrix(2,3,0); m; m.parent() [0 0 0] [0 0 0] Full MatrixSpace of 2 by 3 dense matrices over Integer Ring sage: m=matrix(QQ,2,3,0); m; m.parent() [0 0 0] [0 0 0] Full MatrixSpace of 2 by 3 dense matrices over Rational Field sage: m=matrix([[1,2,3],[4,5,6]]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Integer Ring sage: m=matrix(QQ,2,[[1,2,3],[4,5,6]]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Rational Field sage: m=matrix(QQ,3,[[1,2,3],[4,5,6]]); m; m.parent() Traceback (most recent call last): ... ValueError: Number of rows does not match up with specified number. sage: m=matrix(QQ,2,3,[[1,2,3],[4,5,6]]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Rational Field sage: m=matrix(QQ,2,4,[[1,2,3],[4,5,6]]); m; m.parent() Traceback (most recent call last): ... ValueError: Number of columns does not match up with specified number. sage: m=matrix([(1,2,3),(4,5,6)]); m; m.parent() [1 2 3] [4 5 6] Full MatrixSpace of 2 by 3 dense matrices over Integer Ring sage: m=matrix([1,2,3,4,5,6]); m; m.parent() [1 2 3 4 5 6] Full MatrixSpace of 1 by 6 dense matrices over Integer Ring sage: m=matrix((1,2,3,4,5,6)); m; m.parent() [1 2 3 4 5 6] Full MatrixSpace of 1 by 6 dense matrices over Integer Ring sage: m=matrix(QQ,[1,2,3,4,5,6]); m; m.parent() [1 2 3 4 5 6] Full MatrixSpace of 1 by 6 dense matrices over Rational Field sage: m=matrix(QQ,3,2,[1,2,3,4,5,6]); m; m.parent() [1 2] [3 4] [5 6] Full MatrixSpace of 3 by 2 dense matrices over Rational Field sage: m=matrix(QQ,2,4,[1,2,3,4,5,6]); m; m.parent() Traceback (most recent call last): ... ValueError: entries has the wrong length sage: m=matrix(QQ,5,[1,2,3,4,5,6]); m; m.parent() Traceback (most recent call last): ... TypeError: cannot construct an element of Full MatrixSpace of 5 by 1 dense matrices over Rational Field from [1, 2, 3, 4, 5, 6]! sage: m=matrix({(1,1): 2}); m; m.parent() [0 0] [0 2] Full MatrixSpace of 2 by 2 sparse matrices over Integer Ring sage: m=matrix(QQ,{(1,1): 2}); m; m.parent() [0 0] [0 2] Full MatrixSpace of 2 by 2 sparse matrices over Rational Field sage: m=matrix(QQ,3,{(1,1): 2}); m; m.parent() [0 0 0] [0 2 0] [0 0 0] Full MatrixSpace of 3 by 3 sparse matrices over Rational Field sage: m=matrix(QQ,3,4,{(1,1): 2}); m; m.parent() [0 0 0 0] [0 2 0 0] [0 0 0 0] Full MatrixSpace of 3 by 4 sparse matrices over Rational Field sage: m=matrix(QQ,2,{(1,1): 2}); m; m.parent() [0 0] [0 2] Full MatrixSpace of 2 by 2 sparse matrices over Rational Field sage: m=matrix(QQ,1,{(1,1): 2}); m; m.parent() Traceback (most recent call last): ... IndexError: invalid entries list sage: m=matrix({}); m; m.parent() [] Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring sage: m=matrix(QQ,{}); m; m.parent() [] Full MatrixSpace of 0 by 0 sparse matrices over Rational Field sage: m=matrix(QQ,2,{}); m; m.parent() [0 0] [0 0] Full MatrixSpace of 2 by 2 sparse matrices over Rational Field sage: m=matrix(QQ,2,3,{}); m; m.parent() [0 0 0] [0 0 0] Full MatrixSpace of 2 by 3 sparse matrices over Rational Field sage: m=matrix(2,{}); m; m.parent() [0 0] [0 0] Full MatrixSpace of 2 by 2 sparse matrices over Integer Ring sage: m=matrix(2,3,{}); m; m.parent() [0 0 0] [0 0 0] Full MatrixSpace of 2 by 3 sparse matrices over Integer Ring sage: m=matrix(0); m; m.parent() [] Full MatrixSpace of 0 by 0 dense matrices over Integer Ring sage: m=matrix(0,2); m; m.parent() [] Full MatrixSpace of 0 by 2 dense matrices over Integer Ring sage: m=matrix(2,0); m; m.parent() [] Full MatrixSpace of 2 by 0 dense matrices over Integer Ring sage: m=matrix(0,[1]); m; m.parent() Traceback (most recent call last): ... ValueError: entries has the wrong length sage: m=matrix(1,0,[]); m; m.parent() [] Full MatrixSpace of 1 by 0 dense matrices over Integer Ring sage: m=matrix(0,1,[]); m; m.parent() [] Full MatrixSpace of 0 by 1 dense matrices over Integer Ring sage: m=matrix(0,[]); m; m.parent() [] Full MatrixSpace of 0 by 0 dense matrices over Integer Ring sage: m=matrix(0,{}); m; m.parent() [] Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring sage: m=matrix(0,{(1,1):2}); m; m.parent() Traceback (most recent call last): ... IndexError: invalid entries list sage: m=matrix(2,0,{(1,1):2}); m; m.parent() Traceback (most recent call last): ... IndexError: invalid entries list sage: import numpy sage: n=numpy.array([[numpy.complex(0,1),numpy.complex(0,2)],[3,4]],complex) sage: m=matrix(n); m; m.parent() [1.0*I 2.0*I] [ 3.0 4.0] Full MatrixSpace of 2 by 2 dense matrices over Complex Double Field sage: n=numpy.array([[1,2],[3,4]],'int32') sage: m=matrix(n); m; m.parent() [1 2] [3 4] Full MatrixSpace of 2 by 2 dense matrices over Integer Ring sage: n = numpy.array([[1,2,3],[4,5,6],[7,8,9]],'float32') sage: m=matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Real Double Field sage: n=numpy.array([[1,2,3],[4,5,6],[7,8,9]],'float64') sage: m=matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Real Double Field sage: n=numpy.array([[1,2,3],[4,5,6],[7,8,9]],'complex64') sage: m=matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Complex Double Field sage: n=numpy.array([[1,2,3],[4,5,6],[7,8,9]],'complex128') sage: m=matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Complex Double Field sage: a = matrix([[1,2],[3,4]]) sage: b = matrix(a.numpy()); b [1 2] [3 4] sage: a == b True sage: c = matrix(a.numpy('float32')); c [1.0 2.0] [3.0 4.0] sage: matrix(numpy.array([[5]])) [5] sage: v = vector(ZZ, [1, 10, 100]) sage: m=matrix(ZZ['x'], v); m; m.parent() [ 1 10 100] Full MatrixSpace of 1 by 3 dense matrices over Univariate Polynomial Ring in x over Integer Ring sage: matrix(ZZ, 10, 10, range(100)).parent() Full MatrixSpace of 10 by 10 dense matrices over Integer Ring sage: m = matrix(GF(7), [[1/3,2/3,1/2], [3/4,4/5,7]]); m; m.parent() [5 3 4] [6 5 0] Full MatrixSpace of 2 by 3 dense matrices over Finite Field of size 7 sage: m = matrix([[1,2,3], [RDF(2), CDF(1,2), 3]]); m; m.parent() [ 1.0 2.0 3.0] [ 2.0 1.0 + 2.0*I 3.0] Full MatrixSpace of 2 by 3 dense matrices over Complex Double Field sage: m=matrix(3,3,1/2); m; m.parent() [1/2 0 0] [ 0 1/2 0] [ 0 0 1/2] Full MatrixSpace of 3 by 3 dense matrices over Rational Field sage: matrix([[1],[2,3]]) Traceback (most recent call last): ... ValueError: List of rows is not valid (rows are wrong types or lengths) sage: matrix([[1],2]) Traceback (most recent call last): ... ValueError: List of rows is not valid (rows are wrong types or lengths) sage: matrix(vector(RR,[1,2,3])).parent() Full MatrixSpace of 1 by 3 dense matrices over Real Field with 53 bits of precision sage: matrix(ZZ, [[0] for i in range(10^5)]).is_zero() # see #10158 True AUTHORS: - ??: Initial implementation - Jason Grout (2008-03): almost a complete rewrite, with bits and pieces from the original implementation """ args = list(args) sparse = kwds.get('sparse',False) # if the first object already knows how to make itself into a # matrix, try that, defaulting to a matrix over the integers. if len(args) == 1 and hasattr(args[0], '_matrix_'): try: return args[0]._matrix_(sparse=sparse) except TypeError: return args[0]._matrix_() elif len(args) == 2: if hasattr(args[0], '_matrix_'): try: return args[0]._matrix_(args[1], sparse=sparse) except TypeError: return args[0]._matrix_(args[1]) elif hasattr(args[1], '_matrix_'): try: return args[1]._matrix_(args[0], sparse=sparse) except TypeError: return args[1]._matrix_(args[0]) if len(args) == 0: # if nothing was passed return the empty matrix over the # integer ring. return matrix_space.MatrixSpace(rings.ZZ, 0, 0, sparse=sparse)([]) if len(args) >= 1 and is_Ring(args[0]): # A ring is specified if kwds.get('ring', args[0]) != args[0]: raise ValueError("Specified rings are not the same") else: ring = args[0] args.pop(0) else: ring = kwds.get('ring', None) if len(args) >= 1: # check to see if the number of rows is specified try: import numpy if isinstance(args[0], numpy.ndarray): raise TypeError nrows = int(args[0]) args.pop(0) if kwds.get('nrows', nrows) != nrows: raise ValueError("Number of rows specified in two places and they are not the same") except TypeError: nrows = kwds.get('nrows', None) else: nrows = kwds.get('nrows', None) if len(args) >= 1: # check to see if additionally, the number of columns is specified try: import numpy if isinstance(args[0], numpy.ndarray): raise TypeError ncols = int(args[0]) args.pop(0) if kwds.get('ncols', ncols) != ncols: raise ValueError("Number of columns specified in two places and they are not the same") except TypeError: ncols = kwds.get('ncols', None) else: ncols = kwds.get('ncols', None) # Now we've taken care of initial ring, nrows, and ncols arguments. # We've also taken care of the Sage object case. # Now the rest of the arguments are a list of rows, a flat list of # entries, a callable, a dict, a numpy array, or a single value. if len(args) == 0: # If no entries are specified, pass back a zero matrix entries = 0 entry_ring = rings.ZZ elif len(args) == 1: if isinstance(args[0], (types.FunctionType, types.LambdaType, types.MethodType)): if ncols is None and nrows is None: raise ValueError("When passing in a callable, the dimensions of the matrix must be specified") if ncols is None: ncols = nrows elif nrows is None: nrows = ncols f = args[0] args[0] = [[f(i,j) for j in range(ncols)] for i in range(nrows)] if isinstance(args[0], (list, tuple)): if len(args[0]) == 0: # no entries are specified, pass back the zero matrix entries = 0 entry_ring = rings.ZZ elif isinstance(args[0][0], (list, tuple)) or is_Vector(args[0][0]): # Ensure we have a list of lists, each inner list having the same number of elements first_len = len(args[0][0]) if not all( (isinstance(v, (list, tuple)) or is_Vector(v)) and len(v) == first_len for v in args[0]): raise ValueError("List of rows is not valid (rows are wrong types or lengths)") # We have a list of rows or vectors if nrows is None: nrows = len(args[0]) elif nrows != len(args[0]): raise ValueError("Number of rows does not match up with specified number.") if ncols is None: ncols = len(args[0][0]) elif ncols != len(args[0][0]): raise ValueError("Number of columns does not match up with specified number.") entries = [] for v in args[0]: entries.extend(v) else: # We have a flat list; figure out nrows and ncols if nrows is None: nrows = 1 if nrows > 0: if ncols is None: ncols = len(args[0]) // nrows elif ncols != len(args[0]) // nrows: raise ValueError("entries has the wrong length") elif len(args[0]) > 0: raise ValueError("entries has the wrong length") entries = args[0] if nrows > 0 and ncols > 0 and ring is None: entries, ring = prepare(entries) elif isinstance(args[0], dict): # We have a dictionary # default to sparse sparse = kwds.get('sparse', True) if len(args[0]) == 0: # no entries are specified, pass back the zero matrix entries = 0 else: entries, entry_ring = prepare_dict(args[0]) if nrows is None: nrows = nrows_from_dict(entries) ncols = ncols_from_dict(entries) # note that ncols can still be None if nrows is set -- # it will be assigned nrows down below. # See the construction after the numpy case below. else: import numpy if isinstance(args[0], numpy.ndarray): num_array = args[0] str_dtype = str(num_array.dtype) if not( num_array.flags.c_contiguous is True or num_array.flags.f_contiguous is True): raise TypeError('numpy matrix must be either c_contiguous or f_contiguous') if str_dtype.count('float32')==1: m=matrix(RDF,num_array.shape[0],num_array.shape[1],0) m._replace_self_with_numpy32(num_array) elif str_dtype.count('float64')==1: m=matrix(RDF,num_array.shape[0],num_array.shape[1],0) m._replace_self_with_numpy(num_array) elif str_dtype.count('complex64')==1: m=matrix(CDF,num_array.shape[0],num_array.shape[1],0) m._replace_self_with_numpy32(num_array) elif str_dtype.count('complex128')==1: m=matrix(CDF,num_array.shape[0],num_array.shape[1],0) m._replace_self_with_numpy(num_array) elif str_dtype.count('int') == 1: m = matrix(ZZ, [list(row) for row in list(num_array)]) elif str_dtype.count('object') == 1: #Get the raw nested list from the numpy array #and feed it back into matrix try: return matrix( [list(row) for row in list(num_array)]) except TypeError: raise TypeError("cannot convert NumPy matrix to Sage matrix") else: raise TypeError("cannot convert NumPy matrix to Sage matrix") return m elif nrows is not None and ncols is not None: # assume that we should just pass the thing into the # MatrixSpace constructor and hope for the best # This is not documented, but it is doctested if ring is None: entry_ring = args[0].parent() entries = args[0] else: raise ValueError("Invalid matrix constructor. Type matrix? for help") else: raise ValueError("Invalid matrix constructor. Type matrix? for help") if nrows is None: nrows = 0 if ncols is None: ncols = nrows if ring is None: try: ring = entry_ring except NameError: ring = rings.ZZ return matrix_space.MatrixSpace(ring, nrows, ncols, sparse=sparse)(entries)

What else should you know?

We have barely scratched the surface on Sage’s capabilities. It is important to see that Sage can be made to deal with functions, it can solve equations, and it can make nice plots. I’ll just put some examples of using Sage to do those things here.

Making a (mathematical) function and evaluating it.

f(x) = x^3 + x - 4 f
x |--> x^3 + x - 4
f(7)
346
g(x) = f.derivative()
g(4)
49

A basic 2d plot of our functions

plot([f,g],[x,-5,5])

Plots can be made in a variety of colors, this example uses some standard color names.

where = [x,-5,5] plot(f,where, color='red') + plot(g, where, color='green')

Solving an equation

solve([g(x)==0],x)
[x == -1/3*I*sqrt(3), x == 1/3*I*sqrt(3)]

I denotes the imaginary unit. Sage can handle complex numbers.

Wait. Complex roots! Really? Let’s zoom in…

P = plot(f, [x,-.2,.2], legend_label='$f$') # the default color is blue. And comments can be added after a '#' character. P+= plot(g, [x,-.2,.2], legend_label='$g$', color='red') P.show()

Yes. We see that ff is strictly increasing. Therefore, g(x)g'(x) is never zero. This is also apparent from the graph, too. Since gg is a quadratic polynomial, its two roots must come as a complex conjugate pair.

Of course, Sage has many ways of handling finding roots. Here is another one.

g; g.roots()
x |--> 3*x^2 + 1 [(-1/3*I*sqrt(3), 1), (1/3*I*sqrt(3), 1)]

What else might you like to know?

  • Sage knows LaTeX\LaTeX{}, so you can use that in Markdown or html cells. I did it with the mathematics above.
  • Sage is built on Python, a wonderful programming language. You can use any Python code you want to do your mathematics. For example, I used some Python list comprehensions (which look a lot like set-builder notation) to make the following list.
[3*n for n in range(17)]
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48]

Here is another small bit of Python programming. This time it defines a simple function, and then calls that function to do a computation.

def square_and_add(x,y): z = x^2 + y^2 return z square_and_add(3,4)
25

Where do I get more instruction?

There are some good tutorials available.

You can also look through relevant documentation.

And there a useful Q & A site:

factor(124134)
2 * 3 * 17 * 1217
a = 124134 a.factor()
2 * 3 * 17 * 1217
factor??
File: /projects/sage/sage-6.10/local/lib/python2.7/site-packages/sage/rings/arith.py Source: def factor(n, proof=None, int_=False, algorithm='pari', verbose=0, **kwds): """ Returns the factorization of ``n``. The result depends on the type of ``n``. If ``n`` is an integer, returns the factorization as an object of type ``Factorization``. If n is not an integer, ``n.factor(proof=proof, **kwds)`` gets called. See ``n.factor??`` for more documentation in this case. .. warning:: This means that applying ``factor`` to an integer result of a symbolic computation will not factor the integer, because it is considered as an element of a larger symbolic ring. EXAMPLE:: sage: f(n)=n^2 sage: is_prime(f(3)) False sage: factor(f(3)) 9 INPUT: - ``n`` - an nonzero integer - ``proof`` - bool or None (default: None) - ``int_`` - bool (default: False) whether to return answers as Python ints - ``algorithm`` - string - ``'pari'`` - (default) use the PARI c library - ``'kash'`` - use KASH computer algebra system (requires the optional kash package be installed) - ``'magma'`` - use Magma (requires magma be installed) - ``verbose`` - integer (default: 0); PARI's debug variable is set to this; e.g., set to 4 or 8 to see lots of output during factorization. OUTPUT: - factorization of n The qsieve and ecm commands give access to highly optimized implementations of algorithms for doing certain integer factorization problems. These implementations are not used by the generic factor command, which currently just calls PARI (note that PARI also implements sieve and ecm algorithms, but they aren't as optimized). Thus you might consider using them instead for certain numbers. The factorization returned is an element of the class :class:`~sage.structure.factorization.Factorization`; see Factorization?? for more details, and examples below for usage. A Factorization contains both the unit factor (+1 or -1) and a sorted list of (prime, exponent) pairs. The factorization displays in pretty-print format but it is easy to obtain access to the (prime,exponent) pairs and the unit, to recover the number from its factorization, and even to multiply two factorizations. See examples below. EXAMPLES:: sage: factor(500) 2^2 * 5^3 sage: factor(-20) -1 * 2^2 * 5 sage: f=factor(-20) sage: list(f) [(2, 2), (5, 1)] sage: f.unit() -1 sage: f.value() -20 sage: factor( -next_prime(10^2) * next_prime(10^7) ) -1 * 101 * 10000019 :: sage: factor(-500, algorithm='kash') # optional - kash -1 * 2^2 * 5^3 :: sage: factor(-500, algorithm='magma') # optional - magma -1 * 2^2 * 5^3 :: sage: factor(0) Traceback (most recent call last): ... ArithmeticError: Prime factorization of 0 not defined. sage: factor(1) 1 sage: factor(-1) -1 sage: factor(2^(2^7)+1) 59649589127497217 * 5704689200685129054721 Sage calls PARI's factor, which has proof False by default. Sage has a global proof flag, set to True by default (see :mod:`sage.structure.proof.proof`, or proof.[tab]). To override the default, call this function with proof=False. :: sage: factor(3^89-1, proof=False) 2 * 179 * 1611479891519807 * 5042939439565996049162197 :: sage: factor(2^197 + 1) # long time (2s) 3 * 197002597249 * 1348959352853811313 * 251951573867253012259144010843 Any object which has a factor method can be factored like this:: sage: K.<i> = QuadraticField(-1) sage: factor(122 - 454*i) (-3*i - 2) * (-i - 2)^3 * (i + 1)^3 * (i + 4) To access the data in a factorization:: sage: f = factor(420); f 2^2 * 3 * 5 * 7 sage: [x for x in f] [(2, 2), (3, 1), (5, 1), (7, 1)] sage: [p for p,e in f] [2, 3, 5, 7] sage: [e for p,e in f] [2, 1, 1, 1] sage: [p^e for p,e in f] [4, 3, 5, 7] """ if isinstance(n, (int, long)): n = ZZ(n) if isinstance(n, Integer): return n.factor(proof=proof, algorithm=algorithm, int_ = int_, verbose=verbose) else: # e.g. n = x**2 + y**2 + 2*x*y try: return n.factor(proof=proof, **kwds) except AttributeError: raise TypeError("unable to factor n") except TypeError: # Just in case factor method doesn't have a proof option. try: return n.factor(**kwds) except AttributeError: raise TypeError("unable to factor n")
a.factor??
File: /projects/sage/sage-6.10/src/sage/rings/integer.pyx Source: def factor(self, algorithm='pari', proof=None, limit=None, int_=False, verbose=0): """ Return the prime factorization of this integer as a formal Factorization object. INPUT: - ``algorithm`` - string - ``'pari'`` - (default) use the PARI library - ``'kash'`` - use the KASH computer algebra system (requires the optional kash package) - ``'magma'`` - use the MAGMA computer algebra system (requires an installation of MAGMA) - ``'qsieve'`` - use Bill Hart's quadratic sieve code; WARNING: this may not work as expected, see qsieve? for more information - ``'ecm'`` - use ECM-GMP, an implementation of Hendrik Lenstra's elliptic curve method. - ``proof`` - bool (default: True) whether or not to prove primality of each factor (only applicable for ``'pari'`` and ``'ecm'``). - ``limit`` - int or None (default: None) if limit is given it must fit in a signed int, and the factorization is done using trial division and primes up to limit. OUTPUT: - a Factorization object containing the prime factors and their multiplicities EXAMPLES:: sage: n = 2^100 - 1; n.factor() 3 * 5^3 * 11 * 31 * 41 * 101 * 251 * 601 * 1801 * 4051 * 8101 * 268501 This factorization can be converted into a list of pairs `(p, e)`, where `p` is prime and `e` is a positive integer. Each pair can also be accessed directly by its index (ordered by increasing size of the prime):: sage: f = 60.factor() sage: list(f) [(2, 2), (3, 1), (5, 1)] sage: f[2] (5, 1) Similarly, the factorization can be converted to a dictionary so the exponent can be extracted for each prime:: sage: f = (3^6).factor() sage: dict(f) {3: 6} sage: dict(f)[3] 6 We use proof=False, which doesn't prove correctness of the primes that appear in the factorization:: sage: n = 920384092842390423848290348203948092384082349082 sage: n.factor(proof=False) 2 * 11 * 1531 * 4402903 * 10023679 * 619162955472170540533894518173 sage: n.factor(proof=True) 2 * 11 * 1531 * 4402903 * 10023679 * 619162955472170540533894518173 We factor using trial division only:: sage: n.factor(limit=1000) 2 * 11 * 41835640583745019265831379463815822381094652231 We factor using a quadratic sieve algorithm:: sage: p = next_prime(10^20) sage: q = next_prime(10^21) sage: n = p*q sage: n.factor(algorithm='qsieve') doctest:... RuntimeWarning: the factorization returned by qsieve may be incomplete (the factors may not be prime) or even wrong; see qsieve? for details 100000000000000000039 * 1000000000000000000117 We factor using the elliptic curve method:: sage: p = next_prime(10^15) sage: q = next_prime(10^21) sage: n = p*q sage: n.factor(algorithm='ecm') 1000000000000037 * 1000000000000000000117 TESTS:: sage: n = 42 sage: n.factor(algorithm='foobar') Traceback (most recent call last): ... ValueError: Algorithm is not known """ from sage.structure.factorization import Factorization from sage.structure.factorization_integer import IntegerFactorization if algorithm not in ['pari', 'kash', 'magma', 'qsieve', 'ecm']: raise ValueError("Algorithm is not known") cdef Integer n, p, unit cdef int i cdef n_factor_t f if mpz_sgn(self.value) == 0: raise ArithmeticError("Prime factorization of 0 not defined.") if mpz_sgn(self.value) > 0: n = self unit = one else: n = PY_NEW(Integer) unit = PY_NEW(Integer) mpz_neg(n.value, self.value) mpz_set_si(unit.value, -1) if mpz_cmpabs_ui(n.value, 1) == 0: return IntegerFactorization([], unit=unit, unsafe=True, sort=False, simplify=False) if limit is not None: from sage.rings.factorint import factor_trial_division return factor_trial_division(self, limit) if mpz_fits_slong_p(n.value): if proof is None: from sage.structure.proof.proof import get_flag proof = get_flag(proof, "arithmetic") n_factor_init(&f) n_factor(&f, mpz_get_ui(n.value), proof) F = [(Integer(f.p[i]), int(f.exp[i])) for i from 0 <= i < f.num] F.sort() return IntegerFactorization(F, unit=unit, unsafe=True, sort=False, simplify=False) if mpz_sizeinbase(n.value, 2) < 40: from sage.rings.factorint import factor_trial_division return factor_trial_division(self) if algorithm == 'pari': from sage.rings.factorint import factor_using_pari F = factor_using_pari(n, int_=int_, debug_level=verbose, proof=proof) F.sort() return IntegerFactorization(F, unit=unit, unsafe=True, sort=False, simplify=False) elif algorithm in ['kash', 'magma']: if algorithm == 'kash': from sage.interfaces.all import kash as I else: from sage.interfaces.all import magma as I str_res = I.eval('Factorization(%s)'%n) # The result looks like "[ <n1, p1>, <p2, e2>, ... ] str_res = str_res.replace(']', '').replace('[', '').replace('>', '').replace('<', '').split(',') res = [int(s.strip()) for s in str_res] exp_type = int if int_ else Integer F = [(Integer(p), exp_type(e)) for p,e in zip(res[0::2], res[1::2])] return Factorization(F, unit) elif algorithm == 'qsieve': message = "the factorization returned by qsieve may be incomplete (the factors may not be prime) or even wrong; see qsieve? for details" from warnings import warn warn(message, RuntimeWarning, stacklevel=5) from sage.interfaces.qsieve import qsieve res = [(p, 1) for p in qsieve(n)[0]] F = IntegerFactorization(res, unit) return F else: from sage.interfaces.ecm import ecm res = [(p, 1) for p in ecm.factor(n, proof=proof)] F = IntegerFactorization(res, unit) return F