-
Notifications
You must be signed in to change notification settings - Fork 28
/
contextOperator.py
240 lines (175 loc) · 12.9 KB
/
contextOperator.py
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
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Contextual Anomaly Detector - Open Source Edition
# Copyright (C) 2016, Mikhail Smirnov smirmik@gmail.com
# https://github.com/smirmik/CAD
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero Public License version 3 as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero Public License for more details.
#
# You should have received a copy of the GNU Affero Public License along with
# this program. If not, see http://www.gnu.org/licenses.
#
# ------------------------------------------------------------------------------
class ContextOperator():
def __init__(self, maxLeftSemiContextsLenght):
self.maxLeftSemiContextsLenght = maxLeftSemiContextsLenght
self.factsDics = [{},{}]
self.semiContextDics = [{},{}]
self.semiContextValuesLists = [[],[]]
self.crossedSemiContextsLists = [[],[]]
self.contextsValuesList = []
self.newContextID = False
def getContextByFacts (self, newContextsList, zerolevel = 0 ) :
"""
The function which determines by the complete facts list whether the context
is already saved to the memory. If the context is not found the function
immediately creates such. To optimize speed and volume of the occupied memory
the contexts are divided into semi-contexts as several contexts can contain
the same facts set in its left and right parts.
@param newContextsList: list of potentially new contexts
@param zerolevel: flag indicating the context type in
transmitted list
@return : depending on the type of potentially new context transmitted as
an input parameters the function returns either:
а) flag indicating that the transmitted zero-level context is
a new/existing one;
or:
b) number of the really new contexts that have been saved to the
context memory.
Функция, которая по полному списку фактов определяет существует ли уже в памяти
данный контекст и в случае, если такого контекста нет - сразу создаёт его.
Для оптимизации быстродействия и объема занимаемой оперативной памяти контексты
разделены на полуконтексты, в связи с тем, что сразу несколько контекстов могут
содержать одинаковый набор фактов в левой или правой части.
@param newContextsList: список потенциально новых контекстов
@param zerolevel: флаг, указывающий на то, какой тип контекстов
в передаваемом списке
@return : в зависимости от того, какой тип потенциально новых контекстов был
передан в качестве входных параметров, функция возвращает либо:
а) флаг, указывающий на то, что переданный контекст нулевого
уровня является новым/существующим,
либо:
б) количество контекстов, которые действительно оказались новыми
и были сохранены в памяти контекстов.
"""
numAddedContexts = 0
for leftFacts, rightFacts in newContextsList :
leftHash = leftFacts.__hash__()
rightHash = rightFacts.__hash__()
nextLeftSemiContextNumber = len(self.semiContextDics[0])
leftSemiContextID = self.semiContextDics[0].setdefault(leftHash, nextLeftSemiContextNumber)
if leftSemiContextID == nextLeftSemiContextNumber :
leftSemiContextValues = [[] , len(leftFacts), 0, {}]
self.semiContextValuesLists[0].append(leftSemiContextValues)
for fact in leftFacts :
semiContextList = self.factsDics[0].setdefault(fact, [])
semiContextList.append(leftSemiContextValues)
nextRightSemiContextNumber = len(self.semiContextDics[1])
rightSemiContextID = self.semiContextDics[1].setdefault(rightHash, nextRightSemiContextNumber)
if rightSemiContextID == nextRightSemiContextNumber :
rightSemiContextValues = [[] , len(rightFacts), 0]
self.semiContextValuesLists[1].append(rightSemiContextValues)
for fact in rightFacts :
semiContextList = self.factsDics[1].setdefault(fact, [])
semiContextList.append(rightSemiContextValues)
nextFreeContextIDNumber = len(self.contextsValuesList)
contextID = self.semiContextValuesLists[0][leftSemiContextID][3].setdefault(rightSemiContextID, nextFreeContextIDNumber)
if contextID == nextFreeContextIDNumber :
numAddedContexts += 1
contextValues = [0, zerolevel, leftHash, rightHash]
self.contextsValuesList.append(contextValues)
if zerolevel :
self.newContextID = contextID
return True
else :
contextValues = self.contextsValuesList[contextID]
if zerolevel :
contextValues[1] = 1
return False
return numAddedContexts
def contextCrosser(self, leftOrRight, factsList, newContextFlag = False, potentialNewContexts = []):
if leftOrRight == 0 :
if len(potentialNewContexts) > 0 :
numNewContexts = self.getContextByFacts (potentialNewContexts)
else :
numNewContexts = 0
for semiContextValues in self.crossedSemiContextsLists[leftOrRight] :
semiContextValues[0] = []
semiContextValues[2] = 0
for fact in factsList :
for semiContextValues in self.factsDics[leftOrRight].get(fact, []) :
semiContextValues[0].append(fact)
newCrossedValues = []
for semiContextValues in self.semiContextValuesLists[leftOrRight] :
lenSemiContextValues0 = len(semiContextValues[0])
semiContextValues[2] = lenSemiContextValues0
if lenSemiContextValues0 > 0 :
newCrossedValues.append(semiContextValues)
self.crossedSemiContextsLists[leftOrRight] = newCrossedValues
if leftOrRight :
return self.updateContextsAndGetActive(newContextFlag)
else :
return numNewContexts
def updateContextsAndGetActive(self, newContextFlag):
"""
This function reviews the list of previously selected left semi-contexts,
creates the list of potentially new contexts resulted from intersection
between zero-level contexts, determines the contexts that coincide with
the input data and require activation.
@param newContextFlag: flag indicating that a new zero-level
context is not recorded at the current
step, which means that all contexts
already exist and there is no need to
create new ones.
@return activeContexts: list of identifiers of the contexts which
completely coincide with the input stream,
should be considered active and be
recorded to the input stream of “neurons”
@return potentialNewContextList: list of contexts based on intersection
between the left and the right zero-level
semi-contexts, which are potentially new
contexts requiring saving to the context
memory
Эта функция производит обход по списку отобранных ранее левых полуконтекстов,
создаёт список контекстов, которые являются результатом пересечения контекстов
нулевого уровня и могут быть новыми, определяет какие контексты полностью совпали
входными данными и их надо активировать.
@param newContextsFlag: флаг, указывающий на то, что на текущем шаге не был
записан новый контекст нулевого уровня, а значит не
нужно создавать путем пересечения новые контексты,
т.к. они все уже созданы ранее
@return activeContexts: список индентификаторов контекстов, полностью
совпавших с входным потоком, которые нужно считать
активными и записать во входной поток "нейроны"
@return potentialNewContextList: список контекстов, созданных на основе
пересечения левых и правых полуконтекстов нулевого
уровня, и потенциально являющихся новыми
контекстами, которые нужно запомнить в памяти
контекстов
"""
activeContexts = []
numSelectedContext = 0
potentialNewContextList = []
for leftSemiContextValues in self.crossedSemiContextsLists[0] :
for rightSemiContextID, contextID in leftSemiContextValues[3].iteritems() :
if self.newContextID != contextID :
contextValues = self.contextsValuesList[contextID]
rightSemiContextValue0, rightSemiContextValue1, rightSemiContextValue2 = self.semiContextValuesLists[1][rightSemiContextID]
if leftSemiContextValues[1] == leftSemiContextValues[2] :
numSelectedContext += 1
if rightSemiContextValue2 > 0 :
if rightSemiContextValue1 == rightSemiContextValue2 :
contextValues[0] += 1
activeContexts.append([contextID, contextValues[0], contextValues[2], contextValues[3]])
elif contextValues[1] and newContextFlag and leftSemiContextValues[2] <= self.maxLeftSemiContextsLenght :
potentialNewContextList.append(tuple([tuple(leftSemiContextValues[0]), tuple(rightSemiContextValue0)]))
elif contextValues[1] and newContextFlag and rightSemiContextValue2 > 0 and leftSemiContextValues[2] <= self.maxLeftSemiContextsLenght :
potentialNewContextList.append(tuple([tuple(leftSemiContextValues[0]), tuple(rightSemiContextValue0)]))
self.newContextID = False
return activeContexts, numSelectedContext, potentialNewContextList