Martin Escardo, 21th April 2023
Based on Section 8.1 of the paper https://doi.org/10.2168/LMCS-4(3:3)2008

Updated 25th May 2023 to (i) give an alternative construction of our
formula for a putative root, and (ii) prove its correctness.

We provide a formula for a putative root of any boolean function
f : 𝟚ⁿ β†’ 𝟚, using only f and β‚€, and show its correctness.

In more detail:

Let 𝟚 be the two-point set with elements β‚€ and ₁, referred to as the
type of booleans.

Consider a given boolean function f : 𝟚ⁿ β†’ 𝟚.

Definition. A *root* of f is some xs in 𝟚ⁿ such that f xs = β‚€.

Definition. A *putative root* of f is any xs in 𝟚ⁿ such that if f has
some root, then xs is a root.

Example. If f doesn't have any root, then any xs in 𝟚ⁿ is putative root.

Example. If xs is a root, then xs is a putative root.

Theorem. For any n, there is a formula that mentions only f and β‚€ such
that for any given function f : 𝟚ⁿ β†’ 𝟚, the formula gives a putative
root of f.

We will need to be more precise regarding the formal details of the
statement of this theorem, where we will need to distinguish between
(abstract syntax for) formulas for putative roots and actual putative
roots, but, for the moment, the above imprecise formulation of the
theorem should be good enough.

Example. For n = 3, we have the putative root x := (xβ‚€,x₁,xβ‚‚) where

  y  := f(0,0,f(0,0,0))
  xβ‚€ := f(0,y,f(0,y,0))
  x₁ := f(xβ‚€,0,f(xβ‚€,0,0))
  xβ‚‚ := f(xβ‚€,x₁,0)

The purpose of this Agda file is to construct such a formula for any
given n, and prove that it indeed gives a putative root.

\begin{code}

{-# OPTIONS --safe --without-K #-}

module Various.RootsOfBooleanFunctions where

open import MLTT.Spartan hiding (_^_)
open import MLTT.Two-Properties
open import UF.Base

\end{code}

For any f : 𝟚 β†’ 𝟚, we can check whether it is constantly ₁ by checking
whether f (f β‚€) is ₁, which is easily proved by case analysis on the
value of f β‚€:

\begin{code}

motivating-fact : (f : 𝟚 β†’ 𝟚) β†’ f (f β‚€) = ₁ β†’ (b : 𝟚) β†’ f b = ₁
motivating-fact f = Ξ³ (f β‚€) refl
 where
  Ξ³ : (bβ‚€ : 𝟚) β†’ f β‚€ = bβ‚€ β†’ f bβ‚€ = ₁ β†’ (b : 𝟚) β†’ f b = ₁
  Ξ³ β‚€ p q β‚€ = q
  Ξ³ β‚€ p q ₁ = 𝟘-elim
               (zero-is-not-one
                 (β‚€   =⟨ p ⁻¹ ⟩
                  f β‚€ =⟨ q ⟩
                  ₁   ∎))
  Ξ³ ₁ p q β‚€ = p
  Ξ³ ₁ p q ₁ = q

\end{code}

Motivated by this, we define:

\begin{code}

Ρ𝟚 : (𝟚 β†’ 𝟚) β†’ 𝟚
Ρ𝟚 f = f β‚€

A𝟚 : (𝟚 β†’ 𝟚) β†’ 𝟚
A𝟚 f = f (Ρ𝟚 f)

\end{code}

The desired property of A𝟚 is the following, which follows from the
motivating fact, in one direction, and directly in the other
direction:

\begin{code}

A𝟚-propertyβ†’ : (f : 𝟚 β†’ 𝟚) β†’ A𝟚 f = ₁ β†’ (b : 𝟚) β†’ f b = ₁
A𝟚-propertyβ†’ = motivating-fact

A𝟚-property← : (f : 𝟚 β†’ 𝟚) β†’ ((b : 𝟚) β†’ f b = ₁) β†’ A𝟚 f = ₁
A𝟚-property← f Ξ± = Ξ± (Ρ𝟚 f)

\end{code}

From this it follows directly that for any f : 𝟚 β†’ 𝟚 we can find a
boolean bβ‚€ such that if f bβ‚€ = ₁ then f n = ₁ for every boolean b:

\begin{code}

ΟƒπŸš : (f : 𝟚 β†’ 𝟚) β†’ Ξ£ bβ‚€ κž‰ 𝟚 , (f bβ‚€ = ₁ β†’ (b : 𝟚) β†’ f b = ₁)
ΟƒπŸš f = Ρ𝟚 f , A𝟚-propertyβ†’ f

\end{code}

The functional Ρ𝟚 computes the putative root Ξ΅ f for any f : 𝟚 β†’ 𝟚:

\begin{code}

is-root : {X : 𝓀 Μ‡ } β†’ X β†’ (X β†’ 𝟚) β†’ 𝓀₀ Μ‡
is-root xβ‚€ f = f xβ‚€ = β‚€

has-root : {X : 𝓀 Μ‡ } β†’ (X β†’ 𝟚) β†’ 𝓀 Μ‡
has-root {𝓀} {X} f = Ξ£ x κž‰ X , is-root x f

is-putative-root : {X : 𝓀 Μ‡ } β†’ X β†’ (X β†’ 𝟚) β†’ 𝓀 Μ‡
is-putative-root xβ‚€ f = has-root f β†’ is-root xβ‚€ f

Ρ𝟚-gives-putative-root : {n : β„•} (f : 𝟚 β†’ 𝟚)
                       β†’ is-putative-root (Ρ𝟚 f) f
Ρ𝟚-gives-putative-root f (b , r) =
 different-from-₁-equal-β‚€
  (Ξ» (p : A𝟚 f = ₁) β†’ zero-is-not-one
                       (β‚€   =⟨ r ⁻¹ ⟩
                        f b =⟨ A𝟚-propertyβ†’ f p b ⟩
                        ₁   ∎))
\end{code}

We define the type X ^ n of n-tuples of elements of a type X by
induction as follows.

\begin{code}

data _^_ (X : 𝓀 Μ‡ ) : β„• β†’ 𝓀 Μ‡ where
 ⟨⟩  : X ^ 0
 _,_ : {n : β„•} β†’ X β†’ X ^ n β†’ X ^ (succ n)

\end{code}

(This is just another notation for the type of so-called vectors.)

We will often use the "prepend" function (x ,_), for any given x,
written "cons x", defined by cons x xs = (x , xs), or, equivalently:

\begin{code}

cons : {X : 𝓀 Μ‡ } {n : β„•} β†’ X β†’ X ^ n β†’ X ^ (succ n)
cons x = (x ,_)

\end{code}

We are now ready to compute putative roots of boolean functions. We
will later adapt this argument to give a *formula* for the putative
root.

We define two functions A and Ξ΅ by simultateous induction on n as
follows:

\begin{code}

A : {n : β„•} β†’ (𝟚 ^ n β†’ 𝟚) β†’ 𝟚
Ξ΅ : {n : β„•} β†’ (𝟚 ^ n β†’ 𝟚) β†’ 𝟚 ^ n

A f = f (Ξ΅ f)

Ρ {0}      f = ⟨⟩
Ξ΅ {succ n} f = cons bβ‚€ (Ξ΅ (f ∘ cons bβ‚€) )
 where
  bβ‚€ : 𝟚
  bβ‚€ = Ρ𝟚 (b ↦ A (f ∘ cons b))

\end{code}

It is of course possible to first define Ξ΅, by induction on n, and
then A directly from Ξ΅ as follows. If we also expand the definition of
Ρ𝟚, we get:

\begin{code}

private

 Ξ΅' : {n : β„•} β†’ (𝟚 ^ n β†’ 𝟚) β†’ 𝟚 ^ n
 Ρ' {0}      f = ⟨⟩
 Ξ΅' {succ n} f = cons bβ‚€ (Ξ΅' (f ∘ cons bβ‚€))
  where
   bβ‚€ : 𝟚
   bβ‚€ = (f ∘ cons β‚€) (Ξ΅' (f ∘ cons β‚€))

 A' : {n : β„•} β†’ (𝟚 ^ n β†’ 𝟚) β†’ 𝟚
 A' f = f (Ξ΅' f)

