Python introduction

Python is used as user interface in sagemath.

We can define variables, like variable ‘a’ with integer value ‘2019’. The last expression of some input cell is represented in an output cell.

In [1]:
a = 2019
a
Out[1]:
2019

Only the last one; so the first ‘a’ will not be represented.

In [2]:
a
a
Out[2]:
2019

You can always enforce a string representation with ‘print()’.

In [3]:
print(a)
a
2019
Out[3]:
2019

You also assign two variables simultaneously:

In [4]:
a, b = 2019, 426

String formatting is also provided by python:

In [5]:
print('{} and {}'.format(a, b))
2019 and 426

An example algorithm (Euclidean algorithm) with our first control structure: a while loop

In [6]:
a, b = 2019, 426
n, m = a, b

while n != 0:
    m, n = n, m % n

print('The gcd of {} and {} is {}'.format(a, b, m))
The gcd of 2019 and 426 is 3

We can encapsulate this algorithm in a function. ‘def’ introduces a function. ‘n’ and ‘m’ are parameters. ‘return’ specifies the return value.

In [7]:
def our_gcd(n, m):
    while n != 0:
        m, n = n, m % n
    return m

Call the function named ‘our_gcd’

In [8]:
print(our_gcd(a, b))
3

A partial verification test for ‘our_gcd’:

In [9]:
# a for-loop iterates from 1 (incl.) to 100 (excl.): 1, 2, …, 99
for i in range(1, 100):
    # ‘our_gcd’ is the function defined above, ‘gcd’ is provided by sagemath (NOT python!)
    if our_gcd(i, 56) != gcd(i, 56):
        # raising an exception halts the program and prints an error message
        raise ValueError('our_gcd yields invalid result for {} and {}'.format(i, 56))

You can also rename/assign functions and all objects in python can be printed:

In [10]:
glt_gcd = our_gcd
print(glt_gcd)
<function our_gcd at 0x7fb6e2c0c488>

A simple function with a docstring (i.e. function documentation string). A docstring is given if the first expression is an unassigned string.

In [11]:
def inc(a):
    """Returns the argument incremented by one"""
    return a + 1

‘assert’ can be used to test invariants:

In [12]:
assert inc(41) == 42

‘help’ shows the function documentation with the docstring:

In [13]:
help(inc)
Help on function inc in module __main__:

inc(a)
    Returns the argument incremented by one

With sagemath, an appended question mark also shows the documentation:

In [14]:
gcd?
Signature:      gcd(a, b=None, **kwargs)
Docstring:     
   The greatest common divisor of a and b, or if a is a list and b is
   omitted the greatest common divisor of all elements of a.

   INPUT:

   * "a,b" - two elements of a ring with gcd or

   * "a" - a list or tuple of elements of a ring with gcd

   Additional keyword arguments are passed to the respectively called
   methods.

   OUTPUT:

   The given elements are first coerced into a common parent. Then,
   their greatest common divisor *in that common parent* is returned.

   EXAMPLES:

      sage: GCD(97,100)
      1
      sage: GCD(97*10^15, 19^20*97^2)
      97
      sage: GCD(2/3, 4/5)
      2/15
      sage: GCD([2,4,6,8])
      2
      sage: GCD(srange(0,10000,10))  # fast  !!
      10

   Note that to take the gcd of n elements for n not= 2 you must put
   the elements into a list by enclosing them in "[..]".  Before
   https://trac.sagemath.org/4988 the following wrongly returned 3
   since the third parameter was just ignored:

      sage: gcd(3, 6, 2)
      Traceback (most recent call last):
      ...
      TypeError: gcd() takes ...
      sage: gcd([3, 6, 2])
      1

   Similarly, giving just one element (which is not a list) gives an
   error:

      sage: gcd(3)
      Traceback (most recent call last):
      ...
      TypeError: 'sage.rings.integer.Integer' object is not iterable

   By convention, the gcd of the empty list is (the integer) 0:

      sage: gcd([])
      0
      sage: type(gcd([]))
      <type 'sage.rings.integer.Integer'>
