AP20005 Programming in Physics (using the Python Programming Language)

AP20005 Programming in Physics (using the Python Programming Language)

Online Python Programming websites: (1) OnlineGDB, (2) CodingGround, (3) Rex Tester (4) Google Colab
ONLINE Computer Laboratory and Assignment Schedule
Group 2 Group 1
Time Tue 1:30 - 4:20 Wed 1:30 4:20 Assignment due date Tutor
Lab 1 9 Feb 10 Feb 24 Feb   Anakin  
Lab 2 2 Mar 3 Mar 10 Mar   Udoka
Lab 3 16 Mar 17 Mar 24 Mar   Udoka
Lab 4 30 Mar 31 Mar 14 Apr   Udoka
Lab 5 20 Apr 21 Apr - Anakin
Test 25 Mar 25 Mar Anakin
Assignments / Solutions

Contents

1  Overview of Computers
    1.1  History of Computers
    1.2  Programming Languages
2  Overview of Python
    2.1  The simplest Python program
    2.2  Execute Python Program Online
    2.3  Mathematical operations
    2.4  Comments in a program
    2.5  Using variables
    2.6  If and else
    2.7  While loop
    2.8  Debugging approaches
3  Computer Fundamentals
    3.1  Bits and Bytes
    3.2  Binary and hexadecimal numbers
    3.3  Digital information
    3.4  Computer Architecture
    3.5  Low level programming language
    3.6  High level programming language
4  Python variables and simple data types
    4.1  Variables and identifiers
    4.2  Integers
    4.3  Floating point number
    4.4  Boolean
    4.5  Character and String
5  Operators and Expressions
    5.1  Assignment operator (=)
    5.2  Arithmetic operators (+, - ,* , / , **, %)
    5.3  Compound assignment( +=, -=, *=, /=, **=, %= )
    5.4  Equality and Relational operators ( ==, !=, >, <, >=, <= )
    5.5  Logical operators ( and, or, not )
    5.6  Precedence of operators
6  List and Range
    6.1  List of numbers
    6.2  List of variables of mixed types
    6.3  Modifying elements in a list
    6.4  Range
7  Program control statements
    7.1  If, else, elif
    7.2  While loop
    7.3  For loop
    7.4  Nested loops
8  Functions
    8.1  Function Definition and Usage
    8.2  Arguments of functions
    8.3  Returned value of function
    8.4  Returning multiple values
    8.5  Mathematical Functions
9  Jupyter Notebook and Google Colab
10  Strings and Input / Output
    10.1  Escape sequence
    10.2  String operations
    10.3  Formatted strings
    10.4  Input
    10.5  File Output
    10.6  File Input
11  Python Libraries
    11.1  Introduction
    11.2  NumPy
    11.3  Matplotlib
12  Advanced topic: Classes
Website: http://apricot.ap.polyu.edu.hk/pip   (for access outside our Lab, use login: ep password: ep)
Lecturer: Dr. C.H. Lam (Office: BC615, Tel: 2766-5681)
Tutor (Lab + Grading): Mr. Anakin, Lee Chun Shing (Email: cs.lee@connect.polyu.hk     Office: BC521)
Tutor (Lab + Grading): Mr. Udoka NWANKWO (Email: 18045211r@connect.polyu.hk)
Learning Outcomes and Syllabus: AP20005
Textbooks:
Reference books:
Assessment: Assignments and Tests (40%), Examination (60%)
Python Websites / Software:

Chapter 1
Overview of Computers

1.1  History of Computers

    1946: The first computer - ENIAC (Electronic Numerical Integrator And Computer) in the US Amry using vacuum tubes
    1960s - 1970s: Mainframe computers based on transitors or integrated circuits, e.g. IBM 7090
    1960s - 1970s: Mini-computers, e.g. PDP-7
    1971: first micro-processor - Intel 4004
    1976: Cray-1 supercomputer
    1981: IBM Personal Computer (PC) with Intel 8088 miro-processor
    1990s: Workstation, e.g. Sun SPARCstation
    2000s: Workstation Clusters, e.g. SGI Altix cluster at NASA
    2000s: PC Clusters
    2010s: GPU (Graphic Processing Unit) computing
    2010s: High performance computing, e.g. Sunway supercomputer
Moore's law : The number of transistors in a computer's Central Processing Unit (CPU) roughly doubles very year.

1.2  Programming Languages

Computer softwares are written by human using programming languages.
Popularity of Programming Languagues based on a survey in 2016:
1	Java                    21.465%
2	C                       16.036%
3	C++                     6.914%
4	C#                      4.707%
5	Python                  3.854%
6	PHP                     2.706%
7	Visual Basic .NET       2.582%
8	JavaScript              2.565%
9	Assembly language       2.095%
10	Ruby                    2.047%
11	Perl                    1.841%
12	Delphi/Object Pascal	1.786%
13	Visual Basic            1.684%
14	Swift                   1.363%
15	MATLAB                  1.228%
16	Pascal                  1.194%
17	Groovy                  1.182%
18	Objective-C             1.074%
19	R                       1.054%
20	PL/SQL              	1.016%
...

Python programming language:
Advantage: Disadvantage:
Programming languages I have used (in descend order of experience):

1.3  Software Library

A software library is a collection of programs which you can include into your own program to create the final software. A popular example is Google's artificial intelligence software library called TensorFlow:

Chapter 2
Overview of Python

2.1  The simplest Python program

Below is the Python source code in a file "simple.py" which calculates 12 ×14.
simple.py
print (12*14)
( simple.py )     
Execution of the program gives the answer 168.
Explanation
12*14
an expression for 12 ×14. Multiplication is represented by the operator *.
print ( ... )
Python function for printing to the computer screen

2.2  Execute Python Program Online

The OnlineGDB website includes an Integrated Development Environment (IDE), which is a software assisting the development of Python.
To execute our program:
  1. Using a web browser (e.g. firefox or internet explorer), enter the CodingGround website at OnlineGDB.
  2. In the main.py window in the middle, erase the original program and type our Python program source codes.
  3. Click Run. The answer 168 should appear in the output window in the bottom.