\end{code}

However, we want to highlight the role of A in our definition of Ξ΅.

We have that A f = ₁ if and only if f xs = ₁ for all xs in 𝟚 ^ n:

\begin{code}

A-property← : {n : β„•} (f : 𝟚 ^ n β†’ 𝟚)
            β†’ ((xs : 𝟚 ^ n) β†’ f xs = ₁)
            β†’ A f = ₁
A-property← f Ξ± = Ξ± (Ξ΅ f)

A-property→ : {n : ℕ}
              (f : 𝟚 ^ n β†’ 𝟚)
            β†’ A f = ₁
            β†’ (xs : 𝟚 ^ n) β†’ f xs = ₁
A-propertyβ†’ {0}      f p ⟨⟩ = f ⟨⟩        =⟨ refl ⟩
                              f (Ρ {0} f) =⟨ p ⟩
                              ₁           ∎
A-property→ {succ n} f p (x , xs) = II
 where
  IH : (b : 𝟚) β†’ A (f ∘ cons b) = ₁ β†’ (xs : 𝟚 ^ n) β†’ f (cons b xs) = ₁
  IH b = A-propertyβ†’ {n} (f ∘ cons b)

  bβ‚€ : 𝟚
  bβ‚€ = Ρ𝟚 (b ↦ A (f ∘ cons b))

  I : A (f ∘ cons bβ‚€) = ₁ β†’ (b : 𝟚) β†’ A (f ∘ cons b) = ₁
  I = A𝟚-propertyβ†’ (b ↦ A (f ∘ cons b))

  II : f (x , xs) = ₁
  II = IH x (I p x) xs

Οƒ : {n : β„•} (f : 𝟚 ^ n β†’ 𝟚)
  β†’ Ξ£ xβ‚€ κž‰ 𝟚 ^ n , (f xβ‚€ = ₁ β†’ (x : 𝟚 ^ n) β†’ f x = ₁)
σ f = Ρ f , A-property→ f

\end{code}

From this it follows that Ξ΅ f computes a putative root of f.

\begin{code}

Ξ΅-gives-putative-root : {n : β„•}  (f : 𝟚 ^ n β†’ 𝟚)
                      β†’ is-putative-root (Ξ΅ f) f
Ξ΅-gives-putative-root {n} f (x , p) =
 different-from-₁-equal-β‚€
  (Ξ» (q : A f = ₁) β†’ zero-is-not-one
                       (β‚€   =⟨ p ⁻¹ ⟩
                        f x =⟨ A-propertyβ†’ f q x ⟩
                        ₁   ∎))

\end{code}

Hence we can check whether f has a root by checking whether f (Ξ΅ f) = β‚€.

\begin{code}