Init docstring: x.__init__(...) initializes x; see help(type(x)) for signature
File:           ~/sage/local/lib/python2.7/site-packages/sage/arith/misc.py
Type:           function

With sagemath, two appended question marks shows the source code (might be cython source code):

In [15]:
gcd??
Signature: gcd(a, b=None, **kwargs)
Source:   
def gcd(a, b=None, **kwargs):
    r"""
    The greatest common divisor of a and b, or if a is a list and b is
    omitted the greatest common divisor of all elements of a.

    INPUT:


    -  ``a,b`` - two elements of a ring with gcd or

    -  ``a`` - a list or tuple of elements of a ring with
       gcd


    Additional keyword arguments are passed to the respectively called
    methods.

    OUTPUT:

    The given elements are first coerced into a common parent. Then,
    their greatest common divisor *in that common parent* is returned.

    EXAMPLES::

        sage: GCD(97,100)
        1
        sage: GCD(97*10^15, 19^20*97^2)
        97
        sage: GCD(2/3, 4/5)
        2/15
        sage: GCD([2,4,6,8])
        2
        sage: GCD(srange(0,10000,10))  # fast  !!
        10

    Note that to take the gcd of `n` elements for `n \not= 2` you must
    put the elements into a list by enclosing them in ``[..]``.  Before
    :trac:`4988` the following wrongly returned 3 since the third parameter
    was just ignored::

        sage: gcd(3, 6, 2)
        Traceback (most recent call last):
        ...
        TypeError: gcd() takes ...
        sage: gcd([3, 6, 2])
        1

    Similarly, giving just one element (which is not a list) gives an error::

        sage: gcd(3)
        Traceback (most recent call last):
        ...
        TypeError: 'sage.rings.integer.Integer' object is not iterable

    By convention, the gcd of the empty list is (the integer) 0::

        sage: gcd([])
        0
        sage: type(gcd([]))
        <type 'sage.rings.integer.Integer'>

    TESTS:

    The following shows that indeed coercion takes place before computing
    the gcd. This behaviour was introduced in :trac:`10771`::

        sage: R.<x>=QQ[]
        sage: S.<x>=ZZ[]
        sage: p = S.random_element(degree=(0,10))
        sage: q = R.random_element(degree=(0,10))
        sage: parent(gcd(1/p,q))
        Fraction Field of Univariate Polynomial Ring in x over Rational Field
        sage: parent(gcd([1/p,q]))
        Fraction Field of Univariate Polynomial Ring in x over Rational Field

    Make sure we try QQ and not merely ZZ (:trac:`13014`)::

        sage: bool(gcd(2/5, 3/7) == gcd(SR(2/5), SR(3/7)))
        True

    Make sure that the gcd of Expressions stays symbolic::

        sage: parent(gcd(2, 4))
        Integer Ring
        sage: parent(gcd(SR(2), 4))
        Symbolic Ring
        sage: parent(gcd(2, SR(4)))
        Symbolic Ring
        sage: parent(gcd(SR(2), SR(4)))
        Symbolic Ring

    Verify that objects without gcd methods but which can't be
    coerced to ZZ or QQ raise an error::

        sage: F.<a,b> = FreeMonoid(2)
        sage: gcd(a,b)
        Traceback (most recent call last):
        ...
        TypeError: unable to find gcd

    """
    # Most common use case first:
    if b is not None:
        try:
            return a.gcd(b, **kwargs)
        except (AttributeError, TypeError):
            pass
        try:
            return ZZ(a).gcd(ZZ(b))
        except TypeError:
            raise TypeError("unable to find gcd")

    from sage.structure.sequence import Sequence
    seq = Sequence(a)
    U = seq.universe()
    if U is ZZ or U in integer_types:  # ZZ.has_coerce_map_from(U):
        return GCD_list(a)
    return __GCD_sequence(seq, **kwargs)
File:      ~/sage/local/lib/python2.7/site-packages/sage/arith/misc.py
Type:      function