1 """This a helper module for multivariance.py"""
2
3 import Num
4 import multivariance_classes as M
5 import random
6 import g_implements
7
10 self.classid = classid
11 self.value = vector
12
13
15 """You either give it a complete dataset to look at,
16 including class IDs, *or* the dimensionality of the data
17 (ndim) and a map between classids and integers.
18 This map can be obtained from nice_hash.
19 """
20 import dictops
21
22 if dataset is not None:
23 assert details is None
24 assert ndim is None and idmap is None
25 import nice_hash
26 assert (ndim is None) and (idmap is None)
27 h = nice_hash.nice_hash(lambda x:x)
28 for t in dataset:
29 assert g_implements.impl(t, datum_c), \
30 "Bad input type: %s" % g_implements.why(t, datum_c)
31 h.add(t.classid)
32 ndim = len(dataset[0].value)
33 idmap = h.map()
34 elif details is not None:
35 assert ndim is None and idmap is None
36 ndim = details.ndim()
37 idmap = details.id_to_int
38 assert (ndim is not None) and (idmap is not None)
39 self.Nmu = len(idmap)
40 self.id_to_int = idmap.copy()
41 self.int_to_id = dictops.rev1to1(idmap)
42
43
44 for i in range(len(self.int_to_id)):
45 assert i in self.int_to_id, "Not a good mapping to indices."
46
47
49 __doc__ = """This describes a quadratic model of a known size,
50 with multiple means
51 (one for each different class of data)."""
52
53 - def __init__(self, dataset=None, ndim=None, idmap=None, details=None):
56 __init__.__doc__ = _multi_mu__init__.__doc__
57
58
60 m = self.ndim()
61 return self.Nmu*m + (m*(m+1))/2
62
63
65 m = self.ndim()
66 assert len(prms) == self.modeldim()
67 mu = {}
68 for i in range(self.Nmu):
69 mu[self.int_to_id[i]] = prms[i*m:(i+1)*m]
70
71 invsigma = Num.zeros((m, m), Num.Float)
72 j = self.Nmu*m
73 for i in range(m):
74 tmp = prms[j:j+(m-i)]
75 invsigma[i,i:] = tmp
76 invsigma[i:,i] = tmp
77 j += m-i
78 return self.new(mu, invsigma)
79
80
81 - def new(self, mu, invsigma, bias=0.0):
82 """Mu is a mapping of classids to vectors. invsigma is a square matrix."""
83
84 assert type(mu) == type({})
85
86 return multi_mu_with_numbers(mu, invsigma, self, bias)
87
88
111
112
114 - def __init__(self, mu, invsigma, details, bias=0.0, offset=None):
115 """self.mu, self.invsigma, and self._offset should be considered
116 read-only for all users of this class."""
117 assert isinstance(details, multi_mu)
118 M.model_with_numbers.__init__(self, details, bias)
119 self.mu = Num.array(mu, copy=True)
120
121
122 self.invsigma = Num.array(invsigma)
123 self._offset = offset
124
126 return '<multi_mu: mu=%s; invsigma=%s >' % (str(self.mu), str(self.invsigma))
127
128 __repr__ = __str__
129
130 addoff = M._q_addoff
131
133 n = self.ndim()
134
135 assert self.invsigma.shape == (n,n)
136 assert len(self.mu) == self.desc.Nmu
137 tmp = []
138
139 for i in range(self.desc.Nmu):
140 tmp.append( self.mu[self.desc.int_to_id[i]] )
141 for i in range(n):
142 tmp.append(self.invsigma[i,i:])
143
144 return Num.concatenate(tmp)
145
146
147 - def logp(self, datum):
148 delta = datum.value - self.mu[datum.classid]
149 parab = Num.dot(delta, Num.matrixmultiply(self.invsigma,
150 delta))
151 if not parab >= 0.0:
152 raise M.QuadraticNotNormalizable, "Not positive-definite"
153 return -parab/2.0 + self.offset() + self.bias
154
155
156
158 __doc__ = """This describes a quadratic model of a known size,
159 with multiple means (one for each different class of data).
160 The covariance matrix is shared and diagonal."""
161
162 - def __init__(self, dataset=None, ndim=None, idmap=None, details=None):
165 __init__.__doc__ = _multi_mu__init__.__doc__
166
167
169 m = self.ndim()
170 return self.Nmu*m + m
171
172
174 m = self.ndim()
175 assert len(prms) == self.modeldim()
176 mu = {}
177 for i in range(self.Nmu):
178 mu[self.int_to_id[i]] = prms[i*m:(i+1)*m]
179
180 j = self.Nmu*m
181 invsigma = prms[j:]
182 return self.new(mu, invsigma)
183
184
185 - def new(self, mu, invsigma, bias=0.0):
186 """Mu is a mapping of classids to vectors. Invsigma is a vector."""
187 assert type(mu) == type({})
188 return multi_mu_diag_with_numbers(mu, invsigma, self, bias)
189
190
211
212
214 - def __init__(self, mu, invsigma, details, bias=0.0, offset=None):
215 """self.mu, self.invsigma, and self._offset should be considered
216 read-only for all users of this class."""
217 assert isinstance(details, multi_mu_diag)
218 M.model_with_numbers.__init__(self, details, bias)
219 self.mu = Num.array(mu)
220
221
222 self.invsigma = Num.array(invsigma)
223 self._offset = offset
224
226 return '<multi_mu_diag: mu=%s; invsigma=%s >' % (str(self.mu), str(self.invsigma))
227
228 __repr__ = __str__
229
230 addoff = M._d_addoff
231
233 n = self.ndim()
234
235 assert self.invsigma.shape == (n,)
236 assert len(self.mu) == self.desc.Nmu
237 tmp = []
238
239 for i in range(self.desc.Nmu):
240 tmp.append( self.mu[self.desc.int_to_id[i]] )
241 tmp.append( self.invsigma )
242
243 return Num.concatenate(tmp)
244
245
246 - def logp(self, datum):
247 delta = datum.value - self.mu[datum.classid]
248 parab = Num.sum(self.invsigma * delta**2)
249 if not parab >= 0.0:
250 raise M.QuadraticNotNormalizable, "Not positive-definite"
251 return -parab/2.0 + self.offset() + self.bias
252