Alternatively, you can use other websites listed on the top of this webpage.

2.3  Mathematical operations

Built-in mathematical operations, e.g. +, -, *, /, and also ** (i.e. raise to the power).
Example:
Calculate √5, i.e. square root of 5
power.py
print ( 5 ** 0.5 )
( power.py )     
Execution of the program gives the answer 2.23606797749979.
Explanation
Operator **
x**y gives x raised to the power y
5
an integer
0.5
a floating point number, i.e. non-integer

Math library functions: sin, cos, sqrt, exp, log, etc.
root.py
from math import *
print ( sqrt(5) )
( root.py )     
Explanation
from math import *
Load all functions from the math library for future use.
sqrt( ... )
square root function, which comes with the math library
Library functions expand basic capabilities of python.

2.4  Comments in a program

Explanations about a program can be put as comments, e.g.
root2.py
""" root2.py 
    To compute the root of 5 
    written for Programming in Physics """

# import library
from math import *

# main program
print ( sqrt(5) )  # calculate square root
( root2.py )     
Explanation
"""
3 double-quotes mark the beginning and end of a multi-line comment
#
Hash sign marks the rest of the line as a comment
Comments improves readability of a program. Better readability implies

2.5  Using variables

Example: Quadratic equation
Solve the equation
ax2+bx+c=0
(2.1)
for a=1, b=3 and c=−4.
The solution
x=
−b ±


b2 − 4 a c

2a
(2.2)
can be computed using
quadratic1.py
# Solving ax^2 + bx + c = 0 for a=1, b=3, c=-4
from math import *

print ( (-3 + sqrt(3*3 -4*1*(-4))) / (2*1) )
print ( (-3 - sqrt(3*3 -4*1*(-4))) / (2*1) )
( quadratic1.py )     
It outputs:
1.0
-4.0
Using variables, it can be improved to:
quadratic2.py
# Solving ax^2 + bx + c = 0 for a=1, b=3, c=-4
from math import *

a = 1
b = 3
c = -4
print ( (-b + sqrt(b**2 -4*a*c)) / (2*a) )
print ( (-b - sqrt(b**2 -4*a*c)) / (2*a) )
( quadratic2.py )     
Explanation
Variable
Variable are referred to by names, e.g. a, b, c
Assignment statement
A variable can be assigned a value using the assignment operator '='. Further assignments overwrite old values.
Advantages of quadratic2.py
 
Introducing the determinant
D=b2 − 4 a c
(2.3)

x= −b ±√D

2a
(2.4)
the program can be alternatively written as
quadratic3.py
# Solving ax^2 + bx + c = 0 for a=1, b=3, c=-4
from math import *

a = 1
b = 3
c = -4
D = b**2 -4*a*c # determinant

x1 = (-b + sqrt(D)) / (2*a) # 1st root 
x2 = (-b - sqrt(D)) / (2*a) # 2nd root
print ( x1, x2)
( quadratic3.py )     
It outputs: 1.0 -4.0

2.6  If and else

For a quadratic equation, solutions exist only under certain condition, i.e
     If determinant D ≥ 0, solutions are given by Eq. (2.4)
This can be implemented using an if statement:
quadratic-if.py
# Solving ax^2 + bx + c = 0
from math import *

a = 1
b = 3
c = -4
D = b*b-4*a*c # determinant

if D >= 0:
    # indented lines below executed only if expression is true
    x1 = (-b + sqrt(D)) / (2*a) # 1st root
    x2 = (-b - sqrt(D)) / (2*a) # 2nd root
    print (x1, x2)
print ("End of execution")
( quadratic-if.py )     
It outputs:
1.0 -4.0
End of execution
Explanation
The syntax of the if statement is
Syntax
if <condition>:
    statement

Alternatively, we can say:
     If determinant D ≥ 0, solutions are given by Eq. (2.4), else no solution exists.
This can be implemented using an if-else statement:
quadratic-if2.py
# Solving ax^2 + bx + c = 0
from math import *

a = 1
b = 3
c = -4
D = b*b-4*a*c # determinant

if D >= 0:
    # indented lines below executed only if expression is true
    x1 = (-b + sqrt(D)) / (2*a) # 1st root
    x2 = (-b - sqrt(D)) / (2*a) # 2nd root
    print (x1, x2)
else:
    print ( "no solution" )
( quadratic-if2.py )     
Syntax
if <condition>:
  statement
else:
  statement

2.7  While loop

Very often, we have to repeat similar actions many times, e.g. outputting 0,1,2, .. N−1 to the screen. The following program uses a direct approach for N=5:
noloop.py
print (0)
print (1)
print (2)
print (3)
print (4)
( noloop.py )     
However, for large N, it is tedious to type in the program. The following version is slightly better because it can be entered by simple copy and paste actions:
noloop2.py
i = 0 

print (i)  # i = 0
i = i+1   

print (i)  # i = 1
i = i+1

print (i)  # i = 2
i = i+1

print (i)  # i = 3
i = i+1

print (i)  # i = 4
i = i+1
( noloop2.py )     
Explanation
i = i+1
assign the value of i+1 to the variable i,    i.e. i ← i+1. For example, if i is initially 0, after execution, i becomes 1.
Observing that the same statement "print (i); i = i+1" is repeated 5 times, we can instead use a loop construction, e.g. the while loop:
whileloop.py
i = 0; 
while i < 5:
    print (i)  
    i = i+1   
( whileloop.py )     
Explanation
while
the indented statements below will be executed repeatedly while the condition is true.
Syntax
while <condition>:
    statement

Tracing a program (i.e. running a program line-by-line)
Using OnlineGDB, type in the whileloop.py program. Then,
  1. to start line-by-line program execution, click "Debug"
  2. to execute one line of the program, click "step over".
  3. look at the value of the variable "i" under "Local Variables" on the right panel. See it changes as you click "step over" a few times.
Advantages of Looping
Calculate the factorial n! of n defined by
n! = 1 ×2 ×3 .... ×n
(2.5)
The following program uses a direct approach
factorial1.py
# direct approach to calculate 5! (factorial of 5)
x = 1 * 2 * 3 * 4 * 5
print (x)
( factorial1.py )     
which can be improved to
factorial1a.py
x = 1

i = 1; x = x * i # x=1  
i = 2; x = x * i # x=1.2
i = 3; x = x * i # x=1.2.3
i = 4; x = x * i # x=1.2.3.4
i = 5; x = x * i # x=1.2.3.4.5

print (x)
( factorial1a.py )     
where ";" allows us to put more than one command in a single line. It can be further improved to
factorial2.py
x = 1
i = 1

x = x * i; i = i + 1 # x=1  i=2
x = x * i; i = i + 1 # x=1.2  i=3
x = x * i; i = i + 1 # x=1.2.3  i=4
x = x * i; i = i + 1 # x=1.2.3.4  i=5
x = x * i; i = i + 1 # x=1.2.3.4.5  i=6

print (x)
( factorial2.py )     
A better way is to use the while loop:
factorial-loop.py
# using while-loop to calculate n! (factorial of n)
n = 5
x = 1
i = 1
while i <= n:
    x = x * i
    i = i + 1
print (x)
( factorial-loop.py )     

2.8  Debugging approaches

Bugs and debugging
Mistakes in computer source codes are called bugs. The process of identifying and correcting the bugs is called debugging.
Types of bugs
Syntax errors (i.e. compiler errors, or build errors):
The grammatic rules of Python is not followed, e.g. use of unassigned variable, errors due to a missing colon, etc. (Easy)
Logical errors:
The program can be compiled and executed. However, due to logical or mathematical mistakes in the program, the results are incorrect. (Difficult!)
Logical errors
For example, the program below trys to calculate 5! but outputs 8 instead. Why?
factorial-bug.py
# using while-loop to calculate n! (factorial of n)
n = 5
x = 1
i = 1
while i <= n:
    x = x * i
    i = i + i
print (x)
( factorial-bug.py )     
Common debugging approaches for logical errors
  1. Inspection, i.e. read the source code many times carefully
  2. Dry running, i.e. imitating the execution by doing the calculations by hand
  3. Outputting intermediate values of the variables to obtain more clues
  4. Tracing the execution and examining intermediate variables using a debugger to obtain more clues
  5. Last resort: forget your buggy program. Start all over again
Outputting intermediate values
For example, statements for outputting intermediate values are added for debugging purpose:
factorial-debug.py
# using while-loop to calculate n! (factorial of n)
n = 5
x = 1
i = 1
while i <= n:
    x = x * i
    print ("x = ", x) # debugging
    i = i + i
    print ("i = ", i) # debugging
print (x)
( factorial-debug.py )     

Chapter 3
Computer Fundamentals

3.1  Bits and Bytes

A bit of storage can be either 0 or 1.
1 Byte = 8 bits
Many bits and bytes can be stored in, e.g.:

3.2  Binary and hexadecimal numbers

Decimal number (base 10)
Allowed digits: 0,1,2,3,4,5,6,7,8,9
e.g.   5123 = 5 ×103 + 1 ×102 + 2 ×101 + 3
Each digit requires 4 bits to store (non-optimal efficiency)
Binary number (base 2)
Allowed digits: 0,1
e.g.   1101 = 1 ×23 +1 ×22 + 0 ×21 + 1
Each digit requires 1 bit to store
Hexadecimal (base 16)
Allowed digits: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
e.g.   2F8A = 2 ×163 + 15 ×162 + 8 ×16 + 10
Each digit requires 4 bits to store
hexadecimal decimal      binary

   0          0           0000  
   1          1           0001  
   2          2           0010  
   3          3           0011  
   4          4           0100  
   5          5           0101  
   6          6           0110  
   7          7           0111  
   8          8           1000  
   9          9           1001  
   A          10          1010  
   B          11          1011  
   C          12          1100  
   D          13          1101  
   E          14          1110  
   F          15          1111  

One byte (8 bits) can store one of the following

3.3  Digital information


1 Byte
= 8 bits
1 KB
= 1 Kilo−byte = 1024 bytes ≅ 103 bytes
1 MB
= 1 Mega−byte = (1024)2 bytes ≅ 106 bytes
1 GB
= 1 Giga−byte = (1024)3 bytes ≅ 109 bytes
1 TB
= 1 Tera−byte = (1024)4 bytes ≅ 1012 bytes
Examples of digital information

3.4  Computer Architecture

The inside of a typical desktop computer:
The most important components of a computer include
A simple CPU consists of
A typical Personal Computer Specification:
Processor
AMD Ryzen 7 5800X CPU, 8 cores, 36MB Cache, base frequency 3.8GHz    (i.e. 8 CPU's packed into one chip; 36MB fast memory inside CPU; 3.8 ×109 operations per second)
Main Memory
2 x Kingston Hyper X DDR4 3600MHz 16GB RAM (Total 32GB)
Hard Drive
Micron Crucial CT1000P5SSD8 1TB M.2 SSD
Video Card
Asus GT710-4H-SL-2GD5 2GB Display Card (4 x HDMI) 192 cores

3.5  Low level programming language

A CPU can only directly execute Machine Language / Machine Codes, e.g.
...
48 89 32
...
which represents a 3-bytes command (in hexadecimal). This command can be written in Assembly Language source code as
...
movq %rsi, (%rdx)
...
which means moving an 8-byte value from memory address pointed to by the data register to the source index register.

3.6  High level programming language

Compiled languages: C/C++, Java, Fortran, Pascal, Basic, Matlab, ...
For C++,
Interpreted languages: Python, Perl, Basic, Matlab, ...
For Python,
Typical program development time
     Assembly : C++ : Python = 100 : 5 : 1
Typical program execution time
     Assembly : C++ : Python = 1 : 2 : 40

Chapter 4
Python variables and simple data types

4.1  Variables and identifiers

A variable consists of a number of bytes in computer memory for storing data. Each variable stores data of a specific data type, e.g. integer, floating-point number, etc.
An identifier is a name used to describe variables, functions, or other items.
An identifier of a variable is the variable name.
An identifier
Python reserved words, also called keywords, are:
False, class, finally, is, return, none, continue, for, lambda, try, True, def, from, nonlocal, while, and, del, global, not, with, as, elif, if, or, yield, assert, else, import, pass, break, except, in, raise.

4.2  Integers

Unsigned integer
1 bit:   stores 0 or 1
8 bits ≡ 1 byte:   store 0, 1, ... , or 255      (i.e. 0, ... , 28 - 1)
32 bits ≡ 4 byte:   store 0, 1, ... , or 4294967295      (i.e. 0, ... , 232 - 1)
 
integer (i.e. signed integer)
8 bits ≡ 1 byte:   store -128, -127, ... , or 127      (i.e. 28 possibilities)
32 bits ≡ 4 byte:   store -2147483648, ... , or 2147483647      (i.e. 232 possibilities; used by most CPU's)
 
Python integer data type: int
integer.py
x1 = 5
x2 = 3*2 
x3 = 5/4        # float point division
x4 = 8/4        # float point division
x5 = 7%4        # remainder
x6 = int(2.6)   # type conversion, truncating to integer
x7 = round(2.6) # round up to integer
x8 = 2**100     # a very large integer
print( x1, x2, x3, x4 )
print( x5, x6, x7, x8 )
print( type(5) )  # output data type of a value
print( type(x1), type(x3), type(x4) ) # output data type of variables
( integer.py )     
     Program output:
5 6 1.25 2.0
3 2 3 1267650600228229401496703205376
<class 'int'>
<class 'int'> <class 'float'> <class 'float'>
Explanation
Type Description Storage size Allowed values
int integer variable: larger number needs more bits   −∞  ...   ∞
i.e. arbitrary-precision integer arithmetics

4.3  Floating point number

A double-precision floating point number has 64 bits and is expressed as
x = (−1)s ×m ×2e−1023
(4.1)
Explanation
s   (1 bit)
Sign bit, s = 0 or 1
e   (11 bits)
Exponent, e = 0 .. 2047
m   (52 bits)
Significand (in binary), m = 1. b1 b2 b3 ... b51,     i.e. from 1.0000000000000000000000000000000000000000000000000000 to 1.1111111111111111111111111111111111111111111111111111
Example: double-precision floating point number
A double precision floating point number x is represented by s=1, e=1026 (in decimal), and m=1.1101 (in binary). Calculate x in decimal form.
Answer:
m
=
1 + 1/2 + 1/4 + 0/8 + 1/16 = 1.8125
x
=
(−1)1 ×1.8125 ×21026−1023 = −14.5
Typical properties of single and double precision floating point numbers are
Type Precision Storage Machine epsilon Overflow threshold Underflow threshold
float Double 8 bytes at least (24 bytes) 2−53 ≈ 1.11×10−16 21024 ≈ 1.79×10308 2−1022 ≈ 2.23×10−308
float.py
x1 = 6.022e23         # floating point constant assigned to x1
x2 = 1e300 * 1e100  # overflow -> inf.
x3 = 1e-300 / 1e100 # underflow -> 0
x4 = 1 + 1e-15       # -> 1.000000000000001 
x5 = 1 + 1e-16       # -> 1.0  (why not 1.0000000000000001 ?)
x6 = (1 + 0.1) -1    # -> 0.10000000000000009  (why not 0.1 ?)
print(x1, x2, x3, x4, x5, x6)
( float.py )     
     Program output:
6.022e+23 inf 0.0 1.000000000000001 1.0 0.10000000000000009
Explanation

4.4  Boolean

The data type for a boolean value is
Type Description Storage size possible values
bool Boolean 1 bit at least (24 bytes) True ≡ 1, False ≡ 0
boolean.py
x = 3 < 4 
print( 3 > 4, x, x+1, type(x) )
( boolean.py )     
     Program output:
False True 2 <class 'bool'>

4.5  Character and String

Characters, including letters, digits, and symbols are numbered using the ASCII (American Standard Code for Information Interchange) code.
(which have been generalized to extended ASCII code and unicode)
A string, i.e. character string, consists of an ordered sequence of one or more characters.
string.py
s = "a"           # a string with one character, i.e. length = 1
print(s, ord(s))  # print the character and its ASCII code 
i = 97
print(i, chr(i))  # print the ASCII code and the represented character
print(chr(i+1))
( string.py )     
     Program output:
a 97
97 a
b
Explanation

Chapter 5
Operators and Expressions

5.1  Assignment operator (=)

To assign a value b to variable a, write
a = b
To assign a value c to variables a and b, write
a = b = c

5.2  Arithmetic operators (+, - ,* , / , **, %)

+   addition 
- subtraction
* multiplication
/ division
** power
% modulo, i.e. remainder

5.3  Compound assignment( +=, -=, *=, /=, **=, %= )

A compound assignment statement modifies the value of a variable by operating on its value,
e.g. to increase a by 1, write
a += 1
which is equivalent to
a = a + 1
e.g. to replace a by its product with b, write
a *= b
which is equivalent to
a = a * b

5.4  Equality and Relational operators ( ==, !=, >, <, >=, <= )

These operators give Boolean values (i.e. true or false):
==   equal to
!= not equal to (an alternative form is '<>')
>greater than
< less than
>= greater than or equal to
<= less than or equal to
e.g.
if a==b:
     ...

5.5  Logical operators ( and, or, not )

Python logical operators for Boolean values are 'and', 'or', 'not'.
e.g. the Boolean expression 0 ≤ x < 3.1416 can be written as
if 0 <= x and x < 3.1416:
     ...
print( not True )

5.6  Precedence of operators

Some operation has higher precedence (i.e. higher priority) and will be executed before others. Operations of the same precedence will be executed from the left to the right, e.g.
a = 1 + 2 * 3
is equivalent to
a = 1 + (2 * 3)
e.g.
a = 5 / 3 / 8
is equivalent to
a = (5 / 3) / 8
The order of precedence of some of the operators, starting from the highest, is
**
* / %
+ -
<   >   <=   >=
==   !=   not
and
or
It is a good practice to add parenthesis () to enforce and make explicit the desired order of execution.

Chapter 6
List and Range

6.1  List of numbers

A sequence in mathematics is an ordered set of numbers. For example, consider a sequence {1, 4, 9, 16, 25, 36}
element     0     1     2     3     4     5
value 1 4 9 16 25 36
The above sequence can be stored in a Python data type called list, e.g.
integer_list.py
X = [1, 4, 9, 16, 25, 36] # create a list of integers
print(X)                  # output whole list
print(X[0], X[4])         # output elements 0 and 4
( integer_list.py )     
     Program output:
[1, 4, 9, 16, 25, 36]
1 25
Explanations

6.2  List of variables of mixed types

Elements can be of mixed variable types.
mixed_list.py
L = [ 1, 3.1416, True, "A", "Hello" ]
print(type(L), type(L[0]), type(L[1]), type(L[2]), type(L[3]), type(L[4]))
( mixed_list.py )     
     Program output:
<class 'list'> <class 'int'> <class 'float'> <class 'bool'> <class 'str'> <class 'str'>

6.3  Modifying elements in a list

list_modify.py
X = [1, 4, 9, 16, 25, 36] # create a list of integers
X[1]=5; print(X)          # modify element 1
X.append(49); print(X)    # append a value as last element
X.insert(3,10); print(X)  # insert a value as element 3
del X[3]; print(X)        # delete element 3
X.remove(36); print(X)    # remove the first occurence element by value
( list_modify.py )     
     Program output:
[1, 5, 9, 16, 25, 36]
[1, 5, 9, 16, 25, 36, 49]
[1, 5, 9, 10, 16, 25, 36, 49]
[1, 5, 9, 16, 25, 36, 49]
[1, 5, 9, 16, 25, 49]
Explanations

6.4  Range

We often need simple lists such as [0, 1, 2, 3, ..., N-1]. It is tedious to create the list explicitly if N is large.
A better way is to specify the sequence using a range data type, which can be converted to a list.
range.py
R = range(5)  # create a range
print( R, type(R) )
X = list(R)   # convert the range to a list
print( X, type(X) )
( range.py )     
     Program output:
range(0, 5) <class 'range'>
[0, 1, 2, 3, 4] <class 'list'>
More general usage of range:
range2.py
print( list( range(10) ) )     # from 0 to 9
print( list( range(0,10) ) )   # from 0 to 9, i.e. same as range(10)
print( list( range(1,11) ) )   # from 1 to 10
print( list( range(1,11,2) ) ) # from 1 to 10 with a step 2
( range2.py )     
     Program output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 3, 5, 7, 9]

Chapter 7
Program control statements

7.1  If, else, elif

The full syntax of if, else, and elif (else-if) statement is:
Syntax
if <condition> :
  statement
elif <condition>:
  statement
...
elif <condition>:
  statement
else: 
  statement

Each statement can be single line or multiple lines. 'elif' and 'else' statements are optional.
Nested if statement: A statement in an if construction can itself be an if statement, e.g.
Syntax
if <condition>:
    if <condition>:
        statement
    else:
        statement
else:
    if <condition>:
        statement
    elif <condition>:
        statement

Consider again the quadratic equation
ax2+bx+c=0
(7.1)
If a < > 0, it has solutions,
x=
−b ±


b2 − 4 a c

2a
       for D > 0
(7.2)
Else, it has solution,
x = − c

b
       for b < > 0
(7.3)
quadratic-if3.py
# solving ax^2 + bx + c = 0 for a=1, b=3, c=-4
from math import *

a=1
b=3
c=-4

if a != 0: 
    # quadratic equation
    D = b*b-4*a*c
    if D >= 0:
        x1 = (-b + sqrt(D))/(2*a) # 1st root
        x2 = (-b - sqrt(D))/(2*a) # 2nd root
        print(x1, x2)
else:
    # linear equation
    if b != 0:
        x1 = - c/b
        print(x1) # root
( quadratic-if3.py )     

7.2  While loop

See also Sec. 2.7.
A loop iterates (i.e. repeatedly executes) a statement a number of times.
Syntax
while <condition>:
  statement

Example: Total mass of balls
There are N=100 balls. The i-th ball (0 ≤ i ≤ N−1) has a mass mi = i kg. Calculate the total mass M of all the balls.
We will calculate
M = m0 + m1 + m2 + m3 + ... + mN−1 = N−1

i=0 
mi
where mi = i.
balls_mass_while.py
# Total mass of N balls
N = 100        # no. of balls
M = 0          # partial sum, which becomes total mass
i=0            # ball counter
while i < N:   # repeat N times
    m = i      # m_i (mass of i-th ball)
    M += m     # i.e. M=M+m ( add m_i to partial sum )
    i += 1     # i.e. i=i+1 ( increase ball counter )
print(M)
( balls_mass_while.py )     

7.3  For loop

We often perform a loop N times, where N is a known constant. This means a counter i runs through each value in the range [0, 1, ... N−1]. We can say:
"For each value of i in the range from 0 to N-1, performs ..."
for.py
for i in range(5):
    print(i, end = " ")
( for.py )     
     Program output:
0 1 2 3 4
Syntax
for <integer> in <range>:
  statement

Explanation
The total mass problem can be solved by the following equivalent program:
balls_mass_for.py
# Total mass of N balls
N = 100             # no. of balls
M = 0               # partial sum, which becomes total mass
for i in range(N):  # repeat N times
    m = i           # m_i (mass of i-th ball)
    M += m          # i.e. M=M+m ( add m_i to partial sum )
print(M)
( balls_mass_for.py )     
Alternatively, we can say:
"For each value in the list <list>, performs ..."
for_list.py
L = [1, 1, 2, 3, 5, 8, 13]  # creates a variable of type 'list'
for i in L:
    print(i, end = " ")
( for_list.py )     
     Program output:
1 1 2 3 5 8 13
Syntax
for <variable> in <list>: 
  statement

7.4  Nested loops

Inside a loop, the content can itself be a loop. This is called a nested loop.
Example: Two dice
List all 36 possible outcomes when rolling two dice.
dice.py
# Possible outcomes when rolling 2 dice with nested loops
for i in range(1,7):
    for j in range(1,7):
        print(i, j)
( dice.py )     
Program output: dice.txt
Example: Cards
List all 52 cards in a deck of cards.
cards.py
# A deck of cards
for suit in [ 'diamonds', 'clubs', 'hearts', 'spades' ]:
    for number in [ 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K' ]:
        print( number, ' of ', suit )
( cards.py )     
Program output: cards.txt

Chapter 8
Functions

8.1  Function Definition and Usage

Some segments of codes may be repeated a few times in a program, e.g.
Example: Functions
Calculate the surface area and volume of spheres of radii 1, 3, and 7.
SphereProperties.py
from math import *

r=1
area = 4*pi*r**2 
volume = 4/3*pi*r**3
print(r, area, volume)

r=3
area = 4*pi*r**2 
volume = 4/3*pi*r**3
print(r, area, volume)

r=7
area = 4*pi*r**2 
volume = 4/3*pi*r**3
print(r, area, volume)
( SphereProperties.py )     
     Program output:
1 12.566370614359172 4.1887902047863905
3 113.09733552923255 113.09733552923254
7 615.7521601035994 1436.7550402417319
Repeated codes can be defined in a function. Applying 'function' in Python involves:
Using function, the above program becomes
SphereProperties-function.py
from math import *

def Sphere():  # defining a function
    area = 4*pi*r**2 
    volume = 4/3*pi*r**3
    print(r, area, volume)

r=1
Sphere() # calling the function

r=3
Sphere() # calling the function

r=7
Sphere() # calling the function
( SphereProperties-function.py )     
Syntax of Function Definition
def <function name>():
    statement

Syntax of Calling a Function
<function name>()

Explanation
Advantages of functions

8.2  Arguments of functions

In the example above, the radius is passed (i.e. supplied) to the function using r as a global variable (i.e. a variable accessible everywhere in the program). A much better approach is passing r as a function argument (i.e. function parameter), e.g.
SphereProperties-function.py
from math import *

def Sphere(r):  # defining a function
    area = 4*pi*r**2 
    volume = 4/3*pi*r**3
    print(r, area, volume)

Sphere(1)  # r=1
Sphere(3)  # r=3
Sphere(7)  # r=7

( function-argument.py )     
Syntax : Function Definition with Arguments
def <function name>( [<variable name>] [, ...] ):
      statement

( The square brackets [...] mean optional parts. )
A function can have multiple arguments.
Example: Function Definition with multiple arguments
Calculate the surface area and volume of spheres of radii 1, 3, and 7 and densities 7.87, 8.96, 11.36 respectively.
function-argument2.py
from math import *

def Sphere(r, rho):  # defining a function
    area = 4*pi*r**2 
    volume = 4/3*pi*r**3
    mass = rho * volume
    print(r, area, volume, mass)

Sphere(1, 7.87)  # r=1, rho=7.87
Sphere(3, 8.96)  
Sphere(7, 11.36) 

( function-argument2.py )     

8.3  Returned value of function

A mathematical function can be defined as a Python function, e.g.
Example: The Square Function
Calculate 1.52 by defining a function called sqr.
sqr.py
def sqr(x):
    y = x**2
    print(y)

sqr(1.5)
( sqr.py )     
All the functions above send results to the screen. A drawback is that results cannot be used for further calculation.
Example: The Square Function, again
Calculate 1.52 sin(π/6) by defining a function called sqr.
Solution is to define a function which returns a value:
sqr_return.py
from math import *

def sqr(x):
    y = x**2
    return y  # return a value to the calling line

sum = sqr(1.5) * sin(pi/6)  # the line which calls the function sqr
print(sum)
( sqr_return.py )     
Syntax : Function Definition with Returned Value
def <function name>( [<variable name>] [, ...] ):
    statement
    return <value>
}

Explanation
Example: Returned values of Functions
Calculate the total mass of spheres of radii 1, 3, and 7 and densities 7.87, 8.96, 11.36 respectively.
function_return.py
from math import *

def Sphere(r, rho):  # defining a function
    volume = 4/3*pi*r**3
    mass = rho * volume
    return mass

m1 = Sphere(1, 7.87) 
m2 = Sphere(3, 8.96)  
m3 = Sphere(7, 11.36) 
print (m1+m2+m3)
( function_return.py )     

8.4  Returning multiple values

A function can return more than one values.
Example: Returned values of Functions
Calculate the total mass and total volume of spheres of radii 1, 3, and 7 and densities 7.87, 8.96, 11.36 respectively.
function_return_multi.py
from math import *

def Sphere(r, rho):  # defining a function
    volume = 4/3*pi*r**3
    mass = rho * volume
    return volume, mass  # returning a list of 2 values

L = Sphere(1, 7.87)  # assign list to variable L
v1 = L[0]            # extract values from list
m1 = L[1]

v2, m2 = Sphere(3, 8.96)  # assign list's values directly to variables
v3, m3 = Sphere(7, 11.36) 

print(v1+v2+v3, m1+m2+m3)
( function_return_multi.py )     
Explanation

8.5  Mathematical Functions

Many useful mathematical functions are pre-defined in the math library (requires "from math import *"), including
Function Description
sqrt(x)         square root
exp(x) exponentiation
log(x) natural logarithm
log10(x) base-10 logarithm
fabs(x) absolute value
floor(x) truncate to whole number (not rounding)
sin(x) sine
cos(x) cosine
tan(x) tangent
asin(x) arc-sine
acos(x) arc-cosine
atan(x) arc-tangent
(trigonometric functions assume parameters in radian)

Chapter 9
Jupyter Notebook and Google Colab

    Notebook interface is a worksheet-like environment for both (1) word processing and (2) program development and execution.
Jupyter Notebook is a popular notebook environment originally for Python and now includes many other programming languages. Its new version is called JupyterLab.
Google Colaboratory, i.e. Google Colab, is an online Jupyter notebook environment. Files are stored in Google Drive.
With Google Colab, we can describe and solve our problem about spheres' masses. The resulting notebook can look like a simple report.
This Colab notebook is accessible at https://colab.research.google.com/drive/1E7nws_7QaMpgQN7FZWzvW0dhzCUkW499.
Explanation

Chapter 10
Strings and Input / Output

10.1  Escape sequence

An escape sequence is a combination characters that has a special meaning, e.g.
\n     Linefeed character, i.e. to start a new line
\t tab character, i.e. jump to next tab position (e.g. column 1,9,17,25,...)
\′ single quote
\" double quote
e.g.
escape_sequence.py
print( "A quote (\' or \") can be included in a string" )
print( "1\t10\t100\n1000\t10000\t100000") # output a simple table of numbers
( escape_sequence.py )     
     Program output:
A quote (' or ") can be included in a string
1       10      100
1000    10000   100000

10.2  String operations

Strings can be joined or shortened, e.g.
string_operations.py
s1 = "joining" + " strings"  # add two strings
s2 = s1[8:14]  # substring of characters 8 to 14
s3 = s1[8:]    # substring of characters 8 to end of string
s4 = s1[0:-4]  # substring of characters 0 to 4th last character.
print(s1 + '\n' + s2 + '\n' + s3 + '\n' + s4)
( string_operations.py )     
     Program output:
joining strings
string
strings
joining str
These operations for strings are generally applicable to lists, since a string is a list of characters.

10.3  Formatted strings

( Requires Python 3.6 or newer, e.g. Google Colab or CodingGround, but NOT OnlineGDB. )
Formatted strings provide detailed controls on the construction of strings. e.g.
formatted_strings.py
x = 1
y = 3
print( f"{x} / {y} = {x/y}")  # an expression inside { } will be evaluated 
print( f"{x:10d}{y:10d}") # controlling width
print( f"{x/y:10.3g}{x/y:10.3g} {x/y*1e10:.3g}")  # controlling width and no. of s.f.
( formatted_strings.py )     
     Program output:
1 / 3 = 0.3333333333333333
         1         3
     0.333     0.333 3.33e+09
Explanation
f" ... "
constructs a formatted string
{ ... }
encloses an expression to be evaluated
<integer value>:<width>d
formats an integer to a width <width> right-justified
<float value>:<width>.<n>g
formats a float to a width <width> with <n> significant figures right-justified. Scientific notation is used when appropriate.

10.4  Input

The input() function reads user's input from the keyboard, e.g
input.py
S = input("Please enter your message: ")
print( S, type(S) )
( input.py )     
     Program output (if user enters 'Hello'):
Please enter your message: Hello
Hello <class 'str'>
     Program output (if user enters '12'):
Please enter your message: 12
12 <class 'str'>
     Program output (if user enters '12 25'):
Please enter your message: 12 25
12 25 <class 'str'>
Explanation
To extract numerical values from user input:
input2.py
S = input("Enter two numbers: ")
s1, s2 = S.split()       # splitting string into words
print( s1, s2, s1+s2 )   # adding (i.e. joining) strings, rather than adding numbers
x=float(s1); y=float(s2) # converting string to float
print( x, y, x+y )       # adding numbers
( input_numbers.py )     
     Program output (if user enters '13 28'):
Enter two numbers: 13 28
13 28 1328
13.0 28.0 41.0
Explanation

10.5  File Output

Very often, one wants to output result to a file rather than to the screen, e.g.
fileout.py
ofile = open("numbers.txt", "w")
for i in range(10):
    ofile.write( str(i) + " ")
ofile.close()
( file_output.py )     
It creates a file called numbers.txt.
Explanation
open( <file name>, "w" )
Create and open a file with name <file name> for writing. It returns a file object, i.e. a variable representing the file.
.write( <string> )
A method of the file object which outputs the string to the file.
.close()
A method of the file object which closes the file and finishes outputting.
.txt
A filename extension usually denoting text file format and can be opened by e.g. microsoft notepad.
Example: File Output
Output to a file a table of values from the normal distribution function defined by
f(x) = 1





e−x2/2
(10.1)
for x=−5, −0.49, −0.48, ... 5.
normal_dist.py
from math import *

def f(x):
    return (1/sqrt(2*pi)) * exp(-x**2/2)

ofile = open("normal.txt", "w")
x = -5
while x <= 5:
    ofile.write( str(x) + " " + str(f(x)) + "\n" )
    x += 0.01
ofile.close()
( normal_dist.py )     
The created file is normal.txt.
Explanation
The data file can be used to plot a graph using e.g. MS Excel:

10.6  File Input

Example: file input
Read the file normal.txt and sum up all values in the second column.
file_input.py
infile = open("normal.txt", "r")
sum=0
for line in infile:
    s1, s2 = line.split()
    x=float(s1); y=float(s2)
    sum += y
print(sum)
infile.close()
( file_input.py )     
Explanation
open( <file name>, "r" )
Open a file with name <file name> for reading. It returns a file object.
for <string variable> in <file object>:
The file object supplies a list of lines read from the file. The for-loop loops over each line in the list.

Chapter 11
Python Libraries

11.1  Introduction

Python has built-in data types and functions for essential operations. More data types and functions can be added by using libraries (also called modules) to extend Python's capabilities. Some popular libraries are pre-installed with Python. Some others require downloading and installation separately. For example, OnlineGDB has about 500 libraries installed. Important libraries include math, numpy, matplotlib, scipy, cmath, etc. To see a full list of installed libraries, type ' help "modules" '.
Advantages of Python's capability to use libraries (rather than bulid-in everything):
Before using a library, include the import command.

11.2  NumPy

NumPy is a Python library for numerical calculations. Its functionalities include:
Array
An array is a list with all elements of the same type, e.g. integer or float. (Many programming languages support arrays, but not lists.)
array.py
import numpy as np
L = [1, 4, 9, 16, 25, 36]   # create a list of integers
X1 = np.array(L); print(X1) # convert to array
X2 = np.append( X1, [49, 64]); print(X2)  # append elements to array
X3 = X2[1:7]; print(X3)  # extract sub-array of elements 1 to 7
X4 = X3[:-2]; print(X4)  # extract sub-array from elements 0 excluding last 2
( array.py )     
     Program output:
[ 1 4 9 16 25 36]
[ 1 4 9 16 25 36 49 64]
[ 4 9 16 25 36 49]
[ 4 9 16 25]
i.e. array admits indexing operators similar to those for lists (see Sec. 6.3).
array2.py
import numpy as np
X = np.arange(4);         # creates an array, analogous to range
print(X, X+1, 2*X, X**2)  # simple algebric operations of array elements
print(np.exp(X))          # mathematic function for array elements
print(np.sum(X))          # sum up all elements
Y =np.linspace(2,8,4);    # creates an array with 4 equally spaced points
print(Y, X+Y, X*Y)        # simple algebric oerpations of array elements
( array2.py )     
     Program output:
[0 1 2 3] [1 2 3 4] [0 2 4 6] [0 1 4 9]
[ 1. 2.71828183 7.3890561 20.08553692]
6
[ 2. 4. 6. 8.] [ 2. 5. 8. 11.] [ 0. 4. 12. 24.]
Explanation
X+1, 2*X, X**2, X+Y, X*Y
Algebraic operations on arrays are performed element by element. In many other languages, a for loop over each element is needed.
arange( [<start>, ] <stop> [, <step>] )
creates an array with evenly spaced values from <start> to <stop> (but excluding <stop>) with a step size of <step>. It is similar to range(), but <step> need not be an integer.
linspace( <start>, <stop>, <number> )
creates an array with evenly spaced values from <start> to <stop> (and including <stop>) with <number> elements.
Two dimensional Arrays
A two-dimensional array can store a table of numbers for further processing, e.g.
array2d.py
import numpy as np
X = np.array( [[1, 2, 3], 
               [4, 5, 6]]) # convert a list of list to a 2D array
print(X)        # output entire array
print(X[0,1])   # output element at row 0, column 1
( array2d.py )     
     Program output:
[[1 2 3]
[4 5 6]]
2

11.3  Matplotlib

Matplotlib is a graph plotting library usable in Google Colab.
For example, to evaluated and plot the normal distribution function in Eq. 10.1, we can use the following program:
normal_dist_plot.py
# calculate and plot normal distribution (run in google colab)
from math import *
import matplotlib.pyplot as plt  
import numpy as np  

X = np.linspace(-5,5,101)            # create array of values from -5 to 5 with 101 elements
Y = 1/sqrt(2*pi) * np.exp( -X**2/2 ) # calculate P(x) for each element in X

plt.plot(X, Y)                       # plot a graph
plt.xlabel('x')  
plt.ylabel('P(x)')  
plt.title('Normal distribution')   
plt.savefig('Normal_distribution.jpg')   
( normal_dist_plot.py )     
Click https://colab.research.google.com/drive/1JmPTJX8tuvv9TtczHwuV6fFYyW0DFkdR to open this Colab notebook. The generated file (Normal_distribution.jpg) containing the graph can be downloaded and is shown below:

Chapter 12
Advanced topic: Classes

A new data type can be created by defining a new class. For example, the following program defines a complex number class (which in fact is already available in the library cmath) and adds tow complex numbers:
complex_class.py
class Complex:                 # define a complex data type
    def __init__(self, x, y):  # initialization function of complex variable
        self.re = x            # creates variable re within the complex variable
        self.im = y            # creates variable im within the complex variable

z1 = Complex(1, 1)       # creates a complex variable       
z2 = Complex(1, 2)       # creates another complex variable
z2.im = 5                # variables within complex variable can be modified
zsum = Complex( z1.re + z2.re, z1.im + z2.im )  # addition of complex two variables
print(zsum.re, zsum.im)  # output complex variable by outputing components
( complex_class.py )     
     Program output:
2 6
Explanation
<class name>( ... ) ,     e.g. Complex(1, 1)
Create a variable, i.e. an object, of this class.
class <class name>: ,     e.g. class Complex:
Start the definition of a class.
__init__(self [, ...] )
The constructor function of the class. When an object of this class is created, it is automatically called by the Python interpretor. The first argument (usually represented by the variable named "self") is the created object itself.
self.<attribute name> = <value> , e.g. self.re = x
This assignment operation creates a variable inside the object. Such a variable is called an attribute of the object.
<object name>.<attribute name> , e.g. self.re, z1.re
An attribute of an object can be assessed inside or outside the class definition.
The addition and output of complex numbers can be improved as follows:
complex_class2.py
class Complex:                 # define a complex data type
    def __init__(self, x, y):  # initialization function of complex variable
        self.re = x            # creates variable re within the complex variable
        self.im = y            # creates variable im within the complex variable

    def add(self, z):          # a method for addition
        return Complex(self.re + z.re, self.im + z.im)

    def __add__(self, z):      # an operator for addition
        return Complex(self.re + z.re, self.im + z.im)

    def __str__(self):         # convert the number to a string, used by print()
        return str(self.re) + '+' + str(self.im) + 'i'

z1 = Complex(1, 1)           
z2 = Complex(1, 3)
print( z1, z2, z1.add(z2) )  # addition using a method
print( z1, z2, z1 + z2 )     # addition using an operator
( complex_class2.py )     
     Program output:
1+1i 1+3i 2+4i
1+1i 1+3i 2+4i
Explanation
def add(self, z):
A function defined inside a class definition is called a method.
z1.add(z2)
Calling the method "add" of the object z1 with an argument z2.
def __add__(self, z):
Define a special method of the class associated with the "+" operator.
def __str__(self)
Define a special method of the class called by str() and print() functions.
- End of Lecture Notes -


File translated from TEX by TTH, version 4.15.
On 4 Mar 2021, 15:23.