\begin{code}
{-# OPTIONS --safe #-}
open import Prelude
open import Algebra
open import Algebra.Monus
module Codata.Pairing {S : Type} (mon : TMAPOM S) where
open TMAPOM mon
open import Codata.Chain S
infixr 5 _◂_
record Heap (A : Type) : Type where
coinductive; constructor _◂_
field extract : A
unwrap : List (S × Heap A)
open Heap public
out : Heap A → A × List (S × Heap A)
out xs = extract xs , unwrap xs
module _ {A : Type} (ψ : B → A × List (S × B)) where
hana : B → Heap A
hana′ : A × List (S × B) → Heap A
hana″ : List (S × B) → List (S × Heap A)
hana = hana′ ∘ ψ
hana′ (x , xs) .extract = x
hana′ (x , xs) .unwrap = hana″ xs
hana″ [] = []
hana″ ((w , x) ∷ xs) = (w , hana x) ∷ hana″ xs
open import Data.Link S
open import Data.NonEmpty
_⋈_ : S × Heap A → S × Heap A → S × Heap A
(wₗ , lls) ⋈ (wᵣ , rrs) with wₗ ≤|≥ wᵣ
... | inl (wᵣ∸wₗ , _) = wₗ , extract lls ◂ (wᵣ∸wₗ , rrs) ∷ unwrap lls
... | inr (wₗ∸wᵣ , _) = wᵣ , extract rrs ◂ (wₗ∸wᵣ , lls) ∷ unwrap rrs
\end{code}
%<*merges-pl>
\begin{code}
merges⁺ : S × Heap A → List (S × Heap A)
→ S × Heap A
merges⁺ x₁ [] = x₁
merges⁺ x₁ (x₂ ∷ []) = x₁ ⋈ x₂
merges⁺ x₁ (x₂ ∷ x₃ ∷ xs) =
(x₁ ⋈ x₂) ⋈ merges⁺ x₃ xs
\end{code}
%</merges-pl>
%<*merges>
\begin{code}
merges : List (S × Heap A)
→ Link (Heap A)
merges [] = ⟨⟩
merges (x ∷ xs) = just (merges⁺ x xs)
\end{code}
%</merges>
\begin{code}
open Functor ⦃...⦄
\end{code}
%<*search>
\begin{code}
search : Heap A → Chain A
search = ana (map₂ merges ∘ out)
\end{code}
%</search>
\begin{code}
private module HeapGraph where
GraphOf : Type → Type
GraphOf A = A → List (S × A)
trace-heap : GraphOf A → A → Heap A
trace-heap f = hana (λ x → x , f x)
pathed : GraphOf A → GraphOf (List⁺ A)
pathed g (v ∷ vs) = mapl (map₂ (_∷ v ∷ vs)) (g v)
filterg : (A → Bool) → GraphOf A → GraphOf A
filterg p g x = if p x then g x else []
module _ {V} (disc : Discrete V) where
open import Data.NonEmpty.Discrete disc
dijkstra : V → GraphOf V → Chain (List⁺ V)
dijkstra s g = search (trace-heap (filterg uniq (pathed g)) (s ∷ []))
\end{code}