/- 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. -/ module public import Mathlib.Data.List.Sort public import Mathlib.Order.Lattice.Nat@[expose] public section

Addition chains

An addition chain for $n$ is a strictly increasing sequence $1 = a_0 < a_1 < \cdots < a_r = n$ in which every entry after the first is the sum of two earlier entries. Its length is $r$, the number of additions, and $\ell(n)$ is the least length over all chains ending at $n$.

additionChainLength is an infimum over List ℕ, so an explicit chain bounds it above (additionChainLength_le) but nothing bounds it below until the search is confined. The confinement here is that an addition step at most doubles, so r steps cannot reach past 2 ^ r (getLast_le_two_pow), giving lt_additionChainLength_of_two_pow_lt.

An addition chain is a strictly increasing sequence $1 = a_0 < a_1 < \cdots < a_r$ in which every entry after the first is the sum of two (not necessarily distinct) earlier entries.

IsAdditionChain c asserts that the list $c$ is such a chain: it starts at $1$, is strictly increasing, and every entry other than $1$ is a sum of two entries of $c$.

def IsAdditionChain (c : List ℕ) : Prop := c.head? = some 1 ∧ c.Pairwise (· < ·) ∧ ∀ x ∈ c, x ≠ 1 → ∃ y ∈ c, ∃ z ∈ c, x = y + z

Every quantifier in IsAdditionChain is bounded by the list, so membership is decidable and a concrete chain can be checked by decide.

instance (c : List ℕ) : Decidable (IsAdditionChain c) := c:List ℕ⊢ Decidable (IsAdditionChain c) c:List ℕ⊢ Decidable (c.head? = some 1 ∧ List.Pairwise (fun x1 x2 ↦ x1 < x2) c ∧ ∀ x ∈ c, x ≠ 1 → ∃ y ∈ c, ∃ z ∈ c, x = y + z); All goals completed! 🐙

The length $\ell(n)$ of $n$: the minimal number of addition steps (the number of entries minus one) over all addition chains ending at $n$.

noncomputable def additionChainLength (n : ℕ) : ℕ := sInf { r | ∃ c : List ℕ, IsAdditionChain c ∧ c.getLast? = some n ∧ c.length = r + 1 }

The set of step counts realised by chains ending at n.

def additionChainSteps (n : ℕ) : Set ℕ := { r | ∃ c : List ℕ, IsAdditionChain c ∧ c.getLast? = some n ∧ c.length = r + 1 }theorem additionChainLength_eq_sInf (n : ℕ) : additionChainLength n = sInf (additionChainSteps n) := rfl

Exhibiting a chain bounds ℓ above.

theorem additionChainLength_le {n r : ℕ} (c : List ℕ) (hc : IsAdditionChain c) (hlast : c.getLast? = some n) (hlen : c.length = r + 1) : additionChainLength n ≤ r := Nat.sInf_le ⟨c, hc, hlast, hlen⟩theorem additionChainSteps_nonempty {n r : ℕ} (c : List ℕ) (hc : IsAdditionChain c) (hlast : c.getLast? = some n) (hlen : c.length = r + 1) : (additionChainSteps n).Nonempty := ⟨r, c, hc, hlast, hlen⟩theorem IsAdditionChain.one_le_of_mem {c : List ℕ} (h : IsAdditionChain c) {x : ℕ} (hx : x ∈ c) : 1 ≤ x := c:List ℕh:IsAdditionChain cx:ℕhx:x ∈ c⊢ 1 ≤ x c:List ℕx:ℕhx:x ∈ chhead:c.head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) c⊢ 1 ≤ x cases c with x:ℕhx:x ∈ []hhead:[].head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) []⊢ 1 ≤ x All goals completed! 🐙 x:ℕa:ℕt:List ℕhx:x ∈ a :: thhead:(a :: t).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (a :: t)⊢ 1 ≤ x x:ℕa:ℕt:List ℕhx:x ∈ a :: thsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (a :: t)hhead:a = 1⊢ 1 ≤ x x:ℕt:List ℕhx:x ∈ 1 :: thsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (1 :: t)⊢ 1 ≤ x t:List ℕhsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (1 :: t)hx:1 ∈ 1 :: t⊢ 1 ≤ 1x:ℕt:List ℕhx✝:x ∈ 1 :: thsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (1 :: t)hx:x ∈ t⊢ 1 ≤ x t:List ℕhsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (1 :: t)hx:1 ∈ 1 :: t⊢ 1 ≤ 1 All goals completed! 🐙 x:ℕt:List ℕhx✝:x ∈ 1 :: thsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (1 :: t)hx:x ∈ t⊢ 1 ≤ x All goals completed! 🐙

