summaryrefslogtreecommitdiff
path: root/src/Data/Fin/Occurs.idr
blob: dead0524f08fc0021bfae00c930710609ee72507 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
module Data.Fin.Occurs

import Data.DPair
import Data.Fin.Strong
import Data.Maybe
import Data.Maybe.Properties
import Data.Nat

import Syntax.PreorderReasoning

-- Thinning --------------------------------------------------------------------

export
thin : SFin n -> SFin (pred n) -> SFin n
thin FZ y = FS' y
thin (FS x) FZ = FZ
thin (FS x) (FS y) = FS (thin x y)

-- Properties

export
thinInjective : (x : SFin n) -> {y, z : SFin (pred n)} -> thin x y = thin x z -> y = z
thinInjective FZ prf = injective {f = FS'} prf
thinInjective (FS x) {y = FZ, z = FZ} prf = Refl
thinInjective (FS x) {y = FS y, z = FS z} prf = cong FS $ thinInjective x $ injective prf

export
thinSkips : (x : SFin n) -> (y : SFin (pred n)) -> Not (thin x y = x)
thinSkips FZ y prf = sucNonZero y prf
thinSkips (FS x) (FS y) prf = thinSkips x y (injective prf)

thinSuc : {n : Nat} -> (x : SFin (S n)) -> (y : SFin n) -> thin (FS x) (FS' y) = FS (thin x y)
thinSuc {n = S n} x y = rewrite sucIsFS y in Refl

export
thinInverse : (x, y : SFin n) -> (0 _ : Not (x = y)) -> (z ** thin x z = y)
thinInverse FZ FZ neq = void (neq Refl)
thinInverse FZ (FS y) neq = (y ** sucIsFS y)
thinInverse (FS x) FZ neq = (FZ ** Refl)
thinInverse (FS x) (FS y) neq =
  let (z ** prf) = thinInverse x y (\prf => neq $ cong FS prf) in
  (FS' z ** trans (thinSuc x z) (cong FS $ prf))

-- Thickening ------------------------------------------------------------------

export
thick : SFin n -> SFin n -> Maybe (SFin (pred n))
thick FZ FZ = Nothing
thick FZ (FS y) = Just y
thick (FS x) FZ = Just FZ
thick (FS x) (FS y) = FS' <$> thick x y

export
thickRefl : (x : SFin n) -> IsNothing (thick x x)
thickRefl FZ = ItIsNothing
thickRefl (FS x) = mapNothing FS' (thickRefl x)

export
thickNeq : (x, y : SFin n) -> (0 _ : Not (x = y)) -> IsJust (thick x y)
thickNeq FZ FZ neq = void (neq Refl)
thickNeq FZ (FS y) neq = ItIsJust
thickNeq (FS x) FZ neq = ItIsJust
thickNeq (FS x) (FS y) neq = mapIsJust FS' (thickNeq x y (\prf => neq $ cong FS prf))

export
thickNothing : (x, y : SFin n) -> (0 _ : IsNothing (thick x y)) -> x = y
thickNothing FZ FZ prf = Refl
thickNothing (FS x) (FS y) prf =
  cong FS (thickNothing x y (mapNothingInverse FS' (thick x y) prf))

export thickJust : (x : SFin n) -> (y : SFin n) -> (0 _ : thick x y = Just z) -> thin x z = y
thickJust FZ (FS y) Refl = sucIsFS y
thickJust (FS x) FZ Refl = Refl
thickJust (FS x) (FS y) prf =
  let invertJust = mapJustInverse FS' (thick x y) prf in
  Calc $
    |~ thin (FS x) z
    ~~ thin (FS x) (FS' invertJust.fst) ...(cong (thin (FS x)) $ snd invertJust.snd)
    ~~ FS (thin x invertJust.fst)       ...(thinSuc x invertJust.fst)
    ~~ FS y                             ...(cong FS $ thickJust x y (fst invertJust.snd))

export
thickThin : (x : SFin n) -> (y : SFin (pred n)) -> thick x (thin x y) = Just y
thickThin x y =
  let
    fromJust =
      extractIsJust $
      thickNeq x (thin x y) (\prf => thinSkips x y $ sym prf)
  in
  Calc $
    |~ thick x (thin x y)
    ~~ Just fromJust.fst  ...(fromJust.snd)
    ~~ Just y             ...(cong Just $ thinInjective x $ thickJust x (thin x y) fromJust.snd)