Chuangjie Xu and Martin Escardó 2014 (updated in February 2015)
(Revised and ported to TypeTopology in 2026 by Chuangjie Xu)

Experiments in computing moduli of uniform continuity

\begin{code}

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

open import MLTT.Spartan hiding (_+_)
open import UF.FunExt using (DN-funext)

module C-Spaces.UsingNotNotFunExt.ComputationExperiments (dnfe : ¬¬ DN-funext 𝓤₀ 𝓤₀) where

\end{code}

The development of C-spaces used here depends on the double negation of
function extensionality. This assumption has the form `¬¬ FunExt`, so it occurs
only under negation. Consequently it carries no computational content of its
own and does not obstruct normalization of closed Agda terms.

When we apply the Fan function to a System T-definable function `₂ℕ → ℕ`, we
obtain its least modulus of uniform continuity as a closed Agda term of type
`ℕ`, and this term can normalize to a numeral.

Here we present some functions ₂ℕ → ℕ, their definitions in System T (extended
with a Fan functional), and the normalization result of their uniform-continuity
moduli computed by the Fan functional from the model of C-spaces.

\begin{code}

open import Naturals.Addition

open import C-Spaces.Preliminaries.Booleans.Functions using (if)
open import C-Spaces.Preliminaries.Sequence
open import C-Spaces.Syntax.SystemTWithFan
open import C-Spaces.UsingNotNotFunExt.Space
open import C-Spaces.UsingNotNotFunExt.CartesianClosedness dnfe
open import C-Spaces.UsingNotNotFunExt.DiscreteSpace dnfe
open import C-Spaces.UsingNotNotFunExt.YonedaLemma dnfe
open import C-Spaces.UsingNotNotFunExt.Fan dnfe
open import C-Spaces.UsingNotNotFunExt.UCinT dnfe

\end{code}

We write `⟦ t ⟧` for the interpretation of a closed System-T-with-Fan term
`t : ((Ⓝ ⇨ ②) ⇨ Ⓝ)` as an ordinary function `₂ℕ → ℕ`, and `modu t` for the
modulus computed for `t` by the Fan functional:

\begin{code}

⟦_⟧ : Tm ε ( ((  )  ))  ₂ℕ  
 t  α = pr₁ (pr₁  t ⟧ᵐ ) (ID α)

modu : Tm ε ((  )  )  
modu F = pr₁ fan (pr₁  F ⟧ᵐ )

ONE TWO THREE FOUR FIVE : {Γ : Cxt}  Tm Γ 
ONE   = SUCC · ZERO
TWO   = SUCC · ONE
THREE = SUCC · TWO
FOUR  = SUCC · THREE
FIVE  = SUCC · FOUR

PLUS : {Γ : Cxt}  Tm Γ (    )
PLUS = REC · (LAM (VAR zero)) · LAM (LAM (LAM (SUCC · (VAR (succ zero) · VAR zero))))

PLUS-interpretation :  n m  pr₁ (pr₁ (pr₁  PLUS {ε} ⟧ᵐ ) n) m  n +ᴸ m 
PLUS-interpretation  0       m = refl
PLUS-interpretation (succ n) m = ap succ (PLUS-interpretation n m)

\end{code}

`F₁` is constant.

\begin{code}

F₁ : {Γ : Cxt}  Tm Γ ((  )  )
F₁ = LAM TWO

F₁-interpretation :  F₁   λ α  2 
F₁-interpretation = refl

modulus-of-F₁ : modu F₁  0
modulus-of-F₁ = refl

\end{code}

`F₂` is constant, even though it inspects the first input bit.

\begin{code}

F₂  : {Γ : Cxt}  Tm Γ ((  )  )
F₂ = LAM (IF · (VAR zero · ZERO) · ONE · ONE)

F₂-interpretation :  F₂   λ α  if (α 0) 1 1
F₂-interpretation = refl

modulus-of-F₂ : modu F₂  0
modulus-of-F₂ = refl

\end{code}

`F₃` returns `5` if the fourth bit is `⊥`.
It returns `1` if the fourth bit is `⊤` and the fifth bit is `⊥`.
It returns `2` if both the fourth and fifth bits are `⊤`.

\begin{code}

F₃ : {Γ : Cxt}  Tm Γ ((  )  )
F₃ = LAM (IF · (VAR zero · THREE)
             · FIVE
             · (IF · (VAR zero · FOUR) · ONE · TWO))

F₃-interpretation :  F₃   λ α  if (α 3) 5 (if (α 4) 1 2) 
F₃-interpretation = refl

modulus-of-F₃ : modu F₃  5
modulus-of-F₃ = refl

\end{code}

`F₄` is constant. It inspects the second bit and then the third or fourth bit,
but always returns `0`.

\begin{code}

F₄ : {Γ : Cxt}  Tm Γ ((  )  )
F₄ = LAM (IF · (VAR zero · ONE)
             · (IF · (VAR zero · TWO) · ZERO · ZERO)
             · (IF · (VAR zero · THREE) · ZERO · ZERO))

F₄-interpretation :  F₄   λ α  if (α 1) (if (α 2) 0 0) (if (α 3) 0 0)
F₄-interpretation = refl

modulus-of-F₄ : modu F₄  0
modulus-of-F₄ = refl

\end{code}

If the second bit is `⊥`, then `F₅` applies `SUCC` to `ZERO` three times, so it
returns `3`. If the second bit is `⊤`, then `F₅` applies `SUCC` to `ZERO` twice,
so it returns `2`.

\begin{code}

F₅ : {Γ : Cxt}  Tm Γ ((  )  )
F₅ = LAM (REC · ZERO · LAM SUCC · (IF · (VAR zero · ONE) · THREE · TWO))

F₅-interpretation :  F₅   λ α  ℕ-induction zero  _  succ) (if (α 1) 3 2)
F₅-interpretation = refl

modulus-of-F₅ : modu F₅  2
modulus-of-F₅ = refl

\end{code}

A more complicated example

\begin{code}

F₆ : {Γ : Cxt}  Tm Γ ((  )  )
F₆ = LAM (REC · (IF · (VAR zero · (F₅ · VAR zero)) · FIVE · TWO)
              · LAM SUCC
              · (IF · (VAR zero · (F₄ · VAR zero)) · THREE · TWO))

F₆-interpretation :  F₆   λ α  ℕ-induction (if (α ( F₅  α)) 5 2)
                                                 _  succ)
                                                (if (α ( F₄  α)) 3 2)
F₆-interpretation = refl

modulus-of-F₆ : modu F₆  4
modulus-of-F₆ = refl

\end{code}

An example that explicitly uses the Fan functional

\begin{code}

F₇ : {Γ : Cxt}  Tm Γ ((  )  )
F₇ = LAM (IF · (VAR zero · (FAN · F₅))
             · (PLUS · (FAN · F₆) · (FAN · F₃))
             · (FAN · F₁))

F₇-interpretation :  F₇   λ α  if (α (modu F₅))
                                       (modu F₆ + modu F₃)
                                       (modu F₁)
F₇-interpretation = refl

modulus-of-F₇ : modu F₇  3
modulus-of-F₇ = refl

\end{code}