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

# Torus Embedding: Discrete Lattice to Continuous Torus

Embeds the discrete torus `FinLatticeSites d N = (Fin d → ZMod N)` into the
continuous torus `(Fin d → AddCircle p)` via `ZMod.toAddCircle` and rescaling.

The framework for connecting ZMod-based lattice sites to AddCircle-based
continuous torus representations is due to Yoh Tanimoto.

## Main definitions

- `ContinuousTorus d p` — the continuous torus `(ℝ/pℤ)^d`
- `toScaledAddCircle` — `ZMod N →+ AddCircle p` for arbitrary period `p`
- `siteToTorus` — embedding `FinLatticeSites d N →+ ContinuousTorus d p`
- `siteToUnitTorus` — embedding into the unit torus `(ℝ/ℤ)^d`

## Mathematical background

The discrete torus (ℤ/Nℤ)^d embeds into the continuous torus (ℝ/pℤ)^d via
the map `x ↦ (i ↦ p·(x i)/N mod p)`. This is the composition of Mathlib's
`ZMod.toAddCircle : ZMod N →+ AddCircle 1` with the rescaling equivalence
`AddCircle.equivAddCircle : AddCircle 1 ≃+ AddCircle p`.

This embedding is key for:
- Defining the continuum limit (N → ∞ with the torus fixed)
- Multi-scale renormalization via `ZMod.castHom`
- Fourier analysis on the lattice via AddCircle's Fourier theory
-/

import Lattice.Sites
import Mathlib.Topology.Instances.AddCircle.Real
import Mathlib.Algebra.Group.Pi.Lemmas

noncomputable section

namespace GaussianField

/-! ## Continuous torus -/

/-- The continuous d-dimensional torus with period `p`: the product `(ℝ/pℤ)^d`. -/
abbrev ContinuousTorus (d : ℕ) (p : ℝ) := Fin d → AddCircle p

/-! ## Scaled AddCircle embedding -/

/-- The `AddMonoidHom` from `ZMod N` to `AddCircle p`, sending `j mod N` to
`p·j/N mod p`. Constructed as the composition of `ZMod.toAddCircle` (to the
unit circle) with `AddCircle.equivAddCircle` (rescaling from period 1 to
period p). Due to Yoh Tanimoto. -/
noncomputable def ZMod.toScaledAddCircle (p : ℝ) (N : ℕ) [NeZero N]
    (hp : p ≠ 0) : ZMod N →+ AddCircle p :=
  (AddCircle.equivAddCircle 1 p one_ne_zero hp).toAddMonoidHom.comp ZMod.toAddCircle

lemma ZMod.toScaledAddCircle_injective (p : ℝ) (N : ℕ) [NeZero N] (hp : p ≠ 0) :
    Function.Injective (ZMod.toScaledAddCircle p N hp) :=
  (AddCircle.equivAddCircle 1 p one_ne_zero hp).injective.comp
    (ZMod.toAddCircle_injective N)

@[simp] lemma ZMod.toScaledAddCircle_inj (p : ℝ) {N : ℕ} [NeZero N]
    (hp : p ≠ 0) {j k : ZMod N} :
    ZMod.toScaledAddCircle p N hp j = ZMod.toScaledAddCircle p N hp k ↔ j = k :=
  (ZMod.toScaledAddCircle_injective p N hp).eq_iff

@[simp] lemma ZMod.toScaledAddCircle_eq_zero (p : ℝ) {N : ℕ} [NeZero N]
    (hp : p ≠ 0) {j : ZMod N} :
    ZMod.toScaledAddCircle p N hp j = 0 ↔ j = 0 :=
  map_eq_zero_iff _ (ZMod.toScaledAddCircle_injective p N hp)

/-! ## Torus embedding maps -/

/-- Embed the discrete torus `(ℤ/Nℤ)^d` into the unit continuous torus `(ℝ/ℤ)^d`
via Mathlib's `ZMod.toAddCircle`. Site `x` maps to `(i ↦ (x i)/N mod 1)`. -/
noncomputable def siteToUnitTorus (d N : ℕ) [NeZero N] :
    FinLatticeSites d N →+ ContinuousTorus d 1 :=
  AddMonoidHom.pi (fun i => ZMod.toAddCircle.comp (Pi.evalAddMonoidHom (fun _ => ZMod N) i))

/-- The unit torus embedding is injective. -/
theorem siteToUnitTorus_injective (d N : ℕ) [NeZero N] :
    Function.Injective (siteToUnitTorus d N) := by
  intro x y h; ext i
  have := congr_fun h i
  simpa [siteToUnitTorus, AddMonoidHom.pi, Pi.evalAddMonoidHom] using this

/-- Embed the discrete torus `(ℤ/Nℤ)^d` into the continuous torus `(ℝ/pℤ)^d`.
Sends lattice site `x` to `(i ↦ p·(x i)/N mod p)`. -/
noncomputable def siteToTorus (d N : ℕ) [NeZero N] (p : ℝ) (hp : p ≠ 0) :
    FinLatticeSites d N →+ ContinuousTorus d p :=
  AddMonoidHom.pi (fun i =>
    (ZMod.toScaledAddCircle p N hp).comp (Pi.evalAddMonoidHom (fun _ => ZMod N) i))

/-- The scaled torus embedding is injective. -/
theorem siteToTorus_injective (d N : ℕ) [NeZero N] (p : ℝ) (hp : p ≠ 0) :
    Function.Injective (siteToTorus d N p hp) := by
  intro x y h; ext i
  have := congr_fun h i
  simpa [siteToTorus, AddMonoidHom.pi, Pi.evalAddMonoidHom] using this

/-- The scaled torus embedding relates to the unit embedding via rescaling. -/
theorem siteToTorus_eq_equivAddCircle_comp (d N : ℕ) [NeZero N] (p : ℝ)
    (hp : p ≠ 0) (x : FinLatticeSites d N) (i : Fin d) :
    siteToTorus d N p hp x i =
    AddCircle.equivAddCircle 1 p one_ne_zero hp (siteToUnitTorus d N x i) := by
  simp [siteToTorus, siteToUnitTorus, ZMod.toScaledAddCircle, AddMonoidHom.pi,
    Pi.evalAddMonoidHom]

end GaussianField
