MATH40006 · Practice Paper

MATH40006 2026 Practice Paper 1

Revision questions and worked solutions, presented read-only. This review interface was prepared after the recorded study period.

Status
Completed
Questions completed
3 / 3
Suggested time
60 minutes
Source date
2026-08-01
← Back to course 3 question-and-solution records
Question 120 marks

Scalar/vector field visualisation

MATH40006_Mock_1 July 31, 2026 1 MATH40006 Mock Examination 1 Time allowed: 60 minutes T otal marks: 50 Answer all three questions in this Jupyter notebook. This paper is an original equal-difficulty training paper. It follows the latest regular assessment structure (20 + 20 + 10 marks). [ ]: import numpy as np import sympy as sp import matplotlib.pyplot as plt import pandas as pd from time import perf_counter from copy import copy import pickle import ast sp.init_printing() 1.1 Question 1 (20 marks) The scalar function is v(x,y) = x^2/2 + sin(y), for -2 <= x <= 2 and -pi <= y <= pi. The computational domain is shown below. 1 (a) Define x_values1 and y_values1 as one-dimensional NumPy arrays of 101 equally spaced points on the stated intervals. [2] (b) Use meshgrid to define 101 by 101 arrays x1 and y1. [2] (c) Use imshow, with correct origin and extent, to visualise v on the rectangle. [3] (d) Create a contour plot of v using x1 and y1. [2] (e) Define lower-resolution arrays x_values2 and y_values2 containing 21 equally spaced points on the same intervals. [2] (f) Use meshgrid to define x2 and y2. [2] (g) Since v_x=x and v_y=cos(y), use quiver to plot the vector field (v_y,-v_x) on the lower- resolution grid. [2] (h) Superimpose the vector field in blue on red contours of v. [2] (i) Use plot_wireframe to draw z=v(x,y) from x1 and y1. [3] [ ]: # YOUR CODE HERE raise NotImplementedError()
Worked solution and marking guidance
MATH40006_Mock_1_Solutions July 31, 2026 1 MATH40006 Mock Examination 1 Time allowed: 60 minutes T otal marks: 50 Answer all three questions in this Jupyter notebook. This paper is an original equal-difficulty training paper. It follows the latest regular assessment structure (20 + 20 + 10 marks). 1.1 Complete worked solutions and marking guide [1]: import numpy as np import sympy as sp import matplotlib.pyplot as plt import pandas as pd from time import perf_counter from copy import copy import pickle import ast sp.init_printing() 1.2 Question 1 (20 marks) The scalar function is v(x,y) = x^2/2 + sin(y), for -2 <= x <= 2 and -pi <= y <= pi. The computational domain is shown below. 1 (a) Define x_values1 and y_values1 as one-dimensional NumPy arrays of 101 equally spaced points on the stated intervals. [2] (b) Use meshgrid to define 101 by 101 arrays x1 and y1. [2] (c) Use imshow, with correct origin and extent, to visualise v on the rectangle. [3] (d) Create a contour plot of v using x1 and y1. [2] (e) Define lower-resolution arrays x_values2 and y_values2 containing 21 equally spaced points on the same intervals. [2] (f) Use meshgrid to define x2 and y2. [2] (g) Since v_x=x and v_y=cos(y), use quiver to plot the vector field (v_y,-v_x) on the lower- resolution grid. [2] (h) Superimpose the vector field in blue on red contours of v. [2] (i) Use plot_wireframe to draw z=v(x,y) from x1 and y1. [3] [2]: x_values1 = np.linspace(-2, 2, 101) y_values1 = np.linspace(-np.pi, np .pi, 101) x1, y1 = np.meshgrid(x_values1, y_values1) v1 = x1**2/2 + np.sin(y1) plt.figure() plt.imshow(v1, origin ='lower', extent =[-2,2,-np.pi,np.pi], aspect ='auto') plt.title('v(x,y)') plt.figure() plt.contour(x1, y1, v1) 2 x_values2 = np.linspace(-2, 2, 21) y_values2 = np.linspace(-np.pi, np .pi, 21) x2, y2 = np.meshgrid(x_values2, y_values2) plt.figure() plt.quiver(x2, y2, np .cos(y2), -x2) plt.figure() plt.contour(x1, y1, v1, colors ='red') plt.quiver(x2, y2, np .cos(y2), -x2, color ='blue') fig = plt.figure() ax = fig.add_subplot(111, projection ='3d') ax.plot_wireframe(x1, y1, v1) plt.show() 3 4 5 Marking points / verification. 2 marks for the two correct 1D arrays; 2 for meshgrid; 3 for imshow including origin='lower' and the correct extent; 2 for contours; 2+2 for the coarse grid; 2 for the correct vector components; 2 for the coloured overlay; 3 for a valid 3D wireframe. All generated arrays are 101x101 or 21x21 as required.
Question 220 marks

