/- Copyright 2026 The Formal Conjectures Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -/ import FormalConjecturesUtil

Conjectures about Latin Squares

This file formalizes some conjectures and theorems around latin squares.

References:

    [Wa2011] Wanless, Ian. "Transversals in Latin Squares: A Survey." Surveys in Combinatorics 2011, R. Chapman, Ed. Cambridge University Press, 2011, pp. 403–437. https://users.monash.edu.au/~iwanless/papers/transurveyBCC.pdf

    https://en.wikipedia.org/wiki/Problems_in_Latin_squares

namespace LatinSquare variable {n : }

Two latin squares of the same order are orthogonal if superimposing them gives each ordered pair of symbols at most once.

def Orthogonal (L M : LatinSquare n) : Prop := Function.Injective fun p : Fin n × Fin n => (L.mat p.1 p.2, M.mat p.1 p.2)

A family of latin squares is mutually orthogonal if any two distinct members are orthogonal.

def MutuallyOrthogonal {k n : } (L : Fin k LatinSquare n) : Prop := i j : Fin k, i j Orthogonal (L i) (L j)

A complete set of mutually orthogonal latin squares (MOLS) of order n consists of n - 1 latin squares of order n, pairwise orthogonal to each other.

def HasCompleteMOLS (n : ) : Prop := 0 < n L : Fin (n - 1) LatinSquare n, MutuallyOrthogonal L

Conjecture 3.2 in [Wa2011]: Each Latin square of odd order has at least one transversal.

@[category research open, AMS 5] theorem declaration uses 'sorry'oddOrderLatinSquareTransversal : answer(sorry) Odd n (L : LatinSquare n), σ, IsTransversal L σ := n:True Odd n (L : LatinSquare n), σ, IsTransversal L σ All goals completed! 🐙

The conjecture is known to be true for $n \leq 9$.

@[category research solved, AMS 5] theorem declaration uses 'sorry'oddOrderLeq9LatinSquareTransversal : answer(sorry) n 9, Odd n (L : LatinSquare n), σ, IsTransversal L σ := True n 9, Odd n (L : LatinSquare n), σ, IsTransversal L σ All goals completed! 🐙

The smallest odd number for which this conjecture is not known is 11.

@[category research open, AMS 5] theorem declaration uses 'sorry'latinSquareOrder11Transversal : answer(sorry) (L : LatinSquare 11), σ, IsTransversal L σ := True (L : LatinSquare 11), σ, IsTransversal L σ All goals completed! 🐙

Conjecture 5.1 in [Wa2011]: Every latin square has a near-transversal

@[category research open, AMS 5] theorem declaration uses 'sorry'latinSquareNearTransversal : answer(sorry) (L : LatinSquare n), ρ σ, IsNearTransversal L ρ σ := n:True (L : LatinSquare n), ρ σ, IsNearTransversal L ρ σ All goals completed! 🐙

The number of transversals of the Cayley table of the cyclic group $\mathbb{Z}_n$

def z (n : ) : := numTransversals { mat := Matrix.of fun i j : Fin n => i + j row_injective := fun i _a _b h => n✝:n:i:Fin n_a:Fin n_b:Fin nh:Matrix.of (fun i j => i + j) i _a = Matrix.of (fun i j => i + j) i _b_a = _b n✝:n:i:Fin n_a:Fin n_b:Fin nh:i + _a = i + _b_a = _b; All goals completed! 🐙 col_injective := fun j _a _b h => n✝:n:j:Fin n_a:Fin n_b:Fin nh:(Matrix.of fun i j => i + j).transpose j _a = (Matrix.of fun i j => i + j).transpose j _b_a = _b n✝:n:j:Fin n_a:Fin n_b:Fin nh:_a + j = _b + j_a = _b; All goals completed! 🐙 }

The $0 \times 0$ Cayley table has exactly $1$ transversal (vacuously).

@[category test, AMS 5] theorem z_zero : z 0 = 1 := z 0 = 1 All goals completed! 🐙

The number of transversals of the Cayley table of $\mathbb{Z}_n$ for odd $n$ forms OEIS A006717, starting with $z(1) = 1, z(3) = 3, z(5) = 15, z(7) = 133$.

@[category test, AMS 5] theorem z_odd_values : [z 1, z 3, z 5, z 7] = [1, 3, 15, 133] := [z 1, z 3, z 5, z 7] = [1, 3, 15, 133] All goals completed! 🐙

The Cayley table of $\mathbb{Z}_n$ for positive even $n$ has no transversals.

