Laboratory 1b: Python Review#
Programming skills
Iteration
Functions
Conditional statements
Required hardware: None
Total: 100 points
Student information#
Write your name and email below.
Name:
Email:
Importing required libraries#
import numpy as np # Numpy will assist in manipulating datastructures like arrays.
import matplotlib.pyplot as plt # Matplotlib is MATLAB implementation in python for the purpose of plotting and visualising data.
from matplotlib import rcParams # rcParams
rcParams.update({'font.size': 20}) # for setting text size in plots
Variables and data types#
# --- INTEGER DEFINITION ---
# If no decimal place is provided, Python considers it an integer
a = 9
# --- FLOAT DEFINITION ---
# Specifying a decimal point creates a float
b = 6.05
# --- STRING DEFINITION ---
# Strings are collections of characters, defined with '' or ""
c = 'for'
d = "good"
# --- LIST DEFINITION ---
# Lists are flexible containers that can hold multiple data types
e = [a, b, c]
print("Datatype of variable a = ", type(a))
print("Datatype of variable b = ", type(b))
print("Datatype of variable c = ", type(c))
print("Datatype of variable d = ", type(d))
print("Datatype of variable e = ", type(e))
Datatype of variable a = <class 'int'>
Datatype of variable b = <class 'float'>
Datatype of variable c = <class 'str'>
Datatype of variable d = <class 'str'>
Datatype of variable e = <class 'list'>
# Type conversion from foat to int and int to float
print(int(9.08))
print(float(98))
9
98.0
Common operations on variables#
Addition/Subtraction:
+,-— for numeric variables these perform arithmetic (e.g., \(3 + 2 = 5\)). For sequences like lists or strings,+performs concatenation.Multiplication/Division:
*,/—*multiplies numbers and can repeat sequences;/performs floating-point division (e.g., \(5 / 2 = 2.5\)).Exponentiation:
**— raises a number to a power (e.g., \(2^3\) is written as2 ** 3).Root: Use
np.sqrt()for square roots or fractional powers for \(n^{th}\) roots (e.g.,8 ** (1/3)for \(\sqrt[3]{8}\)).
Data structures#
In computer languages, data structures are systematic ways to represent collections of data. This allows us to manipulate, transform, or search through an entire dataset efficiently.
The most common structures in Python are lists and arrays. Both are sequential, meaning elements are arranged linearly and can be accessed by their position (index).
Lists and arrays#
Python lists#
A general-purpose container that can hold a mixture of different types (integers, strings, or even other lists).
Pros: Flexible and built into Python.
Cons: Slower for mathematical operations and uses more memory.
NumPy arrays#
Specialized for numerical data. All elements are normally of the same type (for example, all floats).
Pros: Extremely fast and supports vectorization (applying mathematics to an entire array at once).
Cons: Less flexible with mixed data types.
Common list commands#
Append:
list.append(x)adds elementxto the end.Delete:
del list[i]removes the element at indexi.Insert:
list.insert(i, x)adds elementxat index positioni.
# Example for working with list
list1 = [3, 14.98, 'cab', np.sqrt(2)]
print(list1)
list1.append(np.sqrt(9))
print(list1)
list1.insert(2, -20) # Adds -20 at index 2 (the 3rd position)
print(list1)
Iteration and indexing#
Both lists and arrays are ordered sequences. Imagine them as a row of boxes, where each box has a specific address called an index.
Zero-based indexing: In Python, we start counting from 0, not 1.
Index |
0 |
1 |
2 |
3 |
4 |
|---|---|---|---|---|---|
Content |
10 |
20 |
30 |
40 |
50 |
my_list[0]would give you 10.my_list[4]would give you 50.
We use iterators (such as a for loop) to visit each box in sequence and perform an action.
# example for using for-loop
for i in range(1, 10):
print("iterating variable value = ", i)
print("Square of the iterating variable = ", i*i)
# example for summing elements using an index-based loop
array1 = np.array([1, -1, 9, -4, 5])
sum_val = 0
for i in range(0, 5):
sum_val = sum_val + array1[i] # the '[i]' keyword after the 'array1' allows one to access the 'ith' element of the array.
print("Total sum of all the elemets =", sum_val)
Problem 1 (5 points). Compute
Start with the code below and fill in the missing pieces.
total = 0
for i in range(____, ____):
total = total + ____
print(total)
Conditional statements#
An if-else statement is a conditional branch. It allows the program to make decisions based on whether a specific condition is True or False.
if: The computer checks the condition. If it is true, the code block directly under it runs.elif(optional): Short for “else if.” It is checked only if the firstifcondition was false.else: The catch-all case. It runs only if none of the preceding conditions were met.
Syntax:
if condition == True:
# run this block
else:
# run this block instead
# Determine whether a number is positive, negative, or zero
num = 10
if num > 0:
print("number is positive")
elif num < 0:
print("number is negative")
else:
print("number is zero")
number is positive
# Example for if-else
number_range_lower_bound = 1
number_range_upper_bound = 11
for i in range(number_range_lower_bound, number_range_upper_bound):
if i % 2 == 0: # Here the '%' operator checks for remainder. If a number is divisible it return 0, else it gives out the remainder.
print("iterator ", i, " is even")
else: # whenever the remainder is non-zero the if-block fails and the else-block is executed.
print("iterator ", i, " is odd")
# Note: The computer will execute any one of the condition blocks. When if-block is satisfied, the else-block won't be executed and vice-versa.
Problem 2 (10 points). Iterate through the integers from 1 through 50 and find all the numbers divisible by 3.
Store the divisible numbers in a new list and print the list.
# Write code here
Built-in functions#
Python provides many ready-to-use functions:
np.array(my_list): Converts a Python list into a NumPy array.len(object): Returns the number of items in a list, array, or string.
# Example of list to array conversion and their dimensions.
list1 = [3, 14.98, 'cab', np.sqrt(2)]
array3 = np.array(list1)
print(array3, array3[2])
print(len(array3[2]), len(list1))
Coding note: Equivalent correct implementations are acceptable unless a problem requires a particular method.
Problem 3 (15 points). Define a list named x containing the integers from \(-10\) through \(10\). Then define a new list y using
Plot y versus x. The graph should resemble a parabola. Unless your instructor says otherwise, special styling, axis labels, and a title are not required.
# Write your code here
User-defined functions#
A user-defined function is a reusable block of code that performs a specific task. We define functions using the def keyword.
How to define a function:
defkeyword: Tells Python you are creating a function.Function name: A descriptive name (for example,
calculate_area).Arguments (inputs): Variables passed inside the parentheses
().Colon
:: Ends the function header.Indented body: Contains the function’s logic.
returnstatement: Sends the result back to the caller.
Example:
def greet_user(name):
message = "Hello " + name
return message
# Example function for adding
def add_nos(a, b):
c = a + b
return c
# Example for calling the function defined above
x, y = 9, 6
z = add_nos(x, y)
print("Result obtained from the function above = ", z)
Problem 4 (15 points). Define a function that finds both roots of a quadratic polynomial:
You may use the quadratic formula:
Assume that \(a \ne 0\) and that the polynomial has two real roots. You do not need to handle linear equations, complex roots, or other edge cases.
# define function
# call function
NumPy array functions#
np.linspace(start, stop, N): Generates \(N\) equally spaced elements.Example:
x = np.linspace(0, 10, 5)creates[0, 2.5, 5, 7.5, 10].
np.asarray(list): Converts a Python list to a NumPy array.Example:
arr = np.asarray([1, 2, 3])converts the list to an array.
np.size(array): Returns the total number of elements in the array.Example:
np.size(np.array([10, 20]))returns2.
Problem 5 (20 points). Approximate the integral
using a left Riemann sum.
A Riemann sum approximates the area under \(f(x)\) by summing rectangle areas. The figure below illustrates this idea (source).
Let \(L_N\) denote the left Riemann sum when \([0,1]\) is divided into \(N\) equal subintervals:
where \(\Delta x = 1/N\) and \(x_i=i\Delta x\).
(a) 5 points: Write code that computes \(L_N\) for \(N=10\).
(b) 5 points: Convert the code from part (a) into a function that computes \(L_N\) for any positive integer \(N\).
(c) 10 points: For Nvals = [10, 100, 1000], compute \(L_N\) for each value and plot \(N\) versus \(L_N\). Compare the approximations explicitly with the exact value \(I=1/3\), and state whether the left sums approach \(1/3\) from above or below.
# Write your code here
Problem 6 (20 points). Find where consecutive values in a list change sign. Let x contain 100 equally spaced values from \(-2\) to \(2\), and let y store the corresponding values of
(a) 5 points: Write a function f that calculates \(f(x)=x^3-x\), then store the sampled values as y = f(x).
(b) 5 points: Given two numbers \(a\) and \(b\), explain what the sign of their product \(ab\) tells you about the signs of \(a\) and \(b\).
(c) 5 points: Write code that identifies and displays the intervals \([x_i,x_{i+1}]\) containing all three sign changes in y.
(d) 5 points: Write code that reports the total number of sign changes.
# Write your code here
Boolean indexing#
Boolean indexing lets you select data from an array using a corresponding array of True and False values.
x = np.array([-3, -1, 2, 5, -4])
x>0
array([False, False, True, True, False])
Problem 7: Boolean-indexing check (5 points total). Run the code above and answer the following short questions:
(a) Use type(...) to determine the output. What NumPy/Python type is it?
(b) How long is it?
(c) Which entries are True?
(d) What happens when you change the last line to x < 0?
x = np.array([-3, -1, 2, 5, -4])
mask = x > 0
x[mask]
array([2, 5])
Continue Problem 7 using the second code example:
(e) What does x[x > 0] return?
(f) What does x[x > 2] return?
This technique is called Boolean indexing: selecting elements from an array with a Boolean (True/False) array of the same length.
# Example for boolean indexing
x = np.array([1, 3, 5, 7, 6, 4, 2])
y = np.array([True, True, True, False, False, True, False])
print("Filtered x: ", x[y])
Filtered x: [1 3 5 4]
# Another example for boolean indexing for fiteration
# A list of temperature readings in Celsius
temps = np.array([-5.2, 12.5, 0.4, -1.8, 25.0, 3.2, -10.5])
# 1. Create a Boolean mask
# This checks which elements are greater than 0
mask = temps > 0
print("Boolean Mask:", mask)
# Output: [False True True False True True False]
# 2. Use the mask to index the array
# This returns only the values where the mask is True
above_freezing = temps[mask]
print("Values above freezing:", above_freezing)
# Output: [12.5 0.4 25. 3.2]
Boolean Mask: [False True True False True True False]
Values above freezing: [12.5 0.4 25. 3.2]
Slicing#
We can also take slices of an array.
arr[a:b]
This selects elements starting at index a
This stops selecting elements before index b
Index b is not included
arr[1:]
This selects elements starting at index 1
Recall, in python, arrays start at index 0
The : with nothing after it means go to the end
It returns all elements except the first one
arr[:-1]
The : with nothing before it means start at index 0
The -1 refers to the last index
It returns all elements except the last one
# --- Example of [:-1] and [1:] Indexing ---
arr = np.array([10, 20, 30, 40, 50])
print(arr)
# arr[:-1] gets all elements EXCEPT the last one: [10, 20, 30, 40]
current_elements = arr[:-1]
print(current_elements)
# arr[1:] gets all elements EXCEPT the first one: [20, 30, 40, 50]
next_elements = arr[1:]
print(next_elements)
# By comparing them, we can find the difference or sign change between neighbors
diff = next_elements - current_elements
print("Difference between neighbors:", diff)
[10 20 30 40 50]
[10 20 30 40]
[20 30 40 50]
Difference between neighbors: [10 10 10 10]
Problem 8 (10 points). Solve the sign-change problem again using NumPy tools such as np.array(), np.sign(), and Boolean indexing. Your solution must:
Create
xandyas NumPy arrays.Construct a Boolean mask for adjacent sign changes without using a loop.
Display the intervals containing the sign changes.
Report the number of sign changes.
Hint: To compare adjacent elements efficiently, use slices such as array[:-1] and array[1:], as shown above.
# Write your code here