Sieve of Sundaram

1.2 Question 2 (20 marks) This question develops the Sieve of Sundaram . It will return all primes not exceeding a positive integer N. (a) Experiment with np.repeat([2,5,9], 3) . Describe what repeat does. [1] (b) Experiment with np.nonzero([0,4,0,7,0]). Describe its output for a one-dimensional ar- ray. [1] (c) Set N=100, set m=(N-1)//2, and create a Boolean array discarded of length m+1, initially all False. [2] 2 (d) For integers i>=1 and j>=i, mark position i+j+2*i*j as discarded whenever that position is at most m. Use nested loops, and stop each inner loop as soon as the position is too large. [5] (e) Use the positions that remain False to construct an array containing all primes at most N. Remember that the odd prime associated with position k is 2*k+1, and include 2 when appropriate. [3] (f) Write a function sundaram_sieve(N) implementing the complete method and returning a NumPy array of primes. It must work for all positive integers N. [6] (g) Test typical cases and edge cases, including at least one value N>=10000. [2] [ ]: # YOUR CODE HERE raise NotImplementedError()
Worked solution and marking guidance
1.3 Question 2 (20 marks) This question develops the Sieve of Sundaram . It will return all primes not exceeding a positive integer N. (a) Experiment with np.repeat([2,5,9], 3) . Describe what repeat does. [1] (b) Experiment with np.nonzero([0,4,0,7,0]). Describe its output for a one-dimensional ar- ray. [1] (c) Set N=100, set m=(N-1)//2, and create a Boolean array discarded of length m+1, initially all False. [2] (d) For integers i>=1 and j>=i, mark position i+j+2*i*j as discarded whenever that position is at most m. Use nested loops, and stop each inner loop as soon as the position is too large. [5] (e) Use the positions that remain False to construct an array containing all primes at most N. Remember that the odd prime associated with position k is 2*k+1, and include 2 when appropriate. [3] (f) Write a function sundaram_sieve(N) implementing the complete method and returning a NumPy array of primes. It must work for all positive integers N. [6] 6 (g) Test typical cases and edge cases, including at least one value N>=10000. [2] [3]: print(np.repeat([2,5,9],3)) print(np.nonzero([0,4,0,7,0])) N = 100 m = (N-1)//2 discarded = np.zeros(m+1, dtype =bool) for i in range(1, m +1): for j in range(i, m +1): k = i + j + 2*i*j if k > m: break discarded[k] = True positions = np.flatnonzero(~discarded)[1:] primes = 2*positions + 1 if N >= 2: primes = np.insert(primes, 0, 2) primes = primes[primes <= N] print(primes) def sundaram_sieve(N): if N < 2: return np.array([], dtype =int) m = (N-1)//2 discarded = np.zeros(m+1, dtype =bool) for i in range(1, m +1): for j in range(i, m +1): k = i + j + 2*i*j if k > m: break discarded[k] = True odd_positions = np.flatnonzero(~discarded)[1:] result = 2*odd_positions + 1 result = result[result <= N] return np.insert(result, 0, 2) for N in [1,2,3,10,100,10000]: p = sundaram_sieve(N) assert np.all(p <= N) assert np.array_equal(p, np .array([q for q in range(2,N+1) if all(q%d for d ␣ ↪in range(2,int(q**0.5)+1))])) print('all sieve tests passed ') [2 2 2 5 5 5 9 9 9] (array([1, 3]),) [ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97] 7 Marking points / verification. 1 mark for an accurate description of each unfamiliar function; 2 for correct state initialisation; 5 for the exact Sundaram index and efficient inner-loop stop; 3 for correct recovery of 2 and odd primes; 6 for a reusable function including N<2; 2 for broad tests. The reference tests compare against independent trial division.
Question 310 marks

