/-
Copyright (c) 2026 Michael R. Douglas. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

# Lattice Sites — Types and Geometry

Defines lattice site types for both finite (periodic boundary conditions)
and infinite lattices, along with nearest-neighbor structure and ℓ¹ norm.

## Main definitions

- `FinLatticeSites d N` — sites of the discrete torus (ℤ/Nℤ)^d
- `InfLatticeSites d` — sites of ℤ^d
- `latticeNorm` — ℓ¹ norm on ℤ^d
- `neighbors` — nearest neighbors on ℤ^d
- `neighborsFinite` — nearest neighbors with periodic BC
-/

import Mathlib.Data.Int.Basic
import Mathlib.Data.Fin.Basic
import Mathlib.Data.Finset.Basic
import Mathlib.Data.ZMod.Basic
import Mathlib.Topology.Algebra.InfiniteSum.Basic
import Mathlib.Analysis.Normed.Group.Basic
import Mathlib.Data.Real.Basic

noncomputable section

namespace GaussianField

/-! ## Site types -/

/-- Finite lattice sites: the discrete torus (ℤ/Nℤ)^d with periodic BC. -/
abbrev FinLatticeSites (d : ℕ) (N : ℕ) := Fin d → ZMod N

/-- Infinite lattice sites: ℤ^d. -/
abbrev InfLatticeSites (d : ℕ) := Fin d → ℤ

/-! ## ℓ¹ norm on ℤ^d -/

/-- The ℓ¹ norm on ℤ^d: `∑ i, |x i|`. Used as weight in rapid-decay seminorms. -/
def latticeNorm {d : ℕ} (x : Fin d → ℤ) : ℝ :=
  ∑ i : Fin d, |(x i : ℝ)|

theorem latticeNorm_nonneg {d : ℕ} (x : Fin d → ℤ) : 0 ≤ latticeNorm x :=
  Finset.sum_nonneg fun _ _ => abs_nonneg _

theorem latticeNorm_zero {d : ℕ} : latticeNorm (fun _ : Fin d => (0 : ℤ)) = 0 := by
  simp [latticeNorm]

theorem latticeNorm_triangle {d : ℕ} (x y : Fin d → ℤ) :
    latticeNorm (fun i => x i + y i) ≤ latticeNorm x + latticeNorm y := by
  simp only [latticeNorm]
  calc ∑ i : Fin d, |(↑(x i + y i) : ℝ)|
      = ∑ i : Fin d, |(↑(x i) : ℝ) + ↑(y i)| := by
        congr 1; ext i; push_cast; ring_nf
    _ ≤ ∑ i : Fin d, (|(↑(x i) : ℝ)| + |(↑(y i) : ℝ)|) :=
        Finset.sum_le_sum fun i _ => abs_add_le _ _
    _ = (∑ i, |(↑(x i) : ℝ)|) + (∑ i, |(↑(y i) : ℝ)|) := Finset.sum_add_distrib

/-! ## Standard basis vectors in ℤ^d -/

/-- The i-th standard basis vector in ℤ^d. -/
def stdBasisInt (d : ℕ) (i : Fin d) : Fin d → ℤ :=
  fun j => if j = i then 1 else 0

/-- The norm of a standard basis vector is 1. -/
theorem latticeNorm_stdBasis {d : ℕ} (i : Fin d) :
    latticeNorm (stdBasisInt d i) = 1 := by
  simp only [latticeNorm, stdBasisInt]
  calc ∑ j : Fin d, |(↑(if j = i then (1 : ℤ) else 0) : ℝ)|
      = ∑ j : Fin d, if j = i then 1 else 0 := by
        congr 1; ext j; split_ifs <;> simp
    _ = 1 := by simp [Finset.sum_ite_eq']

/-- Shifting by +eᵢ changes the norm by at most 1. -/
theorem latticeNorm_shift_le {d : ℕ} (x : Fin d → ℤ) (i : Fin d) :
    latticeNorm (fun j => x j + stdBasisInt d i j) ≤ latticeNorm x + 1 := by
  calc latticeNorm (fun j => x j + stdBasisInt d i j)
      ≤ latticeNorm x + latticeNorm (stdBasisInt d i) :=
        latticeNorm_triangle x (stdBasisInt d i)
    _ = latticeNorm x + 1 := by rw [latticeNorm_stdBasis]

/-- Shifting by -eᵢ changes the norm by at most 1. -/
theorem latticeNorm_shift_sub_le {d : ℕ} (x : Fin d → ℤ) (i : Fin d) :
    latticeNorm (fun j => x j - stdBasisInt d i j) ≤ latticeNorm x + 1 := by
  have : (fun j => x j - stdBasisInt d i j) = (fun j => x j + (-stdBasisInt d i j)) := by
    ext j; ring
  rw [this]
  calc latticeNorm (fun j => x j + (-stdBasisInt d i j))
      ≤ latticeNorm x + latticeNorm (fun j => -stdBasisInt d i j) :=
        latticeNorm_triangle x (fun j => -stdBasisInt d i j)
    _ = latticeNorm x + latticeNorm (stdBasisInt d i) := by
        congr 1; simp only [latticeNorm]; congr 1; ext j
        push_cast; rw [abs_neg]
    _ = latticeNorm x + 1 := by rw [latticeNorm_stdBasis]

/-! ## Nearest neighbors -/

/-- Nearest neighbors of x on ℤ^d: the 2d points {x ± eᵢ : i = 1..d}. -/
def neighbors (d : ℕ) (x : Fin d → ℤ) : Finset (Fin d → ℤ) :=
  Finset.univ.biUnion fun i =>
    {fun j => x j + stdBasisInt d i j,
     fun j => x j - stdBasisInt d i j}

/-- Nearest neighbors on the finite lattice with periodic BC.
    Addition is modulo N in each coordinate. -/
def neighborsFinite (d N : ℕ) [NeZero N] (x : FinLatticeSites d N) :
    Finset (FinLatticeSites d N) :=
  Finset.univ.biUnion fun i =>
    {fun j => if j = i then x j + 1 else x j,
     fun j => if j = i then x j - 1 else x j}

/-! ## Cardinality -/

/-- The number of neighbors is at most 2d. -/
theorem neighbors_card_le (d : ℕ) (x : Fin d → ℤ) :
    (neighbors d x).card ≤ 2 * d := by
  unfold neighbors
  calc (Finset.univ.biUnion _).card
      ≤ ∑ _i ∈ Finset.univ, ({fun j => x j + stdBasisInt d _i j,
          fun j => x j - stdBasisInt d _i j} : Finset _).card :=
        Finset.card_biUnion_le
    _ ≤ ∑ _i : Fin d, 2 := by
        apply Finset.sum_le_sum; intro i _
        exact le_of_le_of_eq (Finset.card_insert_le _ _) (by simp)
    _ = 2 * d := by simp [Finset.sum_const, mul_comm]

end GaussianField
