forked from brenden/ukkonen-animation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUkkonenTree.elm
189 lines (148 loc) · 4.36 KB
/
UkkonenTree.elm
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
module UkkonenTree (..) where
import IntDict exposing (..)
import Dict exposing (..)
import String exposing (..)
import Json.Encode as Json
import Debug
type alias NodeId =
Int
type alias UkkonenTree =
IntDict UkkonenNode
type alias UkkonenNode =
{ edges : Dict Char UkkonenEdge
, suffixLink : Maybe NodeId
}
type alias UkkonenEdge =
{ pointingTo : NodeId
, labelStart : Int
, labelEnd : ClosingIndex
}
type ClosingIndex
= Definite Int
| EndOfString
{-| Create an empty tree
-}
emptyTree : UkkonenTree
emptyTree =
let
newNode = { edges = Dict.empty, suffixLink = Nothing }
in
IntDict.insert 0 newNode IntDict.empty
{-| Get the edge that starts with `char`
-}
getEdge : NodeId -> Char -> UkkonenTree -> Maybe UkkonenEdge
getEdge nodeId char tree =
case IntDict.get nodeId tree of
Just node ->
Dict.get char node.edges
Nothing ->
Debug.crash "Active point is set to a node that doesn't exist"
{-| Add `edge` that starts with `char`
-}
setEdge : NodeId -> NodeId -> Char -> Int -> ClosingIndex -> UkkonenTree -> UkkonenTree
setEdge fromId toId char labelStart labelEnd tree =
let
node = getNode fromId tree
newEdge =
{ pointingTo = toId
, labelStart = labelStart
, labelEnd = labelEnd
}
newEdges = Dict.insert char newEdge node.edges
newNode = { node | edges = newEdges }
in
IntDict.insert fromId newNode tree
{-| Get the node associated with given id
-}
getNode : NodeId -> UkkonenTree -> UkkonenNode
getNode nodeId tree =
case IntDict.get nodeId tree of
Just node ->
node
Nothing ->
Debug.crash "Tried to reference a node that does't exist"
{-| Add a new node to the graph
-}
addNode : UkkonenTree -> ( UkkonenTree, NodeId )
addNode tree =
let
count = IntDict.size tree
newNode = { edges = Dict.empty, suffixLink = Nothing }
newTree = IntDict.insert count newNode tree
in
( newTree, count )
{-| Set the suffix link of a node
-}
setSuffixLink : NodeId -> NodeId -> UkkonenTree -> UkkonenTree
setSuffixLink fromId toId tree =
let
node = getNode fromId tree
in
IntDict.insert fromId { node | suffixLink = Just toId } tree
{-| Prints out a representation of the tree
-}
toString : UkkonenTree -> String
toString =
toString' 0 0
toString' level rootId tree =
let
root = getNode rootId tree
spaces = (String.repeat level " ")
in
spaces
++ (Basics.toString rootId)
++ newLine
++ (String.concat
(Dict.values
(Dict.map
(\edgeLabel ->
\edge ->
spaces
++ (Basics.toString edgeLabel)
++ "->"
++ newLine
++ (toString'
(level + 1)
edge.pointingTo
tree
)
)
root.edges
)
)
)
{-| Convenince method for bulding strings that contain newlines
-}
newLine =
"""
"""
{- Get the string an edge represents -}
edgeString : UkkonenEdge -> String -> String
edgeString edge string =
let labelEnd = case edge.labelEnd of
Definite val -> val
EndOfString -> -1
in
slice
edge.labelStart
labelEnd
string
{-| Gets all suffixes represented in the tree
-}
suffixes : UkkonenTree -> NodeId -> String -> List String
suffixes tree rootId string =
let
root = getNode rootId tree
in
if Dict.size root.edges == 0 then
[""]
else
List.concatMap
(\ edge ->
let edgeLabel = edgeString edge string
in
List.map
(\ childSuffix -> edgeLabel ++ childSuffix)
(suffixes tree edge.pointingTo string)
)
(Dict.values root.edges)