/- 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, hlentheorem 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, hlentheorem IsAdditionChain.one_le_of_mem {c : List } (h : IsAdditionChain c) {x : } (hx : x c) : 1 x := c:List h:IsAdditionChain cx:hx:x c1 x c:List x:hx:x chhead:c.head? = some 1hsorted:List.Pairwise (fun x1 x2 x1 < x2) c1 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 = 11 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 :: t1 1x:t:List hx✝:x 1 :: thsorted:List.Pairwise (fun x1 x2 x1 < x2) (1 :: t)hx:x t1 x t:List hsorted:List.Pairwise (fun x1 x2 x1 < x2) (1 :: t)hx:1 1 :: t1 1 All goals completed! 🐙 x:t:List hx✝:x 1 :: thsorted:List.Pairwise (fun x1 x2 x1 < x2) (1 :: t)hx:x t1 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 ya 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 yb 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 ya 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 ysa 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 ysa 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 yb 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 ysb 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 ysb 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 + 1y 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 ^ rFalse All goals completed! 🐙