summaryrefslogtreecommitdiff
path: root/src/Problem19.agda
blob: 130d46e48b8a17af05537093eba31b504cd5929f (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
{-# OPTIONS --safe #-}

module Problem19 where

open import Data.List hiding ([_])
open import Data.Product
open import Data.Empty
open import Data.List.Properties
open import Data.Sum
open import Data.Unit hiding (_≟_)
open import Data.Char
open import Data.Maybe
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality hiding ([_])

data Regex : Set where
    ∅ : Regex
    ε : Regex
    [_] : Char → Regex
    _∘_ : Regex → Regex → Regex
    _∪_ : Regex → Regex → Regex
    _⋆  : Regex → Regex

variable c : Char
variable R S : Regex
variable s t : List Char

data Matches : Regex → List Char → Set where
   empty : Matches ε []
   char  : Matches [ c ] (c ∷ [])
   comp  : Matches R s → Matches S t → Matches (R ∘ S) (s ++ t)
   un₁   : Matches R s → Matches (R ∪ S) s
   un₂   : Matches S s → Matches (R ∪ S) s
   starₑ : Matches (R ⋆) []
   starₛ : Matches R s → Matches (R ⋆) t → Matches (R ⋆) (s ++ t)

comp⁻¹ : Matches (R ∘ S) s → ∃₂ λ t₁ t₂ → t₁ ++ t₂ ≡ s × Matches R t₁ × Matches S t₂
comp⁻¹ (comp prf prf₁) = _ , _ , refl , prf , prf₁

star⁻¹′ : Matches (R ⋆) s → s ≡ [] ⊎ ∃[ c ] ∃[ t₁ ] ∃[ t₂ ] c ∷ t₁ ++ t₂ ≡ s × Matches R (c ∷ t₁) × Matches (R ⋆) t₂
star⁻¹′ starₑ = inj₁ refl
star⁻¹′ (starₛ {s = []} prf prf₁) = star⁻¹′ prf₁
star⁻¹′ (starₛ {s = x ∷ s} prf prf₁) = inj₂ (x , s , _ , refl , prf , prf₁)

Nullable : Regex → Set
Nullable ∅ = ⊥
Nullable ε = ⊤
Nullable [ x ] = ⊥
Nullable (r ∘ r₁) = Nullable r × Nullable r₁
Nullable (r ∪ r₁) = Nullable r ⊎ Nullable r₁
Nullable (r ⋆) = ⊤

nullable? : (r : Regex) → Dec (Nullable r)
nullable? ∅ = no (λ x → x)
nullable? ε = yes tt
nullable? [ x ] = no (λ x → x)
nullable? (r ∘ r₁) with nullable? r | nullable? r₁
... | no p  | _     = no λ (a , b) → p a
... | _     | no p  = no λ (a , b) → p b
... | yes p | yes q = yes (p , q)
nullable? (r ∪ r₁)  with nullable? r | nullable? r₁
... | yes p | _     = yes (inj₁ p)
... | _     | yes p = yes (inj₂ p)
... | no p  | no q  = no λ { (inj₁ a) → p a ; (inj₂ b) → q b }
nullable? (r ⋆) = yes tt

nullable-correct₁ : ∀ R → Nullable R → Matches R []
nullable-correct₁ ε        _               = empty
nullable-correct₁ (r ∘ r₁) (null₁ , null₂) = comp (nullable-correct₁ r null₁) (nullable-correct₁ r₁ null₂)
nullable-correct₁ (r ∪ r₁) (inj₁ null)     = un₁ (nullable-correct₁ r null)
nullable-correct₁ (r ∪ r₁) (inj₂ null)     = un₂ (nullable-correct₁ r₁ null)
nullable-correct₁ (r ⋆)    _               = starₑ

st≡[]⇒s≡[] : s ++ t ≡ [] → s ≡ []
st≡[]⇒s≡[] {[]} {t} prf = refl

st≡[]⇒t≡[] : s ++ t ≡ [] → t ≡ []
st≡[]⇒t≡[] {[]} {t} prf = prf

nullable-correct₂′ : ∀ {R} → Matches R s → s ≡ [] → Nullable R
nullable-correct₂′ empty            s≡[]  = _
nullable-correct₂′ (comp s∈r t∈r₁)  st≡[] = nullable-correct₂′ s∈r (st≡[]⇒s≡[] st≡[]) , nullable-correct₂′ t∈r₁ (st≡[]⇒t≡[] st≡[])
nullable-correct₂′ (un₁ s∈r)        s≡[]  = inj₁ (nullable-correct₂′ s∈r s≡[])
nullable-correct₂′ (un₂ s∈r)        s≡[]  = inj₂ (nullable-correct₂′ s∈r s≡[])
nullable-correct₂′ starₑ            s≡[]  = _
nullable-correct₂′ (starₛ s∈r s∈r₁) s≡[]  = _

nullable-correct₂ : ∀ R → Matches R [] → Nullable R
nullable-correct₂ r []∈r = nullable-correct₂′ []∈r refl

step : Regex → Char → Regex
step ∅ c = ∅
step ε c = ∅
step [ x ] c with c ≟ x
... |  yes p = ε
... |  no  p = ∅
step (r ∘ r₁) c with nullable? r
... | yes p = (step r c ∘ r₁) ∪ step r₁ c
... | no  p = step r c ∘ r₁
step (r ∪ r₁) c = step r c ∪ step r₁ c
step (r ⋆) c = step r c ∘ (r ⋆)

steps : Regex → List Char → Regex
steps R (x ∷ xs) = steps (step R x) xs
steps R [] = R

step-correct₁ : ∀ R c s → Matches (step R c) s → Matches R (c ∷ s)
step-correct₁ [ x ]    c s   prf   with c ≟ x
step-correct₁ [ x ]    c s empty | yes refl = char
step-correct₁ [ x ]    c s ()    | no p

step-correct₁ (R ∘ R₁) c s prf                   with nullable? R
step-correct₁ (R ∘ R₁) c s (un₁ (comp prf prf₁)) | yes p = comp (step-correct₁ R c _ prf) prf₁
step-correct₁ (R ∘ R₁) c s (un₂ prf)             | yes p = comp (nullable-correct₁ R p) (step-correct₁ R₁ c _ prf)
step-correct₁ (R ∘ R₁) c s (comp prf prf₁)       | no p  = comp (step-correct₁ R c _ prf) prf₁

step-correct₁ (R ∪ R₁) c s (un₁ prf) = un₁ (step-correct₁ R c s prf)
step-correct₁ (R ∪ R₁) c s (un₂ prf) = un₂ (step-correct₁ R₁ c s prf)

step-correct₁ (R ⋆)    c s (comp prf prf₁) = starₛ (step-correct₁ R c _ prf) prf₁

step-correct₂ : ∀ R c s → Matches R (c ∷ s) → Matches (step R c) s
step-correct₂ [ x ]    c s char with x ≟ x
... | yes p = empty
... | no  p = ⊥-elim (p refl)
step-correct₂ (R ∘ R₁) c s prf with nullable? R | comp⁻¹ prf
... | yes p | []     , t₂ , refl , prf , prf₁ = un₂ (step-correct₂ R₁ c s prf₁)
... | yes p | x ∷ t₁ , t₂ , eq   , prf , prf₁ =
  un₁ (subst₂ Matches (cong (λ - → step R - ∘ R₁) (∷-injectiveˡ eq)) (∷-injectiveʳ eq)
    (comp (step-correct₂ R x t₁ prf) prf₁))
... | no p  | []     , t₂ , eq   , prf , prf₁ = ⊥-elim (p (nullable-correct₂ R prf))
... | no p  | x ∷ t₁ , t₂ , eq   , prf , prf₁ =
  subst₂ Matches (cong (λ - → step R - ∘ R₁) (∷-injectiveˡ eq)) (∷-injectiveʳ eq)
    (comp (step-correct₂ R x t₁ prf) prf₁)
step-correct₂ (R ∪ R₁) c s (un₁ prf) = un₁ (step-correct₂ R c s prf)
step-correct₂ (R ∪ R₁) c s (un₂ prf) = un₂ (step-correct₂ R₁ c s prf)
step-correct₂ (R ⋆)    c s prf with star⁻¹′ prf
... | inj₂ (x , t₁ , t₂ , eq , prf , prf₁) =
  subst₂ Matches (cong (λ - → step R - ∘ (R ⋆)) (∷-injectiveˡ eq)) (∷-injectiveʳ eq)
    (comp (step-correct₂ R x t₁ prf) prf₁)

steps-correct₁ : ∀ R s → Matches (steps R s) [] → Matches R s
steps-correct₁ R []      prf = prf
steps-correct₁ R (x ∷ s) prf = step-correct₁ R x s (steps-correct₁ (step R x) s prf)

steps-correct₂ : ∀ R s → Matches R s → Matches (steps R s) []
steps-correct₂ R []      prf = prf
steps-correct₂ R (x ∷ s) prf = steps-correct₂ (step R x) s (step-correct₂ R x s prf)

check-lemma₁ : ∀ R s → Nullable (steps R s) → Matches R s
check-lemma₁ R s null = steps-correct₁ R s (nullable-correct₁ (steps R s) null)

check-lemma₂ : ∀ R s → Matches R s → Nullable (steps R s)
check-lemma₂ R s prf = nullable-correct₂ (steps R s) (steps-correct₂ R s prf)

check : (R : Regex) (s : List Char) → Dec (Matches R s)
check R s with nullable? (steps R s)
... | yes p = yes (check-lemma₁ R s p)
... | no p = no λ m → p (check-lemma₂ R s m)