:tocdepth: 2 .. _short_review_on_python: Short Review on `Python `__ Programming ============================================================================ .. contents:: :local: .. highlight:: python Programming and Data Structures -------------------------------- The `notebook for the first lecture <./ems_2020_day_01_introduction_to_sagemath.ipynb>`__ introduced some basic mathematical computations using *SageMath*. Among the many things that one can do with *SageMath* include the execution of a sequence of instructions. You many have observed this in the yesterday’s notebook. The *SageMath* computer algebra system is in fact an extension of the Python programming language, and allows, with a few exceptions, the use of Python programming constructs. In this notebook, we will briefly discuss how to use the Python programming language within *SageMath*. Hopefully you should be aware that one should avoid using Python keywords as variable or function names since this will cause programming. The list of keywords is available by: .. code:: ipython2 import keyword; keyword.kwlist .. code:: ipython2 2*3;3*4;4*5 # one comment, 3 results In addition to these keywords, we have the constants ``None``\ (empty value, named \ ``NULL`` in other languages), ``True`` and ``False``, and several functions predefined by Python or *SageMath* like ``len()``, ``cos()`` and ``integrate()``. It is better not to use these as variable names, otherwise some functionalities might no longer be available. The interpreter knows some additional commands, like quit to exit the Sage session. We will discover other commands like ``time`` or ``timeit`` later. Function Calls ~~~~~~~~~~~~~~~ To evaluate a function, its arguments should be put inside parentheses — for example ``cos(pi)`` — or in the function call without argument ``reset()``. However, the parentheses are superfluous for a command: the instructions ``print 6*7``\ and ``print(6*7)`` are equivalent. In Python 3, ``print()`` is a function and thus requires parentheses. More About Variables ~~~~~~~~~~~~~~~~~~~~~ As seen previously, *SageMath* denotes the assignment of a value to a variable by the equal sign ``=``. The expression to the right of the equal sign is first evaluated, then its value is saved in the variable whose name is on the left. Thus we have: .. code:: ipython2 y = 3; y = 3 * y + 1; y = 3 * y + 1; y The three first assignments change the value of the variable ``y`` without any output, the last command prints the final value of ``y``. The ``del x`` command discards the value assigned to the variable ``x``, and the function call ``reset()`` recovers the initial *SageMath* state.  Several variables can be assigned *simultaneously*, which differs from *sequential assignments* ``a = b; b = a`` .. code:: ipython2 a, b = 10, 20 # (a, b) = (10, 20) and [10, 20] are also possible .. code:: ipython2 a, b = b, a a,b The assignment ``a, b = b, a`` is equivalent to swapping the values of a and b using an auxiliary variable: .. code:: ipython2 temp = a; a = b; b = temp # equivalent to: a, b = b, a .. raw:: html

The following trick swaps the values of a and b without any auxiliary variable, using additions and subtractions: .. raw:: html

