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." ^0

Python (deterministic transpilation)

python
seconds_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)

text
empties 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