@[category textbook, AMS 5] theorem z_even (n : ) : z (2 * (n + 1)) = 0 := n:z (2 * (n + 1)) = 0 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflz N = 0 have hNpos : 0 < N := n:z (2 * (n + 1)) = 0 All goals completed! 🐙 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }z N = 0 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }IsEmpty { σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ } n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := }.mat i (σ i)False n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iFalse n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ False n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) False -- Sum the cell labels in `ZMod N` via `Nat.cast ∘ Fin.val`. n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iFalse n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflFalse have hcast : i : Fin N, g (i + σ i) = g i + g (σ i) := n:z (2 * (n + 1)) = 0 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rfli:Fin Ng (i + σ i) = g i + g (σ i); All goals completed! 🐙 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gFalse n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE gFalse have hSS : S + S = S := n:z (2 * (n + 1)) = 0 calc S + S = ( i, g i) + i, g (σ i) := n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE gS + S = i, g i + i, g (σ i) All goals completed! 🐙 _ = i, (g i + g (σ i)) := (Finset.sum_add_distrib).symm _ = i, g (i + σ i) := n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE g i, (g i + g (σ i)) = i, g (i + σ i) simp_rw n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE g i, (g i + g (σ i)) = i, g (i + σ i) hcast] _ = S := h1 have hS0 : S = 0 := n:z (2 * (n + 1)) = 0 All goals completed! 🐙 -- `S = ∑_{i < N} i = N(N-1)/2 = (n+1)(2n+1)` in `ZMod N`. have hval : S = (((Finset.range N).sum id : ) : ZMod N) := n:z (2 * (n + 1)) = 0 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE ghSS:S + S = S := Trans.trans (Trans.trans (Trans.trans (Eq.mpr (id (congrArg (fun _a => S + S = i, g i + _a) h2)) (Eq.refl (S + S))) (Eq.symm Finset.sum_add_distrib)) (of_eq_true (Eq.trans (congrArg (fun x => x = x, g (x + σ x)) (Finset.sum_congr (Eq.refl Finset.univ) fun x a => (fun i => Eq.symm (hcast i)) x)) (eq_self (∑ x, g (x + σ x)))))) h1hS0:S = 0 := Mathlib.Tactic.LinearCombination.eq_of_eq hSS (Mathlib.Tactic.LinearCombination.eq_rearrange (Mathlib.Tactic.Ring.of_eq (Mathlib.Tactic.Ring.sub_congr (Mathlib.Tactic.Ring.add_congr (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.add_pf_add_overlap (Mathlib.Tactic.Ring.add_overlap_pf S (Nat.rawCast 1) (Mathlib.Meta.NormNum.IsNat.to_raw_eq (Mathlib.Meta.NormNum.isNat_add (Eq.refl HAdd.hAdd) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Eq.refl 2)))) (Mathlib.Tactic.Ring.add_pf_zero_add 0))) (Mathlib.Tactic.Ring.add_congr (Mathlib.Tactic.Ring.cast_zero (Mathlib.Meta.NormNum.isNat_ofNat (ZMod N) Nat.cast_zero)) (Mathlib.Tactic.Ring.add_congr (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.add_pf_add_overlap (Mathlib.Tactic.Ring.add_overlap_pf S (Nat.rawCast 1) (Mathlib.Meta.NormNum.IsNat.to_raw_eq (Mathlib.Meta.NormNum.isNat_add (Eq.refl HAdd.hAdd) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Eq.refl 2)))) (Mathlib.Tactic.Ring.add_pf_zero_add 0))) (Mathlib.Tactic.Ring.add_pf_zero_add (S ^ Nat.rawCast 1 * Nat.rawCast 2 + 0))) (Mathlib.Tactic.Ring.sub_pf (Mathlib.Tactic.Ring.neg_add (Mathlib.Tactic.Ring.neg_mul S (Nat.rawCast 1) (Mathlib.Tactic.Ring.neg_one_mul (Mathlib.Meta.NormNum.IsInt.to_raw_eq (Mathlib.Meta.NormNum.isInt_mul (Eq.refl HMul.hMul) (Mathlib.Meta.NormNum.IsInt.of_raw (ZMod N) (Int.negOfNat 1)) (Mathlib.Meta.NormNum.IsNat.to_isInt (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 2)) (Eq.refl (Int.negOfNat 2)))))) Mathlib.Tactic.Ring.neg_zero) (Mathlib.Tactic.Ring.add_pf_add_overlap_zero (Mathlib.Tactic.Ring.add_overlap_pf_zero S (Nat.rawCast 1) (Mathlib.Meta.NormNum.IsInt.to_isNat (Mathlib.Meta.NormNum.isInt_add (Eq.refl HAdd.hAdd) (Mathlib.Meta.NormNum.IsNat.to_isInt (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 2)) (Mathlib.Meta.NormNum.IsInt.of_raw (ZMod N) (Int.negOfNat 2)) (Eq.refl (Int.ofNat 0))))) (Mathlib.Tactic.Ring.add_pf_zero_add 0)))) (Mathlib.Tactic.Ring.cast_zero (Mathlib.Meta.NormNum.isNat_ofNat (ZMod N) Nat.cast_zero)))) i, g i = ((Finset.range N).sum id) n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE ghSS:S + S = S := Trans.trans (Trans.trans (Trans.trans (Eq.mpr (id (congrArg (fun _a => S + S = i, g i + _a) h2)) (Eq.refl (S + S))) (Eq.symm Finset.sum_add_distrib)) (of_eq_true (Eq.trans (congrArg (fun x => x = x, g (x + σ x)) (Finset.sum_congr (Eq.refl Finset.univ) fun x a => (fun i => Eq.symm (hcast i)) x)) (eq_self (∑ x, g (x + σ x)))))) h1hS0:S = 0 := Mathlib.Tactic.LinearCombination.eq_of_eq hSS (Mathlib.Tactic.LinearCombination.eq_rearrange (Mathlib.Tactic.Ring.of_eq (Mathlib.Tactic.Ring.sub_congr (Mathlib.Tactic.Ring.add_congr (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.add_pf_add_overlap (Mathlib.Tactic.Ring.add_overlap_pf S (Nat.rawCast 1) (Mathlib.Meta.NormNum.IsNat.to_raw_eq (Mathlib.Meta.NormNum.isNat_add (Eq.refl HAdd.hAdd) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Eq.refl 2)))) (Mathlib.Tactic.Ring.add_pf_zero_add 0))) (Mathlib.Tactic.Ring.add_congr (Mathlib.Tactic.Ring.cast_zero (Mathlib.Meta.NormNum.isNat_ofNat (ZMod N) Nat.cast_zero)) (Mathlib.Tactic.Ring.add_congr (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.atom_pf S) (Mathlib.Tactic.Ring.add_pf_add_overlap (Mathlib.Tactic.Ring.add_overlap_pf S (Nat.rawCast 1) (Mathlib.Meta.NormNum.IsNat.to_raw_eq (Mathlib.Meta.NormNum.isNat_add (Eq.refl HAdd.hAdd) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 1) (Eq.refl 2)))) (Mathlib.Tactic.Ring.add_pf_zero_add 0))) (Mathlib.Tactic.Ring.add_pf_zero_add (S ^ Nat.rawCast 1 * Nat.rawCast 2 + 0))) (Mathlib.Tactic.Ring.sub_pf (Mathlib.Tactic.Ring.neg_add (Mathlib.Tactic.Ring.neg_mul S (Nat.rawCast 1) (Mathlib.Tactic.Ring.neg_one_mul (Mathlib.Meta.NormNum.IsInt.to_raw_eq (Mathlib.Meta.NormNum.isInt_mul (Eq.refl HMul.hMul) (Mathlib.Meta.NormNum.IsInt.of_raw (ZMod N) (Int.negOfNat 1)) (Mathlib.Meta.NormNum.IsNat.to_isInt (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 2)) (Eq.refl (Int.negOfNat 2)))))) Mathlib.Tactic.Ring.neg_zero) (Mathlib.Tactic.Ring.add_pf_add_overlap_zero (Mathlib.Tactic.Ring.add_overlap_pf_zero S (Nat.rawCast 1) (Mathlib.Meta.NormNum.IsInt.to_isNat (Mathlib.Meta.NormNum.isInt_add (Eq.refl HAdd.hAdd) (Mathlib.Meta.NormNum.IsNat.to_isInt (Mathlib.Meta.NormNum.IsNat.of_raw (ZMod N) 2)) (Mathlib.Meta.NormNum.IsInt.of_raw (ZMod N) (Int.negOfNat 2)) (Eq.refl (Int.ofNat 0))))) (Mathlib.Tactic.Ring.add_pf_zero_add 0)))) (Mathlib.Tactic.Ring.cast_zero (Mathlib.Meta.NormNum.isNat_ofNat (ZMod N) Nat.cast_zero)))) i Finset.range N, i = x Finset.range N, x All goals completed! 🐙 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE ghSS:S + S = S := Trans.trans (Trans.trans (Trans.trans (Eq.mpr (id (congrArg (fun _a => S + S = i, g i + _a) h2)) (Eq.refl (S + S))) (Eq.symm Finset.sum_add_distrib)) (of_eq_true (Eq.trans (congrArg (fun x => x = x, g (x + σ x)) (Finset.sum_congr (Eq.refl Finset.univ) fun x a => (fun i => Eq.symm (hcast i)) x)) (eq_self (∑ x, g (x + σ x)))))) h1hS0:(N * (N - 1) / 2) = 0hval:S = ((Finset.range N).sum id)False have hdiv : N * (N - 1) / 2 = (n + 1) * (2 * n + 1) := n:z (2 * (n + 1)) = 0 All goals completed! 🐙 n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE ghSS:S + S = S := Trans.trans (Trans.trans (Trans.trans (Eq.mpr (id (congrArg (fun _a => S + S = i, g i + _a) h2)) (Eq.refl (S + S))) (Eq.symm Finset.sum_add_distrib)) (of_eq_true (Eq.trans (congrArg (fun x => x = x, g (x + σ x)) (Finset.sum_congr (Eq.refl Finset.univ) fun x a => (fun i => Eq.symm (hcast i)) x)) (eq_self (∑ x, g (x + σ x)))))) h1hS0:((n + 1) * (2 * n + 1)) = 0hval:S = ((Finset.range N).sum id)hdiv:N * (N - 1) / 2 = (n + 1) * (2 * n + 1)False n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE ghSS:S + S = S := Trans.trans (Trans.trans (Trans.trans (Eq.mpr (id (congrArg (fun _a => S + S = i, g i + _a) h2)) (Eq.refl (S + S))) (Eq.symm Finset.sum_add_distrib)) (of_eq_true (Eq.trans (congrArg (fun x => x = x, g (x + σ x)) (Finset.sum_congr (Eq.refl Finset.univ) fun x a => (fun i => Eq.symm (hcast i)) x)) (eq_self (∑ x, g (x + σ x)))))) h1hS0:((n + 1) * (2 * n + 1)) = 0hval:S = ((Finset.range N).sum id)hdiv:N * (N - 1) / 2 = (n + 1) * (2 * n + 1)hdvd:N (n + 1) * (2 * n + 1) := (ZMod.natCast_eq_zero_iff ((n + 1) * (2 * n + 1)) N).mp hS0False -- `N = (n+1) * 2`; cancelling `(n+1)` forces `2 ∣ 2n+1`, impossible. n:N: := 2 * (n + 1)hN_def:N = 2 * (n + 1) := rflhNpos:0 < N := mul_pos (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 2)) (Eq.refl (Nat.ble 1 2))) (Right.add_pos_of_nonneg_of_pos (zero_le n) (Mathlib.Meta.Positivity.pos_of_isNat (Mathlib.Meta.NormNum.isNat_ofNat (Eq.refl 1)) (Eq.refl (Nat.ble 1 1))))this:NeZero N := { out := LT.lt.ne' hNpos }x✝:{ σ // IsTransversal { mat := Matrix.of fun i j => i + j, row_injective := , col_injective := } σ }σ:Fin N Fin N:Function.Injective σhimg:Function.Injective fun i => i + σ iσE:Fin N Fin N := Equiv.ofBijective σ fE:Fin N Fin N := Equiv.ofBijective (fun i => i + σ i) g:Fin N ZMod N := fun i => iS:ZMod N := i, g ihS_def:S = i, g i := rflhcast: (i : Fin N), g (i + σ i) = g i + g (σ i) := fun i => of_eq_true (Eq.trans (congrArg (fun x => x = i + (σ i)) (Eq.trans (ZMod.natCast_mod (i + (σ i)) N) (Nat.cast_add i (σ i)))) (eq_self (i + (σ i))))h1: i, g (i + σ i) = S := Equiv.sum_comp fE gh2: i, g (σ i) = S := Equiv.sum_comp σE ghSS:S + S = S := Trans.trans (Trans.trans (Trans.trans (Eq.mpr (id (congrArg (fun _a => S + S = i, g i + _a) h2)) (Eq.refl (S + S))) (Eq.symm Finset.sum_add_distrib)) (of_eq_true (Eq.trans (congrArg (fun x => x = x, g (x + σ x)) (Finset.sum_congr (Eq.refl Finset.univ) fun x a => (fun i => Eq.symm (hcast i)) x)) (eq_self (∑ x, g (x + σ x)))))) h1hS0:((n + 1) * (2 * n + 1)) = 0hval:S = ((Finset.range N).sum id)hdiv:N * (N - 1) / 2 = (n + 1) * (2 * n + 1)hdvd:2 2 * n + 1False All goals completed! 🐙

Conjecture 6.7 in [Wa2011]: There exist real constants $0 < c_1 < c_2 < 1$ such that $$ c_1^n n! \leq z_n \leq c_2^n n! $$ for all odd $n \geq 3$.

@[category research open, AMS 5] theorem declaration uses 'sorry'numTransversalsZn : answer(sorry) ∃ᵉ (c₁ > (0 : )) (c₂ < (1 : )) (_ : c₁ < c₂), n 3, Odd n (z n : ) Set.Icc (c₁ ^ n * n.factorial) (c₂ ^ n * n.factorial) := True c₁ > 0, c₂ < 1, (_ : c₁ < c₂), n 3, Odd n (z n) Set.Icc (c₁ ^ n * n.factorial) (c₂ ^ n * n.factorial) All goals completed! 🐙

Conjecture 6.9 in [Wa2011]: $$ \lim_{\substack{n \to \infty \ n \text{ odd}}} \frac{1}{n} \log(z_n / n!) = -1 $$ It is not even known if this limit exists. Note that $z_n = 0$ for even $n$ (see z_even), so the limit must be restricted to odd $n$; here we parametrise odd $n$ as $2k + 1$.

@[category research open, AMS 5] theorem declaration uses 'sorry'growthRateZn : answer(sorry) Filter.Tendsto (fun k => (1 : ) / (2 * k + 1) * Real.log (z (2 * k + 1) / (2 * k + 1).factorial)) Filter.atTop (nhds (-1)) := True Filter.Tendsto (fun k => 1 / (2 * k + 1) * Real.log ((z (2 * k + 1)) / (2 * k + 1).factorial)) Filter.atTop (nhds (-1)) All goals completed! 🐙

The maximum number of transversals over all latin squares of order n.

def T (n : ) : := Finset.sup Finset.univ (fun L : LatinSquare n => numTransversals L)

Theorem 7.2 in [Wa2011]: For all $n \geq 5$, $$ 15^{n/5} \leq T(n) \leq c^n \sqrt{n} \cdot n! $$ where $c = \sqrt{\frac{3 - \sqrt{3}}{6}} \cdot e^{\sqrt{3}/6}$

@[category research solved, AMS 5] theorem declaration uses 'sorry'maxTransversalsBound : let c := Real.sqrt ((3 - Real.sqrt 3) / 6) * Real.exp (Real.sqrt 3 / 6) n : , n 5 (T n : ) Set.Icc ((15 : ) ^ ((n : ) / 5)) (c ^ n * Real.sqrt n * n.factorial) := let c := ((3 - 3) / 6) * Real.exp (3 / 6); n 5, (T n) Set.Icc (15 ^ (n / 5)) (c ^ n * n * n.factorial) All goals completed! 🐙

MOLS existence problem: determine exactly which orders n admit a complete set of n - 1 mutually orthogonal latin squares.

Equivalently, this asks for which orders affine planes of order n exist. Complete sets are known for prime-power orders; the smallest currently unresolved order is 12.

@[category research open, AMS 5] theorem declaration uses 'sorry'molsExistenceProblem : answer(sorry) = {n : | HasCompleteMOLS n} := sorry = {n | HasCompleteMOLS n} All goals completed! 🐙

The smallest unresolved case of the MOLS existence problem: whether there are 11 mutually orthogonal latin squares of order 12.

@[category research open, AMS 5] theorem declaration uses 'sorry'molsOrder12 : answer(sorry) HasCompleteMOLS 12 := True HasCompleteMOLS 12 All goals completed! 🐙 /- TODO(rao107): Conjecture 8.5 in [Wa2011]: Every latin square has the maximum number of disjoint duplexes. In particular, every latin square of even order has a 2-partition and every latin square of odd order has a (2, 2, 2, ..., 2, 1)-partition. -/ /- TODO(rao107): Conjecture 8.6 in [Wa2011]: For all even $n > 4$ there exists a latin square of ordern $n$ which has no transversal but does contain a 3-plex. -/ /- TODO(rao107): Conjecture 9.2 in [Wa2011]: If $n$ is even, then $f(n, 2) = n$; if $n$ is odd, then $f(n, 2) > n$. -/ /- TODO(rao107): Conjecture 10.10 in [Wa2011]: Every latin hypercube of odd dimension or of odd oder has a transversal. -/ end LatinSquare