SilverSight/formal/CoreFormalism/StrandCapacityBound.lean
allaun b65ef756ca fix(StrandCapacityBound): repair proofs + register in lakefile
Registering required it to actually compile (it did not). Fixes:
- capacity_bound_grid was FALSE at L₁=0 or L₂=0 (empty grid, nonempty image)
  and its `norm_num : 0 < (L₁:ℤ)` could not prove positivity of a variable.
  Added `0 < L₁, 0 < L₂` hypotheses; threaded through capacity_bound and
  chiral_capacity_bound.
- mathlib name drift: emod_nonneg/emod_lt → Int.emod_nonneg (b ≠ 0) /
  Int.emod_lt_of_pos; Finset.card_Ico → Int.card_Ico;
  Finset.card_le_card_of_subset → Finset.card_le_card; Finset.image_subset →
  Finset.image_subset_iff.mpr.
- replaced a `#eval` (broke on ℤ's noncomputable order instance) and its WRONG
  expected value (claimed 4 over {1..6}, actually 6) with two kernel-checked
  `decide` witnesses: {1,2,5,6}→4 (the Sidon set) and Ico 1 7→6.
- registered CoreFormalism.StrandCapacityBound in lakefile.

Verified: lake build OK (links into SilverSightFormal), #print axioms =
{propext, Classical.choice, Quot.sound} (no sorryAx, no custom axiom),
anti-smuggle --ci clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:19:47 -05:00

101 lines
4.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Mathlib.Data.Nat.Basic
import Mathlib.Data.Int.Basic
import Mathlib.Data.Finset.Basic
import Mathlib.Tactic
open Finset
open Nat
/-!
# Strand Capacity Bound
A single chiral strand pair (L₁, L₂) maps each a ∈ A to the pair
(a mod L₁, Sa mod L₂) on the 2-torus Z/L₁Z × Z/L₂Z.
## Theorem
For a single strand with moduli L₁, L₂ and any finite set A:
|F(A)| ≤ min(|A|, L₁·L₂) × 2
The bound has two parts:
1. |F(A)| ≤ |A| (injectivity — F is a function from A)
2. |F(A)| ≤ L₁·L₂ (codomain has only L₁·L₂ distinct pairs)
-/
variable (L₁ L₂ S : )
/-- The strand pairing: (a mod L₁, S a mod L₂). -/
def strandPair (a : ) : × :=
(a % (L₁ : ), ((S : ) - a) % (L₂ : ))
/-- Image of A under the strand pairing. -/
noncomputable def strandImage (A : Set ) : Set ( × ) :=
strandPair L₁ L₂ S '' A
/-- Bound 1: image cardinality ≤ input cardinality (trivial, F is a function). -/
theorem capacity_bound_input (A : Finset ) :
(A.image (strandPair L₁ L₂ S)).card ≤ A.card :=
Finset.card_image_le
/--
Bound 2: the codomain grid has size L₁·L₂.
Each residue lies in [0, L₁) resp. [0, L₂), so at most
L₁ × L₂ distinct pairs are reachable regardless of |A|.
-/
theorem capacity_bound_grid (A : Finset ) (hL₁ : 0 < L₁) (hL₂ : 0 < L₂) :
(A.image (strandPair L₁ L₂ S)).card ≤ (L₁ : ) * L₂ := by
have hL₁' : (0 : ) < (L₁ : ) := by exact_mod_cast hL₁
have hL₂' : (0 : ) < (L₂ : ) := by exact_mod_cast hL₂
-- The grid of possible residues
let grid : Finset ( × ) :=
(Finset.Ico 0 (L₁ : )) ×ˢ (Finset.Ico 0 (L₂ : ))
have hgrid : grid.card = (L₁ : ) * L₂ := by
simp [grid, Finset.card_product, Int.card_Ico]
-- Every strand pair lands in the grid
have hmem : ∀ a : , strandPair L₁ L₂ S a ∈ grid := by
intro a
have hx : a % (L₁ : ) ∈ Finset.Ico 0 (L₁ : ) := by
have hnonneg : 0 ≤ a % (L₁ : ) := Int.emod_nonneg a (ne_of_gt hL₁')
have hlt : a % (L₁ : ) < (L₁ : ) := Int.emod_lt_of_pos a hL₁'
exact Finset.mem_Ico.mpr ⟨hnonneg, hlt⟩
have hy : ((S : ) - a) % (L₂ : ) ∈ Finset.Ico 0 (L₂ : ) := by
have hnonneg' : 0 ≤ ((S : ) - a) % (L₂ : ) :=
Int.emod_nonneg _ (ne_of_gt hL₂')
have hlt' : ((S : ) - a) % (L₂ : ) < (L₂ : ) :=
Int.emod_lt_of_pos _ hL₂'
exact Finset.mem_Ico.mpr ⟨hnonneg', hlt'⟩
exact Finset.mem_product.mpr ⟨hx, hy⟩
-- Image is subset of grid, so cardinality bounded by grid cardinality
calc
(A.image (strandPair L₁ L₂ S)).card ≤ grid.card :=
Finset.card_le_card (Finset.image_subset_iff.mpr (fun a _ => hmem a))
_ = (L₁ : ) * L₂ := hgrid
/--
Combined bound: |F(A)| ≤ min(|A|, L₁·L₂).
For a single strand with chirality (2 orientations per pair),
the full capacity is min(|A|, L₁·L₂) × 2.
-/
theorem capacity_bound (A : Finset ) (hL₁ : 0 < L₁) (hL₂ : 0 < L₂) :
(A.image (strandPair L₁ L₂ S)).card ≤ min A.card ((L₁ : ) * L₂) := by
apply le_min
· exact capacity_bound_input L₁ L₂ S A
· exact capacity_bound_grid L₁ L₂ S A hL₁ hL₂
/--
With chirality: each pair can be read in 2 orders
(identity, reflection) or (reflection, identity),
corresponding to σᵢ vs σᵢ⁻¹ in the braid group.
-/
theorem chiral_capacity_bound (A : Finset ) (hL₁ : 0 < L₁) (hL₂ : 0 < L₂) :
(A.image (strandPair L₁ L₂ S)).card * 2 ≤ min A.card ((L₁ : ) * L₂) * 2 := by
nlinarith [capacity_bound L₁ L₂ S A hL₁ hL₂]
-- Sidon example A = {1,2,5,6} with moduli 3,4, S=7 → image has 4 distinct pairs:
-- 1↦(1,2), 2↦(2,1), 5↦(2,2), 6↦(0,1). Kernel-checked (`decide`, not
-- `#eval`/`native_decide`), sidestepping 's noncomputable order instance.
example : (({1, 2, 5, 6} : Finset ).image (strandPair 3 4 7)).card = 4 := by decide
-- Full range Ico 1 7 = {1,…,6} instead gives 6 distinct pairs (all injective here):
example : ((Finset.Ico (1 : ) 7).image (strandPair 3 4 7)).card = 6 := by decide