Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

""" This module abstracts all operations on the Ontology index.  It is used for 

every read operation on the Ontology. It eases access to the Ontology and 

protects the data structures from direct user access. 

 

This module contains: 

 

- IndexAbstractor: The interface to the Ontology index. 

- AbstractGraph: An object containing selected graph nodes and relations. 

- AbstractGraphNode: A node in a AbstractGraph 

- DotGraph: A Graphical representation of an AbstractGraph with DOT 

 

""" 

 

from io import StringIO 

 

import string 

 

from pysumo.wordnet import WordNet 

 

class IndexAbstractor: 

    """ The IndexAbstractor provides a high-level index of the 

    AbstractSyntaxTree.  Each Ontology is represented by a hashmap, the list of 

    these hashmaps is the index.  Average access time is in O(n) where n is the 

    number of loaded Ontologies. 

 

    Variables: 

 

    - root: The root AbstractSyntaxTree node. 

    - ontologies: The list of currently active Ontologies. 

    - index: The index of all terms in the currently active Ontologies. 

    - wordnet: A reference to the Object containing the SUMO-WordNet mapping. 

 

    Methods: 

 

    - init_wordnet: Initializes the WordNet mapping. 

    - update_index: Updates the index. 

    - search: Searches for a term in the Ontology. 

    - get_ontology_file: Return an in-memory file object for an Ontology. 

    - get_completions: Return a list of possible completions for the current index. 

    - get_graph: Creates an abstract graph containing a view of the Ontology. 

    - wordnet_locate: Returns information about a term from WordNet. 

 

    """ 

 

    def __init__(self): 

        """ Initializes the IndexAbstractor object. """ 

        self.root = None 

        self.ontologies = set() 

        self.index = dict() 

        self.wordnet = None 

 

    def init_wordnet(self): 

        """ Initializes the SUMO mapping to WordNet. """ 

        if self.wordnet is None: 

            self.wordnet = WordNet() 

 

    def update_index(self, ast): 

        """ Updates the index with all new AST nodes in ast. """ 

        self.root = ast 

        self.index = dict() 

        self._build_index() 

 

    def _build_index(self): 

        """ Builds an index from self.root. """ 

        for child in self.root.children: 

            self.ontologies.add(child.ontology) 

            key = normalize(child.children[0].name) 

            asts = self.index.get(key, list()) 

            asts.append(child) 

            self.index[key] = asts 

 

    def get_ontology_file(self, ontology): 

        """ Returns an in-memory file object for the Kif representation of ontology. """ 

        if ontology in self.ontologies: 

            ret = StringIO() 

            ontology.action_log.current.seek(0) 

            ret.write(ontology.action_log.current.read().decode('utf8')) 

            ontology.action_log.current.seek(0) 

            ret.seek(0) 

            return ret 

 

    def get_completions(self): 

        """ Returns a list of possible completions for the currently loaded ontologies. """ 

        return [x[0].children[0].name for x in self.index.values()] 

 

    def search(self, term): 

        """ Search for term in the in-memory Ontology. Returns all objects that 

        match the search. 

 

        Returns: 

 

        - {Ontology : (String, int)[]} 

 

        """ 

        term = normalize(term) 

        ret = {x: list() for x in self.ontologies} 

        for ast in self.index.get(term, []): 

            ret[ast.ontology].append((repr(ast), ast.line)) 

        return ret 

 

    def _find_term(self, term): 

        """ Returns the denormalized version of term. """ 

        term = normalize(term) 

        try: 

            return self.index[term][0].children[0].name 

        except KeyError: 

            pass 

        raise KeyError('%s not in index.' % term) 

 

    def get_graph(self, variant, major=2, minor=1, root=None, depth=None): 

        """ Returns a hierarchical view of the Ontology. 

 

        Arguments: 

 

        - variant: The list of terms against which the resulting AbstractGraph matches. 

        - major: The position of the parent element. 

        - minor: The position of the child element. 

        - root: The root node to which all other nodes are related. 

        - depth: The recursion depth. 

 

        Returns: 

 

        - AbstractGraph 

 

        Raises: 

 

        - KeyError 

 

        """ 

        if variant is None: 

            return AbstractGraph(None, None, None, None, None, self.ontologies) 

        else: 

            var = [(x, normalize(y)) for x, y in variant] 

            try: 

                root = self._find_term(root) 

            except AttributeError: 

                pass 

            return AbstractGraph(var, major, minor, root, depth, self.index) 

 

    def wordnet_locate(self, term): 

        """ Use the mapping from SUMO to WordNet to retrieve information about a term. 

 

        Arguments: 

 

        - term: the term to locate 

 

        Returns: 

 

        - String[] 

 

        Raises: 

 

        - KeyError 

 

        """ 

        try: 

            term = self._find_term(term) 

            results = self.wordnet.locate_term(term) 

        except KeyError: 

            results = self._synonym_locate(normalize(term)) 

        except AttributeError: 

            self.init_wordnet() 

            results = self.wordnet.locate_term(term) 

        return [' '.join([x[0], ''.join(['(', x[1].value, '):']), x[2]]) for x in results] 

 

    def _synonym_locate(self, term): 

        try: 

            ret = list() 

            synset = self.wordnet.find_synonym(term) 

            for syn in synset: 

                ret.extend(self.wordnet.locate_term(syn)) 

            return ret 

        except AttributeError: 

            self.init_wordnet() 

            return self._synonym_locate(term) 

 

