module StringLab.Data.List.Factor where

FactorsπŸ”—

A word is a factor of a word if there merely exists such that

Note that mere existence is required to make this a proposition: there are multiple ways to witness as a factor of a non-empty list.

_βŠ‘_ : List A β†’ List A β†’ Type _
_βŠ‘_ {A = A} xs ys = βˆ₯ Ξ£[ us ∈ List A ] Ξ£[ vs ∈ List A ] us ++ xs ++ vs ≑ ys βˆ₯

A word is a left factor of a word denoted if there exists some such that

_βŠ‘Λ‘_ : List A β†’ List A β†’ Type _
_βŠ‘Λ‘_ {A = A} xs ys = Ξ£[ us ∈ List A ] xs ++ us ≑ ys

Conversely, a word is a right factor of a word denoted if there exists some such that

_βŠ‘Κ³_ : List A β†’ List A β†’ Type _
_βŠ‘Κ³_ {A = A} xs ys = Ξ£[ us ∈ List A ] us ++ xs ≑ ys

A word is a proper left factor of denoted if there exists a non-empty word such that

Likewise, a word is a proper right factor of denoted if there exists a non-empty word such that

_⊏ˑ_ : List A β†’ List A β†’ Type _
_⊏ˑ_ {A = A} xs ys =
  Ξ£[ u ∈ A ] Ξ£[ us ∈ List A ] xs ++ (u ∷ us) ≑ ys

_⊏ʳ_ : List A β†’ List A β†’ Type _
_⊏ʳ_ {A = A} xs ys =
  Ξ£[ u ∈ A ] Ξ£[ us ∈ List A ] (u ∷ us) ++ xs ≑ ys
Note

Left factors are more commonly known as prefixes, and right factors as suffixes. We choose the left/right factor terminology to emphasize the algebraic nature of factorisations.

Convienence functionsπŸ”—

We start by defining some nicer names for left factor corresponding to a right factor, and vice versa.

βŠ‘Λ‘-factor : βˆ€ {xs ys : List A} β†’ xs βŠ‘Λ‘ ys β†’ List A
βŠ‘Λ‘-factor = fst

βŠ‘Κ³-factor : βˆ€ {xs ys : List A} β†’ xs βŠ‘Κ³ ys β†’ List A
βŠ‘Κ³-factor = fst

βŠ‘Λ‘-dual-βŠ‘Κ³ : βˆ€ {xs ys : List A} β†’ (p : xs βŠ‘Λ‘ ys) β†’ βŠ‘Λ‘-factor p βŠ‘Κ³ ys
βŠ‘Λ‘-dual-βŠ‘Κ³ {xs = xs} (vs , p) = xs , p

βŠ‘Κ³-dual-βŠ‘Λ‘ : βˆ€ {xs ys : List A} β†’ (p : xs βŠ‘Κ³ ys) β†’ βŠ‘Κ³-factor p βŠ‘Λ‘ ys
βŠ‘Κ³-dual-βŠ‘Λ‘ {xs = xs} (vs , p) = xs , p

Note that the corresponding right factor of a proper left factor may not be proper, and vice versa for proper right factors.

⊏ˑ-factor : βˆ€ {xs ys : List A} β†’ xs ⊏ˑ ys β†’ List A
⊏ˑ-factor (u , us , _) = u ∷ us

⊏ˑ-dual-βŠ‘Κ³ : {xs ys : List A} β†’ (p : xs ⊏ˑ ys) β†’ ⊏ˑ-factor p βŠ‘Κ³ ys
⊏ˑ-dual-βŠ‘Κ³ {xs = xs} (u , us , p) = xs , p

⊏ʳ-factor : βˆ€ {xs ys : List A} β†’ xs ⊏ʳ ys β†’ List A
⊏ʳ-factor (u , us , _) = u ∷ us

⊏ʳ-dual-βŠ‘Λ‘ : {xs ys : List A} β†’ (p : xs ⊏ʳ ys) β†’ ⊏ʳ-factor p βŠ‘Λ‘ ys
⊏ʳ-dual-βŠ‘Λ‘ {xs = xs} (u , us , p) = xs , p

However, the corresponding right/left factors of proper left/right factors are always non-empty

⊏ˑ-factor-nonempty
  : βˆ€ {xs ys : List A}
  β†’ (xs⊏ys : xs ⊏ˑ ys)
  β†’ Nonempty (⊏ˑ-factor xs⊏ys)
⊏ˑ-factor-nonempty xs⊏ys = nonempty

⊏ʳ-factor-nonempty
  : βˆ€ {xs ys : List A}
  β†’ (xs⊏ys : xs ⊏ʳ ys)
  β†’ Nonempty (⊏ʳ-factor xs⊏ys)
⊏ʳ-factor-nonempty xs⊏ys = nonempty

This also gives us a method for constructing proper factors.

++-nonempty-⊏ˑ
  : βˆ€ (xs ys zs : List A)
  β†’ Nonempty ys
  β†’ xs ++ ys ≑ zs
  β†’ xs ⊏ˑ zs
++-nonempty-⊏ˑ xs (y ∷ ys) zs _ p = y , ys , p


++-nonempty-⊏ʳ
  : βˆ€ (xs ys zs : List A)
  β†’ Nonempty xs
  β†’ xs ++ ys ≑ zs
  β†’ ys ⊏ʳ zs
++-nonempty-⊏ʳ (x ∷ xs) ys zs _ p = x , xs , p

The following are also clearly factorisations.

βŠ‘Λ‘-++-inl
  : βˆ€ (xs ys : List A)
  β†’ xs βŠ‘Λ‘ xs ++ ys
βŠ‘Λ‘-++-inl xs ys = ys , refl

⊏ˑ-++-inl
  : βˆ€ (xs ys : List A)
  β†’ ⦃ _ : Nonempty ys ⦄
  β†’ xs ⊏ˑ xs ++ ys
⊏ˑ-++-inl xs (y ∷ ys) = y , ys , refl

βŠ‘Κ³-++-inr
  : βˆ€ (xs ys : List A)
  β†’ ys βŠ‘Κ³ xs ++ ys
βŠ‘Κ³-++-inr xs ys = xs , refl

⊏ʳ-++-inr
  : βˆ€ (xs ys : List A)
  β†’ ⦃ _ : Nonempty xs ⦄
  β†’ ys ⊏ʳ xs ++ ys
⊏ʳ-++-inr (x ∷ xs) ys = x , xs , refl

We also have corresponding versionns of these lemmas for fused reverse-and-add, though we only include the version we need for the time being.

βŠ‘Κ³-⋉-inr :  βˆ€ (xs ys : List A) β†’ xs βŠ‘Κ³ ys ⋉ xs
βŠ‘Κ³-⋉-inr xs ys = reverse ys , sym (⋉-exchangel [] ys xs)

Strengthening and weakeningπŸ”—

Clearly, proper left/right factors are left/right factors.

⊏ʳ-weaken : βˆ€ {xs ys : List A} β†’ xs ⊏ʳ ys β†’ xs βŠ‘Κ³ ys
⊏ʳ-weaken (u , us , p) = (u ∷ us) , p

⊏ˑ-weaken : βˆ€ {xs ys : List A} β†’ xs ⊏ˑ ys β†’ xs βŠ‘Λ‘ ys
⊏ˑ-weaken (u , us , p) = (u ∷ us) , p

Moreover, a left/right factor of is either a proper factor, or equal to Note that this does not require decidable equality; just check the length of the other list.

βŠ‘Λ‘-strengthen : βˆ€ {xs ys : List A} β†’ xs βŠ‘Λ‘ ys β†’ (xs ≑ ys) ⊎ (xs ⊏ˑ ys)
βŠ‘Λ‘-strengthen ([] , p) = inl (sym (++-idr _) βˆ™ p)
βŠ‘Λ‘-strengthen (u ∷ us , p) = inr (u , us , p)

βŠ‘Κ³-strengthen : βˆ€ {xs ys : List A} β†’ xs βŠ‘Κ³ ys β†’ (xs ≑ ys) ⊎ (xs ⊏ʳ ys)
βŠ‘Κ³-strengthen ([] , p) = inl p
βŠ‘Κ³-strengthen (u ∷ us , p) = inr (u , us , p)

We can also mediate between proper right factors of non-empty lists, and factors of the tails of those lists.

βŠ‘Κ³-consr
  : βˆ€ {xs : List A} {y : A} {ys : List A}
  β†’ xs βŠ‘Κ³ ys
  β†’ xs ⊏ʳ (y ∷ ys)
βŠ‘Κ³-consr {y = y} (us , p) = y , us , ap (y ∷_) p

⊏ʳ-tailr
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ʳ ys
  β†’ xs βŠ‘Κ³ tail ys
⊏ʳ-tailr (u , us , p) = us , ap tail p

Dual results hold for left factors and snoc.

⊏ˑ-snocr
  : βˆ€ {xs : List A} {ys : List A} {y : A}
  β†’ xs βŠ‘Λ‘ ys
  β†’ xs ⊏ˑ (ys ∷r y)