.. code:: ipython2 x, y = var('x, y'); a = x ; b = y .. code:: ipython2 a, b .. code:: ipython2 a = a + b ; b = a - b ; a = a - b .. code:: ipython2 a,b The instruction ``a = b = c = 0`` assigns the same value, here ``0``, to several variables; the instructions ``x += 5`` and ``n *= 2`` are respectively equivalent to ``x = x+5`` and ``n = n*2``. The comparison between two objects is performed by the double equal sign \`==: .. code:: ipython2 2 + 2 == 2^2, 3 * 3 == 3^3 Click `here <#day-02-toc>`__ if you want to go back to the table of content of this notebook. Otherwise, continue to the next `Section <#algorithmics>`__. Algorithmics ------------- The paradigm of *structured programming* consists in designing a computer program as a finite sequence of instructions, which are executed in order. Those instructions can be **atomic** or **composed**: an example of atomic instruction is the assignment of a value to a variable a composed instruction, like a loop or a conditional, is made up from several instructions, themselves atomic or composed. Loops/ Enumeration Loops ~~~~~~~~~~~~~~~~~~~~~~~~~ An enumeration loop performs the same computation for all integer values of an index :math:`k \in \{a, . . . , b\}`: the following example outputs the beginning of the multiplication table by 7: .. code:: ipython2 for k in [1..5]: print 7*k # block containing a single instruction # The colon symbol “:” at the end of the first line starts the instruction block In this example, the repeated instruction block contains a single instruction (namely **print**), which is indented to the right with respect to the **for** keyword. A block with several instructions has its instructions written one below the other, with the same indentation. The block positioning is important: the two programs below, which differ in the indentation of a single line, yield different results. .. code:: ipython2 S = 0 for k in [1..3]: S = S+k S = 2*S S .. code:: ipython2 S = 0 for k in [1..3]: S = S+k S = 2*S S On the left the instruction \**S = 2*S*\* is executed only once at the end of the loop, while on the right it is executed at every iteration, which explains the different results:   .. math:: S = (0 + 1 + 2 + 3) · 2 = 12  \qquad S = ((((0 + 1) · 2) + 2) · 2 + 3) · 2 = 22. **While Loops**. The other kind of loops are the while loops. Like the enumeration loops, they execute a certain number of times the same sequence of instructions; however, here the number of repetitions is not known a priori, but depends on a condition. The *while loop*, as its name says, executes instructions while a given condition is fulfilled. The following example computes the sum of the squares of non-negative integers whose exponential is less or equal to :math:`10^6` i.e., :math:`1^2 + 2^2 + \cdots + 13^2.` .. code:: ipython2 S = 0; k =0 # The sum S starts to 0 while e^k<=10^6: # e^13 <= 10^6 < e^14 S = S + k^2 k = k+1 S The above instruction block contains two assignments: the first one accumulates the new term, and the second one moves to the next index. Those two instructions are indented in the same way inside the while loop structure. Functions and Procedures ~~~~~~~~~~~~~~~~~~~~~~~~ General Syntax.As in other computer languages, the *SageMath* user can define her/his own procedures or functions, using the ``def`` command whose syntax is detailed below. We call a function (resp. procedure) a sub-program with zero, one or several arguments, which returns (resp. does not return) a result. Let us define the function :math:`(x,y) \mapsto x^2 + y^2:`. .. code:: ipython2 def fct2 (x,y): return x^2 + y^2 a = var('a') fct2(a,2*a) .. raw:: html

By default, all variables appearing in a function are considered local variables. Local variables are created at each function call, destroyed at the end of the function, and do not interact with other variables of the same name. In particular, global variables are not modified by the evaluation of a function having local variables of the same name: .. raw:: html

.. code:: ipython2 def foo(u): t = u^2 return t*(t+1) t= 1; u= 2 foo(3),t,u .. raw:: html

It is possible to modify a global variable from within a function, with the global keyword: .. raw:: html

.. code:: ipython2 a = b =1 def f(): global a; a = b= 2 f();a,b .. raw:: html

Iterative and Recursive Methods.  .. raw:: html

.. raw:: html

As we have seen above, a user-defined function is a sequence of instructions. A function is called recursive when duringits evaluation, it calls itself with different parameters. The factorial sequence is a toy example of recursive sequence: .. raw:: html

.. raw:: html

.. math:: 0! = 1,  \qquad (n+1)! = (n+1) \ n!   \quad \text{ for all } n \in \mathbb{N}. .. raw:: html

.. raw:: html

  .. raw:: html

.. raw:: html

The two following functions yield the same result for a nonnegative integer argument n; the first function uses the iterative method with a for loop,  while the second one is a word-by-word translation of the above recursive definition: .. raw:: html

.. code:: ipython2 def fact1 (n): res = 1 for k in [1..n]: res = res*k return res .. code:: ipython2 def fact2 (n): if n == 0: return 1 else: return n*fact2(n-1) **Global List Operations**: The addition operator ``+`` concatenates two lists, and the multiplication operator ``*``, together with an integer, performs an iterated concatenation: .. code:: ipython2 L = [1, 2, 3] ; L + [10, 20, 30] .. code:: ipython2 4 * [1, 2, 3] .. raw:: html

The concatenation of the two sub-lists L[:k] and L[k:] reconstructs the original list. This explains why the left bound p of a sub-list L[p:q] is included .. raw:: html

.. code:: ipython2 L = 5*[10, 20, 30]; L[:3]+L[3:] == L .. raw:: html

The operator made from two points “..” makes it easy to construct integerlists without explicitly enumerating all elements, and can be mixed with isolatedelements: .. raw:: html