root-existence-criterion : {n : β„•}  (f : 𝟚 ^ n β†’ 𝟚)
                         β†’ has-root f ↔ is-root (Ξ΅ f) f
root-existence-criterion {n} f = (I , II)
 where
  I : has-root f β†’ f (Ξ΅ f) = β‚€
  I = Ξ΅-gives-putative-root f

  II : f (Ξ΅ f) = β‚€ β†’ has-root f
  II p = Ξ΅ f , p

\end{code}

The above computes a putative root, but what we want to do in this
file is to give a *formula* for computing putative roots using only β‚€
and f, as discussed above. In a way, this is already achieved
above. Here are some examples:

\begin{code}

exampleβ‚‚ : (f : 𝟚 ^ 2 β†’ 𝟚)
         β†’ Ξ΅ f = (f (β‚€ , f (β‚€ , β‚€ , ⟨⟩) , ⟨⟩) ,
                   f (f (β‚€ , f (β‚€ , β‚€ , ⟨⟩) , ⟨⟩) , β‚€ , ⟨⟩) ,
                   ⟨⟩)
exampleβ‚‚ f = refl

example₃ : (f : 𝟚 ^ 3 β†’ 𝟚) β†’
 let
  y  = f (β‚€ , β‚€ , f (β‚€ , β‚€ , β‚€ , ⟨⟩) , ⟨⟩)
  xβ‚€ = f (β‚€ , y , f (β‚€ , y , β‚€ , ⟨⟩) , ⟨⟩)
  x₁ = f (xβ‚€ , β‚€ , f (xβ‚€ , β‚€ , β‚€ , ⟨⟩) , ⟨⟩)
  xβ‚‚ = f (xβ‚€ , x₁ , β‚€ , ⟨⟩)
 in
  Ξ΅ f = (xβ‚€ , x₁ , xβ‚‚ , ⟨⟩)
example₃ f = refl

\end{code}

But we want to make this explicit. For that purpose, we introduce a
type E of symbolic expressions, or formulas, using only the symbol O
(standing for β‚€) and the symbol 𝕗 (standing for any given function
f : 𝟚 ^ n β†’ 𝟚), defined by induction as follows, with n as a fixed
parameter:

\begin{code}

data E (n : β„•) : 𝓀₀ Μ‡ where
 O : E n
 𝕗 : E n ^ n β†’ E n

\end{code}

Given a function f : 𝟚 ^ n β†’ 𝟚, any expression e of type E n can be
evaluated to a boolean by replacing the symbol O by the boolean β‚€ and
the symbol 𝕗 by the function f, by induction on formulas, where we use
the variable e to range over expressions, and the variable es to range
over tuples of expressions.

\begin{code}

module _ {n : β„•} (f : 𝟚 ^ n β†’ 𝟚) where

 eval  : E n β†’ 𝟚
 evals : {k : β„•} β†’ E n ^ k β†’ 𝟚 ^ k

 eval O      = β‚€
 eval (𝕗 es) = f (evals es)

 evals ⟨⟩       = ⟨⟩
 evals (e , es) = eval e , evals es

\end{code}

We use the following auxilary constructions to define a formula for a
putative root of any n-ary boolean function:

\begin{code}

π•”π• π•Ÿπ•€  : {n : β„•}   β†’ E (succ n) β†’ E n     β†’ E (succ n)
π•”π• π•Ÿπ•€s : {n k : β„•} β†’ E (succ n) β†’ E n ^ k β†’ E (succ n) ^ k

π•”π• π•Ÿπ•€ eβ‚€ O      = O
π•”π• π•Ÿπ•€ eβ‚€ (𝕗 es) = (𝕗 ∘ cons eβ‚€) (π•”π• π•Ÿπ•€s eβ‚€ es)

π•”π• π•Ÿπ•€s eβ‚€ ⟨⟩       = ⟨⟩
π•”π• π•Ÿπ•€s eβ‚€ (e , es) = π•”π• π•Ÿπ•€ eβ‚€ e , π•”π• π•Ÿπ•€s eβ‚€ es

\end{code}

Their intended behaviour is as follows:

\begin{code}

π•”π• π•Ÿπ•€-behaviour : {n : β„•}
                 (f : 𝟚 ^ succ n β†’ 𝟚)
                 (eβ‚€ : E (succ n))
                 (e  : E n)
               β†’ eval f (π•”π• π•Ÿπ•€ eβ‚€ e) = eval (f ∘ cons (eval f eβ‚€)) e

π•”π• π•Ÿπ•€s-behaviour : {n k : β„•}
                  (f : 𝟚 ^ succ n β†’ 𝟚)
                  (eβ‚€ : E (succ n))
                  (es : E n ^ k)
                β†’ evals f (π•”π• π•Ÿπ•€s eβ‚€ es) = evals (f ∘ cons (eval f eβ‚€)) es

π•”π• π•Ÿπ•€-behaviour f eβ‚€ O      = refl
π•”π• π•Ÿπ•€-behaviour f eβ‚€ (𝕗 es) = ap (f ∘ cons (eval f eβ‚€)) (π•”π• π•Ÿπ•€s-behaviour f eβ‚€ es)

π•”π• π•Ÿπ•€s-behaviour f eβ‚€ ⟨⟩       = refl
π•”π• π•Ÿπ•€s-behaviour f eβ‚€ (e , es) = apβ‚‚ _,_
                                   (π•”π• π•Ÿπ•€-behaviour  f eβ‚€ e )
                                   (π•”π• π•Ÿπ•€s-behaviour f eβ‚€ es)
