Tom de Jong, May 2019.
Refactored Dec 2021.

Least fixed points of Scott continuous maps.

The flag --lossy-unification significantly speeds up the
typechecking.
(https://agda.readthedocs.io/en/latest/language/lossy-unification.html)

\begin{code}

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

open import MLTT.Spartan
open import UF.FunExt
open import UF.PropTrunc

module DomainTheory.Basics.LeastFixedPoint
        (pt : propositional-truncations-exist)
        (fe : Fun-Ext)
        (๐“ฅ : Universe)
       where

open PropositionalTruncation pt

open import UF.UniverseEmbedding

open import Naturals.Order
open import Notation.Order

open import DomainTheory.Basics.Dcpo pt fe ๐“ฅ
open import DomainTheory.Basics.Exponential pt fe ๐“ฅ
open import DomainTheory.Basics.Miscelanea pt fe ๐“ฅ
open import DomainTheory.Basics.Pointed pt fe ๐“ฅ

module _ (๐““ : DCPOโŠฅ {๐“ค} {๐“ฃ}) where

 iter : (n : โ„•) โ†’ โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ โ†’ โŸช ๐““ โŸซ
 iter zero     f = โŠฅ ๐““
 iter (succ n) f = [ ๐““ โป , ๐““ โป ]โŸจ f โŸฉ (iter n f)

 iter-is-monotone : (n : โ„•) โ†’ is-monotone ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) (๐““ โป) (iter n)
 iter-is-monotone zero     f g l = โŠฅ-is-least ๐““ (iter zero g)
 iter-is-monotone (succ n) f g l = iter (succ n) f               โŠ‘โŸช ๐““ โŸซ[ โฆ…1โฆ† ]
                                   [ ๐““ โป , ๐““ โป ]โŸจ g โŸฉ (iter n f) โŠ‘โŸช ๐““ โŸซ[ โฆ…2โฆ† ]
                                   iter (succ n) g               โˆŽโŸช ๐““ โŸซ
  where
   โฆ…1โฆ† = l (iter n f)
   โฆ…2โฆ† = monotone-if-continuous (๐““ โป) (๐““ โป) g (iter n f) (iter n g)
         (iter-is-monotone n f g l)

 n-family : {I : ๐“ฅ ฬ‡ } (ฮฑ : I โ†’ โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ) (n : โ„•) โ†’ I โ†’ โŸช ๐““ โŸซ
 n-family ฮฑ n i = iter n (ฮฑ i)

 n-family-is-directed : {I : ๐“ฅ ฬ‡ } (ฮฑ : I โ†’ โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ)
                        (ฮด : is-Directed ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) ฮฑ)
                        (n : โ„•) โ†’ is-Directed (๐““ โป) (n-family ฮฑ n)
 n-family-is-directed {I} ฮฑ ฮด n =
   inhabited-if-Directed ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ ) โป) ฮฑ ฮด , ฮต
  where
   ฮต : is-Semidirected (๐““ โป) (n-family ฮฑ n)
   ฮต i j = โˆฅโˆฅ-functor h (semidirected-if-Directed ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) ฮฑ ฮด i j)
    where
     h : (ฮฃ k ๊ž‰ I , (ฮฑ i) โŠ‘โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ (ฮฑ k) ร—
                    (ฮฑ j) โŠ‘โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ (ฮฑ k))
       โ†’ ฮฃ k ๊ž‰ I , (n-family ฮฑ n i) โŠ‘โŸช ๐““ โŸซ (n-family ฮฑ n k) ร—
                   (n-family ฮฑ n j) โŠ‘โŸช ๐““ โŸซ (n-family ฮฑ n k)
     h (k , l , m) = k , (iter-is-monotone n (ฮฑ i) (ฮฑ k) l) ,
                         (iter-is-monotone n (ฮฑ j) (ฮฑ k) m)

 double-โˆ-lemma : {I : ๐“ฅ ฬ‡ } (ฮฑ : I โ†’ โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ)
                  (ฮด : is-Directed ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) ฮฑ)
                  (n : โ„•)
                โ†’ โˆ (๐““ โป) (pointwise-family-is-directed (๐““ โป) (๐““ โป) ฮฑ ฮด
                          (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n)))
                  ๏ผ โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด (succ n))
 double-โˆ-lemma {I} ฮฑ ฮด n = antisymmetry (๐““ โป) x y a b
  where
   ฮต : is-Directed (๐““ โป) (pointwise-family (๐““ โป) (๐““ โป) ฮฑ
        (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n)))
   ฮต = (pointwise-family-is-directed (๐““ โป) (๐““ โป) ฮฑ ฮด
        (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n)))
   ฯ† : (n : โ„•) โ†’ is-Directed (๐““ โป) (n-family ฮฑ n)
   ฯ† n = n-family-is-directed ฮฑ ฮด n

   x : โŸช ๐““ โŸซ
   x = โˆ (๐““ โป) ฮต
   y : โŸช ๐““ โŸซ
   y = โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด (succ n))

   a : x โŠ‘โŸช ๐““ โŸซ y
   a = โˆ-is-lowerbound-of-upperbounds (๐““ โป) ฮต y g
    where
     g : (i : I)
       โ†’ (pointwise-family (๐““ โป) (๐““ โป) ฮฑ (โˆ (๐““ โป) (ฯ† n)) i) โŠ‘โŸช ๐““ โŸซ y
     g i = sup-is-lowerbound-of-upperbounds
            (underlying-order (๐““ โป)) s y u
      where
       ฮฒ : I โ†’ โŸช ๐““ โŸซ
       ฮฒ = [ ๐““ โป , ๐““ โป ]โŸจ ฮฑ i โŸฉ โˆ˜ (n-family ฮฑ n)
       s : is-sup (underlying-order (๐““ โป))
            (pointwise-family (๐““ โป) (๐““ โป) ฮฑ (โˆ (๐““ โป) (ฯ† n)) i) ฮฒ
       s = continuity-of-function (๐““ โป) (๐““ โป) (ฮฑ i) I (n-family ฮฑ n) (ฯ† n)
       u : (j : I) โ†’ ฮฒ j โŠ‘โŸจ ๐““ โป โŸฉ y
       u j = โˆฅโˆฅ-rec (prop-valuedness (๐““ โป) (ฮฒ j) y) v
              (semidirected-if-Directed ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) ฮฑ ฮด i j)
               where
         v : (ฮฃ  k ๊ž‰ I , ฮฑ i โŠ‘โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ ฮฑ k ร— ฮฑ j โŠ‘โŸช ๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““ โŸซ ฮฑ k)
           โ†’ ฮฒ j โŠ‘โŸช ๐““ โŸซ y
         v (k , l , m) = ฮฒ j                                 โŠ‘โŸช ๐““ โŸซ[ โฆ…1โฆ† ]
                         [ ๐““ โป , ๐““ โป ]โŸจ ฮฑ k โŸฉ (iter n (ฮฑ j)) โŠ‘โŸช ๐““ โŸซ[ โฆ…2โฆ† ]
                         iter (succ n) (ฮฑ k)                 โŠ‘โŸช ๐““ โŸซ[ โฆ…3โฆ† ]
                         y                                   โˆŽโŸช ๐““ โŸซ
          where
           โฆ…1โฆ† = l (iter n (ฮฑ j))
           โฆ…2โฆ† = monotone-if-continuous (๐““ โป) (๐““ โป) (ฮฑ k)
                  (iter n (ฮฑ j))
                  (iter n (ฮฑ k))
                  (iter-is-monotone n (ฮฑ j) (ฮฑ k) m)
           โฆ…3โฆ† = โˆ-is-upperbound (๐““ โป) (ฯ† (succ n)) k

   b : y โŠ‘โŸช ๐““ โŸซ x
   b = โˆ-is-lowerbound-of-upperbounds (๐““ โป) (ฯ† (succ n)) x h
    where
     h : (i : I) โ†’ (n-family ฮฑ (succ n) i) โŠ‘โŸช ๐““ โŸซ x
     h i = n-family ฮฑ (succ n) i                โŠ‘โŸช ๐““ โŸซ[ โฆ…1โฆ† ]
           [ ๐““ โป , ๐““ โป ]โŸจ ฮฑ i โŸฉ (โˆ (๐““ โป) (ฯ† n)) โŠ‘โŸช ๐““ โŸซ[ โฆ…2โฆ† ]
           x                                    โˆŽโŸช ๐““ โŸซ
      where
       โฆ…1โฆ† = monotone-if-continuous (๐““ โป) (๐““ โป) (ฮฑ i)
              (iter n (ฮฑ i))
              (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n))
              (โˆ-is-upperbound (๐““ โป) (ฯ† n) i)
       โฆ…2โฆ† = โˆ-is-upperbound (๐““ โป) ฮต i

 iter-is-continuous : (n : โ„•) โ†’ is-continuous ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) (๐““ โป) (iter n)
 iter-is-continuous zero     I ฮฑ ฮด = a , b
  where
   a : (i : I) โ†’ iter zero (ฮฑ i) โŠ‘โŸช ๐““ โŸซ
                 iter zero (โˆ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) {I} {ฮฑ} ฮด)
   a i = โŠฅ-is-least ๐““ (iter zero (โˆ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) {I} {ฮฑ} ฮด))
   b : (u : โŸช ๐““ โŸซ)
     โ†’ ((i : I) โ†’ iter zero (ฮฑ i) โŠ‘โŸช ๐““ โŸซ u)
     โ†’ iter zero (โˆ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) {I} {ฮฑ} ฮด) โŠ‘โŸช ๐““ โŸซ u
   b u l = โŠฅ-is-least ๐““ u
 iter-is-continuous (succ n) I ฮฑ ฮด = ฮณ
  where
   ฮณ : is-sup (underlying-order (๐““ โป))
       (iter (succ n) (โˆ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) ฮด)) (iter (succ n) โˆ˜ ฮฑ)
   ฮณ = transport
       (ฮป - โ†’ is-sup (underlying-order (๐““ โป)) - (iter (succ n) โˆ˜ ฮฑ)) (h โปยน) k
    where
     k : is-sup (underlying-order (๐““ โป))
         (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด (succ n)))
         (iter (succ n) โˆ˜ ฮฑ)
     k = โˆ-is-sup (๐““ โป) (n-family-is-directed ฮฑ ฮด (succ n))
     h = iter (succ n) s                                           ๏ผโŸจ refl โŸฉ
         [ ๐““ โป , ๐““ โป ]โŸจ s โŸฉ (iter n s)                             ๏ผโŸจ โฆ…1โฆ†  โŸฉ
         [ ๐““ โป , ๐““ โป ]โŸจ s โŸฉ (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n)) ๏ผโŸจ refl โŸฉ
         โˆ (๐““ โป) (pointwise-family-is-directed (๐““ โป) (๐““ โป) ฮฑ ฮด
           (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n)))                 ๏ผโŸจ โฆ…2โฆ†  โŸฉ
         โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด (succ n))               โˆŽ
      where
       s = (โˆ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) {I} {ฮฑ} ฮด)
       โฆ…2โฆ† = double-โˆ-lemma ฮฑ ฮด n
       โฆ…1โฆ† = ap ([ ๐““ โป , ๐““ โป ]โŸจ s โŸฉ) e
        where
         e : iter n s ๏ผ โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n)
         e = antisymmetry (๐““ โป) (iter n s) (โˆ (๐““ โป)
              (n-family-is-directed ฮฑ ฮด n)) l m
          where
           IH : is-sup (underlying-order (๐““ โป)) (iter n (โˆ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) ฮด))
                (iter n โˆ˜ ฮฑ)
           IH = iter-is-continuous n I ฮฑ ฮด
           l : iter n s โŠ‘โŸช ๐““ โŸซ โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n)
           l = sup-is-lowerbound-of-upperbounds
                (underlying-order (๐““ โป)) IH
                (โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n))
                (โˆ-is-upperbound (๐““ โป) (n-family-is-directed ฮฑ ฮด n))
           m : โˆ (๐““ โป) (n-family-is-directed ฮฑ ฮด n) โŠ‘โŸช ๐““ โŸซ iter n s
           m = โˆ-is-lowerbound-of-upperbounds (๐““ โป) (n-family-is-directed ฮฑ ฮด n)
                (iter n s)
                (sup-is-upperbound (underlying-order (๐““ โป)) IH)

 iter-c : โ„• โ†’ DCPO[ (๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป , ๐““ โป ]
 iter-c n = iter n , iter-is-continuous n

 iter-is-ฯ‰-chain : (n : โ„•) โ†’ (iter-c n) โŠ‘โŸจ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) โŸนแตˆแถœแต–แต’ (๐““ โป) โŸฉ
                             (iter-c (succ n))
 iter-is-ฯ‰-chain zero     f = โŠฅ-is-least ๐““ (iter (succ zero) f)
 iter-is-ฯ‰-chain (succ n) f = monotone-if-continuous (๐““ โป) (๐““ โป) f
                               (iter n f)
                               (iter (succ n) f)
                               (iter-is-ฯ‰-chain n f)

 iter-increases : (n m : โ„•) โ†’ (n โ‰ค m)
                โ†’ (iter-c n) โŠ‘โŸจ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) โŸนแตˆแถœแต–แต’ (๐““ โป) โŸฉ (iter-c m)
 iter-increases = ฯ‰-chains-increase
                   (underlying-order ๐“”) (reflexivity ๐“”) (transitivity ๐“”)
                   iter-c iter-is-ฯ‰-chain
  where
   ๐“” = ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) โŸนแตˆแถœแต–แต’ (๐““ โป)

 iter-is-directed : is-Directed (((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) โŸนแตˆแถœแต–แต’ (๐““ โป)) iter-c
 iter-is-directed =
  ฯ‰-chains-are-Directed (((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) โŸนแตˆแถœแต–แต’ (๐““ โป))
                        iter-c iter-is-ฯ‰-chain

\end{code}

Since we are working with ๐“ฅ-dcpos, we work with a copy of the type of natural
numbers in ๐“ฅ.

\begin{code}

 private
  โ„•' : ๐“ฅ ฬ‡
  โ„•' = Lift ๐“ฅ โ„•

 iter-c' : โ„•' โ†’ DCPO[ (๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป , ๐““ โป ]
 iter-c' = iter-c โˆ˜ lower

 iter-is-directed' : is-Directed (((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) โŸนแตˆแถœแต–แต’ (๐““ โป)) iter-c'
 iter-is-directed' =
  reindexed-family-is-directed (((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) โŸนแตˆแถœแต–แต’ (๐““ โป))
                               (โ‰ƒ-Lift ๐“ฅ โ„•)
                               iter-c
                               iter-is-directed

 ฮผ : DCPO[ ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) , (๐““ โป) ]
 ฮผ = continuous-functions-sup ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) (๐““ โป) iter-c' iter-is-directed'

 ฮผ-gives-a-fixed-point : (f : DCPO[ (๐““ โป) , (๐““ โป) ])
                       โ†’ [ (๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป , ๐““ โป ]โŸจ ฮผ โŸฉ f
                         ๏ผ [ ๐““ โป , ๐““ โป ]โŸจ f โŸฉ
                            ([ (๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป , ๐““ โป ]โŸจ ฮผ โŸฉ f)
 ฮผ-gives-a-fixed-point fc = antisymmetry (๐““ โป) (ฮฝ fc) (f (ฮฝ fc)) l m
  where
   ฮฝ : DCPO[ (๐““ โป) , (๐““ โป) ] โ†’ โŸช ๐““ โŸซ
   ฮฝ = [ (๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป , ๐““ โป ]โŸจ ฮผ โŸฉ
   f : โŸช ๐““ โŸซ โ†’ โŸช ๐““ โŸซ
   f = [ ๐““ โป , ๐““ โป ]โŸจ fc โŸฉ
   ฮด : is-directed (underlying-order (๐““ โป))
        (pointwise-family ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) (๐““ โป) (iter-c') fc)
   ฮด = pointwise-family-is-directed ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) (๐““ โป) (iter-c')
       iter-is-directed' fc

   l : ฮฝ fc โŠ‘โŸช ๐““ โŸซ f (ฮฝ fc)
   l = โˆ-is-lowerbound-of-upperbounds (๐““ โป) ฮด (f (ฮฝ fc)) h
    where
     h : (n : โ„•') โ†’ iter (lower n) fc โŠ‘โŸช ๐““ โŸซ f (ฮฝ fc)
     h (zero , โ‹†)   = โŠฅ-is-least ๐““ (f (ฮฝ fc))
     h (succ n , โ‹†) = monotone-if-continuous (๐““ โป) (๐““ โป) fc
                       (iter n fc)
                       (ฮฝ fc)
                       (โˆ-is-upperbound (๐““ โป) ฮด (n , โ‹†))
   m : f (ฮฝ fc) โŠ‘โŸช ๐““ โŸซ ฮฝ fc
   m = sup-is-lowerbound-of-upperbounds (underlying-order (๐““ โป))
        (continuity-of-function (๐““ โป) (๐““ โป) fc โ„•' ฮฑ ฮด) (ฮฝ fc) k
    where
     ฮฑ : โ„•' โ†’ โŸช ๐““ โŸซ
     ฮฑ = pointwise-family ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) (๐““ โป) iter-c' fc
     k : (n : โ„•') โ†’ [ ๐““ โป , ๐““ โป ]โŸจ fc โŸฉ (ฮฑ n) โŠ‘โŸช ๐““ โŸซ ฮฝ fc
     k (n , โ‹†) = f (ฮฑ (n , โ‹†))  โŠ‘โŸช ๐““ โŸซ[ reflexivity (๐““ โป) (f (ฮฑ (n , โ‹†)))    ]
                 ฮฑ (succ n , โ‹†) โŠ‘โŸช ๐““ โŸซ[ โˆ-is-upperbound (๐““ โป) ฮด (succ n , โ‹†) ]
                 ฮฝ fc           โˆŽโŸช ๐““ โŸซ

 ฮผ-gives-lowerbound-of-fixed-points :
     (f : DCPO[ (๐““ โป) , (๐““ โป) ])
     (d : โŸช ๐““ โŸซ)
   โ†’ [ ๐““ โป , ๐““ โป ]โŸจ f โŸฉ d  โŠ‘โŸช ๐““ โŸซ d
   โ†’ [ (๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป , ๐““ โป ]โŸจ ฮผ โŸฉ f โŠ‘โŸช ๐““ โŸซ d
 ฮผ-gives-lowerbound-of-fixed-points f d l =
  โˆ-is-lowerbound-of-upperbounds (๐““ โป)
   (pointwise-family-is-directed ((๐““ โŸนแตˆแถœแต–แต’โŠฅ ๐““) โป) (๐““ โป) iter-c'
     iter-is-directed' f)
   d g
   where
    g : (n : โ„•') โ†’ iter (lower n) f โŠ‘โŸช ๐““ โŸซ d
    g (zero , โ‹†)   = โŠฅ-is-least ๐““ d
    g (succ n , โ‹†) = iter (succ n) f    โŠ‘โŸช ๐““ โŸซ[ k ]
                     [ ๐““ โป , ๐““ โป ]โŸจ f โŸฉ d โŠ‘โŸช ๐““ โŸซ[ l ]
                     d                    โˆŽโŸช ๐““ โŸซ
     where
      k = monotone-if-continuous (๐““ โป) (๐““ โป) f (iter n f) d (g (n , โ‹†))

\end{code}