⊏ˑ-snocr {xs = xs} {ys = ys} {y = y} (us , p) =
  head y us ,
  tail (us ∷r y) ,
  path
  where
    path : xs ++ head y us ∷ tail (us ∷r y) ≑ ys ∷r y
    path =
      xs ++ head y us ∷ tail (us ∷r y) β‰‘βŸ¨ ap (xs ++_) (head-tail-∷ y us) βŸ©β‰‘
      xs ++ us ∷r y                    β‰‘Λ˜βŸ¨ ++-assoc xs us (y ∷ []) βŸ©β‰‘Λ˜
      (xs ++ us) ∷r y                  β‰‘βŸ¨ ap (_∷r y) p βŸ©β‰‘
      ys ∷r y                          ∎

⊏ˑ-initr
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ˑ ys
  β†’ xs βŠ‘Λ‘ init ys
⊏ˑ-initr {xs = xs} {ys = ys} (u , us , p) =
  init (u ∷ us) ,
  path
  where
    path : xs ++ init (u ∷ us) ≑ init ys
    path =
      xs ++ init (u ∷ us) β‰‘Λ˜βŸ¨ init-nonempty-++ xs (u ∷ us) βŸ©β‰‘Λ˜
      init (xs ++ u ∷ us) β‰‘βŸ¨ ap init p βŸ©β‰‘
      init ys             ∎

In fact, we can precisely characterise proper left/right factors as left/right factors whose corresponding right/left factor is nonempty.

βŠΛ‘β‰ƒβŠ‘Λ‘-nonempty
  : βˆ€ {A : Type β„“}
  β†’ (xs ys : List A)
  β†’ (xs ⊏ˑ ys) ≃ (Ξ£[ p ∈ xs βŠ‘Λ‘ ys ] Nonempty (βŠ‘Λ‘-factor p))

βŠΚ³β‰ƒβŠ‘Κ³-nonempty
  : βˆ€ {A : Type β„“}
  β†’ (xs ys : List A)
  β†’ (xs ⊏ʳ ys) ≃ (Ξ£[ p ∈ xs βŠ‘Κ³ ys ] Nonempty (βŠ‘Κ³-factor p))

This is surprisingly annoying to prove: the easiest way is to chain a series of equivalences that reassociate quantifiers, and then invoke nonemptyβ‰ƒβˆ·.

βŠΛ‘β‰ƒβŠ‘Λ‘-nonempty {A = A} xs ys =
  Ξ£[ u ∈ A ] Ξ£[ us ∈ List A ] xs ++ u ∷ us ≑ ys
    β‰ƒβŸ¨ Ξ£-assoc βŸ©β‰ƒ
  Ξ£[ uus ∈ (A Γ— List A) ] xs ++ uus .fst ∷ uus .snd ≑ ys
    β‰ƒβŸ¨ Ξ£-ap (nonemptyβ‰ƒβˆ· e⁻¹) (Ξ» (u , us) β†’ pathβ†’equiv (lemma u us)) βŸ©β‰ƒ
  Ξ£ (Ξ£ (List A) Nonempty) (Ξ» (us , _) β†’ xs ++ us ≑ ys)
    β‰ƒΛ˜βŸ¨ Ξ£-assoc βŸ©β‰ƒΛ˜
  Ξ£[ us ∈ List A ] (Nonempty us Γ— xs ++ us ≑ ys)
    β‰ƒβŸ¨ Ξ£-ap id≃ (Ξ» _ β†’ Γ—-swap) βŸ©β‰ƒ
  Ξ£[ us ∈ List A ] (xs ++ us ≑ ys Γ— Nonempty us)
    β‰ƒβŸ¨ Ξ£-assoc βŸ©β‰ƒ
  Ξ£[ p ∈ xs βŠ‘Λ‘ ys ] Nonempty (p .fst) β‰ƒβˆŽ
  where
    lemma : βˆ€ u us β†’ _
    lemma u us =
      apβ‚‚ _≑_ (apβ‚‚ (Ξ» u us β†’ xs ++ u ∷ us) (sym (transport-refl _)) (sym (transport-refl _ βˆ™ transport-refl _))) refl
The case for right factors is nearly identical and equally as tedious, so we omit the details.
βŠΚ³β‰ƒβŠ‘Κ³-nonempty {A = A} xs ys =
  Ξ£[ u ∈ A ] Ξ£[ us ∈ List A ] u ∷ us ++ xs ≑ ys
    β‰ƒβŸ¨ Ξ£-assoc βŸ©β‰ƒ
  Ξ£[ uus ∈ (A Γ— List A) ] uus .fst ∷ uus .snd ++ xs ≑ ys
    β‰ƒβŸ¨ Ξ£-ap (nonemptyβ‰ƒβˆ· e⁻¹) (Ξ» (u , us) β†’ pathβ†’equiv (lemma u us)) βŸ©β‰ƒ
  Ξ£ (Ξ£ (List A) Nonempty) (Ξ» (us , _) β†’ us ++ xs ≑ ys)
    β‰ƒΛ˜βŸ¨ Ξ£-assoc βŸ©β‰ƒΛ˜
  Ξ£[ us ∈ List A ] (Nonempty us Γ— us ++ xs ≑ ys)
    β‰ƒβŸ¨ Ξ£-ap id≃ (Ξ» _ β†’ Γ—-swap) βŸ©β‰ƒ
  Ξ£[ us ∈ List A ] (us ++ xs ≑ ys Γ— Nonempty us)
    β‰ƒβŸ¨ Ξ£-assoc βŸ©β‰ƒ
  Ξ£[ p ∈ xs βŠ‘Κ³ ys ] Nonempty (p .fst) β‰ƒβˆŽ
  where
    lemma : βˆ€ u us β†’ _
    lemma u us =
      apβ‚‚ _≑_ (apβ‚‚ (Ξ» u us β†’ u ∷ us ++ xs) (sym (transport-refl _)) (sym (transport-refl _ βˆ™ transport-refl _))) refl

Bottom elementsπŸ”—

The empty list is a bottom element for all the factorization orders.

βŠ‘Λ‘-bot : βˆ€ {xs : List A} β†’ [] βŠ‘Λ‘ xs
βŠ‘Λ‘-bot {xs = xs} = xs , refl

⊏ˑ-bot : βˆ€ {x : A} {xs : List A} β†’ [] ⊏ˑ (x ∷ xs)
⊏ˑ-bot {x = x} {xs = xs} = x , xs , refl

βŠ‘Κ³-bot : βˆ€ {xs : List A} β†’ [] βŠ‘Κ³ xs
βŠ‘Κ³-bot {xs = xs} = xs , ++-idr xs

⊏ʳ-bot : βˆ€ {x : A} {xs : List A} β†’ [] ⊏ʳ (x ∷ xs)
⊏ʳ-bot {x = x} {xs = xs} = x , xs , ++-idr (x ∷ xs)

There are no proper left or right factors of the empty list.

βŠ‘Λ‘-strict-bot : βˆ€ {x : A} {xs : List A} β†’ Β¬ (x ∷ xs βŠ‘Λ‘ [])
βŠ‘Λ‘-strict-bot (us , p) = absurd (βˆ·β‰ [] p)

⊏ˑ-strict-bot : βˆ€ (xs : List A) β†’ Β¬ (xs ⊏ˑ [])
⊏ˑ-strict-bot xs (u , us , p) = absurd (βˆ·β‰ [] (++-zeror xs (u ∷ us) p))

βŠ‘Κ³-strict-bot : βˆ€ {x : A} {xs : List A} β†’ Β¬ (x ∷ xs βŠ‘Κ³ [])
βŠ‘Κ³-strict-bot {x = x} {xs = xs} (us , p) = absurd (βˆ·β‰ [] (++-zeror us (x ∷ xs) p))

⊏ʳ-strict-bot : βˆ€ (xs : List A) β†’ Β¬ (xs ⊏ʳ [])
⊏ʳ-strict-bot xs (u , us , p) = absurd (βˆ·β‰ [] p)

There are many ways we can repackage this fact: the following list is not exhaustive, and covers all the cases we will need.

empty-not-⊏ʳ-empty
  : βˆ€ {xs ys : List A}
  β†’ Empty xs β†’ Empty ys
  β†’ Β¬ (xs ⊏ʳ ys)
empty-not-⊏ʳ-empty {xs = []} {ys = []} _ _ = ⊏ʳ-strict-bot []

⊏ʳ-nonempty
  : βˆ€ {xs : List A}
  β†’ Nonempty xs
  β†’ [] ⊏ʳ xs
⊏ʳ-nonempty {xs = x ∷ xs} _ = ⊏ʳ-bot

nonempty-⊏ˑ
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ˑ ys
  β†’ Nonempty ys
nonempty-⊏ˑ {ys = []} xs⊏ys = absurd (⊏ˑ-strict-bot _ xs⊏ys)
nonempty-⊏ˑ {ys = y ∷ ys} xs⊏ys = nonempty

nonempty-⊏ʳ
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ʳ ys
  β†’ Nonempty ys
nonempty-⊏ʳ {ys = []} xs⊏ys = absurd (⊏ʳ-strict-bot _ xs⊏ys)
nonempty-⊏ʳ {ys = y ∷ ys} xs⊏ys = nonempty

MonotonicityπŸ”—

If has a nonempty left/right factor then must also be nonempty.