Dropping the last entry of a chain leaves a chain. The entries are positive, so a summand of the last entry is never the last entry itself and so survives the drop.

ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ y⊢ ∃ y ∈ ys, ∃ z ∈ ys, a + b = y + z ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ y⊢ a ∈ ysys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ y⊢ b ∈ ys ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ y⊢ a ∈ ys ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:a ∈ ys⊢ a ∈ ysys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:a ∈ [y]⊢ a ∈ ys ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:a ∈ ys⊢ a ∈ ys All goals completed! 🐙 ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:a ∈ [y]⊢ a ∈ ys All goals completed! 🐙 ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ y⊢ b ∈ ys ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:b ∈ ys⊢ b ∈ ysys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:b ∈ [y]⊢ b ∈ ys ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:b ∈ ys⊢ b ∈ ys All goals completed! 🐙 ys:List ℕy:ℕhys:ys ≠ []hhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + za:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hx:a + b ∈ yshx1:a + b ≠ 1hxy:a + b < yha1:1 ≤ ahb1:1 ≤ bhay:a ≠ yhby:b ≠ yh:b ∈ [y]⊢ b ∈ ys All goals completed! 🐙

Every step at most doubles, so a chain of r steps cannot reach past 2 ^ r.

ys:List ℕy:ℕih:IsAdditionChain ys → ∀ (hne : ys ≠ []), ys.getLast hne ≤ 2 ^ (ys.length - 1)hne:ys ++ [y] ≠ []hys:ys ≠ []hchain:IsAdditionChain yshhead:(ys ++ [y]).head? = some 1hsorted:List.Pairwise (fun x1 x2 ↦ x1 < x2) (ys ++ [y])hsum:∀ x ∈ ys ++ [y], x ≠ 1 → ∃ y_1 ∈ ys ++ [y], ∃ z ∈ ys ++ [y], x = y_1 + zhy1:y ≠ 1a:ℕha:a ∈ ys ++ [y]b:ℕhb:b ∈ ys ++ [y]hyab:y = a + bha1:1 ≤ ahb1:1 ≤ bhays:a ∈ yshbys:b ∈ yshsub:List.Pairwise (fun {a b} ↦ a ≤ b) yshla:a ≤ ys.getLast ⋯hlb:b ≤ ys.getLast ⋯hih:ys.getLast hys ≤ 2 ^ (ys.length - 1)hlen:(ys ++ [y]).length - 1 = ys.lengthhyl:ys.length = ys.length - 1 + 1⊢ y ≤ 2 ^ (ys.length - 1) * 2 All goals completed! 🐙

The doubling bound, transported to ℓ: reaching n takes at least log₂ n steps.

n:ℕhne:(additionChainSteps n).Nonemptyc:List ℕhc:IsAdditionChain chlast:c.getLast? = some nhlen:c.length = sInf (additionChainSteps n) + 1hcne:c ≠ []this✝:c.getLast hcne = nthis:n ≤ 2 ^ (sInf (additionChainSteps n) + 1 - 1)⊢ n ≤ 2 ^ additionChainLength n All goals completed! 🐙

The lower-bound tool: r steps cannot reach past 2 ^ r.

n:ℕr:ℕhne:(additionChainSteps n).Nonemptyh:2 ^ r < nhcon:additionChainLength n ≤ rh1:n ≤ 2 ^ additionChainLength nh2:2 ^ additionChainLength n ≤ 2 ^ r⊢ False All goals completed! 🐙