\begin{code}
{-# OPTIONS --safe #-}

open import Prelude
open import Algebra
open import Algebra.Monus

module Codata.Bush {W : Type} (mon : WellFoundedMonus W) where

open WellFoundedMonus mon

open Weight (weight W tapom)

open import Data.Weighted ⊕-semigroup hiding (⟪_⟫)
open import Data.Weighted.Monad (weight W tapom) hiding (_>>=_; return)
import Data.Weighted.Monad (weight _ tapom) as WB

open import Codata.Chain W

record Forest∞ (A : Type) : Type where
  coinductive; constructor ⟪_⟫
  field out : (W × List (Forest∞ A))  A
open Forest∞ public

Forest : Type  Type
Forest = List  Forest∞

private variable s : W

foldWeight : (A  Weighted B)  List A  Weighted B
foldWeight f = foldr (_∪_  f) ⟅⟆

module _ {A : Type} {s : W} where

  open Reasoning
  
  mutual
    depth  :  w  Acc [ s ]_≺_ w
            Forest A  Weighted A
    depth w wf =
      foldr (_∪_  (step w wf  return)  out) ⟅⟆
      where
      return = WB.return

    step  :  w  Acc [ s ]_≺_ w
           W × Forest A  Weighted A
    step w wf (v , _) with s ≤? v | v ≤? w
    ... | no _ | _ = ⟅⟆
    ... | _ | no _ = ⟅⟆
    step w (acc wf) (v , x) | yes s≤v | yes (k , w≡v∙k) =
        depth k (wf k ≲[ ≤[ ≤-cong k s≤v ] ≲; ≡[ comm k v ] ≲; ≡[ sym w≡v∙k ] ]) x

\end{code}
%<*cutoff-sig>
\begin{code}[number=code:cutoff-sig]
_∣_⊢_  : Forest A  Step  W  Weighted A
\end{code}
%</cutoff-sig>
\begin{code}
xs  s  w = depth w (well-founded s w) xs

Equiv-UpTo : Forest A  Forest A  Type
\end{code}
%<*equiv-def>
\begin{code}
Equiv-UpTo xs ys =
   s w  xs  s  w  ys  s  w
\end{code}
%</equiv-def>
\begin{code}

Bush : Type  Type
\end{code}
%<*bush>
\begin{code}[number=bush]
Bush A = Forest A / Equiv-UpTo
\end{code}
%</bush>
\begin{code}

open import Data.Link W

\end{code}
%<*merge>
\begin{code}
_⋈_ :  W × Forest A  W × Forest A 
       W × Forest A
(wₗ , ls)  (wᵣ , rs) with wₗ ≤|≥ wᵣ
... | inl  (wᵣ∸wₗ  , _) = wₗ  ,  inl (wᵣ∸wₗ  , rs)    ls
... | inr  (wₗ∸wᵣ  , _) = wᵣ  ,  inl (wₗ∸wᵣ  , ls)    rs
\end{code}
%</merge>
\begin{code}
merges⁺ : W × Forest A  List (W × Forest A)  W × Forest A
merges⁺ x₁ [] = x₁
merges⁺ x₁ (x₂  []) = x₁  x₂
merges⁺ x₁ (x₂  x₃  xs) = (x₁  x₂)  merges⁺ x₃ xs
\end{code}
%<*merges-sig>
\begin{code}
merges :  List (W × Forest A) 
          Link (Forest A)
\end{code}
%</merges-sig>
\begin{code}
merges [] = nothing
merges (x  xs) = just (merges⁺ x xs)
\end{code}
%<*popMin>
\begin{code}
popMin : Forest A  List A × Link (Forest A)
popMin = map₂ merges  swap  partition out
\end{code}
%</popMin>
%<*search>
\begin{code}
search : Forest A  Chain (List A)
search = ana popMin
\end{code}
%</search>