nonempty-βŠ‘Λ‘-stable
  : βˆ€ {xs : List A} {ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄
  β†’ xs βŠ‘Λ‘ ys
  β†’ Nonempty ys
nonempty-βŠ‘Λ‘-stable {xs = x ∷ xs} {ys = []} (us , p) =
  absurd (βˆ·β‰ [] p)
nonempty-βŠ‘Λ‘-stable {xs = x ∷ xs} {ys = y ∷ ys} (us , p) =
  nonempty

nonempty-βŠ‘Κ³-stable
  : βˆ€ {xs : List A} {ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄
  β†’ xs βŠ‘Κ³ ys
  β†’ Nonempty ys
nonempty-βŠ‘Κ³-stable {xs = x ∷ xs} {ys = []} (us , p) =
  absurd (βˆ·β‰ [] (++-zeror us (x ∷ xs) p))
nonempty-βŠ‘Κ³-stable {xs = x ∷ xs} {ys = y ∷ ys} (us , p) =
  nonempty

Lengths of factorsπŸ”—

If is a proper left factor of then the length of is strictly smaller than the length of

⊏ˑ-length-<
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ˑ ys
  β†’ length xs Nat.< length ys
⊏ˑ-length-< {xs = xs} {ys = ys} (u , us , xs+us=ys) =
  ≀-trans (+-≀l (suc (length xs)) (length us)) $
  ≀-refl' 1+∣xs∣+∣us∣=∣ys∣
  where
    1+∣xs∣+∣us∣=∣ys∣ : 1 + length xs + length us ≑ length ys
    1+∣xs∣+∣us∣=∣ys∣ =
      1 + length xs + length us   β‰‘Λ˜βŸ¨ +-sucr (length xs) (length us) βŸ©β‰‘Λ˜
      length xs + (1 + length us) β‰‘βŸ¨βŸ©
      length xs + length (u ∷ us) β‰‘Λ˜βŸ¨ length-++ xs (u ∷ us) βŸ©β‰‘Λ˜
      length (xs ++ u ∷ us)       β‰‘βŸ¨ ap length xs+us=ys βŸ©β‰‘
      length ys                   ∎

Extending factorsπŸ”—

We can extend left prefixes on the left, and right prefixes on the right.

βŠ‘Λ‘-++-extendl
  : βˆ€ {ws xs ys zs : List A}
  β†’ ws ≑ xs β†’ ys βŠ‘Λ‘ zs β†’ (ws ++ ys) βŠ‘Λ‘ (xs ++ zs)
βŠ‘Λ‘-++-extendl {ws = ws} {ys = ys} p (us , q) =
  us , ++-assoc ws ys us βˆ™ apβ‚‚ _++_ p q

⊏ˑ-++-extendl
  : βˆ€ {ws xs ys zs : List A}
  β†’ ws ≑ xs β†’ ys ⊏ˑ zs β†’ (ws ++ ys) ⊏ˑ (xs ++ zs)
⊏ˑ-++-extendl {ws = ws} {ys = ys} p (u , us , q) =
  u , us , ++-assoc ws ys (u ∷ us) βˆ™ apβ‚‚ _++_ p q

βŠ‘Κ³-++-extendr
  : βˆ€ {ws xs ys zs : List A}
  β†’ ws βŠ‘Κ³ xs β†’ ys ≑ zs β†’ (ws ++ ys) βŠ‘Κ³ (xs ++ zs)
βŠ‘Κ³-++-extendr {ws = ws} {ys = ys} (us , p) q =
  us , sym (++-assoc us ws ys) βˆ™ apβ‚‚ _++_ p q

⊏ʳ-++-extendr
  : βˆ€ {ws xs ys zs : List A}
  β†’ ws ⊏ʳ xs β†’ ys ≑ zs β†’ (ws ++ ys) ⊏ʳ (xs ++ zs)
⊏ʳ-++-extendr {ws = ws} {ys = ys} (u , us , p) q =
  u , us , sym (++-assoc (u ∷ us) ws ys) βˆ™ apβ‚‚ _++_ p q

As corollaries, we get can extend left/right prefixes with a single element on the left/right, resp.

βŠ‘Λ‘-∷-extendl
  : βˆ€ {x y : A} {xs ys : List A}
  β†’ x ≑ y β†’ xs βŠ‘Λ‘ ys β†’ (x ∷ xs) βŠ‘Λ‘ (y ∷ ys)
βŠ‘Λ‘-∷-extendl p q = βŠ‘Λ‘-++-extendl (ap (_∷ []) p) q

⊏ˑ-∷-extendl
  : βˆ€ {x y : A} {xs ys : List A}
  β†’ x ≑ y β†’ xs ⊏ˑ ys β†’ (x ∷ xs) ⊏ˑ (y ∷ ys)
⊏ˑ-∷-extendl p q = ⊏ˑ-++-extendl (ap (_∷ []) p) q

βŠ‘Κ³-∷r-extendr
  : βˆ€ {x y : A} {xs ys : List A}
  β†’ xs βŠ‘Κ³ ys β†’ x ≑ y β†’ (xs ∷r x) βŠ‘Κ³ (ys ∷r y)
βŠ‘Κ³-∷r-extendr p q = βŠ‘Κ³-++-extendr p (ap (_∷ []) q)

⊏ʳ-∷r-extendr
  : βˆ€ {x y : A} {xs ys : List A}
  β†’ xs ⊏ʳ ys β†’ x ≑ y β†’ (xs ∷r x) ⊏ʳ (ys ∷r y)
⊏ʳ-∷r-extendr p q = ⊏ʳ-++-extendr p (ap (_∷ []) q)

We also have extension lemmata for fused reverse-and-concatenate.

βŠ‘Κ³-⋉-extendr
  : βˆ€ {ws xs ys zs : List A}
  β†’ ws βŠ‘Λ‘ xs β†’ ys ≑ zs β†’ (ws ⋉ ys) βŠ‘Κ³ (xs ⋉ zs)
βŠ‘Κ³-⋉-extendr {ws = ws} {xs = xs} {ys = ys} {zs = zs} (vs , p) ys=zs =
  reverse vs ,
  ⋉-exchanger vs [] (ws ⋉ ys)
  βˆ™ ⋉-assocl vs ws ys
  βˆ™ apβ‚‚ (_⋉_) p ys=zs

Inversion lemmasπŸ”—

Next, we prove a battery of rather tedious inversion lemmas. These sorts of lemmas are (understandably) often omitted in informal accounts of the subject, but we are being completely formal, so a bit of elbow grease is required. Luckily, none of them are particularly hard, so we shall gloss over the proofs.

We begin by charaterising left factors of non-empty lists. In particular, if is a nonempty factor of a nonempty list then their first elements must be equal, and their tails must be factors.

βŠ‘Λ‘-head
  : {xs ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄ β†’ ⦃ _ : Nonempty ys ⦄
  β†’ xs βŠ‘Λ‘ ys β†’ head⁺ xs ≑ head⁺ ys
βŠ‘Λ‘-head {xs = x ∷ xs} {ys = y ∷ ys} (us , p) = ∷-head-inj p

βŠ‘Λ‘-tail
  : {xs ys : List A}
  β†’ xs βŠ‘Λ‘ ys β†’ tail xs βŠ‘Λ‘ tail ys
βŠ‘Λ‘-tail {xs = []} {ys = ys} _ = βŠ‘Λ‘-bot
βŠ‘Λ‘-tail {xs = x ∷ xs} {ys = []} (us , p) = absurd (βˆ·β‰ [] p)
βŠ‘Λ‘-tail {xs = x ∷ xs} {ys = y ∷ ys} (us , p) = us , ∷-tail-inj p

⊏ˑ-head
  : βˆ€ {xs ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄ β†’ ⦃ _ : Nonempty ys ⦄
  β†’ xs ⊏ˑ ys β†’ head⁺ xs ≑ head⁺ ys
⊏ˑ-head {xs = x ∷ xs} {ys = y ∷ ys} (u , us , p) = ∷-head-inj p

⊏ˑ-tail
  : βˆ€ {xs ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄ β†’ ⦃ _ : Nonempty ys ⦄
  β†’ xs ⊏ˑ ys
  β†’ tail xs ⊏ˑ tail ys
⊏ˑ-tail {xs = x ∷ xs} {ys = y ∷ ys} (u , us , p) = u , us , ∷-tail-inj p

We also have analogous lemmas for right factors and init/last.

βŠ‘Κ³-last :
  βˆ€ {xs ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄ β†’ ⦃ _ : Nonempty ys ⦄
  β†’ xs βŠ‘Κ³ ys β†’ last⁺ xs ≑ last⁺ ys
βŠ‘Κ³-last {xs = x ∷ xs} {ys = y ∷ ys} (us , p) =
  last xs x                β‰‘Λ˜βŸ¨ last-nonempty-++ us (x ∷ xs) x x βŸ©β‰‘Λ˜
  last ⌜ us ++ x ∷ xs ⌝ x  β‰‘βŸ¨ ap! p βŸ©β‰‘
  last (y ∷ ys) x          β‰‘βŸ¨βŸ©
  last ys y                ∎

βŠ‘Κ³-init : βˆ€ {xs ys : List A} β†’ xs βŠ‘Κ³ ys β†’ init xs βŠ‘Κ³ init ys
βŠ‘Κ³-init {xs = []} {ys = ys} xsβŠ‘ys = βŠ‘Κ³-bot
βŠ‘Κ³-init {xs = x ∷ xs} {ys = []} xsβŠ‘ys = absurd (βŠ‘Κ³-strict-bot xsβŠ‘ys)
βŠ‘Κ³-init {xs = x ∷ xs} {ys = y ∷ ys} (us , p) =
  us , (sym (init-nonempty-++ us (x ∷ xs)) βˆ™ ap init p)

⊏ʳ-last
  : βˆ€ {xs ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄ β†’ ⦃ _ : Nonempty ys ⦄
  β†’ xs ⊏ʳ ys β†’ last⁺ xs ≑ last⁺ ys
⊏ʳ-last (u , us , p) = βŠ‘Κ³-last (u ∷ us , p)

⊏ʳ-init
  : βˆ€ {xs ys : List A}
  β†’ ⦃ Nonempty xs ⦄ β†’ ⦃ Nonempty ys ⦄
  β†’ xs ⊏ʳ ys β†’ init xs ⊏ʳ init ys
⊏ʳ-init {xs = x ∷ xs} {ys = y ∷ ys} (u , us , p) =
  u , us , sym (init-nonempty-++ (u ∷ us) (x ∷ xs)) βˆ™ ap init p

Moreover, if is a (proper) right factor of then the tail of is a (proper) right factor of the tail of

βŠ‘Κ³-tail
  : βˆ€ {xs ys : List A}
  β†’ xs βŠ‘Κ³ ys β†’ tail xs βŠ‘Κ³ tail ys
⊏ʳ-∷-tail
  : βˆ€ {xs ys : List A}
  β†’ ⦃ _ : Nonempty xs ⦄ β†’ ⦃ _ : Nonempty ys ⦄
  β†’ xs ⊏ʳ ys β†’ tail xs ⊏ʳ tail ys
The proof is easy, but tedious. Dedicated readers can click β€œread more” to see the details.
βŠ‘Κ³-tail {xs = []} {ys = ys} xsβŠ‘ys = βŠ‘Κ³-bot
βŠ‘Κ³-tail {xs = x ∷ xs} {ys = []} xsβŠ‘ys = absurd (βŠ‘Κ³-strict-bot xsβŠ‘ys)
βŠ‘Κ³-tail {xs = x ∷ xs} {ys = y ∷ ys} (us , p) =
  tail (us ∷r x) , us+xs=ys
  where
    us+xs=ys : tail (us ∷r x) ++ xs ≑ ys
    us+xs=ys =
      tail (us ∷r x) ++ xs β‰‘Λ˜βŸ¨ tail-nonempty-++ (us ∷r x) xs βŸ©β‰‘Λ˜
      tail (us ∷r x ++ xs) β‰‘βŸ¨ ap tail (++-assoc us (x ∷ []) xs) βŸ©β‰‘
      tail (us ++ x ∷ xs)  β‰‘βŸ¨ ap tail p βŸ©β‰‘
      ys                   ∎

⊏ʳ-∷-tail {xs = x ∷ xs} {ys = y ∷ ys} (u , us , p) = head x us , tail (us ∷r x) , us+xs=ys
  where
    us+xs=ys : head x us ∷ tail (us ∷r x) ++ xs ≑ ys
    us+xs=ys =
      head x us ∷ tail (us ∷r x) ++ xs β‰‘βŸ¨ ap (_++ xs) (head-tail-∷ x us) βŸ©β‰‘
      us ∷r x ++ xs                    β‰‘βŸ¨ ++-assoc us (x ∷ []) xs βŸ©β‰‘
      us ++ x ∷ xs                     β‰‘βŸ¨ ∷-tail-inj p βŸ©β‰‘
      ys                               ∎

We can repackage some of these inversion lemmas in forms that are more ergonomic in some situations.

βŠ‘Κ³-∷-inversion
  : βˆ€ {us : List ⌞ A ⌟} {x : ⌞ A ⌟} {xs : List ⌞ A ⌟}
  β†’ us βŠ‘Κ³ x ∷ xs
  β†’ (us ≑ x ∷ xs) ⊎ us βŠ‘Κ³ xs
βŠ‘Κ³-∷-inversion ([] , p) = inl p
βŠ‘Κ³-∷-inversion (v ∷ vs , p) = inr (vs , ∷-tail-inj p)

⊏ʳ-∷-shrinkl
  : βˆ€ {u : ⌞ A ⌟} {us : List ⌞ A ⌟} {xs : List ⌞ A ⌟}
  β†’ u ∷ us ⊏ʳ xs
  β†’ us ⊏ʳ xs
⊏ʳ-∷-shrinkl {u = u} {us = us} (v , vs , p) =
  v ,
  vs ∷r u ,
  ap (v ∷_) (++-assoc vs (u ∷ []) us) βˆ™ p

βŠ‘Κ³-∷-extendr
  : βˆ€ {us : List ⌞ A ⌟} {x : ⌞ A ⌟} {xs : List ⌞ A ⌟}
  β†’ us βŠ‘Κ³ xs
  β†’ us βŠ‘Κ³ (x ∷ xs)
βŠ‘Κ³-∷-extendr {x = x} (vs , p) = (x ∷ vs , ap (x ∷_) p)

Factorisations as ordersπŸ”—

The left/right factorisation relations are reflexive.

βŠ‘Λ‘-refl' : βˆ€ {xs  ys : List A} β†’ xs ≑ ys β†’ xs βŠ‘Λ‘ ys
βŠ‘Λ‘-refl' p = [] , ++-idr _ βˆ™ p

βŠ‘Λ‘-refl : βˆ€ {xs : List A} β†’ xs βŠ‘Λ‘ xs
βŠ‘Λ‘-refl {xs = xs} = [] , ++-idr _

βŠ‘Κ³-refl' : βˆ€ {xs  ys : List A} β†’ xs ≑ ys β†’ xs βŠ‘Κ³ ys
βŠ‘Κ³-refl' p = [] , p

βŠ‘Κ³-refl : βˆ€ {xs : List A} β†’ xs βŠ‘Κ³ xs
βŠ‘Κ³-refl {xs = xs} = [] , refl

Conversely, the proper factor relations are irreflexive.

⊏ˑ-irrefl' : βˆ€ {xs ys : List A} β†’ xs ⊏ˑ ys β†’ xs β‰  ys
⊏ʳ-irrefl' : βˆ€ {xs ys : List A} β†’ xs ⊏ʳ ys β†’ xs β‰  ys

This follows from some easy algebra: if they were reflexive, – then there would be some nonempty such that had a fixpoint.

⊏ˑ-irrefl' {ys = ys} (u , us , p) xs=ys =
  ++-no-fixl _ (u ∷ us) (ap (_++ u ∷ us) (sym xs=ys) βˆ™ p)

⊏ʳ-irrefl' (u , us , p) xs=ys =
  ++-no-fixr (u ∷ us) _ (ap (u ∷ us ++_) (sym xs=ys) βˆ™ p)

The more general form of irreflexivity can be annoying to use, so we repackage the result into a friendlier form.

⊏ˑ-irrefl : βˆ€ {xs : List A} β†’ Β¬ (xs ⊏ˑ xs)
⊏ˑ-irrefl xs⊏xs = ⊏ˑ-irrefl' xs⊏xs refl

⊏ʳ-irrefl : βˆ€ {xs : List A} β†’ Β¬ (xs ⊏ʳ xs)
⊏ʳ-irrefl xs⊏xs = ⊏ʳ-irrefl' xs⊏xs refl

The (proper) factorisation relations are not only (ir)reflexive, they are transitive! This follows from some easy algebra in all cases.

βŠ‘Λ‘-trans : βˆ€ {xs ys zs : List A} β†’ xs βŠ‘Λ‘ ys β†’ ys βŠ‘Λ‘ zs β†’ xs βŠ‘Λ‘ zs
βŠ‘Λ‘-trans (us , p) (vs , q) =
  us ++ vs , sym (++-assoc _ us vs) βˆ™ ap (_++ vs) p βˆ™ q

βŠ‘Κ³-trans : βˆ€ {xs ys zs : List A} β†’ xs βŠ‘Κ³ ys β†’ ys βŠ‘Κ³ zs β†’ xs βŠ‘Κ³ zs
βŠ‘Κ³-trans (us , p) (vs , q) =
  vs ++ us , ++-assoc vs us _ βˆ™ ap (vs ++_) p βˆ™ q

⊏ˑ-trans : βˆ€ {xs ys zs : List A} β†’ xs ⊏ˑ ys β†’ ys ⊏ˑ zs β†’ xs ⊏ˑ zs
⊏ˑ-trans (u , us , p) (v , vs , q) =
  u , (us ++ v ∷ vs) , sym (++-assoc _ (u ∷ us) (v ∷ vs)) βˆ™ ap (_++ v ∷ vs) p βˆ™ q

⊏ʳ-trans : βˆ€ {xs ys zs : List A} β†’ xs ⊏ʳ ys β†’ ys ⊏ʳ zs β†’ xs ⊏ʳ zs
⊏ʳ-trans (u , us , p) (v , vs , q) =
  v , (vs ++ u ∷ us) , ++-assoc (v ∷ vs) (u ∷ us) _ βˆ™ ap (v ∷ vs ++_) p βˆ™ q

We also have joint transitivity of the proper and non-proper factorisation relations.

⊏ˑ-βŠ‘Λ‘-trans : βˆ€ {xs ys zs : List A} β†’ xs ⊏ˑ ys β†’ ys βŠ‘Λ‘ zs β†’ xs ⊏ˑ zs
βŠ‘Λ‘-⊏ˑ-trans : βˆ€ {xs ys zs : List A} β†’ xs βŠ‘Λ‘ ys β†’ ys ⊏ˑ zs β†’ xs ⊏ˑ zs
⊏ʳ-βŠ‘Κ³-trans : βˆ€ {xs ys zs : List A} β†’ xs ⊏ʳ ys β†’ ys βŠ‘Κ³ zs β†’ xs ⊏ʳ zs
βŠ‘Κ³-⊏ʳ-trans : βˆ€ {xs ys zs : List A} β†’ xs βŠ‘Κ³ ys β†’ ys ⊏ʳ zs β†’ xs ⊏ʳ zs
These all follow from our previous transitivity lemmas.
⊏ˑ-βŠ‘Λ‘-trans {xs = xs} {ys = ys} {zs = zs} xs⊏ys ysβŠ‘zs =
  Equiv.from (βŠΛ‘β‰ƒβŠ‘Λ‘-nonempty xs zs) $
    βŠ‘Λ‘-trans (⊏ˑ-weaken xs⊏ys) ysβŠ‘zs ,
    auto

βŠ‘Λ‘-⊏ˑ-trans {xs = xs} {ys = ys} {zs = zs} xsβŠ‘ys ys⊏zs =
  Equiv.from (βŠΛ‘β‰ƒβŠ‘Λ‘-nonempty xs zs) $
    βŠ‘Λ‘-trans xsβŠ‘ys (⊏ˑ-weaken ys⊏zs) ,
    auto

⊏ʳ-βŠ‘Κ³-trans {xs = xs} {ys = ys} {zs = zs} xs⊏ys ysβŠ‘zs =
  Equiv.from (βŠΚ³β‰ƒβŠ‘Κ³-nonempty xs zs) $
    βŠ‘Κ³-trans (⊏ʳ-weaken xs⊏ys) ysβŠ‘zs ,
    auto

βŠ‘Κ³-⊏ʳ-trans {xs = xs} {ys = ys} {zs = zs} xsβŠ‘ys ys⊏zs =
  Equiv.from (βŠΚ³β‰ƒβŠ‘Κ³-nonempty xs zs) $
    βŠ‘Κ³-trans xsβŠ‘ys (⊏ʳ-weaken ys⊏zs) ,
    auto

The proper left/right factor relations are jointly asymmetric with both non-proper factorisation relations.

⊏ˑ-βŠ‘Λ‘-asym
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ˑ ys
  β†’ ys βŠ‘Λ‘ xs
  β†’ βŠ₯
⊏ˑ-βŠ‘Κ³-asym
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ˑ ys
  β†’ ys βŠ‘Κ³ xs
  β†’ βŠ₯
⊏ʳ-βŠ‘Λ‘-asym
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ʳ ys
  β†’ ys βŠ‘Λ‘ xs
  β†’ βŠ₯
⊏ʳ-βŠ‘Κ³-asym
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ʳ ys
  β†’ ys βŠ‘Κ³ xs
  β†’ βŠ₯

All these follow from fixpoint arguments.

⊏ʳ-βŠ‘Λ‘-asym {ys = ys} (u , us , p) (vs , q) =
  ++-no-fix (u ∷ us) ys vs (inl nonempty) (ap (u ∷ us ++_) q βˆ™ p)

⊏ˑ-βŠ‘Κ³-asym {ys = ys} (u , us , p) (vs , q) =
  ++-no-fix vs ys (u ∷ us) (inr nonempty) (sym (++-assoc vs ys (u ∷ us)) βˆ™ ap (_++ u ∷ us) q βˆ™ p)

⊏ʳ-βŠ‘Κ³-asym {xs = xs} {ys = ys} (u , us , p) (vs , q) =
  ++-no-fixr (u ∷ us ++ vs) ys $
  (u ∷ us ++ vs) ++ ys β‰‘βŸ¨ ++-assoc (u ∷ us) vs ys βŸ©β‰‘
  u ∷ us ++ vs ++ ys   β‰‘βŸ¨ ap (u ∷ us ++_) q βŸ©β‰‘
  u ∷ us ++ xs         β‰‘βŸ¨ p βŸ©β‰‘
  ys                   ∎

⊏ˑ-βŠ‘Λ‘-asym {xs = xs} {ys = ys} (u , us , p) (vs , q) =
  ++-no-fixl xs (u ∷ us ++ vs) $
  xs ++ u ∷ us ++ vs β‰‘Λ˜βŸ¨ ++-assoc xs (u ∷ us) vs βŸ©β‰‘Λ˜
  (xs ++ u ∷ us) ++ vs β‰‘βŸ¨ ap (_++ vs) p βŸ©β‰‘
  ys ++ vs             β‰‘βŸ¨ q βŸ©β‰‘
  xs                   ∎

Non-joint asymmetry follows immediately from weakening

⊏ˑ-asym
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ˑ ys β†’ ys ⊏ˑ xs
  β†’ βŠ₯
⊏ˑ-asym xs⊏ys ys⊏xs = ⊏ˑ-βŠ‘Λ‘-asym xs⊏ys (⊏ˑ-weaken ys⊏xs)

⊏ʳ-asym
  : βˆ€ {xs ys : List A}
  β†’ xs ⊏ʳ ys β†’ ys ⊏ʳ xs
  β†’ βŠ₯
⊏ʳ-asym xs⊏ys ys⊏xs = ⊏ʳ-βŠ‘Κ³-asym xs⊏ys (⊏ʳ-weaken ys⊏xs)

Levi’s lemmaπŸ”—

The next obvious step is to prove antisymmetry of the factorisation relations. This is slightly tricker than the other cases, so we will take a slight detour to prove Levi’s lemma (Levi 1944): if two words then there is some list that characterises their overlap. In more succinct terms, the free monoid is equidivisible.

++-equidiv
  : βˆ€ {β„“} {A : Type β„“}
  β†’ (as bs xs ys : List A)
  β†’ as ++ bs ≑ xs ++ ys
  β†’ Ξ£[ us ∈ List A ] ((as ≑ xs ++ us Γ— us ++ bs ≑ ys) ⊎ (as ++ us ≑ xs Γ— bs ≑ us ++ ys))

The proof is somewhat obvious, but contains algorithmic content. We proceed by induction down and when one of them is empty, we simply returun the other list.

++-equidiv [] bs xs ys as+bs=xs+ys =
  xs , inr (refl , as+bs=xs+ys)
++-equidiv (a ∷ as) bs [] ys as+bs=xs+ys =
  a ∷ as , inl (refl , as+bs=xs+ys)

If the are both non-empty, we just recurse.

++-equidiv (a ∷ as) bs (x ∷ xs) ys as+bs=xs+ys with ++-equidiv as bs xs ys (∷-tail-inj as+bs=xs+ys)
... | us , inl (as=xs+us , us+bs=ys) =
  us , inl (apβ‚‚ _∷_ (∷-head-inj as+bs=xs+ys) as=xs+us , us+bs=ys)
... | us , inr (as+us=xs , bs=us+ys) =
  us , (inr (apβ‚‚ _∷_ (∷-head-inj as+bs=xs+ys) as+us=xs , bs=us+ys))

Levi’s lemma has some extremely useful corollaries. First, observe that if and are both left/right factors of some common word then either is a proper left/right factor of is a proper left/right of or

βŠ‘Λ‘-equidiv
  : βˆ€ {xs ys zs : List A}
  β†’ xs βŠ‘Λ‘ zs
  β†’ ys βŠ‘Λ‘ zs
  β†’ Tri _⊏ˑ_ xs ys

βŠ‘Κ³-equidiv
  : βˆ€ {xs ys zs : List A}
  β†’ xs βŠ‘Κ³ zs
  β†’ ys βŠ‘Κ³ zs
  β†’ Tri _⊏ʳ_ xs ys

The argument is quite elegant: by definition, for some We then invoke Levi’s lemma to find their overlap: if the overlap is empty, then we immediately know that Moreover, we can deduce if is a proper left factor of or vice-versa by the direction the overlap extends in!

βŠ‘Λ‘-equidiv {xs = xs} {ys = ys} {zs = zs} (us , p) (vs , q)
  with ++-equidiv xs us ys vs (p βˆ™ sym q)
... | [] , inl (xs=ys+[] , _) =
  eq (flip ⊏ˑ-irrefl' xs=ys) xs=ys (flip ⊏ˑ-irrefl' (sym xs=ys))
  where
    xs=ys : xs ≑ ys
    xs=ys = xs=ys+[] βˆ™ ++-idr ys
... | [] , inr ([]+xs=ys , _) =
  eq (flip ⊏ˑ-irrefl' xs=ys) xs=ys (flip ⊏ˑ-irrefl' (sym xs=ys))
  where
    xs=ys : xs ≑ ys
    xs=ys = sym (++-idr xs) βˆ™ []+xs=ys
... | w ∷ ws , inl (xs=ys+ws , _) =
  gt (⊏ˑ-asym ys⊏xs) (⊏ˑ-irrefl' ys⊏xs ∘ sym) ys⊏xs
  where
    ys⊏xs : ys ⊏ˑ xs
    ys⊏xs = w , ws , sym xs=ys+ws
... | w ∷ ws , inr (xs+ws=ys , _) =
  lt xs⊏ys (⊏ˑ-irrefl' xs⊏ys) (⊏ˑ-asym xs⊏ys)
  where
    xs⊏ys : xs ⊏ˑ ys
    xs⊏ys = w , ws , xs+ws=ys
The right case follows the same line of argument, so we omit the details.
βŠ‘Κ³-equidiv {xs = xs} {ys = ys} {zs = zs} (us , p) (vs , q)
  with ++-equidiv us xs vs ys (p βˆ™ sym q)
... | [] , inl (_ , xs=ys) =
  eq (flip ⊏ʳ-irrefl' xs=ys) xs=ys (flip ⊏ʳ-irrefl' (sym xs=ys))
... | [] , inr (_ , xs=ys) =
  eq (flip ⊏ʳ-irrefl' xs=ys) xs=ys (flip ⊏ʳ-irrefl' (sym xs=ys))
... | w ∷ ws , inl (_ , ws+xs=ys) =
  lt xs⊏ys (⊏ʳ-irrefl' xs⊏ys) (⊏ʳ-asym xs⊏ys)
  where
    xs⊏ys : xs ⊏ʳ ys
    xs⊏ys = w , ws , ws+xs=ys
... | w ∷ ws , inr (_ , xs=ws+ys) =
  gt (⊏ʳ-asym ys⊏xs) (⊏ʳ-irrefl' ys⊏xs ∘ sym) ys⊏xs
  where
    ys⊏xs : ys ⊏ʳ xs
    ys⊏xs = w , ws , sym xs=ws+ys

We can whittle Levi’s lemma down to an even finer point: if is a proper left/right factor of then is either:

  1. A proper left/right factor of
  2. Equal to
  3. Properly left/right factored by and the corresponding right/left factor is a proper left/right factor of
⊏ˑ-split-++
  : βˆ€ {A : Type β„“} (xs ys zs : List A)
  β†’ xs ⊏ˑ ys ++ zs
  β†’ (xs ⊏ˑ ys) ⊎ (xs ≑ ys) ⊎ (Ξ£[ ys⊏xs ∈ ys ⊏ˑ xs ] ⊏ˑ-factor ys⊏xs ⊏ˑ zs)
⊏ʳ-split-++
  : βˆ€ {A : Type β„“} (xs ys zs : List A)
  β†’ xs ⊏ʳ ys ++ zs
  β†’ (xs ⊏ʳ zs) ⊎ (xs ≑ zs) ⊎ (Ξ£[ zs⊏xs ∈ zs ⊏ʳ xs ] ⊏ʳ-factor zs⊏xs ⊏ʳ ys)

We shall present the proof for right factors. By definition, if is a proper left factor of then there is some nonempty such that Once we apply Levi’s lemma, the rest of the proof essentially becomes definition unfolding.

⊏ʳ-split-++ xs ys zs (u , us , us+xs=ys+zs)
  with ++-equidiv (u ∷ us) xs ys zs us+xs=ys+zs
... | [] , inl (_ , xs=zs) =
  inr (inl xs=zs)
... | [] , inr (_ , xs=zs) =
  inr (inl xs=zs)
... | w ∷ ws , inl (_ , ws+xs=zs) =
  inl (w , ws , ws+xs=zs)
... | w ∷ ws , inr (us+ws=ys , xs=ws+zs) =
  inr (inr ((w , ws , sym xs=ws+zs) , u , us , us+ws=ys))
The left factor case is equivalent, though marginally more tedious.
⊏ˑ-split-++ xs ys zs (u , us , xs+us=ys+zs)
  with ++-equidiv xs (u ∷ us) ys zs xs+us=ys+zs
... | [] , inl (xs=ys , _) =
  inr (inl (xs=ys βˆ™ ++-idr ys))
... | [] , inr (xs=ys , _) =
  inr (inl (sym (++-idr xs) βˆ™ xs=ys))
... | w ∷ ws , inl (xs=ys+ws , ws+us=zs) =
  inr (inr ((w , ws , sym xs=ys+ws) , u , us , ws+us=zs))
... | w ∷ ws , inr (xs+ws=ys , _) =
  inl (w , ws , xs+ws=ys)

AsymmetryπŸ”—

Now that we have Levi’s lemma and its corollaries, antisymmetry is easy.

βŠ‘Λ‘-antisym : βˆ€ {xs ys : List A} β†’ xs βŠ‘Λ‘ ys β†’ ys βŠ‘Λ‘ xs β†’ xs ≑ ys
βŠ‘Κ³-antisym : βˆ€ {xs ys : List A} β†’ xs βŠ‘Κ³ ys β†’ ys βŠ‘Κ³ xs β†’ xs ≑ ys

Suppose that and are left/right factors of one another. In particular, this means that and are both factors of By equidivisibility, we have that or one of or is a proper factor of the other. Joint asymmetry rules out those two cases, which lets us deduce that

βŠ‘Λ‘-antisym {xs = xs} {ys = ys} xsβŠ‘ys ysβŠ‘xs
  with βŠ‘Λ‘-equidiv xsβŠ‘ys βŠ‘Λ‘-refl
... | lt xs⊏ys _ _ = absurd (⊏ˑ-βŠ‘Λ‘-asym xs⊏ys ysβŠ‘xs)
... | eq _ xs=ys _ = xs=ys
... | gt _ _ ys⊏xs = absurd (⊏ˑ-βŠ‘Λ‘-asym ys⊏xs xsβŠ‘ys)

βŠ‘Κ³-antisym {xs = xs} {ys = ys} xsβŠ‘ys ysβŠ‘xs
  with βŠ‘Κ³-equidiv xsβŠ‘ys βŠ‘Κ³-refl
... | lt xs⊏ys _ _ = absurd (⊏ʳ-βŠ‘Κ³-asym xs⊏ys ysβŠ‘xs)
... | eq _ xs=ys _ = xs=ys
... | gt _ _ ys⊏xs = absurd (⊏ʳ-βŠ‘Κ³-asym ys⊏xs xsβŠ‘ys)

Uniqueness of left and right factorsπŸ”—

Note that we do not require mere existence in the definition of left/right factor. This is because there is only one such that witnesses a list as a left/right factor!

βŠ‘Λ‘-unique
  : βˆ€ {xs ys : List A}
  β†’ (p q : xs βŠ‘Λ‘ ys)
  β†’ βŠ‘Λ‘-factor p ≑ βŠ‘Λ‘-factor q

βŠ‘Κ³-unique
  : βˆ€ {xs ys : List A}
  β†’ (p q : xs βŠ‘Κ³ ys)
  β†’ βŠ‘Κ³-factor p ≑ βŠ‘Κ³-factor q

Like many things, these are essentially restatements of Levi’s lemma. We shall focus our attention on the left-factor case. Suppose that If we apply Levi’s lemma to this equation, we can immediately see that the only possible outcome is that any other case results in a fixpoint of concatenation.

βŠ‘Λ‘-unique {xs = xs} {ys = ys} (us , p) (vs , q)
  with ++-equidiv xs us xs vs (p βˆ™ sym q)
... | [] , (inl (_ , us=vs)) = us=vs
... | [] , (inr (_ , us=vs)) = us=vs
... | w ∷ ws , inl (xs=xs+ws , _) =
  absurd (++-no-fixl xs (w ∷ ws) (sym xs=xs+ws))
... | w ∷ ws , inr (xs+ws=xs , _) =
  absurd (++-no-fixl xs (w ∷ ws) (xs+ws=xs))
A dual argument works for right factors.
βŠ‘Κ³-unique {xs = xs} {ys = ys} (us , p) (vs , q)
  with ++-equidiv us xs vs xs (p βˆ™ sym q)
... | [] , (inl (us=vs , _)) = us=vs βˆ™ ++-idr vs
... | [] , (inr (us=vs , _)) = sym (++-idr us) βˆ™ us=vs
... | w ∷ ws , inl (_ , ws+xs=xs) =
  absurd (++-no-fixr (w ∷ ws) xs ws+xs=xs)
... | w ∷ ws , inr (_ , xs=ws+xs) =
  absurd (++-no-fixr (w ∷ ws) xs (sym xs=ws+xs))

If is a set, then we can prove that _βŠ‘Λ‘_ and _βŠ‘Κ³_ are both propositions.

βŠ‘Λ‘-is-prop
  : βˆ€ {xs ys : List A}
  β†’ is-set A
  β†’ is-prop (xs βŠ‘Λ‘ ys)
βŠ‘Λ‘-is-prop A-set p q =
  Ξ£-prop-path (Ξ» _ β†’ ListPath.List-is-hlevel zero A-set _ _)
    (βŠ‘Λ‘-unique p q)

βŠ‘Κ³-is-prop
  : βˆ€ {xs ys : List A}
  β†’ is-set A
  β†’ is-prop (xs βŠ‘Κ³ ys)
βŠ‘Κ³-is-prop A-set p q =
  Ξ£-prop-path (Ξ» _ β†’ ListPath.List-is-hlevel zero A-set _ _)
    (βŠ‘Κ³-unique p q)

AtomsπŸ”—

Recall that an atomic element in a monoid is one that cannot be written as a product of two non-invertible elements. When specialized to the free monoid, this precisely describes singleton lists.

We have a handful of useful results detailing factors of atomic elements, but they are all repackaged forms of the same idea: namely, that the only factors of a singleton list are the empty list and itself.

βŠ‘Κ³-atom
  : βˆ€ {xs : List A} {y : A}
  β†’ xs βŠ‘Κ³ y ∷ []
  β†’ Empty xs ⊎ xs ≑ y ∷ []
βŠ‘Κ³-atom {xs = []} {y = y} xsβŠ‘y =
  inl empty
βŠ‘Κ³-atom {xs = x ∷ []} {y = y} xsβŠ‘y =
  inr (ap (_∷ []) (βŠ‘Κ³-last xsβŠ‘y))
βŠ‘Κ³-atom {xs = x ∷ x' ∷ xs} {y = y} xsβŠ‘y =
  absurd (βŠ‘Κ³-strict-bot (βŠ‘Κ³-init xsβŠ‘y))

⊏ʳ-atom
  : βˆ€ {xs : List A} {y : A}
  β†’ xs ⊏ʳ y ∷ []
  β†’ Empty xs
⊏ʳ-atom {xs = []} {y = y} p = empty
⊏ʳ-atom {xs = x ∷ xs} {y = y} p =
  absurd (⊏ʳ-strict-bot (init (x ∷ xs)) (⊏ʳ-init p))

nonempty-¬⊏ʳ-atom
  : βˆ€ {xs : List A} {y : A}
  β†’ Nonempty xs
  β†’ Β¬ (xs ⊏ʳ y ∷ [])
nonempty-¬⊏ʳ-atom ne xs⊏y = Equiv.to empty≃¬nonempty (⊏ʳ-atom xs⊏y) ne

We also take the time to observe that the atom last xs of a non-empty list is a factor of x ∷ xs.

last-nonempty-⊏ʳ
  : βˆ€ (x : A) (xs : List A)
  β†’ ⦃ _ : Nonempty xs ⦄
  β†’ last⁺ xs ∷ [] ⊏ʳ x ∷ xs
last-nonempty-⊏ʳ x (x' ∷ xs) =
  x , init (x' ∷ xs) , ap (x ∷_) (init-last-∷r xs x')

Relating left and right factorsπŸ”—

A word is a right factor of if and only if the reverse of is a left factor of the reverse of

βŠ‘Κ³β‰ƒreverse-βŠ‘Λ‘
  : βˆ€ (xs ys : List A)
  β†’ (xs βŠ‘Κ³ ys) ≃ (reverse xs βŠ‘Λ‘ reverse ys)

The proof is essentially β€œreverse is an anti-isomorphism”.

βŠ‘Κ³β‰ƒreverse-βŠ‘Λ‘ xs ys =
  Ξ£-ap reverse-≃ Ξ» us β†’
    us ++ xs ≑ ys                         β‰ƒβŸ¨ ap reverse , equivβ†’cancellable reverse-is-equiv βŸ©β‰ƒ
    reverse (us ++ xs) ≑ reverse ys       β‰ƒβŸ¨ βˆ™-pre-equiv (sym (reverse-++ us xs)) βŸ©β‰ƒ
    reverse xs ++ reverse us ≑ reverse ys β‰ƒβˆŽ

We can extend this result to proper factors by recalling that proper factors are precisely factors whose other half is non-empty.

βŠΚ³β‰ƒreverse-⊏ˑ
  : βˆ€ (xs ys : List A)
  β†’ (xs ⊏ʳ ys) ≃ (reverse xs ⊏ˑ reverse ys)
βŠΚ³β‰ƒreverse-⊏ˑ xs ys =
  xs ⊏ʳ ys                                              β‰ƒβŸ¨ βŠΚ³β‰ƒβŠ‘Κ³-nonempty xs ys βŸ©β‰ƒ
  (Ξ£[ p ∈ xs βŠ‘Κ³ ys ] Nonempty (p .fst))                 β‰ƒβŸ¨ Ξ£-ap (βŠ‘Κ³β‰ƒreverse-βŠ‘Λ‘ xs ys) (Ξ» xsβŠ‘ys β†’ reverse-nonempty (xsβŠ‘ys .fst) e⁻¹) βŸ©β‰ƒ
  (Ξ£[ p ∈ reverse xs βŠ‘Λ‘ reverse ys ] Nonempty (p .fst)) β‰ƒΛ˜βŸ¨ βŠΛ‘β‰ƒβŠ‘Λ‘-nonempty (reverse xs) (reverse ys) βŸ©β‰ƒΛ˜
  reverse xs ⊏ˑ reverse ys                              β‰ƒβˆŽ

A similar argument lets us deduce that left factors are the same as reversed right factors.

βŠ‘Λ‘β‰ƒreverse-βŠ‘Κ³
  : βˆ€ (xs ys : List A)
  β†’ (xs βŠ‘Λ‘ ys) ≃ (reverse xs βŠ‘Κ³ reverse ys)
βŠ‘Λ‘β‰ƒreverse-βŠ‘Κ³ xs ys =
  Ξ£-ap reverse-≃ Ξ» us β†’
    xs ++ us ≑ ys                         β‰ƒβŸ¨ ap reverse , equivβ†’cancellable reverse-is-equiv βŸ©β‰ƒ
    reverse (xs ++ us) ≑ reverse ys       β‰ƒβŸ¨ βˆ™-pre-equiv (sym (reverse-++ xs us)) βŸ©β‰ƒ
    reverse us ++ reverse xs ≑ reverse ys β‰ƒβˆŽ

Deciding if a list is a factorπŸ”—

If has decidable equality, then we have an easy, efficient algorithm for checking if lists are left factors of one another: simply start checking from the head of the list.

instance
  Dec-βŠ‘Λ‘
    : βˆ€ {xs ys : List A}
    β†’ ⦃ _ : Discrete A ⦄
    β†’ Dec (xs βŠ‘Λ‘ ys)
  Dec-βŠ‘Λ‘ {xs = []} {ys = ys} = yes (ys , refl)
  Dec-βŠ‘Λ‘ {xs = x ∷ xs} {ys = []} = no (βˆ·β‰ [] ∘ snd)
  Dec-βŠ‘Λ‘ {xs = x ∷ xs} {ys = y ∷ ys} with x ≑? y
  ... | yes x=y =
    invmap
      (Ξ£-mapβ‚‚ (apβ‚‚ _∷_ x=y))
      (Ξ£-mapβ‚‚ ∷-tail-inj)
      (holds? (xs βŠ‘Λ‘ ys))
  ... | no ¬x=y = no (¬x=y ∘ ∷-head-inj ∘ snd)

Deciding if a list is a right factor is a bit tricker. We are using linked lists as our main datastructure of choice, so they have an inherent leftward bias. There isn’t a good choice here; any solution that tries to use lengths will also end up eating a cost, and accessing the last element is also Therefore, the best option is to reverse the lists, and check if it is a right factor.

  Dec-βŠ‘Κ³
    : βˆ€ {xs ys : List A}
    β†’ ⦃ _ : Discrete A ⦄
    β†’ Dec (xs βŠ‘Κ³ ys)
  Dec-βŠ‘Κ³ {xs = xs} {ys = ys} =
    Equivβ†’Dec (βŠ‘Κ³β‰ƒreverse-βŠ‘Λ‘ xs ys)
      (holds? (reverse xs βŠ‘Λ‘ reverse ys))

Well-foundednessπŸ”—

Both the proper left and proper right factor relations are well-founded. This is a critical fact for the correctness of many algorithms, as it lets us prove that the actually terminate.

In a surprising role-reversal, the proof for right factors is easier! This ends up boiling down to the fact that we need make calls on increasingly smaller tails of lists, which lines up with the natural direction of structural induction over lists. From an algorithmic perspective, this is also the preferable iteration order: we don’t need to traverse the entire list to start working, which means that any algorithms that use right-factor induction are naturally online.

⊏ʳ-wf : Wf {A = List A} _⊏ʳ_
⊏ʳ-wf xs = go xs xs βŠ‘Κ³-refl
  module ⊏ʳ-wf where
    go : (xs ys : List A) β†’ .(ys βŠ‘Κ³ xs) β†’ Acc _⊏ʳ_ ys
    go xs [] p = acc (Ξ» zs zs⊏[] β†’ absurd (⊏ʳ-strict-bot zs zs⊏[]))
    go [] (y ∷ ys) p = absurd (βŠ‘Κ³-strict-bot p)
    go (x ∷ xs) (y ∷ ys) p = acc Ξ» zs zs⊏y∷ys β†’
      go xs zs (⊏ʳ-tailr (⊏ʳ-βŠ‘Κ³-trans zs⊏y∷ys p))

Left factors are much more troublesome, and require us to reverse a list. The fundamental issue here is that we need to shrink the list from starting from the final element, which just does not line up with structural recursion over lists. Reversing a list fixes this, but does make the proof much clunkier.

⊏ˑ-wf : Wf {A = List A} _⊏ˑ_
⊏ˑ-wf xs = go (reverse xs) xs (βŠ‘Λ‘-refl' (sym (reverse-reverse xs)))
  module ⊏˘ˑ-wf where
    go : (xs ys : List A) β†’ .(ys βŠ‘Λ‘ reverse xs) β†’ Acc _⊏ˑ_ ys
    go xs [] p = acc Ξ» zs zs⊏[] β†’ absurd (⊏ˑ-strict-bot zs zs⊏[])
    go [] (y ∷ ys) p = absurd (βŠ‘Λ‘-strict-bot p)
    go (x ∷ xs) (y ∷ ys) p = acc Ξ» zs zs⊏y∷ys β†’
      go xs zs $α΅’
        βŠ‘Λ‘-trans (⊏ˑ-initr (⊏ˑ-βŠ‘Λ‘-trans zs⊏y∷ys p)) $
        βŠ‘Λ‘-refl' (init-nonempty-⋉ xs (x ∷ []))

FixpointsπŸ”—

We can repackage our prior fixpoint lemmas as statements about factors; this is essentially a restatement of irreflexivity.

βŠ‘Κ³-no-fixl
  : βˆ€ (xs ys : List A)
  β†’ Nonempty ys
  β†’ Β¬ (xs ++ ys βŠ‘Κ³ xs)
βŠ‘Κ³-no-fixl xs ys ne (vs , p) = ++-no-fix vs xs ys (inr ne) p

βŠ‘Κ³-no-fixr
  : βˆ€ (xs ys : List A)
  β†’ ⦃ Nonempty xs ⦄
  β†’ Β¬ (xs ++ ys βŠ‘Κ³ ys)
βŠ‘Κ³-no-fixr xs ys (vs , p) =
  ++-no-fixr (vs ++ xs) ys ⦃ ++-nonemptyr vs xs auto ⦄ (++-assoc vs xs ys βˆ™ p)

Factors of concatenationsπŸ”—

If is a proper right factor of and then is a proper right factor of

⊏ʳ-++-restrictl
  : βˆ€ {ws xs : List A}
  β†’ (ys zs : List A)
  β†’ length ys ≑ length zs
  β†’ (ws ++ ys) ⊏ʳ (xs ++ zs) β†’ ws ⊏ʳ xs

The proof is a bit of straightforward algebra that hinges on the following observation from earlier: if and then Once we have this, the proof is reduced to shuffling around a take.

⊏ʳ-++-restrictl {ws = ws} {xs = xs} ys zs ys-zs-same-len (u , us , p) =
  ++-nonempty-⊏ʳ (u ∷ us) ws xs nonempty $
    u ∷ us ++ ws                                               β‰‘Λ˜βŸ¨ take-all (length (u ∷ us ++ ws)) (u ∷ us ++ ws) ≀-refl βŸ©β‰‘Λ˜
    take (length (u ∷ us ++ ws)) (u ∷ us ++ ws)                β‰‘Λ˜βŸ¨ take-++l (length (u ∷ us ++ ws)) (u ∷ us ++ ws) ys ≀-refl βŸ©β‰‘Λ˜
    take ⌜ length (u ∷ us ++ ws) ⌝ ((u ∷ us ++ ws) ++ ys)      β‰‘βŸ¨ ap! us+ws-xs-same-len βŸ©β‰‘
    take (length xs) ((u ∷ us ++ ws) ++ ys)                    β‰‘βŸ¨ ap (take (length xs)) (++-assoc (u ∷ us) ws ys) βŸ©β‰‘
    take (length xs) (u ∷ us ++ ws ++ ys)                      β‰‘βŸ¨ ap (take (length xs)) p βŸ©β‰‘
    take (length xs) (xs ++ zs)                                β‰‘βŸ¨ take-++l (length xs) xs zs ≀-refl βŸ©β‰‘
    take (length xs) xs                                        β‰‘βŸ¨ take-all (length xs) xs ≀-refl βŸ©β‰‘
    xs                                                         ∎
  where
    us+ws-xs-same-len : length (u ∷ us ++ ws) ≑ length xs
    us+ws-xs-same-len =
      length-++-cancelr (u ∷ (us ++ ws)) xs ys zs
        (ap length (++-assoc (u ∷ us) ws ys βˆ™ p))
        ys-zs-same-len

A similar strategy lets us conclude that if and is a proper right factor of then is a proper right factor of

⊏ʳ-++-restrictr
  : βˆ€ {ys zs : List A}
  β†’ (ws xs : List A)
  β†’ length ws ≑ length xs
  β†’ (ws ++ ys) ⊏ʳ (xs ++ zs) β†’ ys ⊏ʳ zs
⊏ʳ-++-restrictr {ys = ys} {zs = zs} ws xs ws-xs-same-len (u , us , p) =
  ++-nonempty-⊏ʳ (drop (length ws) (u ∷ us ++ ws)) ys zs
    (drop-nonempty (length ws) (u ∷ us ++ ws) (s≀s len-ws≀len-us+ws)) $
      drop (length ws) (u ∷ us ++ ws) ++ ys     β‰‘Λ˜βŸ¨ drop-++r (length ws) (u ∷ us ++ ws) ys (≀-sucr len-ws≀len-us+ws) βŸ©β‰‘Λ˜
      drop ⌜ length ws ⌝ ((u ∷ us ++ ws) ++ ys) β‰‘βŸ¨ ap! ws-xs-same-len βŸ©β‰‘
      drop (length xs) ((u ∷ us ++ ws) ++ ys)   β‰‘βŸ¨ ap (drop (length xs)) (++-assoc (u ∷ us) ws ys) βŸ©β‰‘
      drop (length xs) (u ∷ us ++ ws ++ ys)     β‰‘βŸ¨ ap (drop (length xs)) p βŸ©β‰‘
      drop (length xs) (xs ++ zs)               β‰‘βŸ¨ drop-++r (length xs) xs zs ≀-refl βŸ©β‰‘
      drop (length xs) xs ++ zs                 β‰‘βŸ¨ ap (_++ zs) (drop-all (length xs) xs ≀-refl) βŸ©β‰‘
      zs                                        ∎
    where
      len-ws≀len-us+ws : length ws ≀ length (us ++ ws)
      len-ws≀len-us+ws =
        ≀-trans (+-≀r (length us) (length ws)) $
        ≀-refl' (sym (length-++ us ws))

We also have a curious little result that relates right and left factors. Namely, if is a proper right factor of and is a left factor of then the corresponding left factor of is a right factor of

⊏ʳ-++-restrictr-βŠ‘Λ‘
  : βˆ€ (xs ys zs : List A)
  β†’ xs ⊏ʳ ys ++ zs
  β†’ (p : ys βŠ‘Λ‘ xs)
  β†’ p .fst ⊏ʳ zs

The theorem statement is honestly harder than the proof, which gives way after a bit of algebra.

⊏ʳ-++-restrictr-βŠ‘Λ‘ xs ys zs (u , us , us+xs=ys+zs) (vs , ys+vs=xs) = vs⊏zs
  where
    us+ys+vs=ys+zs : u ∷ us ++ ys ++ vs ≑ ys ++ zs
    us+ys+vs=ys+zs =
      u ∷ us ++ ys ++ vs β‰‘βŸ¨ ap (u ∷ us ++_) ys+vs=xs βŸ©β‰‘
      u ∷ us ++ xs       β‰‘βŸ¨ us+xs=ys+zs βŸ©β‰‘
      ys ++ zs           ∎

    ys+vs⊏ys+zs : ys ++ vs ⊏ʳ ys ++ zs
    ys+vs⊏ys+zs = u , us , us+ys+vs=ys+zs

    vs⊏zs : vs ⊏ʳ zs
    vs⊏zs = ⊏ʳ-++-restrictr ys ys refl ys+vs⊏ys+zs

Factors of powersπŸ”—

Clearly, is a proper left factor of if is nonempty.

⊏ˑ-powers-inl
  : βˆ€ (xs : List A) (k : Nat) (ys : List A)
  β†’ ⦃ Nonempty ys ⦄
  β†’ xs ⊏ˑ powers xs (suc k) ys
⊏ˑ-powers-inl xs k ys =
  ⊏ˑ-++-inl xs (powers xs k ys) ⦃ powers-nonemptyr xs k ys auto ⦄

Conversly, is a proper right factor of if is nonempty.

⊏ʳ-powers-inr
  : βˆ€ (xs : List A) (k : Nat) (ys : List A)
  β†’ ⦃ Nonempty xs ⦄
  β†’ ys ⊏ʳ powers xs (suc k) ys
⊏ʳ-powers-inr xs zero ys = ⊏ʳ-++-inr xs ys
⊏ʳ-powers-inr xs (suc k) ys =
  ⊏ʳ-trans (⊏ʳ-powers-inr xs k ys) $
  ⊏ʳ-++-inr xs (powers xs (suc k) ys)

Factors of dropπŸ”—

If we remove a non-zero number of element from then we get a proper right factor.

drop-suc-⊏ʳ : βˆ€ (n : Nat) (xs : List A) β†’ ⦃ Nonempty xs ⦄ β†’ drop (suc n) xs ⊏ʳ xs
drop-suc-⊏ʳ zero (x ∷ xs) = x , [] , refl
drop-suc-⊏ʳ (suc n) (x ∷ []) = x , [] , refl
drop-suc-⊏ʳ (suc n) (x ∷ x' ∷ xs) =
  ⊏ʳ-trans (drop-suc-⊏ʳ n (x' ∷ xs)) $
  ⊏ʳ-++-inr (x ∷ []) (x' ∷ xs)

References

  • Levi, F. W. 1944. β€œOn Semigroups.” Bulletin of the Calcutta Mathematical Society 36: 141–46.