\end{code}

With this, we can give a formula to compute Ξ΅:

\begin{code}

Ξ΅-formula : (n : β„•) β†’ E n ^ n
Ρ-formula 0        = ⟨⟩
Ξ΅-formula (succ n) = cons cβ‚€ (π•”π• π•Ÿπ•€s cβ‚€ (Ξ΅-formula n))
 where
  cβ‚€ : E (succ n)
  cβ‚€ = (𝕗 ∘ cons O) (π•”π• π•Ÿπ•€s O (Ξ΅-formula n))

\end{code}

Notice the similarity with the definition of Ξ΅, in particular with its
incarnation Ξ΅'.

Here is an example that illustrates this concretely:

\begin{code}

example₃-formula :
 let
  y  = 𝕗 (O , O , 𝕗 (O , O , O , ⟨⟩) , ⟨⟩)
  xβ‚€ = 𝕗 (O , y , 𝕗 (O , y , O , ⟨⟩) , ⟨⟩)
  x₁ = 𝕗 (xβ‚€ , O , 𝕗 (xβ‚€ , O , O , ⟨⟩) , ⟨⟩)
  xβ‚‚ = 𝕗 (xβ‚€ , x₁ , O , ⟨⟩)
 in
  Ξ΅-formula 3 = (xβ‚€ , x₁ , xβ‚‚ , ⟨⟩)
example₃-formula = refl

\end{code}

The desired property of the formula is that evaluating it with any
concrete f gives the putative root Ξ΅ f of f:

\begin{code}

Ξ΅-formula-lemma : (n : β„•) (f : 𝟚 ^ n β†’ 𝟚)
                β†’ evals f (Ξ΅-formula n) = Ξ΅ f
Ξ΅-formula-lemma 0        f = refl
Ξ΅-formula-lemma (succ n) f = Ξ³
 where
  es : E n ^ n
  es = Ξ΅-formula n

  bβ‚€ : 𝟚
  bβ‚€ = (f ∘ cons β‚€) (Ξ΅ (f ∘ cons β‚€))

  cβ‚€ : E (succ n)
  cβ‚€ = (𝕗 ∘ cons O) (π•”π• π•Ÿπ•€s O es)

  IH : (b : 𝟚) β†’ evals (f ∘ cons b) es = Ξ΅ (f ∘ cons b)
  IH b = Ρ-formula-lemma n (f ∘ cons b)

  cβ‚€-property : eval f cβ‚€ = bβ‚€
  cβ‚€-property =
   eval f cβ‚€                            =⟨ refl ⟩
   (f ∘ cons β‚€) (evals f (π•”π• π•Ÿπ•€s O es))  =⟨ I ⟩
   (f ∘ cons β‚€) (evals (f ∘ cons β‚€) es) =⟨ II ⟩
   (f ∘ cons β‚€) (Ξ΅ (f ∘ cons β‚€))        =⟨ refl ⟩
   bβ‚€                                   ∎
    where
     I  = ap (f ∘ cons β‚€) (π•”π• π•Ÿπ•€s-behaviour f O es)
     II = ap (f ∘ cons β‚€) (IH β‚€)

  γ : evals f (Ρ-formula (succ n)) = Ρ f
  γ = evals f (Ρ-formula (succ n))               =⟨ refl ⟩
      cons (eval f cβ‚€) (evals f (π•”π• π•Ÿπ•€s cβ‚€ es))   =⟨ I ⟩
      cons bβ‚€ (evals f (π•”π• π•Ÿπ•€s cβ‚€ es))            =⟨ II ⟩
      cons bβ‚€ (evals (f ∘ cons (eval f cβ‚€)) es)  =⟨ III ⟩
      cons bβ‚€ (evals (f ∘ cons bβ‚€) es)           =⟨ IV ⟩
      cons bβ‚€ (Ξ΅ (f ∘ cons bβ‚€))                  =⟨ refl ⟩
      Ρ f                                        ∎
       where
        I   = ap (Ξ» - β†’ cons - (evals f (π•”π• π•Ÿπ•€s cβ‚€ es))) cβ‚€-property
        II  = ap (cons bβ‚€) (π•”π• π•Ÿπ•€s-behaviour f cβ‚€ es)
        III = ap (Ξ» - β†’ cons bβ‚€ (evals (f ∘ cons -) es)) cβ‚€-property
        IV  = ap (cons bβ‚€) (IH bβ‚€)

\end{code}

From this, together with "Ξ΅-gives-putative-root" proved above, it
follows immediately that "Ξ΅-formula n" gives a formula for a putative
root of any n-ary boolean function:

\begin{code}

Ξ΅-formula-theorem : (n : β„•) (f : 𝟚 ^ n β†’ 𝟚)
                  β†’ is-putative-root (evals f (Ξ΅-formula n)) f
Ξ΅-formula-theorem n f = Ξ³
 where
  Ξ΄ : is-putative-root (Ξ΅ f) f
    β†’ is-putative-root (evals f (Ξ΅-formula n)) f
  δ i ρ = f (evals f (Ρ-formula n)) =⟨ ap f (Ρ-formula-lemma n f) ⟩
          f (Ρ f)                   =⟨ i ρ ⟩
          β‚€                         ∎

  Ξ³ : is-putative-root (evals f (Ξ΅-formula n)) f
  Ξ³ = Ξ΄ (Ξ΅-gives-putative-root f)

\end{code}

