pith. machine review for the scientific record. sign in

IndisputableMonolith.Decision.Trolley

IndisputableMonolith/Decision/Trolley.lean · 148 lines · 11 declarations

show as:
view math explainer →

open module explainer GitHub source

Explainer status: ready · generated 2026-05-13 19:18:39.480911+00:00

   1import Mathlib
   2import IndisputableMonolith.Constants
   3import IndisputableMonolith.Cost
   4
   5/-!
   6# The Trolley Problem as a J/σ Tradeoff
   7
   8## §XXIII.C row "Philosophical paradoxes" — Trolley side.
   9
  10The trolley problem: a runaway trolley will kill 5 people unless
  11diverted onto a side track that will kill 1 person.  Pull the
  12lever to divert (utilitarian) or do nothing (deontological)?
  13
  14In RS: utilitarianism minimizes J-cost (5 lives saved >
  151 life saved).  Deontology preserves σ-conservation: the act of
  16pulling the lever creates a σ-imbalance (an act of agency that
  17breaks the no-action equilibrium), even though it strictly
  18decreases J.
  19
  20The genuine moral tension is the J/σ tradeoff:
  21
  22  - Pulling the lever: J decreases (5 → 1 deaths) but σ-skew
  23    is created (active killing introduces an agency-imbalance).
  24  - Not pulling: σ is preserved but J is maximal.
  25
  26The 14 DREAM virtues from `Ethics/Virtues/CompletenessClosure`
  27provide the structural bridge: a virtue-aligned action can be
  28J-reducing AND σ-preserving simultaneously, but the trolley
  29constraints force a strict tradeoff.
  30
  31## What this module provides
  32
  331. `TrolleyChoice`: inductive `pull | doNothing`.
  342. `livesLost`: 1 (pull) or 5 (doNothing).
  353. `sigmaCost`: 1 (pull, agency imbalance) or 0 (doNothing).
  364. `jCost`: lives lost (proxy for J-cost on the lives manifold).
  375. `tradeoff_strict`: pulling lowers J but raises σ.
  386. `no_strictly_dominant_choice`: neither choice dominates the
  39   other on both axes.
  407. Master cert `TrolleyTradeoffCert` with 5 fields.
  41-/
  42
  43namespace IndisputableMonolith
  44namespace Decision
  45namespace Trolley
  46
  47open Constants
  48
  49noncomputable section
  50
  51/-- The trolley choice: pull the lever or do nothing. -/
  52inductive TrolleyChoice where
  53  | pull
  54  | doNothing
  55  deriving DecidableEq, Inhabited
  56
  57namespace TrolleyChoice
  58
  59/-- Display name. -/
  60def name : TrolleyChoice → String
  61  | pull      => "pull lever"
  62  | doNothing => "do nothing"
  63
  64end TrolleyChoice
  65
  66/-- Lives lost as a function of choice. -/
  67def livesLost (c : TrolleyChoice) : ℕ :=
  68  match c with
  69  | TrolleyChoice.pull      => 1
  70  | TrolleyChoice.doNothing => 5
  71
  72/-- σ-cost: agency imbalance from active killing. -/
  73def sigmaCost (c : TrolleyChoice) : ℝ :=
  74  match c with
  75  | TrolleyChoice.pull      => 1
  76  | TrolleyChoice.doNothing => 0
  77
  78/-- J-cost proxy: lives lost as real number. -/
  79def jCost (c : TrolleyChoice) : ℝ := (livesLost c : ℝ)
  80
  81/-- Pulling lowers J: `jCost(pull) < jCost(doNothing)`. -/
  82theorem pull_lowers_J : jCost TrolleyChoice.pull < jCost TrolleyChoice.doNothing := by
  83  unfold jCost livesLost
  84  norm_num
  85
  86/-- Pulling raises σ: `sigmaCost(pull) > sigmaCost(doNothing)`. -/
  87theorem pull_raises_sigma :
  88    sigmaCost TrolleyChoice.pull > sigmaCost TrolleyChoice.doNothing := by
  89  unfold sigmaCost
  90  norm_num
  91
  92/-- The tradeoff is strict: lowering J requires raising σ, and
  93    vice versa. -/
  94theorem tradeoff_strict :
  95    jCost TrolleyChoice.pull < jCost TrolleyChoice.doNothing ∧
  96    sigmaCost TrolleyChoice.pull > sigmaCost TrolleyChoice.doNothing :=
  97  ⟨pull_lowers_J, pull_raises_sigma⟩
  98
  99/-- No choice strictly dominates the other on both axes.
 100    Pulling is better on J, worse on σ; doNothing is the reverse. -/
 101theorem no_strictly_dominant_choice
 102    (c1 c2 : TrolleyChoice)
 103    (h_diff : c1 ≠ c2) :
 104    ¬ (jCost c1 < jCost c2 ∧ sigmaCost c1 < sigmaCost c2) := by
 105  intro ⟨hJ, hσ⟩
 106  cases c1 with
 107  | pull =>
 108    cases c2 with
 109    | pull => exact absurd rfl h_diff
 110    | doNothing =>
 111      have := pull_raises_sigma
 112      linarith
 113  | doNothing =>
 114    cases c2 with
 115    | pull =>
 116      have := pull_lowers_J
 117      linarith
 118    | doNothing => exact absurd rfl h_diff
 119
 120/-! ## Master certificate -/
 121
 122/-- **TROLLEY TRADEOFF MASTER CERTIFICATE.** -/
 123structure TrolleyTradeoffCert where
 124  pull_lives_lost : livesLost TrolleyChoice.pull = 1
 125  doNothing_lives_lost : livesLost TrolleyChoice.doNothing = 5
 126  tradeoff :
 127    jCost TrolleyChoice.pull < jCost TrolleyChoice.doNothing ∧
 128    sigmaCost TrolleyChoice.pull > sigmaCost TrolleyChoice.doNothing
 129  no_dominance :
 130    ∀ (c1 c2 : TrolleyChoice), c1 ≠ c2 →
 131      ¬ (jCost c1 < jCost c2 ∧ sigmaCost c1 < sigmaCost c2)
 132  pull_creates_agency_imbalance :
 133    sigmaCost TrolleyChoice.pull = 1
 134
 135/-- The master certificate is inhabited. -/
 136def trolleyTradeoffCert : TrolleyTradeoffCert where
 137  pull_lives_lost := rfl
 138  doNothing_lives_lost := rfl
 139  tradeoff := tradeoff_strict
 140  no_dominance := no_strictly_dominant_choice
 141  pull_creates_agency_imbalance := rfl
 142
 143end
 144
 145end Trolley
 146end Decision
 147end IndisputableMonolith
 148

source mirrored from github.com/jonwashburn/shape-of-logic