.. code:: ipython2 [1..3, 7, 10..13] .. raw:: html

We explain below how to build the image of a list under a function, and a sub-list of a list. The corresponding functions are map and filter, together with the [..for..x..in..]construction. Mathematics often involve lists made by applying a function :math:`f` to its elements: .. raw:: html

.. raw:: html

.. math:: (a_0,a_1,\cdots,a_{n-1}) \mapsto  (fa_0,fa_1,\cdots,fa_{n-1})  . .. raw:: html

.. raw:: html

The map command builds this “map”: the following example applies the trigonometric function cos to a list of usual angles: .. raw:: html

.. code:: ipython2 map (cos, [0, pi/6, pi/4, pi/3, pi/2]) .. raw:: html

A user-defined function — with def — or a lambda-expression might also be used as first argument of map; the following command is equivalent to the above, using the function :math:`t \mapsto \cos t`: .. raw:: html

.. code:: ipython2 map (lambda t: cos(t), [0, pi/6, pi/4, pi/3, pi/2]) .. raw:: html

The lambda command is followed by the parameters separated by commas, and the colon must be followed by exactly one expression, which is the function result (without the returnkeyword).  A lambda expression may contain a test, whence the following functions are equivalent: .. raw:: html

.. raw:: html

  .. raw:: html

.. raw:: html

fctTest1 = lambda x: res1 if cond else res2 .. raw:: html

.. raw:: html

  .. raw:: html

.. raw:: html

def fctTest2 (x): .. raw:: html

.. raw:: html

  if cond: return res1  .. raw:: html

.. raw:: html

  else: return res2   .. raw:: html

.. raw:: html

  .. raw:: html

.. raw:: html

As a consequence, the three following map commands are equivalent, the composition :math:`N \circ \cos` being expressed in different ways: .. raw:: html

.. code:: ipython2 map (lambda t: N(cos(t)), [0, pi/6, pi/4, pi/3, pi/2]) .. code:: ipython2 map (N, map (cos, [0, pi/6, pi/4, pi/3, pi/2])) .. code:: ipython2 map (compose(N, cos), [0, pi/6, pi/4, pi/3, pi/2]) .. raw:: html

The filter command builds the sub-list of the elements satisfying a given condition. To get all integers in 1, …, 57 that are prime: .. raw:: html

.. code:: ipython2 filter (is_prime, [1..57]) .. raw:: html

The test condition might be defined inside the filter command, as in thefollowing example which finds by exhaustive search all fourth roots of 7 modulothe prime 37; this equation has four solutions 3, 18, 19 and 34: .. raw:: html

.. code:: ipython2 p = 37 ; filter (lambda n: n^4 % p == 7, [0..p-1]) .. raw:: html

Another way to build a list is using the comprehension form [..for..x..in..]; both commands below enumerate odd integers from 1 to 31: .. raw:: html

.. code:: ipython2 map(lambda n:2*n+1, [0..15]) .. code:: ipython2 [2*n+1 for n in [0..15]] .. raw:: html

The comprehension command is independent of the for loop. Associated with the if condition, it yields an equivalent construction to filter: .. raw:: html

.. code:: ipython2 filter(is_prime, [1..55]) .. code:: ipython2 [p for p in [1..55] if is_prime()] .. raw:: html

In the two following examples, we combine the if and filter tests with the comprehension for to determine a list of primes congruent to 1 modulo 4, then a list of squares of prime numbers: .. raw:: html

.. code:: ipython2 filter (is_prime, [4*n+1 for n in [0..20]]) .. code:: ipython2 [n^2 for n in [1..20] if is_prime(n)] In the first case the **is_prime** test is performed after the computation of :math:`4n + 1`, while in the second one the primality test is done before the computation of the square :math:`n^2`. Click `here <#day-02-toc>`__ if you want to go back to the table of content of this notebook. Otherwise, continue to the next `Section <#2d-graphics>`__. Graphics in Two Dimensions --------------------------- **Graphical Representation of a Function**: To draw the graph of a symbolic or Python function on an interval ``[a, b]``, we use ``plot(f(x), a, b)`` or the alternative syntax ``plot(f(x), x, a, b)``. .. code:: ipython2 plot(x * sin(1/x), x, -2, 2, plot_points=500) .. raw:: html

