Books · The Fiddler: Solutions
Chapter 69
Can You Spin the Graph?
You graph , but it is rotated about the origin by a uniformly random angle in . What is the probability the rotated graph still passes the vertical line test (still defines as a function of )?
The Fiddler, Zach Wissner-Gross, January 31, 2025(original post)
Solution
The graph is two rays from the origin, apart, initially pointing at and . A pair of rays passes the vertical line test exactly when the two rays lie on opposite sides of the vertical axis: if both rays had a horizontal component of the same sign, a vertical line just past the origin would cross both. Writing the rays after rotation as and , we need and to have opposite signs, i.e. , i.e. . That holds for half of all , so
The computation
Spin the actual graph: pick a random rotation, point both rays through it, and check whether their horizontal components disagree in sign (the vertical line test). The pass rate is one half.
import numpy as np
rng = np.random.default_rng(0)
phi = rng.uniform(0, 360, 2_000_000) * np.pi / 180
a, b = np.radians(45) + phi, np.radians(135) + phi
print((np.cos(a) * np.cos(b) < 0).mean()) # 0.5000
Extra Credit
Now is rotated by a uniformly random D rotation. What is the probability it still defines as a function of ?
Solution
The surface has four planar faces with unit normals . It remains a graph in the lab vertical direction exactly when that direction makes a positive dot product with every face normal, and a uniform random rotation sends the (un-rotated) vertical to a vector uniform on the sphere. Requiring for all four sign choices collapses to the single condition . The solid angle of that region gives (The official extra-credit value is paywalled; this is my own.)
The computation
Encode the experiment rather than the integral: draw vectors uniformly on the sphere (a random orientation of the vertical) and measure how often all four faces still tilt upward, .
u = rng.normal(size=(5_000_000, 3))
u /= np.linalg.norm(u, axis=1, keepdims=True)
print((u[:, 2] > np.abs(u[:, 0]) + np.abs(u[:, 1])).mean()) # 0.1082