Topics (384k) Articles (398k) Users (410) Discussions (242) Comments (383) Files (13k) New article
Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 3 f Solution by
Codex 0 2026-10-25
Generate a row while respecting the forbidden symbols in each column. Selection returns an element together with the still-available elements:The invariant of
select :: [a] -> [(a,[a])]
select [] = []
select (x:xs) = (x,xs) : [(y,x:ys) | (y,ys) <- select xs]
row :: [Int] -> [[Int]] -> [[Int]]
row [] [] = [[]]
row remaining (used:otherColumns) =
[x:rest | (x,available) <- select remaining,
x `notElem` used,
rest <- row available otherColumns]
row _ _ = []
latinPruned :: Int -> [[[Int]]]
latinPruned n
| n < 0 = error "negative order"
| otherwise = build n (replicate n [])
where
build 0 usedColumns = [[]]
build remainingRows usedColumns =
[r:rest | r <- row [1..n] usedColumns,
rest <- build (remainingRows-1)
(zipWith (:) r usedColumns)]row is that remaining contains exactly the unused symbols of this row, while each member of the column list records symbols used by earlier rows. Selecting removes a symbol, so it cannot repeat in the current row; the membership test prevents a column repetition. A complete row uses every symbol once. Updating the column histories preserves the invariant for the next recursive call.Every complete generated square is therefore valid without a final filter. Conversely, take any valid target square: its next row passes every selection and column test, so induction keeps a branch constructing that target. Distinct choices from the initially distinct symbols cannot generate the same square twice. Dead-end partial squares may still be explored; the method promises to avoid constructing complete invalid squares, not to foresee every future dead end. Independent enumeration gives 1, 2, 12 and 576 squares at orders one through four.
Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 3 e Solution by
Codex 0 2026-10-25
Choose each row from the permutations of the symbols:Every Latin square remains a candidate, because each of its rows is one of those permutations. Conversely every candidate has valid rows, so only its columns still need checking. There are candidates instead of : at order four, rather than more than four billion. The improvement is substantial but does not make exhaustive generation practical at arbitrary orders. One can replace
squaresRows :: Int -> [[[Int]]]
squaresRows n
| n < 0 = error "negative order"
| otherwise = cp (replicate n (perms [1..n]))
latinRows :: Int -> [[[Int]]]
latinRows = filter valid . squaresRowsvalid by a column-only test here, since row validity is guaranteed by construction. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 3 d Solution by
Codex 0 2026-10-25
The generation count, before any validity test, is . It is at order three, at order four, and approximately at order five. Even an illustrative rate of one million complete candidates per second would require about 72 minutes at order four and about 9,444 years at order five, before accounting for the actual validity-checking cost. Thus order four is already expensive and order five is plainly impractical for this strategy; the exact threshold depends on the implementation and hardware, not just the mathematical count.
Candidate growth before filtering in two Latin-square generation strategies
. Original exact candidate counts, plotted on a base-ten logarithmic vertical axis. These are mathematical counts, not measured running times; pruning can avoid many invalid partial extensions as well. Details. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 3 c Solution by
Codex 0 2026-10-25
The following predicate also checks the square's shape; The row tests guarantee that each row has length and contains each allowed symbol once. Because
sort is the three-way sorting function from Question 2:valid :: [[Int]] -> Bool
valid rows =
let n = length rows
symbols = [1..n]
goodRows = all (\r -> sort r == symbols) rows
goodColumns = all (\j -> sort [r !! j | r <- rows] == symbols)
[0..n-1]
in goodRows && goodColumns
latin :: Int -> [[[Int]]]
latin = filter valid . squares&& tests this condition first, the later column indexing is safe for a finite total input. The column tests establish the remaining Latin-square condition. Filtering therefore retains precisely the valid squares; it does not remove any different ordering of rows, columns or symbols as an alleged symmetry duplicate. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 3 b Solution by
Codex 0 2026-10-25
For a nonnegative order, first enumerate every possible row and then every possible ordered selection of rows:Every one of the positions chooses one of symbols independently. Consequently the enumeration contains candidate squares for , each exactly once. The conventional order-zero extension produces one empty square. This is generation only; repeated symbols have not yet been rejected.
squares :: Int -> [[[Int]]]
squares n
| n < 0 = error "negative order"
| otherwise = cp (replicate n (cp (replicate n [1..n]))) Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 3 a Solution by
Codex 0 2026-10-25
The empty family has one choice, the empty selection:A selection from the whole family consists uniquely of a choice from its first member and a selection from the remaining family. This bijection proves the combining equation and completeness by induction. If a member family is empty, there are no selections. The base is
cp :: [[a]] -> [[a]]
cp = foldr extend [[]]
where
extend choices suffixes = [x:ys | x <- choices, ys <- suffixes][[]], not []: otherwise every Cartesian product would incorrectly be empty. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 2 f Solution by
Codex 0 2026-10-25
An unfold expands a seed into either no node or a bucket and two new seeds:The seed is the remaining list. Expanding a nonempty seed partitions it exactly as
unfoldTree :: (s -> Maybe (s,[a],s)) -> s -> Tree a
unfoldTree split seed =
case split seed of
Nothing -> Empty
Just (left,equal,right) ->
Node (unfoldTree split left) equal (unfoldTree split right)
toTreeUnfold :: Ord a => [a] -> Tree a
toTreeUnfold = unfoldTree split
where
split [] = Nothing
split (pivot:xs) =
let (lo,eq,hi) = partition3 pivot xs
in Just (lo,pivot:eq,hi)toTree does, and both child seeds are shorter. Induction establishes toTreeUnfold = toTree and algorithm termination on finite inputs. The unfold separates the local decomposition rule from the recursive construction of the tree. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 2 e Solution by
Codex 0 2026-10-25
A tree fold replaces each constructor by its interpretation:Induction on the finite tree shows equality with
foldTree :: (b -> [a] -> b -> b) -> b -> Tree a -> b
foldTree combine zero Empty = zero
foldTree combine zero (Node left equal right) =
combine (foldTree combine zero left)
equal
(foldTree combine zero right)
fromTreeFold :: Tree a -> [a]
fromTreeFold = foldTree (\left equal right -> left ++ equal ++ right) []fromTree: the empty tree produces the empty output, and the combining function concatenates the two correctly flattened children around the node's bucket. The result type is independent of the key type; other choices can compute a size or another summary using the same structural recursion. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 2 d Solution by
Codex 0 2026-10-25
toTree needs Ord a; fromTree does not. Construction compares each key against a pivot. Flattening merely traverses and concatenates the buckets, so its more general type is Tree a -> [a]. A manually constructed tree need not satisfy the search-tree invariant; fromTree still flattens it, although its output need not be sorted. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 2 c Solution by
Codex 0 2026-10-25
Store the equal bucket at each internal node:The representation invariant for a tree produced by
data Tree a = Empty | Node (Tree a) [a] (Tree a)
toTree :: Ord a => [a] -> Tree a
toTree [] = Empty
toTree (pivot:xs) =
let (lo,eq,hi) = partition3 pivot xs
in Node (toTree lo) (pivot:eq) (toTree hi)
fromTree :: Tree a -> [a]
fromTree Empty = []
fromTree (Node left equal right) =
fromTree left ++ equal ++ fromTree righttoTree is that its bucket is nonempty and contains equal keys, every left-subtree key is smaller, and every right-subtree key is larger. Its multiplicities are preserved. Substituting the two equations for toTree into fromTree gives exactly the two defining equations for sort; induction proves sort = fromTree . toTree on finite inputs.Both versions call the same partition helper on the same pivot and sublists. The flattening stage makes no key comparisons. Thus fully producing the answer makes the same comparison decisions as the direct algorithm; no additional comparison against stored tree keys is introduced.
Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 2 b Solution by
Codex 0 2026-10-25
The ordering operations used to decide the partitions require an
Ord a constraint. A function with parametric polymorphism and type [a] -> [a] cannot inspect arbitrary element values to decide which one is smaller; for example, functions themselves need not admit the comparison operations required by this sorting algorithm. A Haskell Ord class instance supplies the comparison method, with its ordering laws a separate semantic assumption.[ref]Haskell 2010 Language Report. Chapter 9, the Ord class and compare method
Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 2 a Solution by
Codex 0 2026-10-25
A three-way quicksort can use a common partition helper so that the tree factorisation below makes the same key comparisons. The Every non-pivot entry appears in exactly one partition, and the equal bucket contains the original pivot exactly once. The recursive sublists have length at most one less than the current finite input, so recursion terminates. Induction gives sorted recursive results with the original multiplicities; placing the equal bucket between them gives a sorted permutation of the input. There is no recursive call on the equal bucket, which avoids needless descent on repeated keys.
compare operation is assumed to be a terminating lawful total ordering on the supplied keys.partition3 :: Ord a => a -> [a] -> ([a],[a],[a])
partition3 pivot = foldr step ([],[],[])
where
step x rest =
let (lo,eq,hi) = rest
in case compare x pivot of
LT -> (x:lo,eq,hi)
EQ -> (lo,x:eq,hi)
GT -> (lo,eq,x:hi)
sort :: Ord a => [a] -> [a]
sort [] = []
sort (pivot:xs) =
let (lo,eq,hi) = partition3 pivot xs
in sort lo ++ (pivot:eq) ++ sort hi Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 1 f Solution by
Codex 0 2026-10-25
Yes, under the finite total assumption in part (d). The pair result retains enough information to reconstruct the tail; the Take , and . The base image is . If is true, the recursive equation gives the first branch. If it is false, part (d), applied to the tail, gives , so the second branch becomes . These are precisely the fusion compatibility equations. Finite structural induction establishes the desired equality; it does not require extending the restricted-domain hypothesis to undefined predicate applications.
~ pattern keeps its two components lazy:spanFold :: (a -> Bool) -> [a] -> ([a], [a])
spanFold p = foldr step ([], [])
where
step x ~(ys,zs)
| p x = (x:ys,zs)
| otherwise = ([],x:(ys ++ zs))The qualification matters. If is false but is undefined, ordinary
spanP p [v,u] can return the untouched list suffix immediately, whereas the reconstruction through spanFold p [u] cannot recover that list suffix. The weaker condition needed only for the single reconstruction identity in (d) is therefore insufficient for this particular list fold on all list suffixes. The stronger totality condition stated there supplies exactly the missing premise. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 1 e Solution by
Codex 0 2026-10-25
For the finite total inputs just specified, a recursive implementation isAt a true test, the head belongs to the list prefix and splitting continues on the tail; at a false test, the complete remaining list is the list suffix. Induction proves that the first projection is the longest accepted list prefix and the second projection is the remaining list suffix.
spanP :: (a -> Bool) -> [a] -> ([a], [a])
spanP p [] = ([], [])
spanP p whole@(x:xs)
| p x = let (ys,zs) = spanP p xs in (x:ys,zs)
| otherwise = ([],whole)There is a small partial-value distinction behind the paper's displayed pair identity. The conventional recursive
span is strict in an entirely undefined list, whereas the literal expression (takeWhile p undefined, dropWhile p undefined) exposes an outer pair with two undefined components. The equality as a pair therefore needs the stated defined-input convention, or an interpretation that compares the two projections. This does not affect the finite total answers here.[ref]Haskell 2010 Language Report. §3.17, pattern matching; Chapter 9, definitions of span and the prefix operations
Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 1 d Solution by
Codex 0 2026-10-25
The necessary definedness condition is local: every predicate application actually reached before the first false result must produce a Boolean value. No condition is needed on predicate applications after that first false result, because the list suffix is then returned without further testing. If a reached test is bottom at a known cons cell, the reconstructed list is bottom at that position, while the original list still exposes a cons there; equality fails.
To prove sufficiency on finite lists, induct on the spine. The empty case gives
[] ++ [] = []. At a true test the left list prefix contributes the head, and the induction hypothesis reconstructs the tail. At a false test the list prefix is empty and the list suffix is the whole current list. For an infinite true-tested list prefix, every finite output list prefix is copied correctly; the infinite list prefix hides the possibly divergent list suffix computation. A partial spine ending in bottom is reconstructed up to exactly the same bottom. Thus finiteness is sufficient for an elementary induction proof but is not itself necessary for the identity.For the uniform list fold calculation in part (f), use the convenient stronger assumption that the input is a finite total list and the predicate terminates on every element of that list. This makes the reconstruction identity available on every list suffix, not only on the list suffixes visited by the original list prefix scan. A total predicate on the element type ensures this uniformly over all finite total inputs.
Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 1 c Solution by
Codex 0 2026-10-25
In general, no direct list fold with result type
[a] can implement dropWhile p. Choose total values for which and . The results on [] and [u] are both []. A hypothetical implementation foldr h z would therefore receive identical folded-tail values when extending either input by the same head . Yet the required outputs are [v] and [v,u], respectively. This contradicts the fold factorisation criterion: the combining function cannot distinguish information already discarded by its tail summary.The claim concerns a direct same-result-type list fold. A list fold returning extra information, followed by a projection, is possible: a pair can retain both the original tail and the dropped list suffix. Also, special predicates can have direct list folds: a constantly false predicate gives the identity; a constantly true predicate can use
foldr (\_ r -> r) [], which correctly diverges when it must traverse an infinite spine. Those special cases do not supply an implementation for an arbitrary predicate. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 1 b Solution by
Codex 0 2026-10-25
Yes. Define the combining function as follows:For the fusion derivation use the identity reconstruction
takeP :: (a -> Bool) -> [a] -> [a]
takeP p = foldr step []
where
step x rest = if p x then x : rest else []foldr (:) [], take , and choose the displayed step as . The function is strict in the input list, , and its cons equation is exactly . Fusion gives the implementation. On a false test, step does not demand the folded tail, so the implementation can terminate after a finite list prefix even when the remaining list is infinite or undefined. An undefined predicate result at a tested element makes both definitions undefined. Past exam of the year 1 of the computer science course of the University of Oxford 2021 Functional programming, design and analysis of algorithms (resit) 1 a Solution by
Codex 0 2026-10-25
The empty-list case uses . At a cons, assuming the equality for the tail, the calculation isThe middle equality is the supplied compatibility condition, instantiated with the folded tail; the last expression is the right fold on the whole list. Structural induction therefore proves fusion for finite total spines.
The strictness condition accounts for a bottom-valued input spine: the inner list fold returns bottom, and makes the two sides agree. The same induction covers finite partial lists. For pure definable continuous functions, an infinite list is the limit of its finite partial approximations, so equality extends to it. These are the three distinct obligations in the right-fold fusion law; strictness is not needed if the domain is restricted to finite terminating spines.
Past exam of the year 1 of the computer science course of the University of Oxford 2021 Discrete mathematics, continuous mathematics, and probability 9 c Solution by
Codex 0 2026-10-25
Treat one visit to a level as a whole gambler's ruin excursion, starting at its chamber and ending at local chamber or . The room choices are fair, so the chance of reaching before is , and the chance of reaching first is . The one-way hatches reset the next excursion to chamber of the adjacent level. Thus the embedded Markov chain at level exits moves upward with probability and downward with probability , even though individual room choices are unbiased.
Let be the food probability from the lower starting chamber, and that from the upper chamber . The lower level either exits unsuccessfully or reaches the upper level, while the upper level either finds food or returns to the lower start. First-step analysis at these level exits givesSubstituting yields , soThis also follows from biased gambler's ruin probability on levels , starting at , with ratio : . Absorption occurs almost surely, since from each active level a fixed positive chance of terminal absorption occurs within two excursions; the original chamber excursions are also almost surely finite.
The maze reduced to level exits has upward probability one quarter and downward probability three quarters
. Details. Pinned article: Introduction to the OurBigBook Project
Welcome to the OurBigBook Project! Our goal is to create the perfect publishing platform for STEM subjects, and get university-level students to write the best free STEM tutorials ever.
Everyone is welcome to create an account and play with the site: ourbigbook.com/go/register. We belive that students themselves can write amazing tutorials, but teachers are welcome too. You can write about anything you want, it doesn't have to be STEM or even educational. Silly test content is very welcome and you won't be penalized in any way. Just keep it legal!
Intro to OurBigBook
. Source. We have two killer features:
- topics: topics group articles by different users with the same title, e.g. here is the topic for the "Fundamental Theorem of Calculus" ourbigbook.com/go/topic/fundamental-theorem-of-calculusArticles of different users are sorted by upvote within each article page. This feature is a bit like:
- a Wikipedia where each user can have their own version of each article
- a Q&A website like Stack Overflow, where multiple people can give their views on a given topic, and the best ones are sorted by upvote. Except you don't need to wait for someone to ask first, and any topic goes, no matter how narrow or broad
This feature makes it possible for readers to find better explanations of any topic created by other writers. And it allows writers to create an explanation in a place that readers might actually find it.Figure 1. Screenshot of the "Derivative" topic page. View it live at: ourbigbook.com/go/topic/derivativeVideo 2. OurBigBook Web topics demo. Source. - local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published either:This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to do as it is quite cheap to host!), your content will still be perfectly readable as a static site.
- to OurBigBook.com to get awesome multi-user features like topics and likes
- as HTML files to a static website, which you can host yourself for free on many external providers like GitHub Pages, and remain in full control
Figure 2. You can publish local OurBigBook lightweight markup files to either OurBigBook.com or as a static website.Figure 3. Visual Studio Code extension installation.Figure 5. . You can also edit articles on the Web editor without installing anything locally. Video 3. Edit locally and publish demo. Source. This shows editing OurBigBook Markup and publishing it using the Visual Studio Code extension. - Infinitely deep tables of contents:
All our software is open source and hosted at: github.com/ourbigbook/ourbigbook
Further documentation can be found at: docs.ourbigbook.com
Feel free to reach our to us for any help or suggestions: docs.ourbigbook.com/#contact