Which has our desired theorem as a corollary, namely that, for every n,
there is a formula for a putative root of any n-ary boolean function:

\begin{code}

putative-root-formula-theorem
 : (n : β„•) β†’ Ξ£ es κž‰ E n ^ n , ((f : 𝟚 ^ n β†’ 𝟚) β†’ is-putative-root (evals f es) f)
putative-root-formula-theorem n = Ξ΅-formula n , Ξ΅-formula-theorem n

\end{code}

Our original definition of the formula for the putative root was the following:

\begin{code}

Ρᡉ : {n k : β„•} β†’ (E k ^ n β†’ E k) β†’ E k ^ n
Ρᡉ {0}      {k} f = ⟨⟩
Ρᡉ {succ n} {k} f = cons cβ‚€ (Ρᡉ (f ∘ cons cβ‚€))
 where
  cβ‚€ : E k
  cβ‚€ = (f ∘ cons O) (Ρᡉ (f ∘ cons O))

Ξ΅-formula' : (n : β„•) β†’ E n ^ n
Ξ΅-formula' n = Ρᡉ 𝕗

example₃-formula' :
 let
  y  = 𝕗 (O , O , 𝕗 (O , O , O , ⟨⟩) , ⟨⟩)
  xβ‚€ = 𝕗 (O , y , 𝕗 (O , y , O , ⟨⟩) , ⟨⟩)
  x₁ = 𝕗 (xβ‚€ , O , 𝕗 (xβ‚€ , O , O , ⟨⟩) , ⟨⟩)
  xβ‚‚ = 𝕗 (xβ‚€ , x₁ , O , ⟨⟩)
 in
  Ξ΅-formula' 3 = (xβ‚€ , x₁ , xβ‚‚ , ⟨⟩)
example₃-formula' = refl

formulas-agreement₃ : Ξ΅-formula' 3 = Ξ΅-formula 3
formulas-agreement₃ = refl

formulas-agreementβ‚„ : Ξ΅-formula' 4 = Ξ΅-formula 4
formulas-agreementβ‚„ = refl

\end{code}

TODO. The above formula grows doubly exponentially in size. However,
using variables for common subexpressions, they grow
exponentially. Define a type of expression accomodating variables for
common subexpressions and produce a version Ξ΅-formula that produced
such reduced-size expressions.

The advantage of this definition is that it is almost literally the
same as that of Ξ΅'.

The disadvantage is that it is difficult to find a suitable induction
hypothesis to prove the correctness of Ξ΅-formula' directly. We did
find such a proof, but it is long and messy, and we decided not to
include it here for that reason.

We proposed the following challenges in social media, which were
solved by Alice Laroche.

Challenges.

(1) Find an elegant proof that the function Ξ΅-formula' gives a
formulate for putative roots.

(2) Moreover, show that Ξ΅-formula' = Ξ΅-formula.

(3) Show that Ξ΅ gives the infimum of the (possibly empty) set of roots
in the lexicographic order.

It is easier to prove (2) and then deduce (1), using the idea of proof
of Ξ΅-formula-theorem, rather than prove (1) directly.

Added by Alice Laroche, 1st June 2023.

We show that both definitions are equivalent, and from that deduce the
correctness of Ξ΅-formula'.

We first define another pair of auxiliary constructions that will be
used to reason about Ρᡉ.

\begin{code}

π•žπ•’π•‘ : {n m : β„•} (f : E m ^ n β†’ E m ^ m) β†’ E n β†’ E m
π•žπ•’π•‘s : {n m k : β„•} (f : E m ^ n β†’ E m ^ m) β†’ E n ^ k β†’ E m ^ k

π•žπ•’π•‘ f O = O
π•žπ•’π•‘ f (𝕗 es) = 𝕗 (f (π•žπ•’π•‘s f es))

π•žπ•’π•‘s f ⟨⟩ = ⟨⟩
π•žπ•’π•‘s f (e , es) = π•žπ•’π•‘ f e , π•žπ•’π•‘s f es

\end{code}

Notice that π•”π• π•Ÿπ•€ and π•”π• π•Ÿπ•€ are more refined versions of π•žπ•’π•‘ and π•žπ•’π•‘s

\begin{code}

π•žπ•’π•‘-cons-π•”π• π•Ÿπ•€ : {n k : β„•}
                (eβ‚€ : E (succ n))
                (e : E n)
               β†’ π•žπ•’π•‘ (cons eβ‚€ ) e = π•”π• π•Ÿπ•€ eβ‚€ e
π•žπ•’π•‘s-cons-π•”π• π•Ÿπ•€s : {n k : β„•}
                β†’ (eβ‚€ : E (succ n))
                β†’ (es : E n ^ k)
                β†’ π•žπ•’π•‘s (cons eβ‚€ ) es = π•”π• π•Ÿπ•€s eβ‚€ es

π•žπ•’π•‘-cons-π•”π• π•Ÿπ•€ {n} {k} eβ‚€ O = refl
π•žπ•’π•‘-cons-π•”π• π•Ÿπ•€ {n} {k} eβ‚€ (𝕗 es) = ap (𝕗 ∘ cons eβ‚€) (π•žπ•’π•‘s-cons-π•”π• π•Ÿπ•€s eβ‚€ es)

π•žπ•’π•‘s-cons-π•”π• π•Ÿπ•€s {n} {k} eβ‚€ ⟨⟩ = refl
π•žπ•’π•‘s-cons-π•”π• π•Ÿπ•€s {n} {k} eβ‚€ (e , es) = apβ‚‚ _,_
                                         (π•žπ•’π•‘-cons-π•”π• π•Ÿπ•€ {k = k} eβ‚€ e)
                                         (π•žπ•’π•‘s-cons-π•”π• π•Ÿπ•€s eβ‚€ es)

