-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAlgebraicGraph.hs
248 lines (189 loc) · 8.18 KB
/
AlgebraicGraph.hs
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
module AlgebraicGraph where
import qualified Data.Set as S
data AlgebraicGraph a
= Empty
| Node a
| Overlay (AlgebraicGraph a) (AlgebraicGraph a)
| Connect (AlgebraicGraph a) (AlgebraicGraph a)
-- (1, 2), (1, 3)
angle :: AlgebraicGraph Int
angle = Connect (Node 1) (Overlay (Node 2) (Node 3))
-- (1, 2), (1, 3), (2, 3)
triangle :: AlgebraicGraph Int
triangle = Connect (Node 1) (Connect (Node 2) (Node 3))
{-
*** TODO ***
Mulțimea nodurilor grafului.
Hint: S.union
-}
nodes :: Ord a => AlgebraicGraph a -> S.Set a
nodes Empty = (S.fromList [])
nodes (Node a) = (S.fromList [a])
nodes (Overlay a b) = (S.union (nodes a) (nodes b))
nodes (Connect a b)= (S.union (nodes a) (nodes b))
{-
*** TODO ***
Mulțimea arcelor grafului.
Hint: S.union, S.cartesianProduct
-}
edges :: Ord a => AlgebraicGraph a -> S.Set (a, a)
edges Empty = (S.fromList [])
edges (Node a) = (S.fromList [(a,a)])
edges (Overlay a b) = (S.filter (\(x, y) -> x /= y) (S.union (edges a) (edges b)))
edges (Connect a b) = (S.filter (\(x, y) -> x /= y) (S.union (S.cartesianProduct (nodes a) (nodes b)) (S.union (edges a) (edges b))))
{-
*** TODO ***
Mulțimea nodurilor înspre care pleacă arce dinspre nodul curent.
ATENȚIE! NU folosiți funcția edges definită mai sus, pentru că ar genera
prea multe muchii inutile.
-}
outNeighbors :: Ord a => a -> AlgebraicGraph a -> S.Set a
outNeighbors node Empty = (S.fromList [])
outNeighbors node (Node a) = (S.fromList [])
outNeighbors node (Overlay a b) = (S.union (outNeighbors node a) (outNeighbors node b))
outNeighbors node (Connect a b)
| (node `S.member` (nodes a)) || (node `S.member` (nodes b)) = (if (node `S.member` (nodes a)) then (nodes b) else (outNeighbors node b))
| otherwise = (S.fromList [])
{-
*** TODO ***
Mulțimea nodurilor dinspre care pleacă arce înspre nodul curent.
ATENȚIE! NU folosiți funcția edges definită mai sus, pentru că ar genera
prea multe muchii inutile.
-}
inNeighbors :: Ord a => a -> AlgebraicGraph a -> S.Set a
inNeighbors node Empty = (S.fromList [])
inNeighbors node (Node a) = (S.fromList [])
inNeighbors node (Overlay a b) = (S.union (inNeighbors node a) (inNeighbors node b))
inNeighbors node (Connect a b)
| (node `S.member` (nodes a)) || (node `S.member` (nodes b)) = (if (node `S.member` (nodes b)) then (S.union (inNeighbors node b) (nodes a)) else (inNeighbors node a))
| otherwise = (S.fromList [])
{-
*** TODO ***
Instanțiați clasa Num cu tipul (AlgebraicGraph a), astfel încât:
- un literal întreg să fie interpretat ca un singur nod cu eticheta egală
cu acel literal
- operația de adunare să fie intepretată ca Overlay
- operația de înmulțire să fie interpretată drept Connect.
Celelalte funcții din clasă nu sunt relevante. Veți obține warning-uri
pentru neimplementarea lor, dar puteți să le ignorați.
După instanțiere, veți putea evalua în consolă expresii ca:
> 1 :: AlgebraicGraph Int
Node 1
> 1*(2+3) :: AlgebraicGraph Int
Connect (Node 1) (Overlay (Node 2) (Node 3))
-}
instance Num a => Num (AlgebraicGraph a) where
fromInteger = Node . fromInteger
(+) x y = (Overlay x y)
(*) x y = (Connect x y)
{-
*** TODO ***
Instanțiați clasa Show cu tipul (AlgebraicGraph a), astfel încât
reprezentarea sub formă de șir de caractere a unui graf să reflecte
expresiile aritmetice definite mai sus. Puteți pune un nou rând de paranteze
la fiecare subexpresie compusă.
Exemple:
> Node 1
1
> Connect (Node 1) (Overlay (Node 2) (Node 3))
(1*(2+3))
-}
instance Show a => Show (AlgebraicGraph a) where
show Empty = ""
show (Node x) = show x
show (Overlay a b) = ('(' : []) ++ (show a) ++ ('+' : []) ++ (show b) ++ (')' : [])
show (Connect a b) = ('(' : []) ++ (show a) ++ ('*' : []) ++ (show b) ++ (')' : [])
{-
*** TODO ***
Observați că instanța predefinită de Eq pentru tipul (AlgebraicGraph a)
nu surprinde corect egalitatea a două grafuri, deoarece același graf
conceptual poate avea două descrieri simbolice diferite.
Prin urmare, instanțiați clasa Eq cu tipul (AlgebraicGraph a), astfel încât
să comparați propriu-zis mulțimile de noduri și de arce.
Exemple:
> Node 1 == 1
True
> Node 1 == 2
False
> angle == 1*2 + 1*3
True
> triangle == (1*2)*3
True
-}
instance Ord a => Eq (AlgebraicGraph a) where
g1 == g2 = (edges g1) == (edges g2) && (nodes g1) == (nodes g2)
{-
*** TODO ***
Extinde un graf existent, atașând noi subgrafuri arbitrare în locul nodurilor
individuale. Funcția primită ca prim parametru determină această
corespondență între noduri și subgrafuri. Observați că tipul etichetelor
noi (b) poate diferi de al etichetelor vechi (a).
Exemplu:
> extend (\n -> if n == 1 then 4+5 else Node n) $ 1*(2+3)
((4+5)*(2+3))
-}
extend :: (a -> AlgebraicGraph b) -> AlgebraicGraph a -> AlgebraicGraph b
extend f Empty = Empty
extend f (Node a) = (f a)
extend f (Overlay a b) = (Overlay (extend f a) (extend f b))
extend f (Connect a b) = (Connect (extend f a) (extend f b))
remove :: Eq a => a -> AlgebraicGraph a -> AlgebraicGraph a
remove node graph = (extend (\n -> (if node == n then Empty else (Node n))) graph)
{-
*** TODO ***
Divizează un nod în mai multe noduri, cu eliminarea nodului inițial.
Arcele în care era implicat vechiul nod trebuie să devină valabile
pentru noile noduri.
Implementați splitNode folosind extend!
-}
splitNode :: Eq a
=> a -- nodul divizat
-> [a] -- nodurile cu care este înlocuit
-> AlgebraicGraph a -- graful existent
-> AlgebraicGraph a -- graful obținut
splitNode node targets graph = (remove node (foldl (\acc x -> (extend (\n -> (if node == n then ((Overlay (Node x) (Node node))) else (Node n))) acc)) graph targets))
{-
*** TODO ***
Instanțiați clasa Functor cu constructorul de tip AlgebraicGraph, astfel
încât să puteți aplica o funcție pe toate etichetele unui graf.
fmap reprezintă generalizarea lui map pentru orice fel de structură.
Implementați fmap folosind extend!
Exemplu:
> fmap (+ 10) $ 1*(2+3) :: AlgebraicGraph Int
(11*(12+13))
-}
instance Functor AlgebraicGraph where
-- fmap :: (a -> b) -> AlgebraicGraph a -> AlgebraicGraph b
fmap f graph = (extend (\n -> (Node (f n))) graph)
{-
*** TODO ***
Îmbină mai multe noduri într-unul singur, pe baza unei proprietăți
respectate de nodurile îmbinate, cu eliminarea acestora. Arcele în care
erau implicate vechile noduri vor referi nodul nou.
Implementați mergeNodes folosind fmap!
-}
mergeNodes :: (a -> Bool) -- proprietatea îndeplinită de nodurile îmbinate
-> a -- noul nod
-> AlgebraicGraph a -- graful existent
-> AlgebraicGraph a -- graful obținut
mergeNodes prop node graph = (fmap (\n -> (if (prop n) then node else n)) graph)
{-
*** TODO ***
Filtrează un graf, păstrând doar nodurile care satisfac proprietatea dată.
Implementați filterGraph folosind extend!
Exemplu:
> nodes $ filterGraph odd $ 1*(2+3)
fromList [1,3]
> edges $ filterGraph odd $ 1*(2+3)
fromList [(1,3)]
-}
filterGraph :: (a -> Bool) -> AlgebraicGraph a -> AlgebraicGraph a
filterGraph prop graph = (extend (\n -> (if (prop n) then (Node n) else Empty)) graph)
{-
*** TODO ***
Întoarce graful rezultat prin eliminarea unui nod și a arcelor în care
acesta este implicat. Dacă nodul nu există, se întoarce același graf.
Implementați removeNode folosind filterGraph!
-}
removeNode :: Eq a => a -> AlgebraicGraph a -> AlgebraicGraph a
removeNode node graph = (filterGraph (\n -> (if n == node then False else True)) graph)