Case 991
The cistern lost its top half far faster than its bottom half
the_cistern_lost_its_top_half_far_faster_than_its_bottom_half.eml - A straight-sided cistern empties through a hole in its floor in exactly 600 seconds from full. The caretaker reasons that half the water leaves in half the time and sets the refill valve to open at 300 seconds, when the cistern should be half full. How much water is really left at 300 seconds is computed below.
ok: true — round-trip fixpoint reached (python1 == python2)updated 2026-09-24
EML
eml# Self-authored for the EML case corpus (no external origin). A straight-sided
# cistern empties through a hole in its floor in exactly 600 seconds from full.
# The caretaker reasons that half the water leaves in half the time and sets the
# refill valve to open at 300 seconds, when the cistern should be half full.
# How much water is really left at 300 seconds is computed below.
#
# The reasoning is careful. The full emptying time really is 600 seconds,
# timed; the cistern really is straight-sided, so height and volume go
# together; half of 600 really is 300; and the intent is exactly 'refill at
# half full'.
#
# Water leaves the hole at a speed set by the square root of the depth above
# it, so a full cistern empties fast and a nearly empty one trickles. The top
# half of the water goes in 175 seconds, the bottom half takes the other 425,
# and at 300 seconds only a quarter of the water is left.
600 => seconds_to_empty_from_full
7071 => one_over_root_two_per_myriad
one_over_root_two_per_myriad * one_over_root_two_per_myriad => root_check_square
int(seconds_to_empty_from_full * (10000 - one_over_root_two_per_myriad) / 10000) => seconds_for_the_top_half
seconds_to_empty_from_full - seconds_for_the_top_half => seconds_for_the_bottom_half
int(seconds_for_the_bottom_half * 100 / seconds_for_the_top_half) => bottom_half_vs_top_half_per_hundred
int(seconds_to_empty_from_full / 2) => refill_valve_opens_at_s
int((seconds_to_empty_from_full - refill_valve_opens_at_s) * (seconds_to_empty_from_full - refill_valve_opens_at_s) * 1000 / (seconds_to_empty_from_full * seconds_to_empty_from_full)) => water_left_at_the_valve_per_mille
1000 - water_left_at_the_valve_per_mille => water_gone_at_the_valve_per_mille
"empties from full in : " + str(seconds_to_empty_from_full) + " s" ^0
"one over root two : " + str(one_over_root_two_per_myriad) + " per ten thousand, squared " + str(root_check_square) + " per hundred million" ^0
"" ^0
"top half of the water : gone in " + str(seconds_for_the_top_half) + " s" ^0
"bottom half of the water : gone in " + str(seconds_for_the_bottom_half) + " s" ^0
"bottom half vs top half : " + str(bottom_half_vs_top_half_per_hundred) + " per hundred of the time" ^0
"" ^0
"refill valve opens at : " + str(refill_valve_opens_at_s) + " s" ^0
"water left then : " + str(water_left_at_the_valve_per_mille) + " per mille" ^0
"water gone then : " + str(water_gone_at_the_valve_per_mille) + " per mille" ^0
"" ^0
# ---- what the caretaker verified ----
"the half-in-half-the-time reasoning" ^0
" emptying time : " + str(seconds_to_empty_from_full) + " s, timed from full" ^0
" shape : straight-sided, so height and volume go together" ^0
" arithmetic : half of " + str(seconds_to_empty_from_full) + " is " + str(refill_valve_opens_at_s) ^0
" intent : refill at half full" ^0
" facts wrong : 0" ^0
" verdict : AT " + str(refill_valve_opens_at_s) + " SECONDS THE CISTERN IS HALF FULL" ^0
"" ^0
" timing the whole emptying is the part done right here, and it" ^0
" is why " + str(seconds_to_empty_from_full) + " s is exactly how long the cistern takes to run dry" ^0
"" ^0
# ---- how a cistern empties ----
"the speed follows the depth" ^0
" what drives the water out : the depth of water above the hole" ^0
" how fast it leaves : with the square root of that depth, fast" ^0
" when full, a trickle near the end" ^0
" the top half : leaves while the push is strongest, in " + str(seconds_for_the_top_half) + " s" ^0
" the bottom half : leaves under a weakening push, in " + str(seconds_for_the_bottom_half) + " s," ^0
" " + str(bottom_half_vs_top_half_per_hundred) + " per hundred of the top half's time" ^0
" at " + str(refill_valve_opens_at_s) + " s : " + str(water_gone_at_the_valve_per_mille) + " per mille of the water is already gone" ^0
"" ^0
# ---- what the caretaker got ----
"the refill" ^0
" believed : the valve opens on a half-full cistern" ^0
" actual : it opens with " + str(water_left_at_the_valve_per_mille) + " per mille left" ^0
" is the emptying time wrong : no; " + str(seconds_to_empty_from_full) + " s, exactly" ^0
" does water leave at a steady rate : no; the rate falls with" ^0
" the depth, so time and level do not go together" ^0
"" ^0
# ---- null control ----
# The same cistern timed with the square-root outflow instead of a steady one.
300 => nc_time_for_the_top_half_read_as_steady_s
175 => nc_time_for_the_top_half_from_the_square_root_s
125 => nc_seconds_the_square_root_saves
"null control - let the outflow follow the depth" ^0
" time for the top half, read as steady : " + str(nc_time_for_the_top_half_read_as_steady_s) + " s" ^0
" time for the top half, from the square root : " + str(nc_time_for_the_top_half_from_the_square_root_s) + " s" ^0
" seconds the square root saves : " + str(nc_seconds_the_square_root_saves) ^0
" no cistern and no hole changed; the rate was allowed to fall" ^0
" as the water above the hole got shallower" ^0
"" ^0
# ---- the rule ----
"what a timed emptying of " + str(seconds_to_empty_from_full) + " seconds guarantees" ^0
" the cistern runs dry at " + str(seconds_to_empty_from_full) + " s : exactly" ^0
" it is half full at " + str(refill_valve_opens_at_s) + " s : not addressed; the water leaves with" ^0
" the square root of its depth, the top half goes in " + str(seconds_for_the_top_half) + " s," ^0
" and at " + str(refill_valve_opens_at_s) + " s only " + str(water_left_at_the_valve_per_mille) + " per mille is left" ^0
"" ^0
"a tank does not empty like a clock runs; the water is its own pump, and the" ^0
"pump gets weaker with every litre it sends out" ^0
"" ^0
"The cistern empties in " + str(seconds_to_empty_from_full) + " s - timed, exactly. But the water leaves with the" ^0
"square root of its depth, so the top half goes in " + str(seconds_for_the_top_half) + " s and the bottom half" ^0
"takes " + str(seconds_for_the_bottom_half) + ", and at " + str(refill_valve_opens_at_s) + " s only " + str(water_left_at_the_valve_per_mille) + " per mille is left, until the refill is" ^0
"timed by the square root of the depth rather than by half the clock." ^0Python (deterministic transpilation)
pythonseconds_to_empty_from_full = 600
one_over_root_two_per_myriad = 7071
root_check_square = one_over_root_two_per_myriad * one_over_root_two_per_myriad
seconds_for_the_top_half = int(seconds_to_empty_from_full * (10000 - one_over_root_two_per_myriad) / 10000)
seconds_for_the_bottom_half = seconds_to_empty_from_full - seconds_for_the_top_half
bottom_half_vs_top_half_per_hundred = int(seconds_for_the_bottom_half * 100 / seconds_for_the_top_half)
refill_valve_opens_at_s = int(seconds_to_empty_from_full / 2)
water_left_at_the_valve_per_mille = int((seconds_to_empty_from_full - refill_valve_opens_at_s) * (seconds_to_empty_from_full - refill_valve_opens_at_s) * 1000 / (seconds_to_empty_from_full * seconds_to_empty_from_full))
water_gone_at_the_valve_per_mille = 1000 - water_left_at_the_valve_per_mille
print("empties from full in : " + str(seconds_to_empty_from_full) + " s")
print("one over root two : " + str(one_over_root_two_per_myriad) + " per ten thousand, squared " + str(root_check_square) + " per hundred million")
print("")
print("top half of the water : gone in " + str(seconds_for_the_top_half) + " s")
print("bottom half of the water : gone in " + str(seconds_for_the_bottom_half) + " s")
print("bottom half vs top half : " + str(bottom_half_vs_top_half_per_hundred) + " per hundred of the time")
print("")
print("refill valve opens at : " + str(refill_valve_opens_at_s) + " s")
print("water left then : " + str(water_left_at_the_valve_per_mille) + " per mille")
print("water gone then : " + str(water_gone_at_the_valve_per_mille) + " per mille")
print("")
print("the half-in-half-the-time reasoning")
print(" emptying time : " + str(seconds_to_empty_from_full) + " s, timed from full")
print(" shape : straight-sided, so height and volume go together")
print(" arithmetic : half of " + str(seconds_to_empty_from_full) + " is " + str(refill_valve_opens_at_s))
print(" intent : refill at half full")
print(" facts wrong : 0")
print(" verdict : AT " + str(refill_valve_opens_at_s) + " SECONDS THE CISTERN IS HALF FULL")
print("")
print(" timing the whole emptying is the part done right here, and it")
print(" is why " + str(seconds_to_empty_from_full) + " s is exactly how long the cistern takes to run dry")
print("")
print("the speed follows the depth")
print(" what drives the water out : the depth of water above the hole")
print(" how fast it leaves : with the square root of that depth, fast")
print(" when full, a trickle near the end")
print(" the top half : leaves while the push is strongest, in " + str(seconds_for_the_top_half) + " s")
print(" the bottom half : leaves under a weakening push, in " + str(seconds_for_the_bottom_half) + " s,")
print(" " + str(bottom_half_vs_top_half_per_hundred) + " per hundred of the top half's time")
print(" at " + str(refill_valve_opens_at_s) + " s : " + str(water_gone_at_the_valve_per_mille) + " per mille of the water is already gone")
print("")
print("the refill")
print(" believed : the valve opens on a half-full cistern")
print(" actual : it opens with " + str(water_left_at_the_valve_per_mille) + " per mille left")
print(" is the emptying time wrong : no; " + str(seconds_to_empty_from_full) + " s, exactly")
print(" does water leave at a steady rate : no; the rate falls with")
print(" the depth, so time and level do not go together")
print("")
nc_time_for_the_top_half_read_as_steady_s = 300
nc_time_for_the_top_half_from_the_square_root_s = 175
nc_seconds_the_square_root_saves = 125
print("null control - let the outflow follow the depth")
print(" time for the top half, read as steady : " + str(nc_time_for_the_top_half_read_as_steady_s) + " s")
print(" time for the top half, from the square root : " + str(nc_time_for_the_top_half_from_the_square_root_s) + " s")
print(" seconds the square root saves : " + str(nc_seconds_the_square_root_saves))
print(" no cistern and no hole changed; the rate was allowed to fall")
print(" as the water above the hole got shallower")
print("")
print("what a timed emptying of " + str(seconds_to_empty_from_full) + " seconds guarantees")
print(" the cistern runs dry at " + str(seconds_to_empty_from_full) + " s : exactly")
print(" it is half full at " + str(refill_valve_opens_at_s) + " s : not addressed; the water leaves with")
print(" the square root of its depth, the top half goes in " + str(seconds_for_the_top_half) + " s,")
print(" and at " + str(refill_valve_opens_at_s) + " s only " + str(water_left_at_the_valve_per_mille) + " per mille is left")
print("")
print("a tank does not empty like a clock runs; the water is its own pump, and the")
print("pump gets weaker with every litre it sends out")
print("")
print("The cistern empties in " + str(seconds_to_empty_from_full) + " s - timed, exactly. But the water leaves with the")
print("square root of its depth, so the top half goes in " + str(seconds_for_the_top_half) + " s and the bottom half")
print("takes " + str(seconds_for_the_bottom_half) + ", and at " + str(refill_valve_opens_at_s) + " s only " + str(water_left_at_the_valve_per_mille) + " per mille is left, until the refill is")
print("timed by the square root of the depth rather than by half the clock.")stdout (executed)
textempties from full in : 600 s
one over root two : 7071 per ten thousand, squared 49999041 per hundred million
top half of the water : gone in 175 s
bottom half of the water : gone in 425 s
bottom half vs top half : 242 per hundred of the time
refill valve opens at : 300 s
water left then : 250 per mille
water gone then : 750 per mille
the half-in-half-the-time reasoning
emptying time : 600 s, timed from full
shape : straight-sided, so height and volume go together
arithmetic : half of 600 is 300
intent : refill at half full
facts wrong : 0
verdict : AT 300 SECONDS THE CISTERN IS HALF FULL
timing the whole emptying is the part done right here, and it
is why 600 s is exactly how long the cistern takes to run dry
the speed follows the depth
what drives the water out : the depth of water above the hole
how fast it leaves : with the square root of that depth, fast
when full, a trickle near the end
the top half : leaves while the push is strongest, in 175 s
the bottom half : leaves under a weakening push, in 425 s,
242 per hundred of the top half's time
at 300 s : 750 per mille of the water is already gone
the refill
believed : the valve opens on a half-full cistern
actual : it opens with 250 per mille left
is the emptying time wrong : no; 600 s, exactly
does water leave at a steady rate : no; the rate falls with
the depth, so time and level do not go together
null control - let the outflow follow the depth
time for the top half, read as steady : 300 s
time for the top half, from the square root : 175 s
seconds the square root saves : 125
no cistern and no hole changed; the rate was allowed to fall
as the water above the hole got shallower
what a timed emptying of 600 seconds guarantees
the cistern runs dry at 600 s : exactly
it is half full at 300 s : not addressed; the water leaves with
the square root of its depth, the top half goes in 175 s,
and at 300 s only 250 per mille is left
a tank does not empty like a clock runs; the water is its own pump, and the
pump gets weaker with every litre it sends out
The cistern empties in 600 s - timed, exactly. But the water leaves with the
square root of its depth, so the top half goes in 175 s and the bottom half
takes 425, and at 300 s only 250 per mille is left, until the refill is
timed by the square root of the depth rather than by half the clock.Trace event types
eml:run:starteml:assigneml:outputeml:run:done