Among the numerous options of the plot command, we mention the following: .. raw:: html

.. raw:: html .. raw:: html

To visualise the graph, we assign the graphical object to a variable, say g, then we use the show command; in addition we can give bounds for the y-axis (g.show(ymin=-1, ymax=3)) or choose the aspect ratio (g.show(aspect_ratio=1) to have equal scales for x and y).  .. raw:: html

.. raw:: html

The graph obtained may be exported using the save command into several formats defined by the suffixes .pdf, .png, .ps, .eps, .svg and .sobj .. raw:: html

.. raw:: html

g.save(name, aspect_ratio=1, xmin=-1, xmax=3, ymin=-1, ymax=3) .. raw:: html

.. raw:: html

Let us draw on the same graphics the sine function and its first Taylor polynomials at 0. .. raw:: html

.. code:: ipython2 def p(x, n): return(taylor(sin(x), x, 0, n)) xmax = 15 ; n = 15 g = plot(sin(x), x, -xmax, xmax) for d in range(n): g += plot(p(x, 2 * d + 1), x, -xmax, xmax,color=(1.7*d/(2*n), 1.5*d/(2*n), 1-3*d/(4*n))) g.show(ymin=-2, ymax=2) .. raw:: html

We can also create an animation, to see how the Taylor polynomials approximate better and better the sine function when their degree increases. To keep the animation, it suffices to save it in the gif format. .. raw:: html

.. code:: ipython2 a = animate([[sin(x), taylor(sin(x), x, 0, 2*k+1)]\ for k in range(0, 14)], xmin=-14, xmax=14,\ ymin=-3, ymax=3, figsize=[8, 4]) a.show(); a.save('/home/yae/Desktop/plots/animation.gif') .. code:: ipython2 t = var('t') x = cos(t) + cos(7*t)/2 + sin(17*t)/3 y = sin(t) + sin(7*t)/2 + cos(17*t)/3 g = parametric_plot((x, y), (t, 0, 2*pi)) g.show(aspect_ratio=1) Data Plot ~~~~~~~~~~ .. raw:: html

To construct a bar graph, two distinct functions are available. On the one hand, bar_chart takes as input an integer list and draws vertical bars whose height is given by the list elements (in the given order). The width option enables us tochoose the bar width. .. code:: ipython2 bar_chart([randrange(15) for i in range(20)]) .. code:: ipython2 bar_chart([x^2 for x in range(1,20)], width=0.2) .. raw:: html

On the other hand, to draw the histogram of a random variable from a list offloating-point numbers, we use the plot_histogram function. The list values arefirst sorted and grouped into intervals (the number of intervals is given by the option binswhose default value is 50). The height of each bar being proportional to the number of corresponding values. .. raw:: html

.. code:: ipython2 liste = [10 + floor(10*sin(i)) for i in range(100)] bar_chart(liste) More on plotting ~~~~~~~~~~~~~~~~~ .. code:: ipython2 g(x) = sin(x)/x; diff(g(x), x) .. code:: ipython2 limit(g(x), x=0); # evaluate the limit .. code:: ipython2 plot(g(x), (x,-30,30),figsize=4) .. code:: ipython2 gplot = plot(g, (-10,10), legend_label=r'$g(x) = %s$'%latex(g(x)),figsize=5) gplot .. code:: ipython2 hplot = plot(g,(-10,10), color='darkgreen', legend_label=r'$h(x)=\cos(x)$',figsize=5, gridlines=[range(10),srange(0,1,0.1)]) hplot Exercises ---------- 1. Given the lists: :: list_a = ["Evans", "Yae", "Jan"] list_b = ["Mary", "Rosemond", "Jjulian", "Frances"] Create the least possible list of pairs {(a, b) \| a :raw-latex:`\in `list_a, b:raw-latex:`\in `list_b} 2. Given the list [(“Evans”, “Ocansey”), (“Yae”, “Gaba”), (“Jeff”, “Sanders”), (“Karthy”, “Green”)] where the first and second element of each tuple in the list is the first and last name. Write a program that creates two tuples, first_name and last_name which will collects all the first names and last names of each tuple in the list. -------------- .. raw:: html < `1. Introduction to Sagemath `__\ \| `Table of contents `__ \| `3. Sum of squares and plotting `__ > --------------