π•žπ•’π•‘-π•žπ•’π•‘  : {n m : β„•}
            (f : E m ^ (succ n) β†’ E m ^ m)
            (eβ‚€ : E (succ n)) β†’ (e : E n)
         β†’ π•žπ•’π•‘ f (π•žπ•’π•‘ (cons eβ‚€) e) = π•žπ•’π•‘ (f ∘ cons (π•žπ•’π•‘ f eβ‚€)) e

π•žπ•’π•‘-π•žπ•’π•‘s : {n m k : β„•}
           (f : E m ^ (succ n) β†’ E m ^ m)
           (eβ‚€ : E (succ n)) β†’ (es : E n ^ k)
         β†’ π•žπ•’π•‘s f (π•žπ•’π•‘s (cons eβ‚€) es) = π•žπ•’π•‘s (f ∘ cons (π•žπ•’π•‘ f eβ‚€)) es

π•žπ•’π•‘-π•žπ•’π•‘ f eβ‚€ O      = refl
π•žπ•’π•‘-π•žπ•’π•‘ f eβ‚€ (𝕗 es) = ap (𝕗 ∘ f ∘ cons (π•žπ•’π•‘ f eβ‚€)) (π•žπ•’π•‘-π•žπ•’π•‘s f eβ‚€ es)

π•žπ•’π•‘-π•žπ•’π•‘s f eβ‚€ ⟨⟩       = refl
π•žπ•’π•‘-π•žπ•’π•‘s f eβ‚€ (e , es) = apβ‚‚ _,_ (π•žπ•’π•‘-π•žπ•’π•‘ f eβ‚€ e) (π•žπ•’π•‘-π•žπ•’π•‘s f eβ‚€ es)

\end{code}

Using the additional flexibility given by those functions we can show
how to unroll the compositions that happen in Ρᡉ.

\begin{code}

unroll-Ρᡉ-lemma : {n k : β„•}
                  (f : E k ^ n β†’ E k ^ k)
                β†’ Ρᡉ (𝕗 ∘ f) = π•žπ•’π•‘s f (Ρᡉ 𝕗)
unroll-Ρᡉ-lemma {0}      {k} f = refl
unroll-Ρᡉ-lemma {succ n} {k} f = Ξ³
 where
  cβ‚€ : E k
  cβ‚€ = (𝕗 ∘ f ∘ cons O) (Ρᡉ (𝕗 ∘ f ∘ cons O))

  c₁ : E (succ n)
  c₁ = (𝕗 ∘ cons O) (Ρᡉ (𝕗 ∘ cons O))

  cβ‚€-property : cβ‚€ = π•žπ•’π•‘ f c₁
  cβ‚€-property = (𝕗 ∘ f ∘ cons O) (Ρᡉ (𝕗 ∘ f ∘ cons O))        =⟨ I ⟩
                (𝕗 ∘ f ∘ cons O) (π•žπ•’π•‘s (f ∘ cons O) (Ρᡉ 𝕗))   =⟨ refl ⟩
                π•žπ•’π•‘ (f ∘ cons O) (𝕗 (Ρᡉ 𝕗))                   =⟨ II ⟩
                π•žπ•’π•‘ f (π•žπ•’π•‘ (cons O) (𝕗 (Ρᡉ 𝕗)))               =⟨ refl ⟩
                π•žπ•’π•‘ f ((𝕗 ∘ cons O) ((π•žπ•’π•‘s (cons O) (Ρᡉ 𝕗)))) =⟨ III ⟩
                π•žπ•’π•‘ f ((𝕗 ∘ cons O) (Ρᡉ (𝕗 ∘ cons O)))        =⟨ refl ⟩
                π•žπ•’π•‘ f c₁                                      ∎
   where
     I = ap (𝕗 ∘ f ∘ cons O) (unroll-Ρᡉ-lemma (f ∘ cons O))
     II = π•žπ•’π•‘-π•žπ•’π•‘ f O (𝕗 (Ρᡉ 𝕗)) ⁻¹
     III = ap (π•žπ•’π•‘ f ∘ (𝕗 ∘ cons O)) (unroll-Ρᡉ-lemma (cons O) ⁻¹)

  Ξ³ :  Ρᡉ (𝕗 ∘ f) = π•žπ•’π•‘s f (Ρᡉ 𝕗)
  Ξ³ = Ρᡉ (𝕗 ∘ f) =⟨ refl ⟩
      cβ‚€ , (Ρᡉ (𝕗 ∘ f ∘ cons cβ‚€))                  =⟨ I ⟩
      π•žπ•’π•‘ f c₁ , (Ρᡉ (𝕗 ∘ f ∘ cons (π•žπ•’π•‘ f c₁)))    =⟨ II ⟩
      π•žπ•’π•‘ f c₁ , π•žπ•’π•‘s (f ∘ cons (π•žπ•’π•‘ f c₁)) (Ρᡉ 𝕗) =⟨ III ⟩
      π•žπ•’π•‘ f c₁ , π•žπ•’π•‘s f (π•žπ•’π•‘s (cons c₁) (Ρᡉ 𝕗))    =⟨ IV ⟩
      π•žπ•’π•‘ f c₁ , π•žπ•’π•‘s f (Ρᡉ (𝕗 ∘ cons c₁))         =⟨ refl ⟩
      π•žπ•’π•‘s f (c₁ , (Ρᡉ (𝕗 ∘ cons c₁)))             =⟨ refl ⟩
      π•žπ•’π•‘s f (Ρᡉ 𝕗)                                ∎
   where
    I   = ap (Ξ» x β†’ x , (Ρᡉ (𝕗 ∘ f ∘ cons x))) cβ‚€-property
    II  = ap (π•žπ•’π•‘ f c₁ ,_) (unroll-Ρᡉ-lemma (f ∘ cons (π•žπ•’π•‘ f c₁)))
    III = ap (π•žπ•’π•‘ f c₁ ,_) (π•žπ•’π•‘-π•žπ•’π•‘s f c₁ (Ρᡉ 𝕗) ⁻¹)
    IV  = ap (Ξ» x β†’ π•žπ•’π•‘ f c₁ , π•žπ•’π•‘s f x) (unroll-Ρᡉ-lemma (cons c₁) ⁻¹)

