-
Notifications
You must be signed in to change notification settings - Fork 1
/
auxClasses.py
191 lines (165 loc) · 6.72 KB
/
auxClasses.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
"""
@author: sibirbil
"""
import numpy as np
class SklearnEstimator:
'''
This base class is dummy, just for guideline. Sklearn does not
provide a base class that has both fit and predict
'''
def fit(self, X: np.array, y: np.array):
raise NotImplementedError('Needs to implement fit(X, y)')
def predict(self, X0: np.array):
raise NotImplementedError('Needs to implement predict(X, y)')
class Coefficients:
def __init__(self, yvals=np.empty(shape=(0), dtype=np.float64),
rows=np.empty(shape=(0), dtype=np.int32),
cols=np.empty(shape=(0), dtype=np.int32),
costs=np.empty(shape=(0), dtype=np.float64)):
self.yvals = yvals
self.rows = rows
self.cols = cols
self.costs = costs
def _cleanup(self):
self.yvals = np.empty(shape=(0), dtype=np.float64)
self.rows=np.empty(shape=(0), dtype=np.int32)
self.cols=np.empty(shape=(0), dtype=np.int32)
self.costs=np.empty(shape=(0), dtype=np.float64)
class Clause:
def __init__(self, feature=None, ub=np.inf, lb=-np.inf):
self.feature = feature # used feature
self.ub = ub # upper bound
self.lb = lb # lower bound
def _toText(self, feature_names=None):
# returnString = ''
# if (self.lb != -np.inf and self.ub != np.inf):
# returnString += '{:.2f}'.format(self.lb) + ' < ' + \
# 'x[' + str(self.feature) + ']' + ' <= ' + '{:.2f}'.format(self.ub)
# else:
# if (self.lb != -np.inf):
# returnString += 'x[' + str(self.feature) + ']' + \
# ' > ' + '{:.2f}'.format(self.lb)
# if (self.ub != np.inf):
# returnString += 'x[' + str(self.feature) + ']' + \
# ' <= ' + '{:.2f}'.format(self.ub)
# return returnString
returnString = ''
if feature_names is None:
if (self.lb != -np.inf and self.ub != np.inf):
returnString += '{:.2f}'.format(self.lb) + ' < ' + \
'x[' + str(self.feature) + ']' + ' <= ' + '{:.2f}'.format(self.ub)
else:
if (self.lb != -np.inf):
returnString += 'x[' + str(self.feature) + ']' + \
' > ' + '{:.2f}'.format(self.lb)
if (self.ub != np.inf):
returnString += 'x[' + str(self.feature) + ']' + \
' <= ' + '{:.2f}'.format(self.ub)
else:
if (self.lb != -np.inf and self.ub != np.inf):
returnString += '{:.2f}'.format(self.lb) + ' < ' + \
feature_names[self.feature] + ' <= ' + '{:.2f}'.format(self.ub)
else:
if (self.lb != -np.inf):
returnString += feature_names[self.feature] + \
' > ' + '{:.2f}'.format(self.lb)
if (self.ub != np.inf):
returnString += feature_names[self.feature] + \
' <= ' + '{:.2f}'.format(self.ub)
return returnString
def printClause(self):
print(self._toText())
# print(self._toText(feature_names))
def _checkArray(self, X):
# Converts input to a double array
if (type(X) != np.ndarray):
X = np.array(X)
if (len(X.shape) == 0):
X = np.array([[X]])
if (len(X.shape) == 1):
X = np.array([X])
return X
def checkClause(self, X):
X = self._checkArray(X)
n = len(X)
returnList = np.array(n * [False])
for indx, x0 in enumerate(X):
val = x0[self.feature]
if (self.lb != -np.inf and self.ub != np.inf):
if (self.lb < val and val <= self.ub):
returnList[indx] = True
else:
if (self.lb != -np.inf):
if (self.lb < val):
returnList[indx] = True
if (self.ub != np.inf):
if (val <= self.ub):
returnList[indx] = True
return returnList
class Rule:
def __init__(self, label=None, clauses=[], weight=None):
self.label = label # class
self.clauses = clauses # clauses
self.weight = weight # weight
self.cleaned = False
def _toText(self, feature_names=None):
returnString = ''
for clause in self.clauses:
returnString += clause._toText(feature_names) + '\n'
if (len(self.clauses) == 0): # No Rule
returnString += '# No Rule #'
return returnString
def addClause(self, clause):
if (self.clauses == []):
self.clauses = [clause]
else:
self.clauses.append(clause)
def length(self):
if (~self.cleaned):
self._cleanRule()
self.cleaned = True
return len(self.clauses)
def printRule(self, feature_names=None):
if (~self.cleaned):
self._cleanRule()
self.cleaned = True
print(self._toText(feature_names))
def _checkArray(self, X):
# Converts input to a double array
if (type(X) != np.ndarray):
X = np.array(X)
if (len(X.shape) == 0):
X = np.array([[X]])
if (len(X.shape) == 1):
X = np.array([X])
return X
def checkRule(self, X):
X = self._checkArray(X)
n = len(X)
returnList = np.array(n * [False])
trueSampleIndices = np.array(range(n))
for clause in self.clauses:
remOnes = clause.checkClause(X[trueSampleIndices, :])
trueSampleIndices = trueSampleIndices[remOnes]
if (trueSampleIndices.size == 0):
break
returnList[trueSampleIndices] = True
return returnList
def _cleanRule(self):
# TODO: Probably can be done more efficiently
# but overhead is negligible
if (~self.cleaned):
n = len(self.clauses)
remainingRules = set(range(n))
for i in range(n-1):
ci = self.clauses[i]
for j in range(i+1, n):
cj = self.clauses[j]
if (ci.feature == cj.feature):
ci.ub = np.min([ci.ub, cj.ub])
ci.lb = np.max([ci.lb, cj.lb])
if (j in remainingRules):
remainingRules.remove(j)
newClauses = [self.clauses[i] for i in remainingRules]
self.clauses = newClauses
self.cleaned = True