Back to courses

MATH40006 Practice Paper 3

English review edition prepared on 4 October 2026 from a preserved source copy. It is a later presentation, not the historical study interface. Source checks and difficulty judgements describe the original material author's own process; they do not indicate Imperial College London endorsement.

Source SHA-256: d57867278a2aa68e4fcd3638e8e79e36c7820fdfa4f9d578c1ca1cd820cc36c0
Source date: 2026-08-06

Notes — cell 1

# MATH40006 Revised Historical-Coverage Mock 3

**Time allowed:** 60 minutes 
**Total marks:** 50 
**Questions:** 3 (20 + 20 + 10) 
**Role:** 2023-24 historical ability: prime algorithms, recursion and lexicon data

Answer all questions in this Jupyter notebook. Show testing code and outputs. Unless the question explicitly requests an in-place operation, functions should return a value without changing their inputs.

Code — cell 2

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
import math
sp.init_printing()

def primes_numpy(n):
    pos=np.ones(n+1,dtype=bool); pos[:2]=False
    for p in range(2,int(np.sqrt(n))+1):
        if pos[p]: pos[p*p::p]=False
    return np.arange(n+1)[pos]

mini=[{'word':'Alpha','description':'first'}, {'word':'Beta','description':'second'}, {'word':'Delta','description':'change'}, {'word':'Gamma','description':'third'}]
with open('mini_lexicon.dat','w',encoding='utf-8') as f: f.write(repr(mini))

Notes — cell 3

## Question 1 (20 marks)

The supplied `primes_numpy` implements the Sieve of Eratosthenes.

(a) Test it for a prime upper bound, a composite upper bound and a square of a prime. **[3]**

(b) Write in-place `conditional_append(primes,p)`, testing divisors only up to sqrt(p). **[5]**

(c) Test both append and no-append branches. **[3]**

(d) Write `primes_incremental(n)` starting with `[2]` and testing odd candidates only. **[4]**

(e) Check equality with `primes_numpy` for several values. **[2]**

(f) Use `perf_counter` for a fair comparison at `n=100000`. **[2]**

(g) Give one cautious sentence explaining the observed difference. **[1]**

Code — cell 4

# YOUR CODE HERE
raise NotImplementedError()

Notes — cell 5

## Question 2 (20 marks)

Define recursively, for positive integers, `s3(n)=n` when `n<3`, and otherwise
` s3(n)=s3(n//3)+(n%3)`.

(a) Implement `s3` recursively and return an int. **[4]**

(b) Test at least four values including 1, 8 and 2026. **[2]**

(c) Produce a point plot for 1 to 500. **[2]**

(d) Write `ternary_digits(n)` and `list_crush(lis)`, where the latter replaces each maximal run of equal elements by one copy. **[5]**

(e) Verify for 1 to 500 that `s3(n)` equals the sum of the ternary digits, and separately demonstrate `list_crush` on a non-trivial list. **[4]**

(f) Give a Theta bound for the recursive running time in terms of n. **[3]**

Code — cell 6

# YOUR CODE HERE
raise NotImplementedError()

Notes — cell 7

## Question 3 (10 marks)

Execute the setup cell, which creates `mini_lexicon.dat` as text representing a list of dictionaries.

(a) Read the file as text and parse it safely with `ast.literal_eval`. **[2]**

(b) Build a list of `(word,description)` tuples. **[1]**

(c) Write and test a sequential lookup that returns `'failed'` when absent. **[3]**

(d) Convert the same data to a dictionary and a pandas Series. **[2]**

(e) Verify all three structures agree for a hit and handle a miss. **[2]**

Code — cell 8

# YOUR CODE HERE
raise NotImplementedError()