unroll-Ρᡉ : {n : β„•}
            (eβ‚€ : E (succ n))
          β†’ Ρᡉ (𝕗 ∘ (cons eβ‚€)) = π•”π• π•Ÿπ•€s eβ‚€ (Ρᡉ 𝕗)
unroll-Ρᡉ eβ‚€ = unroll-Ρᡉ-lemma (cons eβ‚€) βˆ™ π•žπ•’π•‘s-cons-π•”π• π•Ÿπ•€s eβ‚€ (Ρᡉ 𝕗)

\end{code}

From this we can show that Ξ΅-formula' n and Ξ΅-formula n are indeed
equal.

\begin{code}

formulas-are-equal : (n : β„•) β†’ Ξ΅-formula' n = Ξ΅-formula n
formulas-are-equal 0 = refl
formulas-are-equal (succ n) = Ξ³
 where
  cβ‚€ : E (succ n)
  cβ‚€ = (𝕗 ∘ cons O) (Ρᡉ (𝕗 ∘ cons O))

  c₁ : E (succ n)
  c₁ = (𝕗 ∘ cons O) (π•”π• π•Ÿπ•€s O (Ξ΅-formula n))

  cβ‚€-property : cβ‚€ = c₁
  cβ‚€-property = (𝕗 ∘ cons O) (Ρᡉ (𝕗 ∘ cons O))       =⟨ I ⟩
                (𝕗 ∘ cons O) (π•”π• π•Ÿπ•€s O (Ρᡉ 𝕗))        =⟨ II ⟩
                (𝕗 ∘ cons O) (π•”π• π•Ÿπ•€s O (Ξ΅-formula n)) ∎
   where
    I = ap (𝕗 ∘ cons O) (unroll-Ρᡉ O)
    II = ap (𝕗 ∘ cons O ∘ π•”π• π•Ÿπ•€s O) (formulas-are-equal n)

  γ : Ρ-formula' (succ n) = Ρ-formula (succ n)
  γ = Ρ-formula' (succ n)            =⟨ refl ⟩
      Ρᡉ 𝕗                           =⟨ refl ⟩
      cβ‚€ , Ρᡉ (𝕗 ∘ cons cβ‚€)          =⟨ I ⟩
      cβ‚€ , (π•”π• π•Ÿπ•€s cβ‚€ (Ξ΅-formula' n)) =⟨ refl ⟩
      cβ‚€ , (π•”π• π•Ÿπ•€s cβ‚€ (Ρᡉ 𝕗))         =⟨ II ⟩
      cβ‚€ , (π•”π• π•Ÿπ•€s cβ‚€ (Ξ΅-formula n))  =⟨ III ⟩
      c₁ , (π•”π• π•Ÿπ•€s c₁ (Ξ΅-formula n))  =⟨ refl ⟩
      Ρ-formula (succ n) ∎
   where
    I   = ap (cβ‚€ ,_) (unroll-Ρᡉ cβ‚€)
    II  = ap (Ξ» x β†’ cβ‚€ , (π•”π• π•Ÿπ•€s cβ‚€ x)) (formulas-are-equal n)
    III = ap (Ξ» x β†’ x , (π•”π• π•Ÿπ•€s x (Ξ΅-formula n))) cβ‚€-property
\end{code}

It then follows immediately by transport that Ξ΅-formula' is correct.

\begin{code}

Ξ΅-formula'-theorem : (n : β„•) (f : 𝟚 ^ n β†’ 𝟚)
                   β†’ is-putative-root (evals f (Ξ΅-formula' n)) f
Ξ΅-formula'-theorem n f = transport (Ξ» x β†’ is-putative-root (evals f x) f)
                                   (formulas-are-equal n ⁻¹)
                                   (Ξ΅-formula-theorem n f)

\end{code}

Added by Alice Laroche, 5th june 2023.

We prove that Ξ΅ f indeed computes the infimum of the set of roots
ordered by the lexicographical order.

\begin{code}

open import Notation.Order

lex-order : {X : 𝓀 Μ‡ } {n : β„•} β†’ (X β†’ X β†’  π“₯ Μ‡ ) β†’ (X ^ n β†’ X ^ n β†’ 𝓀 βŠ” π“₯ Μ‡ )
lex-order {n = 0}      _≀_ _        _        = πŸ™
lex-order {n = succ n} _≀_ (x , xs) (y , ys) = (x ≀ y)
                                             Γ— ((x = y) β†’ lex-order _≀_ xs ys)

_≀₂ₗₑₓ_ : {n : β„•} (xs ys : 𝟚 ^ n) β†’ 𝓀₀ Μ‡
_≀₂ₗₑₓ_ = lex-order _≀₂_

open import TypeTopology.InfProperty

Ξ΅-is-roots-lower-bound : {n : β„•}
                        (f : 𝟚 ^ n β†’ 𝟚)
                      β†’ is-roots-lower-bound _≀₂ₗₑₓ_ f (Ξ΅ f)
Ξ΅-is-roots-lower-bound {0}      f _        p = ⋆
Ξ΅-is-roots-lower-bound {succ n} f (x , xs) p = Ξ³ (x , xs) p
 where
  bβ‚€ : 𝟚
  bβ‚€ = Ρ𝟚 (b ↦ A (f ∘ cons b))

  bβ‚€-property : (xs : 𝟚 ^ n) β†’ f (β‚€ , xs) = β‚€ β†’ bβ‚€ = β‚€
  bβ‚€-property xs p = Ξ΅-gives-putative-root (f ∘ cons β‚€) (xs , p)

  Ξ΄ : (b : 𝟚) (xs : 𝟚 ^ n) β†’ f (b , xs) = β‚€ β†’ bβ‚€ = b β†’ Ξ΅ (f ∘ cons bβ‚€) ≀₂ₗₑₓ xs
  Ξ΄ b xs p refl = Ξ΅-is-roots-lower-bound (f ∘ cons bβ‚€) xs p

  Ξ³ : (xs : 𝟚 ^ (succ n)) β†’ f xs = β‚€ β†’ Ξ΅ f ≀₂ₗₑₓ  xs
  Ξ³ (β‚€ , xs) p = β‚€-minimal-converse (bβ‚€-property xs p) , Ξ΄ β‚€ xs p
  Ξ³ (₁ , xs) p = ₁-top , Ξ΄ ₁ xs p

lower-bound-property : {n : β„•}
                       (f : 𝟚 ^ (succ n) β†’ 𝟚)
                       (b : 𝟚)
                       (xs : 𝟚 ^ n)
                     β†’ is-roots-lower-bound _≀₂ₗₑₓ_ f (b , xs)
                     β†’ is-roots-lower-bound _≀₂ₗₑₓ_ (f ∘ cons b) xs
lower-bound-property f b xs lower-bound ys p = prβ‚‚ (lower-bound (b , ys) p) refl

Ξ΅-is-upper-bound-of-roots-lower-bounds : {n : β„•}
                                         (f : 𝟚 ^ n β†’ 𝟚)
                                       β†’ is-upper-bound-of-lower-bounds _≀₂ₗₑₓ_ f (Ξ΅ f)
Ξ΅-is-upper-bound-of-roots-lower-bounds {0}      f xs lower-bound = ⋆
Ξ΅-is-upper-bound-of-roots-lower-bounds {succ n} f xs lower-bound = Ξ³ xs lower-bound
 where

  bβ‚€ : 𝟚
  bβ‚€ = Ρ𝟚 (b ↦ A (f ∘ cons b))

  bβ‚€-property : (xs : 𝟚 ^ n)
              β†’ is-roots-lower-bound _≀₂ₗₑₓ_ f (₁ , xs)
              β†’ (b : 𝟚) β†’ b = bβ‚€ β†’ ₁ ≀ bβ‚€
  bβ‚€-property xs lower-bound β‚€ eq = transport (₁ ≀_) eq
                                     (pr₁ (lower-bound (β‚€ , Ξ΅ (f ∘ cons β‚€))
                                                       (eq ⁻¹)))
  bβ‚€-property xs lower-bound ₁ eq = transport (₁ ≀_) eq ⋆

  δ : (b : 𝟚) (xs : 𝟚 ^ n)
    β†’ is-roots-lower-bound _≀₂ₗₑₓ_ f (b , xs)
    β†’ b = bβ‚€
    β†’ xs ≀₂ₗₑₓ Ξ΅ (f ∘ cons bβ‚€)
  Ξ΄ b xs lower-bound refl = Ξ΅-is-upper-bound-of-roots-lower-bounds
                             (f ∘ cons bβ‚€) xs
                             (lower-bound-property f bβ‚€ xs lower-bound)

  Ξ³ : (xs : 𝟚 ^ (succ n)) β†’ is-roots-lower-bound _≀₂ₗₑₓ_ f xs β†’ xs ≀₂ₗₑₓ Ξ΅ f
  Ξ³ (β‚€ , xs) lower-bound = ⋆ ,
                           Ξ΄ β‚€ xs lower-bound
  Ξ³ (₁ , xs) lower-bound = bβ‚€-property xs lower-bound bβ‚€ refl ,
                           Ξ΄ ₁ xs lower-bound

Ξ΅-is-roots-infimum : {n : β„•} (f : 𝟚 ^ n β†’ 𝟚) β†’ is-roots-infimum _≀₂ₗₑₓ_ f (Ξ΅ f)
Ξ΅-is-roots-infimum f = Ξ΅-is-roots-lower-bound f ,
                       Ξ΅-is-upper-bound-of-roots-lower-bounds f

𝟚^n-has-inf : {n : β„•} β†’ has-inf {X = 𝟚 ^ n} _≀₂ₗₑₓ_
𝟚^n-has-inf f =  Ρ f ,
                 Ξ΅-gives-putative-root f ,
                 Ξ΅-is-roots-infimum f

\end{code}

End of Alice's contribution.