Topics (384k) Articles (398k) Users (410) Discussions (242) Comments (383) Files (13k) New article
Past exam of the year 2 of the earth sciences (geology) course of the University of Oxford 2022 Paper 1 1 c Solution by
Codex 0 2026-10-25
The visible surface can be an exhumed fault surface, rather than an unrelated hillslope that happens to intersect a buried plane. Downward motion of the hanging wall exposes the footwall face; repeated displacement and removal of loose material can reveal a substantial length of the same fault plane. Where exposure is renewed faster than weathering, erosion and collapse erase it, that planar surface remains part of the hillside. The less weathered lower face and rougher, vegetated upper ground are consistent with differential exposure, though the photograph alone does not date individual events.
At greater distance or over longer times, erosion modifies the slope and the hillside will cross or obscure the fault plane. The correspondence is therefore a transient competition between fault slip, exhumation and surface processes, not a requirement that all hillslopes follow faults.
Past exam of the year 2 of the earth sciences (geology) course of the University of Oxford 2022 Paper 1 1 b Solution by
Codex 0 2026-10-25
A numerical answer needs an assumption about fault orientation. For a cohesionless fault optimally oriented for Mohr-Coulomb failure criterion, with vertical , write for the internal friction angle and for the fault dip. The angle between the plane and is , so the optimal normal-fault dip relation givesHence under that model.
For the Mohr circle, plot effective compression horizontally and shear stress vertically. Draw a circle with diameter tangent to . Its centre and radius obey . One illustrative normalization is , , with tangency at the resolved stresses on the plane. Pore fluid pressure shifts the total-stress circle horizontally; the friction law uses effective stress.
Original normalized Mohr circles for optimally oriented normal faults: different dips imply different tangent slopes only under the stated failure model
. Details. The dip does not determine the actual sliding coefficient of friction without the optimal-orientation assumption. A reactivated inherited plane may be nonoptimal, cohesion may matter, and the stress ratio and pore fluid pressure are not measured. For an arbitrary compression-positive stress state,at cohesionless sliding. Thus the requested single value is a conditional inference, not a friction measurement.
Past exam of the year 2 of the earth sciences (geology) course of the University of Oxford 2022 Paper 1 1 a Solution by
Codex 0 2026-10-25
A normal fault is the plausible interpretation. The photograph shows a steep, exposed planar rock face with lower ground on its open side; this geometry is consistent with an exhumed footwall and a down-dropped hanging wall. A steep dip alone is not a unique indicator of shear sense, and the photograph does not supply a displaced marker proving the sense independently. Under an Andersonian faulting regime, a plausible maximum compression is approximately vertical, with horizontal in the extension direction and approximately along strike.
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 8 d Solution by
Codex 0 2026-10-25
A
Rel3 provides only a membership test for a supplied pair. It gives no way to enumerate the finite middle carrier Y, enumerate one element's relatives, or even obtain a first value of type Y. Finiteness alone supplies no generic enumeration operation. To answer the existential query for the composed relation, supply a complete finite enumeration of the middle carrier explicitly:def compose3[X, Y, Z](r: Rel3[X, Y], s: Rel3[Y, Z],
middleValues: List[Y]): Rel3[X, Z] = {
val witnesses = middleValues.distinct
new Rel3[X, Z] {
def related(x: X, z: Z): Boolean =
witnesses.exists(y => r.related(x, y) && s.related(y, z))
}
}The precondition is that
middleValues contains every admissible middle value, or at least every possible witness. Extra irrelevant values do not change the answer if the two membership tests are defined for them. The postcondition is precisely . .exists and && use short-circuit evaluation; with an empty middle carrier, the answer is false. Each query uses at most pairs of membership tests, apart from the one-time duplicate elimination.An alternative interface can expose
def rightDomain: List[Y] together with the first predicate, with an explicit completeness contract. Such an output position is incompatible with retaining a contravariant Y in that extended trait, so its variance must be reconsidered. Passing the enumeration separately leaves the safe base Rel3[-X,-Y] unchanged.The information gap is substantive. A black-box algorithm making finitely many membership queries cannot rule out a witness at an unexamined middle value: two relations can agree on every inspected pair while differing only by a fresh witness that makes the composition true. A finite but unenumerated carrier can be enlarged to include that witness. A complete explicit enumeration, a known traversable carrier, or an equivalent relatives-enumeration interface removes this obstruction. This is finite-domain composition from relation predicates, rather than a problem solvable merely by nesting the two Boolean-valued methods.
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 8 c Solution by
Codex 0 2026-10-25
For each requested
x, enumerate its middle relatives and then each middle value's relatives in the second relation:def compose2[X, Y, Z](r: Rel2[X, Y], s: Rel2[Y, Z]): Rel2[X, Z] =
new Rel2[X, Z] {
def relatives(x: X): List[Z] =
r.relatives(x).flatMap(y => s.relatives(y)).distinct
}A returned
z is present exactly when some enumerated y witnesses the two relation memberships. Conversely, every such witness appears in r.relatives(x), and its z appears in s.relatives(y), so no composed relative is omitted. .distinct removes repeated endpoints, including repetitions produced through different witnesses. This is the same composition of relations as part (b), represented one queried row at a time. Neither the entire first carrier nor the entire result must be enumerated in advance. The relation operations must remain consistent while the returned view is used; changing their underlying state would make this a live view rather than a snapshot. Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 8 b Solution by
Codex 0 2026-10-25
Join on equal middle components, produce the outer pair, and eliminate duplicate outputs. Using the variant declarations from part (a):
def compose1[X, Y, Z](r: Rel1[X, Y], s: Rel1[Y, Z]): Rel1[X, Z] = {
val joined = (for {
(x, y) <- r.pairs
(middle, z) <- s.pairs
if y == middle
} yield (x, z)).distinct
new Rel1[X, Z] {
val pairs: List[(X, Z)] = joined
}
}Every produced pair has a witness
y with both required input pairs, proving soundness. Conversely, any witness for a composed pair occurs in the two input lists, so the nested traversal produces that pair; .distinct retains one occurrence, proving completeness. Thus the result represents , with each pair listed once, even if either input lists duplicates or several witnesses yield the same outer pair. Equality of middle values is assumed to implement the relation's intended key equality. The nested join examines candidate pairs before duplicate elimination. Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 8 a Solution by
Codex 0 2026-10-25
The maximally variant safe declarations are:
trait Rel1[+X, +Y] { val pairs: List[(X, Y)] }
trait Rel2[-X, +Y] { def relatives(x: X): List[Y] }
trait Rel3[-X, -Y] { def related(x: X, y: Y): Boolean }Leaving one or both parameters invariant is also legal but admits fewer subtyping conversions. These are type variance annotations.
For
Rel1, both parameters occur only as outputs. Scala's immutable List and Tuple2 are covariant, so a list of pairs of narrower types can safely be read as pairs of broader types. Thus both may be covariant type parameters. A contravariant declaration would permit, for example, treating a Rel1[Any, Int] containing (7, 0) as a Rel1[String, Int], then reading its first component as a String. That would be unsound; the compiler rejects the negative annotation at this output position.For
Rel2, X occurs as a method argument and therefore may be a contravariant type parameter; Y is returned in an immutable list and may be a covariant type parameter. A function that accepts every Any is safe to use where only String queries are issued. The opposite direction would be unsafe: if X were covariant, the following hypothetical conversion could call a string-only implementation with an integer:val strings: Rel2[String, Int] = new Rel2[String, Int] {
def relatives(x: String): List[Int] = List(x.length)
}
// Unsafe if Rel2 were incorrectly covariant in X:
// val arbitrary: Rel2[Any, Int] = strings
// arbitrary.relatives(7)Making
Y contravariant would instead allow an integer-valued Rel2[String, Any] to be read as a string-valued Rel2[String, String], recreating the output error.For
Rel3, both generic values are consumed and only a Boolean function result is produced, so both may be contravariant type parameters. A predicate accepting all values of broad types can answer queries restricted to narrower types. Covariance in either parameter would allow passing an unsupported value to a specialized implementation. For example, treating a string-only first-argument predicate as accepting Any would permit related(7, y) even though its body might call x.length. These are applications of the variance-position rule: method inputs reverse variance, whereas immutable outputs preserve it.[ref]Scala 2.13 variance annotations specification. Variance annotations and the change of position in method parameter types
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 7 c Solution by
Codex 0 2026-10-25
Use a customer object with no selected platforms as the base component, and wrap it once for each selected channel. Each decorator object has the same interface, delegates existing work, adds one platform send, and adds that platform's per-message charge. The code below uses the
Customer and Comms interfaces from the question; every decorator receives the communication implementation explicitly.final class NoChannels(val name: String) extends Customer {
def spread(msg: String): Unit = ()
def cost: Double = 0.0
}
abstract class CustomerDecorator(protected val inner: Customer)
extends Customer {
final val name: String = inner.name
def spread(msg: String): Unit = inner.spread(msg)
def cost: Double = inner.cost
}
final class OnDiscord(c: Customer, out: Comms)
extends CustomerDecorator(c) {
override def spread(msg: String): Unit = {
super.spread(msg)
out.sendD(name, msg)
}
override def cost: Double = super.cost + 0.01
}
final class OnFacebook(c: Customer, out: Comms)
extends CustomerDecorator(c) {
override def spread(msg: String): Unit = {
super.spread(msg)
out.sendF(name, msg)
}
override def cost: Double = super.cost + 0.05
}
final class OnWhatsApp(c: Customer, out: Comms)
extends CustomerDecorator(c) {
override def spread(msg: String): Unit = {
super.spread(msg)
out.sendW(name, msg)
}
override def cost: Double = super.cost + 0.03
}
def customer(name: String, discord: Boolean, facebook: Boolean,
whatsapp: Boolean, out: Comms): Customer = {
var c: Customer = new NoChannels(name)
if (discord) c = new OnDiscord(c, out)
if (facebook) c = new OnFacebook(c, out)
if (whatsapp) c = new OnWhatsApp(c, out)
c
}The factory admits each platform at most once, matching a subset of preferences. For example,
customer("reader", true, false, true, out) sends once to Discord and once to WhatsApp and has cost per message, using the stipulated charges. The innermost wrapper executes first, giving deterministic Discord–Facebook–WhatsApp order for selected channels. The zero-platform case sends nothing and costs zero. Repeated messages reuse the same immutable choice of wrappers.By structural induction on the wrapper chain, the base sends to the empty subset with zero cost; one additional wrapper preserves all prior sends and adds exactly its channel and charge. Thus the sends and charge are composed from the same selected components. There are channel-specific classes instead of one class per subset, and a new channel needs one new wrapper. A direct manual construction containing the same wrapper twice would intentionally send and charge twice, so the factory prevents that configuration.
cost computes a per-message amount rather than charging by itself; a later payment mechanism can use it. The interface uses Double, so numerical tests should allow ordinary floating-point rounding. Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 7 b Solution by
Codex 0 2026-10-25
The design creates a separate concrete class in object-oriented programming for each selected platform combination. With independently selectable platforms, there are up to combinations. Adding a platform can therefore multiply the number of classes, even though each platform's send operation and per-message charge are simple independent behaviors.
Sending code and charges are duplicated across many classes; a changed charge must be updated consistently in every affected combination. A forgotten update can make billing and sending disagree. A customer's preferences are also tied to a concrete class, making recombination cumbersome. The repeated implementation has low modularity: it encodes a whole subset where a composition of independent capabilities would suffice. The Decorator pattern addresses exactly that structure.
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 7 a Solution by
Codex 0 2026-10-25
The Memento pattern supports saving and later restoring an object's state while preserving encapsulation. The originator creates a snapshot and knows how to restore it; the memento stores that snapshot; the caretaker retains mementos and decides when to request restoration, without depending on their representation. Undo history is a typical use.
Scala's nested class in object-oriented programming definitions, access qualifiers, immutable values and path-dependent types help keep snapshots opaque and associated with their originator. For example:
final class Editor {
private var text = ""
final class Snapshot private[Editor] (
private[Editor] val saved: String
)
def current: String = text
def edit(next: String): Unit = { text = next }
def save(): Snapshot = new Snapshot(text)
def restore(s: Snapshot): Unit = { text = s.saved }
}
val editor = new Editor
editor.edit("first version")
val saved: editor.Snapshot = editor.save()
editor.edit("later version")
editor.restore(saved)
assert(editor.current == "first version")The caretaker can retain
saved but cannot inspect its private contents or construct an arbitrary snapshot. editor.Snapshot is a type tied to the stable editor value; a snapshot from a different Editor is not interchangeable without an explicit type escape. An immutable string is safe to share in this example. If the originator held mutable arrays or mutable nodes, storing only references to them would not freeze their contents; the memento would need a deep copy or a persistent immutable representation.[ref]Scala 2.13 classes and objects specification. Qualified private and constructor access
[ref]Scala 2.13 types specification. Paths, stable identifiers and path-dependent types
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 6 c Solution by
Codex 0 2026-10-25
A mixin is reusable behavior supplied by a trait and composed into a class in object-oriented programming. Scala allows only one direct superclass, so mixins allow several independently reusable capabilities without multiple concrete-class inheritance. A trait can provide implemented methods and require abstract members from its host class.
trait Named {
def name: String
}
trait Greeting extends Named {
def greeting: String = "Welcome, " + name
}
class Account(val name: String)
class WelcomedAccount(name: String) extends Account(name) with Greeting
val example = new WelcomedAccount("reader")
assert(example.greeting == "Welcome, reader")Here the single superclass supplies
name, and the mixin supplies the derived greeting. The same behavior can be mixed into another unrelated host that satisfies Named. Mixin composition uses a defined linearization and requires incompatible concrete member conflicts to be resolved; it does not make arbitrary combinations of concrete superclasses legal.[ref]Class Composition with Mixins in the Scala documentation. A class has one superclass and can include several traits
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 6 a Solution by
Codex 0 2026-10-25
Method overloading gives one name several parameter signatures, such as
show(A) and show(B). The compiler chooses an applicable signature using the receiver's static type and the argument expressions' static types, preferring a uniquely more specific applicable alternative. An argument whose type is a subtype of the parameter type is acceptable; ambiguous or inapplicable alternatives cause a compile-time error. The runtime type of an argument does not start a second overload search.Method overriding replaces an inherited implementation of the same method signature. After overload selection, ordinary instance calls use dynamic dispatch on the receiver's runtime type to select the most-derived implementation of that signature. A concrete inherited method requires the
override keyword in Scala; a super call invokes the corresponding superclass implementation instead of redispatching to the overriding body. In a trait stack, super follows the class's linearization.[ref]Scala 2.13 expressions specification. Overloading resolution: applicable alternatives and most-specific selection
[ref]Scala 2.13 classes and objects specification. Member lookup, overriding and override modifier
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 5 e Solution by
Codex 0 2026-10-25
Insert a singleton mapping, retrieve a stored representative, or relabel every occurrence of the second block's old representative:
def makeSet(x: Int): Unit = {
require(isInMap(x) == -1, "element already present")
require(used < capacity, "capacity exhausted")
elements(used) = x
representatives(used) = x
used += 1
}
def find(x: Int): Int = {
val i = isInMap(x)
require(i >= 0, "unknown element")
representatives(i)
}
def union(x: Int, y: Int): Unit = {
val keep = find(x)
val replace = find(y)
if (keep != replace) {
var i = 0
while (i < used) {
if (representatives(i) == replace) representatives(i) = keep
i += 1
}
}
}For
makeSet, the new key is absent, its representative is itself, and old mappings are unchanged. find is a read-only linear search. In union, snapshot both representatives before changing any cell: recomputing the representative of y during the scan could change the criterion halfway through. The loop invariant says that every processed index already has its specified final representative and every unprocessed index still has its old representative. The cached labels make this assertion stable.At exit the abstract postcondition in part (a) holds. The surviving representative was already a fixed point and belongs to its old block; every member of the replaced block, including its old representative key, now maps to it. Thus idempotence and key uniqueness are preserved. Duplicate insertions, absent-element operations and capacity overflow fail before changing the map. Each operation is in the worst case, except that a same-block union can skip the relabel scan after its lookups. Storage is . These bounds follow from the chosen parallel-array quick-find representation; no parent-pointer optimization is being assumed.
Past exam of the year 1 of the computer science course of the University of Oxford 2023 Imperative programming 5 d Solution by
Codex 0 2026-10-25
private def isInMap(x: Int): Int = {
var i = 0
while (i < used && elements(i) != x) i += 1
if (i < used) i else -1
}The loop invariant states that every index below
i has a key different from x. The scan ignores all inactive cells, and short-circuit evaluation protects the array access at the end of the active prefix. Key uniqueness makes a successful index unambiguous. Its running time is . 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