Mediants and Farey refinement

1.3 Question 3 (10 marks) For two vectors [a,b] and [c,d], define their mediant vector to be [a+c,b+d]. The helper riffle alternates two lists: def riffle(l1,l2): out = l1 + l2 out[::2] = l1 out[1::2] = l2 return out (a) Write neighbor_mediants(lis) returning mediants of each adjacent pair. [2] (b) Test it on [array([0,1]), array([1,1]), array([1,0])] . [1] (c) Write riffled_mediants(lis) that inserts each mediant between its two parents. [2] (d) Test it on the same list. [1] (e) Write farey_refinement(n): start with [array([0,1]), array([1,1])] , apply riffled_mediants exactly n times, and return all vectors as SymPy Rationals. [3] (f) Test farey_refinement(3). [1] [ ]: def riffle(l1,l2): out = l1 + l2 out[::2] = l1 out[1::2] = l2 return out # YOUR CODE HERE raise NotImplementedError() 3
Worked solution and marking guidance
1.4 Question 3 (10 marks) For two vectors [a,b] and [c,d], define their mediant vector to be [a+c,b+d]. The helper riffle alternates two lists: def riffle(l1,l2): out = l1 + l2 out[::2] = l1 out[1::2] = l2 return out (a) Write neighbor_mediants(lis) returning mediants of each adjacent pair. [2] (b) Test it on [array([0,1]), array([1,1]), array([1,0])] . [1] (c) Write riffled_mediants(lis) that inserts each mediant between its two parents. [2] (d) Test it on the same list. [1] (e) Write farey_refinement(n): start with [array([0,1]), array([1,1])] , apply riffled_mediants exactly n times, and return all vectors as SymPy Rationals. [3] (f) Test farey_refinement(3). [1] [4]: def riffle(l1,l2): out = l1 + l2 out[::2] = l1 out[1::2] = l2 return out def neighbor_mediants(lis): return [lis[i] + lis[i+1] for i in range(len(lis)-1)] base = [np.array([0,1]), np .array([1,1]), np .array([1,0])] print(neighbor_mediants(base)) def riffled_mediants(lis): return riffle(lis, neighbor_mediants(lis)) print(riffled_mediants(base)) def farey_refinement(n): lis = [np.array([0,1]), np .array([1,1])] for _ in range(n): lis = riffled_mediants(lis) 8 return [sp.Rational(v[0],v[1]) for v in lis] ans = farey_refinement(3) print(ans) assert ans == [sp.Rational(0),sp.Rational(1,4),sp.Rational(1,3),sp. ↪Rational(2,5),sp.Rational(1,2),sp.Rational(3,5),sp.Rational(2,3),sp. ↪Rational(3,4),sp.Rational(1)] [array([1, 2]), array([2, 1])] [array([0, 1]), array([1, 2]), array([1, 1]), array([2, 1]), array([1, 0])] [0, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 1] Marking points / verification. 2 marks for all adjacent vector sums; 1 for the required test; 2 for correct interleaving including both endpoints; 1 for its test; 3 for exactly n refinements and Rational conversion; 1 for the stated generation. 9