ZK-Bootcamp - Precourse Practise
Numpy warmup
Make sure you have numpy installed.
!python -m pip install numpy
Requirement already satisfied: numpy in c:\python312\lib\site-packages (2.3.0)
[notice] A new release of pip is available: 24.2 -> 25.1.1
[notice] To update, run: python.exe -m pip install --upgrade pip
import numpy as np
Exercise 1, add two arrays together
We have two arrays: A and B
A = [[1,2,3],[4,5,6],[7,8,9]]
B = [[1,1,1],[2,2,2],[3,3,3]]
C = [[2,3,4],[6,7,8],[10,11,12]]
Your code should work for general matrices, not just the ones above. Use np.array
, not np.matrix
. Your function will need to cast the above to np.arrays. If you get stuck ask chatGPT!
A = [[1,2,3],[4,5,6],[7,8,9]]
B = [[1,1,1],[2,2,2],[3,3,3]]
C = [[2,3,4],[6,7,8],[10,11,12]]
def add_arrays(A, B):
# your code here
for i in range(len(A)): # Iterate through rows
for j in range(len(A[i])): # Iterate through columns
C[i][j] = A[i][j] + B[i][j]
return C
assert (add_arrays(A, B) == np.array(C)).all()
What does the .all()
do? The above operation does an elementwise equality check. It checks that every item in the array is True
.
print(np.array([True, True, True]).all())
print(np.array([False, True, True]).all())
True
False
Exercise 2, element-wise and matrix multiplication
When dealing with numpy arrays, we need to be clear if we are doing matrix multiplication or elementwise multiplication.
Your task is to write functions for both. Numpy supports both, figure out how it does it. Don’t implement it manually
def matrix_multiply(A, B):
A = np.array(A)
B = np.array(B)
C = A @ B # Using numpy's matrix multiplication
return C
R = [[14,14,14],[32,32,32],[50,50,50]]
assert (matrix_multiply(A, B) == np.array(R)).all()
def element_wise_multiply(A, B):
A = np.array(A)
B = np.array(B)
C = A * B # Element-wise multiplication
return C
R = [[1,2,3],[8,10,12],[21,24,27]]
assert (element_wise_multiply(A, B) == np.array(R)).all()
To avoid giving hints, we won’t supply the test case here. But you can check your work online!
Exercise 3, the dot product
The dot product is another kind of multiplication.
We expect [1,2,3,4] $\cdot$ [1,2,3,4] to be equal (1 * 1) + (2 * 2) + (3 * 3) + (4 * 4) = 1 + 4 + 9 + 16 = 20
Figure out numpy’s implementation and do it. Don’t implement it manually.
def dot_product(A, B):
A = np.array(A)
B = np.array(B)
C = np.dot(A, B)
return C
D_A = [1,2,3,4]
D_B = [1,2,3,4]
D = 30
assert (dot_product(D_A, D_B) == D).all()
Exercise 4, linear combinations
A linear combination is a Vector multiplied by a constant plus another Vector multiplied by a constant.
Aa + Bb = C (A, B, C are vectors, a and b are scalars)
Compute the linear combination in the general case.
def linearCombination(A, B, a, b):
A = np.array(A)
B = np.array(B)
return a * A + b * B
vector1 = np.array([1,2])
vector2 = np.array([5,6])
scalar1 = 3
scalar2 = 10
assert (np.array([53, 66]) == linearCombination(vector1, vector2, scalar1, scalar2)).all()
Exercise 5, modular arithmetic
Modular arithmetic is important in cryptography. The challenge here is to compute the modular inverse of 15 % 1223. That is 15 * x % 1223 == 1. The basic syntax for this is the same as other languages
(5 * 16) % 1223
80
(5 + 1219) % 1223
1
Be very careful, because the mod operator sometimes takes precedence!
## Todo: compute x
x = pow(5, -1, 1223) # Modular multiplicative inverse of 5 mod 1223
assert (5 * x )% 1223 == 1
Hint: Python 3.8 has a very nice way to do this
Exercise 6, Column and Row Slicing
Numpy let’s you select rows and columns from matrices. For example, given
[[1,2,3],
[4,5,6],
[7,8,9]]
you can retrive [2,5,8] or [7,8,9] conveniently. Implement those below:
def get_column_as_1d(A, col_number):
A = np.array(A)
return A[:, col_number] # Return the specified column as a 1D array
def get_row_as_1d(A, col_number):
A = np.array(A)
return A[col_number, :] # Return the specified row as a 1D array
A = [[1,2,3],[4,5,6],[7,8,9]]
print(get_column_as_1d(A, 1)) # [2,5,8]
[2 5 8]
print(get_row_as_1d(A, 2)) # [7,8,9]
[7 8 9]