chumpy-fixed 0.71__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
chumpy/ch_random.py ADDED
@@ -0,0 +1,32 @@
1
+ """
2
+ Author(s): Matthew Loper
3
+
4
+ See LICENCE.txt for licensing and contact information.
5
+ """
6
+
7
+ import numpy.random
8
+ from .ch import Ch
9
+
10
+ api_not_implemented = ['choice','bytes','shuffle','permutation']
11
+
12
+ api_wrapped_simple = [
13
+ # simple random data
14
+ 'rand','randn','randint','random_integers','random_sample','random','ranf','sample',
15
+
16
+ # distributions
17
+ 'beta','binomial','chisquare','dirichlet','exponential','f','gamma','geometric','gumbel','hypergeometric',
18
+ 'laplace','logistic','lognormal','logseries','multinomial','multivariate_normal','negative_binomial',
19
+ 'noncentral_chisquare','noncentral_f','normal','pareto','poisson','power','rayleigh','standard_cauchy',
20
+ 'standard_exponential','standard_gamma','standard_normal','standard_t','triangular','uniform','vonmises',
21
+ 'wald','weibull','zipf']
22
+
23
+ api_wrapped_direct = ['seed', 'get_state', 'set_state']
24
+
25
+ for rtn in api_wrapped_simple:
26
+ exec('def %s(*args, **kwargs) : return Ch(numpy.random.%s(*args, **kwargs))' % (rtn, rtn))
27
+
28
+ for rtn in api_wrapped_direct:
29
+ exec('%s = numpy.random.%s' % (rtn, rtn))
30
+
31
+ __all__ = api_wrapped_simple + api_wrapped_direct
32
+
chumpy/extras.py ADDED
@@ -0,0 +1,72 @@
1
+ __author__ = 'matt'
2
+
3
+ from . import ch
4
+ import numpy as np
5
+ from .utils import row, col
6
+ import scipy.sparse as sp
7
+ import scipy.special
8
+
9
+ class Interp3D(ch.Ch):
10
+ dterms = 'locations'
11
+ terms = 'image'
12
+
13
+ def on_changed(self, which):
14
+ if 'image' in which:
15
+ self.gx, self.gy, self.gz = np.gradient(self.image)
16
+
17
+ def compute_r(self):
18
+ locations = self.locations.r.copy()
19
+ for i in range(3):
20
+ locations[:,i] = np.clip(locations[:,i], 0, self.image.shape[i]-1)
21
+ locs = np.floor(locations).astype(np.uint32)
22
+ result = self.image[locs[:,0], locs[:,1], locs[:,2]]
23
+ offset = (locations - locs)
24
+ dr = self.dr_wrt(self.locations).dot(offset.ravel())
25
+ return result + dr
26
+
27
+ def compute_dr_wrt(self, wrt):
28
+ if wrt is self.locations:
29
+ locations = self.locations.r.copy()
30
+ for i in range(3):
31
+ locations[:,i] = np.clip(locations[:,i], 0, self.image.shape[i]-1)
32
+ locations = locations.astype(np.uint32)
33
+
34
+ xc = col(self.gx[locations[:,0], locations[:,1], locations[:,2]])
35
+ yc = col(self.gy[locations[:,0], locations[:,1], locations[:,2]])
36
+ zc = col(self.gz[locations[:,0], locations[:,1], locations[:,2]])
37
+
38
+ data = np.vstack([xc.ravel(), yc.ravel(), zc.ravel()]).T.copy()
39
+ JS = np.arange(locations.size)
40
+ IS = JS // 3
41
+
42
+ return sp.csc_matrix((data.ravel(), (IS, JS)))
43
+
44
+
45
+ class gamma(ch.Ch):
46
+ dterms = 'x',
47
+
48
+ def compute_r(self):
49
+ return scipy.special.gamma(self.x.r)
50
+
51
+ def compute_dr_wrt(self, wrt):
52
+ if wrt is self.x:
53
+ d = scipy.special.polygamma(0, self.x.r)*self.r
54
+ return sp.diags([d.ravel()], [0])
55
+
56
+ # This function is based directly on the "moment" function
57
+ # in scipy, specifically in mstats_basic.py.
58
+ def moment(a, moment=1, axis=0):
59
+ if moment == 1:
60
+ # By definition the first moment about the mean is 0.
61
+ shape = list(a.shape)
62
+ del shape[axis]
63
+ if shape:
64
+ # return an actual array of the appropriate shape
65
+ return ch.zeros(shape, dtype=float)
66
+ else:
67
+ # the input was 1D, so return a scalar instead of a rank-0 array
68
+ return np.float64(0.0)
69
+ else:
70
+ mn = ch.expand_dims(a.mean(axis=axis), axis)
71
+ s = ch.power((a-mn), moment)
72
+ return s.mean(axis=axis)
chumpy/linalg.py ADDED
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env python
2
+ # encoding: utf-8
3
+
4
+ """
5
+ Author(s): Matthew Loper
6
+
7
+ See LICENCE.txt for licensing and contact information.
8
+ """
9
+
10
+
11
+ __all__ = ['inv', 'svd', 'det', 'slogdet', 'pinv', 'lstsq', 'norm']
12
+
13
+ import numpy as np
14
+ import scipy.sparse as sp
15
+ from .ch import Ch, depends_on
16
+ from .ch_ops import NanDivide
17
+ from .ch_ops import asarray as ch_asarray
18
+ from .ch_ops import sqrt as ch_sqrt
19
+ from .ch_ops import sum as ch_sum
20
+ from .reordering import concatenate as ch_concatenate
21
+ from .ch_random import randn as ch_random_randn
22
+ from .utils import row, col
23
+
24
+
25
+ try:
26
+ asarray = ch_asarray
27
+ import inspect
28
+ exec(''.join(inspect.getsourcelines(np.linalg.tensorinv)[0]))
29
+ __all__.append('tensorinv')
30
+ except: pass
31
+
32
+ def norm(x, ord=None, axis=None):
33
+ if ord is not None or axis is not None:
34
+ raise NotImplementedError("'ord' and 'axis' should be None for now.")
35
+
36
+ return ch_sqrt(ch_sum(x**2))
37
+
38
+ # This version works but derivatives are too slow b/c of nested loop in Svd implementation.
39
+ # def lstsq(a, b):
40
+ # u, s, v = Svd(a)
41
+ # x = (v.T / s).dot(u.T.dot(b))
42
+ # residuals = NotImplementedError # ch_sum((a.dot(x) - b)**2, axis=0)
43
+ # rank = NotImplementedError
44
+ # s = NotImplementedError
45
+ # return x, residuals, rank, s
46
+
47
+ def lstsq(a, b, rcond=-1):
48
+ if rcond != -1:
49
+ raise Exception('non-default rcond not yet implemented')
50
+
51
+ x = Ch(lambda a, b : pinv(a).dot(b))
52
+ x.a = a
53
+ x.b = b
54
+ residuals = ch_sum( (x.a.dot(x) - x.b) **2 , axis=0)
55
+ rank = NotImplementedError
56
+ s = NotImplementedError
57
+
58
+ return x, residuals, rank, s
59
+
60
+ def Svd(x, full_matrices=0, compute_uv=1):
61
+
62
+ if full_matrices != 0:
63
+ raise Exception('full_matrices must be 0')
64
+ if compute_uv != 1:
65
+ raise Exception('compute_uv must be 1')
66
+
67
+ need_transpose = x.shape[0] < x.shape[1]
68
+
69
+ if need_transpose:
70
+ x = x.T
71
+
72
+ svd_d = SvdD(x=x)
73
+ svd_v = SvdV(x=x, svd_d=svd_d)
74
+ svd_u = SvdU(x=x, svd_d=svd_d, svd_v=svd_v)
75
+
76
+ if need_transpose:
77
+ return svd_v, svd_d, svd_u.T
78
+ else:
79
+ return svd_u, svd_d, svd_v.T
80
+
81
+
82
+ class Pinv(Ch):
83
+ dterms = 'mtx'
84
+
85
+ def on_changed(self, which):
86
+ mtx = self.mtx
87
+ if mtx.shape[1] > mtx.shape[0]:
88
+ result = mtx.T.dot(Inv(mtx.dot(mtx.T)))
89
+ else:
90
+ result = Inv(mtx.T.dot(mtx)).dot(mtx.T)
91
+ self._result = result
92
+
93
+ def compute_r(self):
94
+ return self._result.r
95
+
96
+ def compute_dr_wrt(self, wrt):
97
+ if wrt is self.mtx:
98
+ return self._result.dr_wrt(self.mtx)
99
+
100
+ # Couldn't make the SVD version of pinv work yet...
101
+ #
102
+ # class Pinv(Ch):
103
+ # dterms = 'mtx'
104
+ #
105
+ # def on_changed(self, which):
106
+ # u, s, v = Svd(self.mtx)
107
+ # result = (v.T * (NanDivide(1.,row(s)))).dot(u.T)
108
+ # self.add_dterm('_result', result)
109
+ #
110
+ # def compute_r(self):
111
+ # return self._result.r
112
+ #
113
+ # def compute_dr_wrt(self, wrt):
114
+ # if wrt is self._result:
115
+ # return 1
116
+
117
+
118
+
119
+ class LogAbsDet(Ch):
120
+ dterms = 'x'
121
+
122
+ def on_changed(self, which):
123
+ self.sign, self.slogdet = np.linalg.slogdet(self.x.r)
124
+
125
+ def compute_r(self):
126
+ return self.slogdet
127
+
128
+ def compute_dr_wrt(self, wrt):
129
+ if wrt is self.x:
130
+ return row(np.linalg.inv(self.x.r).T)
131
+
132
+ class SignLogAbsDet(Ch):
133
+ dterms = 'logabsdet',
134
+
135
+ def compute_r(self):
136
+ _ = self.logabsdet.r
137
+ return self.logabsdet.sign
138
+
139
+ def compute_dr_wrt(self, wrt):
140
+ return None
141
+
142
+
143
+ class Det(Ch):
144
+ dterms = 'x'
145
+
146
+ def compute_r(self):
147
+ return np.linalg.det(self.x.r)
148
+
149
+ def compute_dr_wrt(self, wrt):
150
+ if wrt is self.x:
151
+ return row(self.r * np.linalg.inv(self.x.r).T)
152
+
153
+
154
+ class Inv(Ch):
155
+ dterms = 'a'
156
+
157
+ def compute_r(self):
158
+ return np.linalg.inv(self.a.r)
159
+
160
+ def compute_dr_wrt(self, wrt):
161
+ if wrt is not self.a:
162
+ return None
163
+
164
+ Ainv = self.r
165
+
166
+ if Ainv.ndim <= 2:
167
+ return -np.kron(Ainv, Ainv.T)
168
+ else:
169
+ Ainv = np.reshape(Ainv, (-1, Ainv.shape[-2], Ainv.shape[-1]))
170
+ AinvT = np.rollaxis(Ainv, -1, -2)
171
+ AinvT = np.reshape(AinvT, (-1, AinvT.shape[-2], AinvT.shape[-1]))
172
+ result = np.dstack([-np.kron(Ainv[i], AinvT[i]).T for i in range(Ainv.shape[0])]).T
173
+ result = sp.block_diag(result)
174
+
175
+ return result
176
+
177
+
178
+ class SvdD(Ch):
179
+ dterms = 'x'
180
+
181
+ @depends_on('x')
182
+ def UDV(self):
183
+ result = np.linalg.svd(self.x.r, full_matrices=False)
184
+ result = [result[0], result[1], result[2].T]
185
+ result[1][np.abs(result[1]) < np.spacing(1)] = 0.
186
+ return result
187
+
188
+ def compute_r(self):
189
+ return self.UDV[1]
190
+
191
+ def compute_dr_wrt(self, wrt):
192
+ if wrt is not self.x:
193
+ return
194
+
195
+ u, d, v = self.UDV
196
+ shp = self.x.r.shape
197
+ u = u[:shp[0], :shp[1]]
198
+ v = v[:shp[1], :d.size]
199
+
200
+ result = np.einsum('ik,jk->kij', u, v)
201
+ result = result.reshape((result.shape[0], -1))
202
+ return result
203
+
204
+
205
+ class SvdV(Ch):
206
+ terms = 'svd_d'
207
+ dterms = 'x'
208
+
209
+ def compute_r(self):
210
+ return self.svd_d.UDV[2]
211
+
212
+ def compute_dr_wrt(self, wrt):
213
+ if wrt is not self.x:
214
+ return
215
+
216
+ U,_D,V = self.svd_d.UDV
217
+
218
+ shp = self.svd_d.x.r.shape
219
+ mxsz = max(shp[0], shp[1])
220
+ #mnsz = min(shp[0], shp[1])
221
+ D = np.zeros(mxsz)
222
+ D[:_D.size] = _D
223
+
224
+ omega = np.zeros((shp[0], shp[1], shp[1], shp[1]))
225
+
226
+ M = shp[0]
227
+ N = shp[1]
228
+
229
+ assert(M >= N)
230
+
231
+ for i in range(shp[0]):
232
+ for j in range(shp[1]):
233
+ for k in range(N):
234
+ for l in range(k+1, N):
235
+ mtx = np.array([
236
+ [D[l],D[k]],
237
+ [D[k],D[l]]])
238
+
239
+ rhs = np.array([U[i,k]*V[j,l], -U[i,l]*V[j,k]])
240
+ result = np.linalg.solve(mtx, rhs)
241
+
242
+ omega[i,j,k,l] = result[1]
243
+ omega[i,j,l,k] = -result[1]
244
+
245
+ #print 'v size is %s' % (str(V.shape),)
246
+ #print 'v omega size is %s' % (str(omega.shape),)
247
+ assert(V.shape[1] == omega.shape[2])
248
+ return np.einsum('ak,ijkl->alij', -V, omega).reshape((self.r.size, wrt.r.size))
249
+
250
+
251
+ class SvdU(Ch):
252
+ dterms = 'x'
253
+ terms = 'svd_d', 'svd_v'
254
+
255
+ def compute_r(self):
256
+ return self.svd_d.UDV[0]
257
+
258
+ def compute_dr_wrt(self, wrt):
259
+ if wrt is self.x:
260
+ # return (
261
+ # self.svd_d.x.dot(self.svd_v)
262
+ # /
263
+ # self.svd_d.reshape((1,-1))
264
+ # ).dr_wrt(self.svd_d.x)
265
+ return (
266
+ NanDivide(
267
+ self.svd_d.x.dot(self.svd_v),
268
+ self.svd_d.reshape((1,-1)))
269
+ ).dr_wrt(self.svd_d.x)
270
+
271
+
272
+ inv = Inv
273
+ svd = Svd
274
+ det = Det
275
+ pinv = Pinv
276
+
277
+ def slogdet(*args):
278
+ n = len(args)
279
+ if n == 1:
280
+ r2 = LogAbsDet(x=args[0])
281
+ r1 = SignLogAbsDet(r2)
282
+ return r1, r2
283
+ else:
284
+ r2 = [LogAbsDet(x=arg) for arg in args]
285
+ r1 = [SignLogAbsDet(r) for r in r2]
286
+ r2 = ch_concatenate(r2)
287
+ return r1, r2
288
+
289
+ def main():
290
+
291
+ tmp = ch_random_randn(100).reshape((10,10))
292
+ print('chumpy version: ' + str(slogdet(tmp)[1].r))
293
+ print('old version:' + str(np.linalg.slogdet(tmp.r)[1]))
294
+
295
+ eps = 1e-10
296
+ diff = np.random.rand(100) * eps
297
+ diff_reshaped = diff.reshape((10,10))
298
+ print(np.linalg.slogdet(tmp.r+diff_reshaped)[1] - np.linalg.slogdet(tmp.r)[1])
299
+ print(slogdet(tmp)[1].dr_wrt(tmp).dot(diff))
300
+
301
+ print(np.linalg.slogdet(tmp.r)[0])
302
+ print(slogdet(tmp)[0])
303
+
304
+ if __name__ == '__main__':
305
+ main()
306
+
chumpy/logic.py ADDED
@@ -0,0 +1,39 @@
1
+ """
2
+ Author(s): Matthew Loper
3
+
4
+ See LICENCE.txt for licensing and contact information.
5
+ """
6
+
7
+ __author__ = 'matt'
8
+
9
+
10
+ __all__ = [] # added to incrementally below
11
+
12
+ from . import ch
13
+ from .ch import Ch
14
+ import numpy as np
15
+
16
+ class LogicFunc(Ch):
17
+ dterms = 'a' # we keep this here so that changes to children of "a" will trigger cache changes
18
+ terms = 'args', 'kwargs', 'funcname'
19
+
20
+ def compute_r(self):
21
+ arr = self.a
22
+ fn = getattr(np, self.funcname)
23
+ return fn(arr, *self.args, **self.kwargs)
24
+
25
+ def compute_dr_wrt(self, wrt):
26
+ pass
27
+
28
+
29
+ unaries = 'all', 'any', 'isfinite', 'isinf', 'isnan', 'isneginf', 'isposinf', 'logical_not'
30
+ for unary in unaries:
31
+ exec("def %s(a, *args, **kwargs): return LogicFunc(a=a, args=args, kwargs=kwargs, funcname='%s')" % (unary, unary))
32
+ __all__ += unaries
33
+
34
+
35
+
36
+ if __name__ == '__main__':
37
+ from . import ch
38
+ print(all(np.array([1,2,3])))
39
+ print(isinf(np.array([0,2,3])))
chumpy/monitor.py ADDED
@@ -0,0 +1,149 @@
1
+ '''
2
+ Logging service for tracking dr tree changes from root objective
3
+ and record every step that incrementally changes the dr tree
4
+
5
+ '''
6
+ import os, sys, time
7
+ import json
8
+ import psutil
9
+
10
+ import scipy.sparse as sp
11
+ import numpy as np
12
+ from . import reordering
13
+
14
+ _TWO_20 = float(2 **20)
15
+
16
+ '''
17
+ memory utils
18
+
19
+ '''
20
+ def pdb_mem():
21
+ from .monitor import get_current_memory
22
+ mem = get_current_memory()
23
+ if mem > 7000:
24
+ import pdb;pdb.set_trace()
25
+
26
+ def get_peak_mem():
27
+ '''
28
+ this returns peak memory use since process starts till the moment its called
29
+ '''
30
+ import resource
31
+ rusage_denom = 1024.
32
+ if sys.platform == 'darwin':
33
+ # ... it seems that in OSX the output is different units ...
34
+ rusage_denom = rusage_denom * rusage_denom
35
+ mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / rusage_denom
36
+ return mem
37
+
38
+ def get_current_memory():
39
+ p = psutil.Process(os.getpid())
40
+ mem = p.memory_info()[0]/_TWO_20
41
+
42
+ return mem
43
+
44
+ '''
45
+ Helper for Profiler
46
+ '''
47
+
48
+ def build_cache_info(k, v, info_dict):
49
+ if v is not None:
50
+ issparse = sp.issparse(v)
51
+ size = v.size
52
+ if issparse:
53
+ nonzero = len(v.data)
54
+ else:
55
+ nonzero = np.count_nonzero(v)
56
+ info_dict[k.short_name] = {
57
+ 'sparse': issparse,
58
+ 'size' : str(size),
59
+ 'nonzero' : nonzero,
60
+ }
61
+
62
+
63
+ def cache_info(ch_node):
64
+ result = {}
65
+ if isinstance(ch_node, reordering.Concatenate) and hasattr(ch_node, 'dr_cached') and len(ch_node.dr_cached) > 0:
66
+ for k, v in ch_node.dr_cached.items():
67
+ build_cache_info(k, v, result)
68
+ elif len(ch_node._cache['drs']) > 0:
69
+ for k, v in ch_node._cache['drs'].items():
70
+ build_cache_info(k, v, result)
71
+
72
+ return result
73
+
74
+ class DrWrtProfiler(object):
75
+ base_path = os.path.abspath('profiles')
76
+
77
+ def __init__(self, root, base_path=None):
78
+ self.root = root.obj
79
+ self.history = []
80
+
81
+ ts = time.time()
82
+ if base_path:
83
+ self.base_path = base_path
84
+
85
+ self.path = os.path.join(self.base_path, 'profile_%s.json' % str(ts))
86
+ self.root_path = os.path.join(self.base_path, 'root_%s.json' % str(ts))
87
+
88
+
89
+ with open(self.root_path, 'w') as f:
90
+ json.dump(self.dump_tree(self.root), f, indent=4)
91
+
92
+ def dump_tree(self, node):
93
+ if not hasattr(node, 'dterms'):
94
+ return []
95
+
96
+ node_dict = self.serialize_node(node, verbose=False)
97
+ if hasattr(node, 'visited') and node.visited:
98
+ node_dict.update({'indirect':True})
99
+ return node_dict
100
+
101
+ node.visited = True
102
+ children_list = []
103
+ for dterm in node.dterms:
104
+ if hasattr(node, dterm):
105
+ child = getattr(node, dterm)
106
+ if hasattr(child, 'dterms') or hasattr(child, 'terms'):
107
+ children_list.append(self.dump_tree(child))
108
+ node_dict.update({'children':children_list})
109
+ return node_dict
110
+
111
+ def serialize_node(self, ch_node, verbose=True):
112
+ node_id = id(ch_node)
113
+ name = ch_node.short_name
114
+ ts = time.time()
115
+ status = ch_node._status
116
+ mem = get_current_memory()
117
+ node_cache_info = cache_info(ch_node)
118
+
119
+ rec = {
120
+ 'id': str(node_id),
121
+ 'indirect' : False,
122
+ }
123
+ if verbose:
124
+ rec.update({
125
+ 'name':name,
126
+ 'ts' : ts,
127
+ 'status':status,
128
+ 'mem': mem,
129
+ 'cache': node_cache_info,
130
+ })
131
+ return rec
132
+
133
+ def show_tree(self, label):
134
+ '''
135
+ show tree from the root node
136
+ '''
137
+ self.root.show_tree_cache(label)
138
+
139
+ def record(self, ch_node):
140
+ '''
141
+ Incremental changes
142
+ '''
143
+ rec = self.serialize_node(ch_node)
144
+ self.history.append(rec)
145
+
146
+ def harvest(self):
147
+ print('collecting and dump to file %s' % self.path)
148
+ with open(self.path, 'w') as f:
149
+ json.dump(self.history, f, indent=4)