class AbstractGraph: 

    """ An abstract representation of a subset of an Ontology as a collection 

    of nodes and relations. 

 

    Variables: 

 

    - nodes: The list of graph nodes. 

    - relations: An adjacency matrix of all the paths in the graph. 

 

    """ 

 

    def __init__(self, variant, major, minor, root, depth, info): 

        """ Initializes the AbstractGraph and instantiates variables. """ 

        self.nodes = [] 

        self.relations = dict() 

        self._settings = (variant, major, minor, root, depth) 

        if variant is None: 

            self._ontology_graph(info) 

        else: 

            self._relation_graph(info) 

            if root is not None: 

                self.nodes = sorted(self._filter_root(root, 0)) 

                self.nodes.append(root) 

                self.relations = { 

                    x: y for x, y in self.relations.items() if x in self.nodes} 

 

    def _ontology_graph(self, ontologies): 

        """ Produces an AbstractGraph of all the currently active ontologies. """ 

        self.nodes = [AbstractGraphNode(x) for x in ontologies] 

 

    def _check_matches(self, node): 

        """ Checks if node matches the variant. """ 

        try: 

            for pos, val in self._settings[0]: 

                if pos == 0 and node.name != val: 

                    return False 

                elif pos != 0 and node.children[pos - 1].name != val: 

                    return False 

            return True 

        except IndexError: 

            return False 

 

    def _relation_graph(self, index): 

        """ Produces an AbstractGraph containing all relations of type variant. """ 

        major_pos = self._settings[1] 

        minor_pos = self._settings[2] 

        node_set = set() 

        for ast in index.values(): 

            for node in ast: 

                if self._check_matches(node): 

                    minor = node.children[minor_pos - 1].name 

                    major = node.children[major_pos - 1].name 

                    node_set.add(AbstractGraphNode(minor)) 

                    node_set.add(AbstractGraphNode(major)) 

                    relation = self.relations.get(major, set()) 

                    relation.add(minor) 

                    self.relations[major] = relation 

        self.nodes = sorted(node_set) 

 

    def _filter_root(self, root, depth): 

        """ Filters the AbstractGraph so only children of root are kept up to a maximum depth. """ 

        try: 

            if depth >= self._settings[4]: 

                return set() 

        except TypeError: 

            pass 

        try: 

            rel = set(self.relations[root]) 

        except KeyError: 

            return set() 

        for minor in self.relations[root]: 

            try: 

                rel = rel.union(self._filter_root(minor, depth + 1)) 

            except KeyError: 

                rel.add(minor) 

        return rel 

 

 

class AbstractGraphNode: 

    """ A node in an AbstractGraph. Contains information necessary to recreate 

    an AbstractSyntaxTree from an AbstractGraph. 

 

    Varibles: 

 

    - name: The name of the AbstractGraphNode. 

 

    """ 

 

    def __init__(self, name): 

        """ Initializes an AbstractGraphNode and instantiates variables. """ 

        self.name = name 

 

    def __eq__(self, other): 

        return self.name == other.name 

 

    def __ne__(self, other): 

        return not self.__eq__(other) 

 

    def __lt__(self, other): 

        return self.name < other.name 

 

    def __repr__(self): 

        return str(self.name) 

 

    def __hash__(self): 

        return hash(self.name) 

 

 

def normalize(term): 

    """ Normalizes term to aid in searching. """ 

    for p in string.punctuation: 

        term = term.replace(p, '') 

    return term.lower().strip()