{"cells":[{"cell_type":"markdown","id":"d383f9d1-d536-45aa-9059-c91852c41c5f","metadata":{},"source":"Introduction to Python\n======================\n\n**Author:** Joseph Le Roux\n\n**Date:** 2026-07-19\n\n"},{"cell_type":"markdown","id":"50c7fc78-c93a-4164-aa74-b3fae07cf814","metadata":{},"source":["- AUTHOR: Joseph Le Roux\n","- DATE: 2026-07-19\n","- DESCRIPTION: Introduction to Python\n"]},{"cell_type":"markdown","id":"b282cec3-6d81-42c6-83f6-8d5ab3242a70","metadata":{},"source":["## Bases Python\n\n"]},{"cell_type":"markdown","id":"dc4004e7-1d80-4271-ada1-72195f0c46f9","metadata":{},"source":["Python in 5 minutes!\n\n-   Scripting language\n    -   like perl, bash, ruby\n\n-   Imperative language\n    -   like C, go, pascal, fortran\n\n-   with an object layer\n    -   like java\n\n-   and functional constructs\n    -   scala, haskell, ML\n\n"]},{"cell_type":"markdown","id":"6b97586f-8ab6-48b9-9777-5a71dbadeb0c","metadata":{},"source":["## Traditional Examples\n\n"]},{"cell_type":"markdown","id":"5009df68-ce02-4357-9be3-60d9daa1a62f","metadata":{},"source":["### \"hello world\"\n\n"]},{"cell_type":"markdown","id":"ddc6a521-70d9-440c-9bbd-000763a59c5f","metadata":{},"source":["1 line!\n\n"]},{"cell_type":"markdown","id":"aa1a4b9d-c39b-484c-aa2a-74d408e4435f","metadata":{},"source":["### Evaluation\n\n"]},{"cell_type":"markdown","id":"f839ee4a-00ff-4ca4-9bf1-e870017d3910","metadata":{},"source":["1.  Hover the mouse on the code cell;\n2.  Click on the arrow;\n3.  (the first time this will launch the virtual machine (see top right), and take some time)\n4.  Below the cell, a new box appears with the result (or an error message!)\n\n"]},{"cell_type":"code","execution_count":1,"id":"eef63da6-614c-4c2a-b892-d5a2fc6a93e8","metadata":{},"outputs":[],"source":["print('hello world')"]},{"cell_type":"markdown","id":"ce68d67f-2a0e-4b8a-a008-01496a0dc6eb","metadata":{},"source":["## Display an array\n\n"]},{"cell_type":"markdown","id":"a0ba50ae-a2b7-4206-acb8-70fd067fd3bb","metadata":{},"source":["3 different ways (at least!)\n\n"]},{"cell_type":"code","execution_count":1,"id":"62b75ebc-d7b4-445c-b119-f2194b3feb02","metadata":{},"outputs":[],"source":["# 1 like in C (yuck!)\n\ntab = ['a', 2, 3.14]\nfor i in range(0,len(tab)):\n  print(tab[i])"]},{"cell_type":"code","execution_count":1,"id":"2d02e2f9-f44d-4a78-b997-348c189ba20a","metadata":{},"outputs":[],"source":["# 2 still C but using predefined arguments (yuck too)\nfor i in range(len(tab)):\n  print(tab[i])"]},{"cell_type":"code","execution_count":1,"id":"692cc1ff-55b2-4bb6-988a-05510b056813","metadata":{},"outputs":[],"source":["# python!\nfor e in tab:\n  print(e)"]},{"cell_type":"markdown","id":"1388ab1d-b84b-4e02-9e94-2c9275aad1dc","metadata":{},"source":["## Functions\n\n"]},{"cell_type":"code","execution_count":1,"id":"9d0fba96-d3e7-474a-bf2e-81e5e7e79f72","metadata":{},"outputs":[],"source":["# Define\ndef print_hello(user):\n  print('hello ' + user)\n\n# Use\nprint_hello('Sam')"]},{"cell_type":"markdown","id":"3f3c02a8-efc1-43bf-9c38-be59cf0cf48c","metadata":{},"source":["### Example with recursive functions (1)\n\n"]},{"cell_type":"markdown","id":"9a3f2ece-8b77-4fc1-aa43-18c3b8fe585b","metadata":{},"source":["(and using sub-lists)\n\n"]},{"cell_type":"code","execution_count":1,"id":"a3cfde6b-8af7-4d87-a93c-43708c16e8fc","metadata":{},"outputs":[],"source":["def reverse(tab): # reverse an array\n  if tab == []:\n    return []\n  else:  # concatenation (+) of\n    # 1. 'reverse' applied to tab without the first element\n    # 2. the array consisting of only the first element of tab\n    return reverse(tab[1:]) + tab[:1]\n\n\n# usage\nreverse([1,2,3])"]},{"cell_type":"markdown","id":"540de1fe-d426-4ed9-a93d-71ecbc883a7c","metadata":{},"source":["### Example with recursive functions (2)\n\n"]},{"cell_type":"markdown","id":"0aa7ce10-ef78-4293-8e20-79925aa19ab4","metadata":{},"source":["(and using list comprehensions)\n\nList comprehensions execute a loop and store intermediate results in a list\n\n"]},{"cell_type":"code","execution_count":1,"id":"5a97a3b1-556c-41c9-9d23-4d9a7c4191c8","metadata":{},"outputs":[],"source":["def quick_sort(tab):\n  if tab == []:\n    return []\n  else:\n    pivot = tab[0]\n    # select elements smaller than pivot\n    smaller = [x for x in tab[1:] if x < pivot]\n    # select elements larger than pivot\n    larger = [x for x in tab[1:] if x > pivot]\n    return quick_sort(smaller) + [pivot] + quick_sort(larger)"]},{"cell_type":"code","execution_count":1,"id":"8b84f314-8857-4f8a-aa27-ea489dc4c0b5","metadata":{},"outputs":[],"source":["def quick_sort(tab):\n  if tab == []:\n    return []\n  else:\n    pivot = tab[0]\n    # select elements smaller than pivot\n    smaller = [x for x in tab[1:] if x < pivot]\n    # select elements larger than pivot\n    larger = [x for x in tab[1:] if x > pivot]\n    return quick_sort(smaller) + [pivot] + quick_sort(larger)"]},{"cell_type":"markdown","id":"3ee46634-2485-4035-8619-453481978c93","metadata":{},"source":["## Programming Exercise: Recursive Function\n\n"]},{"cell_type":"markdown","id":"b439baa5-d516-47eb-ad56-a1033db74ef5","metadata":{},"source":["Define a function 'fib' that calculates the value of the Fibonacci sequence for the integer passed as a parameter\n\n"]},{"cell_type":"code","execution_count":1,"id":"f45f8d1d-7fab-4620-a89b-bdb50cb3f1c6","metadata":{},"outputs":[],"source":["# your code here"]},{"cell_type":"code","execution_count":1,"id":"47ce030c-a98f-4254-a274-0e71e6058406","metadata":{},"outputs":[],"source":["#test\nassert ((fib(5) == 5) and (fib(12) == 144))"]},{"cell_type":"markdown","id":"d7ebf776-ea2e-4750-bfb4-221dbc7ee4be","metadata":{},"source":["## PyTorch\n\n"]},{"cell_type":"markdown","id":"16022b0a-a531-4e5b-9840-13e38df7b523","metadata":{},"source":["A library for scientific computing (like Matlab&#x2026;) oriented towards machine learning and neural networks\n\nTo use it, you must start by importing it with the `import` directive.\nIn Python you must prefix the functions of a module by the name of this module.\nIn practice we rename the module name to something shorter.\nHere, we rename torch to `t`, and all functions from this library must be preceded by `t.` (`t` followed by `dot`).\n\n"]},{"cell_type":"code","execution_count":1,"id":"9c6bba3c-d311-4dcf-8771-e4dd215f213d","metadata":{},"outputs":[],"source":["import torch as t\n\nprint(t.__version__)"]},{"cell_type":"markdown","id":"e42bc2da-6ae1-48c5-93ad-565b3afd7020","metadata":{},"source":["## Vectors and matrices\n\n"]},{"cell_type":"markdown","id":"9b068645-d5c0-4692-9b1c-d15cc7961c41","metadata":{},"source":["Unlike Python lists, **PyTorch** allows you to define vectors, matrices, and more generally typed tensors on which mathematical operations are efficient.\n\n-   the **tensor** type\n    -   creation from a list will give a vector\n\n"]},{"cell_type":"code","execution_count":1,"id":"bfcfc65c-786d-40b3-a0cb-9d890b2dcda1","metadata":{},"outputs":[],"source":["# here we have a vector of integers (because all elements are integers)\na = t.tensor([3,2,1])\nprint(a, type(a), a.dtype)"]},{"cell_type":"code","execution_count":1,"id":"e5049216-528a-479c-8100-a7faf7d2f9c7","metadata":{},"outputs":[],"source":["# note that the data type is not visible on the type but on the dtype\na = t.tensor([3,2,1.0])\nprint(a, type(a), a.dtype)"]},{"cell_type":"code","execution_count":1,"id":"526763cc-ab7a-4358-b081-e22cdcd0242f","metadata":{},"outputs":[],"source":["# you can directly specify the dtype\nt.tensor([3,2,1], dtype=float)"]},{"cell_type":"markdown","id":"2a450ad2-8412-4ec2-a851-6e5170c3d914","metadata":{},"source":["the `tensor` type will give a matrix from a list of lists\n\n"]},{"cell_type":"code","execution_count":1,"id":"f34a5a6e-52e7-4769-ad52-dba3ca9380d7","metadata":{},"outputs":[],"source":["m = t.tensor([[1,2,3],[4,5,6]])\nprint(m, type(m), m.dtype, m.size(), m.shape)"]},{"cell_type":"markdown","id":"c100073c-2544-40a6-8fd6-85c3a4d87bc9","metadata":{},"source":["## Useful functions for creating tensors\n\n"]},{"cell_type":"code","execution_count":1,"id":"6d05bf96-75a4-44ef-90d2-271b863ca2c0","metadata":{},"outputs":[],"source":["# An array of length 10, filled with integers with value 0\nt.zeros(10, dtype=int)"]},{"cell_type":"code","execution_count":1,"id":"2e5061f3-4a00-4448-8934-f9a499241652","metadata":{},"outputs":[],"source":["# A matrix of size 3x5 filled with floating point numbers with value 1\nt.ones((3, 5), dtype=float)"]},{"cell_type":"code","execution_count":1,"id":"4878694b-fe02-46cb-b525-1990670068d3","metadata":{},"outputs":[],"source":["# A 3x5 matrix filled with 3.14\nt.full((3, 5), 3.14)"]},{"cell_type":"code","execution_count":1,"id":"b614676b-ea07-4bcf-bc58-f1278d464849","metadata":{},"outputs":[],"source":["# An array filled with a linear sequence\n# starting at 0 (included) and ending at 20 (excluded), with a step of 2\nt.arange(0, 20, 2)"]},{"cell_type":"code","execution_count":1,"id":"515f177a-dfe5-49fd-9a4d-3c34102384b4","metadata":{},"outputs":[],"source":["# An array of 5 values, uniformly spaced between 0 and 1 (included)\nt.linspace(0, 1, 5)"]},{"cell_type":"code","execution_count":1,"id":"83cf9d3c-7f25-41f1-85f3-786b0d706c8f","metadata":{},"outputs":[],"source":["# A 3x3 matrix where each element is drawn randomly according to the normal distribution\nt.randn((3, 3))"]},{"cell_type":"code","execution_count":1,"id":"79f5d337-a9b5-49a1-bfd2-44f8d8ef6aa1","metadata":{},"outputs":[],"source":["# The 3x3 identity matrix\n# (identity matrix: https://en.wikipedia.org/wiki/Identity_matrix)\nt.eye(3)"]},{"cell_type":"markdown","id":"45ebcded-0126-47cb-aa78-fa0b7cba91ea","metadata":{},"source":["## Access elements of a tensor\n\n"]},{"cell_type":"markdown","id":"6135a665-f4c3-4b12-95a4-da37358436e9","metadata":{},"source":["Indicate in comments what is displayed\n\n"]},{"cell_type":"code","execution_count":1,"id":"443f83ce-c90c-4532-91e6-4e025946db71","metadata":{},"outputs":[],"source":["x1 = t.randint(10, size=(6,))  # 1-dimensional array\nprint(x1)\nprint(x1[0])\nprint(x1[-1])"]},{"cell_type":"code","execution_count":1,"id":"2943d292-a54d-4f80-9ad8-bce3fba80984","metadata":{},"outputs":[],"source":["print(x1[2:])"]},{"cell_type":"code","execution_count":1,"id":"294e4fff-fcc2-4e7c-aaad-24790a0e1288","metadata":{},"outputs":[],"source":["print(x1[:2])"]},{"cell_type":"code","execution_count":1,"id":"dd10d80e-6301-4a71-bd41-d5a7d7db56cf","metadata":{},"outputs":[],"source":["print(x1[1:4])"]},{"cell_type":"code","execution_count":1,"id":"d0049852-f730-4fc3-a0c1-d6ac6368f47e","metadata":{},"outputs":[],"source":["print(x1[1:4:2])"]},{"cell_type":"code","execution_count":1,"id":"62f14f22-f318-4e64-b6ca-564996ebcf54","metadata":{},"outputs":[],"source":["x1[1] = 1000\nprint(x1)"]},{"cell_type":"code","execution_count":1,"id":"3251db84-1e5a-46f7-8066-98f493c358b6","metadata":{},"outputs":[],"source":["x1[1] = 3.14\nprint(x1)"]},{"cell_type":"code","execution_count":1,"id":"33bd49c1-6f3a-459c-9a78-a488969ce0bb","metadata":{},"outputs":[],"source":["x2 = t.randint(10, size=(3, 4))  # 2-dimensional array\nprint(x2)"]},{"cell_type":"code","execution_count":1,"id":"0d434c93-c1b2-415c-a733-f0ecd60512bd","metadata":{},"outputs":[],"source":["print(x2[0,1])"]},{"cell_type":"code","execution_count":1,"id":"13d3f28b-4673-43f4-ad08-bbae8f6db930","metadata":{},"outputs":[],"source":["print(x2[1,:])"]},{"cell_type":"markdown","id":"e850e7e0-ea10-4e01-a2d7-54b41cbd775d","metadata":{},"source":["## Programming without loops\n\n"]},{"cell_type":"markdown","id":"539e0115-8290-4744-8cc7-f967b3f45067","metadata":{},"source":["Warning: loops in Python are very slow and prevent efficient distribution of calculations.\n\nThe following example (taken from [this site](https://openclassrooms.com/fr/courses/4452741-decouvrez-les-librairies-python-pour-la-data-science/4740941-plongez-en-detail-dans-la-librairie-numpy#/id/r-4771805)) illustrates this.\n\nHere we create a 1D array of size 1000000 initialized randomly and calculate the inverse of each value\n\nIn the naive implementation, we use a loop:\n\n"]},{"cell_type":"code","execution_count":1,"id":"66ad9fe6-815c-4b18-812a-b85b4c57f5f3","metadata":{},"outputs":[],"source":["def compute_inverse(values):\n    output = t.empty(len(values))\n    for i in range(len(values)):\n        output[i] = 1.0 / values[i]\n    return output\n\n# on a small array, for debugging if needed\n#values = t.randint(1, 10, size=(5,))\n#print(compute_inverse(values))\n\nlarge_array = t.randint(1, 100, size=(1000000,))\n\n# %timeit is a Jupyter notebook feature for\n# measuring the execution time of an instruction\n%timeit compute_inverse(large_array)"]},{"cell_type":"markdown","id":"a82a07d6-1db8-40f1-948a-e17ce6a0b512","metadata":{},"source":["PyTorch allows you to broadcast the same calculation across the elements of an array\n\nHere it's almost 500 times faster!\n\n"]},{"cell_type":"code","execution_count":1,"id":"3f289a52-48b6-4dd3-b6f3-a920f489f9bf","metadata":{},"outputs":[],"source":["%timeit (1.0 / large_array)"]},{"cell_type":"markdown","id":"5e644670-6533-4433-b0d5-d60b99fee1c0","metadata":{},"source":["## Programming Exercise: the softmax function\n\n"]},{"cell_type":"markdown","id":"fa16b237-e31b-418e-8ac0-1e423942d50f","metadata":{},"source":["The softmax function $\\sigma : \\mathbb{R}^d \\to \\mathbb{R}^d$ for a vector **v** is defined as follows:\n\n$\\sigma(v)_i = \\frac{e^{v_i}}{\\sum_{j=1}^{d} e^{v_{j}}}$\n\nthat is, each value $v_i$ of $v$ is replaced by its exponential divided by the sum of exponentials of all values of $v$\n\nFirst exercise: implement softmax with a function and a loop:\n\n"]},{"cell_type":"code","execution_count":1,"id":"7e1fc0a8-7cc6-40fb-9cf4-c05e5b9f3f5c","metadata":{},"outputs":[],"source":["large_array = t.rand(1000000) # an array of floats between 0 and 1\n\ndef softmax_loop(v):\n  # replace with the softmax implementation using loop(s)\n  return t.zeros(v.shape) \n\n%timeit softmax_loop(large_array)"]},{"cell_type":"markdown","id":"15b3d1bd-22e6-4926-8f34-56c4be104fc3","metadata":{},"source":["You can use broadcasting to calculate the exponential of each value in parallel with t.exp and the sum with the t.sum function\n\n(in practice you would need to be careful about floating point overflow&#x2026; but this is also true for the loop version)\n\n"]},{"cell_type":"code","execution_count":1,"id":"3f6ce9a0-93ac-4659-9d54-49da3a4637b9","metadata":{},"outputs":[],"source":["def softmax_broadcast(v):\n  # replace with the implementation without loops\n  return t.zeros(v.shape)\n\n%timeit softmax_broadcast(large_array)"]},{"cell_type":"markdown","id":"a2e68d12-24ec-4dd7-822a-b5103fd539c6","metadata":{},"source":["****Of course**** a **softmax** function is already implemented in **torch** but you should not use it ;)\n\n"]},{"cell_type":"code","execution_count":1,"id":"e22cae39-fa74-429d-8747-3c1e1ad0fc56","metadata":{},"outputs":[],"source":["%timeit t.softmax(large_array, 0)"]},{"cell_type":"markdown","id":"2fe2c56b-3e1d-4ee4-9b77-5213216a621a","metadata":{},"source":["## Congratulations, the practical work is complete!\n\n"]}],"metadata":{"org":{"AUTHOR":"Joseph Le Roux","DATE":"2026-07-19","DESCRIPTION":"Introduction to Python"},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.5.2"}},"nbformat":4,"nbformat_minor":5}