1
+ import numbers
1
2
import numpy as np
2
3
import theano .tensor as tt
3
4
from theano import function
@@ -48,7 +49,8 @@ def dist(cls, *args, **kwargs):
48
49
dist .__init__ (* args , ** kwargs )
49
50
return dist
50
51
51
- def __init__ (self , shape , dtype , testval = None , defaults = (), transform = None , broadcastable = None ):
52
+ def __init__ (self , shape , dtype , testval = None , defaults = (),
53
+ transform = None , broadcastable = None ):
52
54
self .shape = np .atleast_1d (shape )
53
55
if False in (np .floor (self .shape ) == self .shape ):
54
56
raise TypeError ("Expected int elements in shape" )
@@ -70,8 +72,10 @@ def get_test_val(self, val, defaults):
70
72
return self .getattr_value (val )
71
73
72
74
if val is None :
73
- raise AttributeError (str (self ) + " has no finite default value to use, checked: " +
74
- str (defaults ) + " pass testval argument or adjust so value is finite." )
75
+ raise AttributeError ("%s has no finite default value to use, "
76
+ "checked: %s. Pass testval argument or "
77
+ "adjust so value is finite."
78
+ % (self , str (defaults )))
75
79
76
80
def getattr_value (self , val ):
77
81
if isinstance (val , string_types ):
@@ -97,7 +101,8 @@ def TensorType(dtype, shape, broadcastable=None):
97
101
98
102
class NoDistribution (Distribution ):
99
103
100
- def __init__ (self , shape , dtype , testval = None , defaults = (), transform = None , parent_dist = None , * args , ** kwargs ):
104
+ def __init__ (self , shape , dtype , testval = None , defaults = (),
105
+ transform = None , parent_dist = None , * args , ** kwargs ):
101
106
super (NoDistribution , self ).__init__ (shape = shape , dtype = dtype ,
102
107
testval = testval , defaults = defaults ,
103
108
* args , ** kwargs )
@@ -137,7 +142,8 @@ def __init__(self, shape=(), dtype=None, defaults=('mode',),
137
142
class Continuous (Distribution ):
138
143
"""Base class for continuous distributions"""
139
144
140
- def __init__ (self , shape = (), dtype = None , defaults = ('median' , 'mean' , 'mode' ), * args , ** kwargs ):
145
+ def __init__ (self , shape = (), dtype = None , defaults = ('median' , 'mean' , 'mode' ),
146
+ * args , ** kwargs ):
141
147
if dtype is None :
142
148
dtype = theano .config .floatX
143
149
super (Continuous , self ).__init__ (
@@ -190,18 +196,13 @@ def draw_values(params, point=None):
190
196
if param .name in named_nodes :
191
197
named_nodes .pop (param .name )
192
198
for name , node in named_nodes .items ():
193
- if not isinstance (node , (tt .sharedvar .TensorSharedVariable ,
199
+ if not isinstance (node , (tt .sharedvar .SharedVariable ,
194
200
tt .TensorConstant )):
195
- givens [name ] = (node , draw_value (node , point = point ))
196
- values = [None for _ in params ]
197
- for i , param in enumerate (params ):
198
- # "Homogonise" output
199
- values [i ] = np .atleast_1d (draw_value (
200
- param , point = point , givens = givens .values ()))
201
- if len (values ) == 1 :
202
- return values [0 ]
203
- else :
204
- return values
201
+ givens [name ] = (node , _draw_value (node , point = point ))
202
+ values = []
203
+ for param in params :
204
+ values .append (_draw_value (param , point = point , givens = givens .values ()))
205
+ return values
205
206
206
207
207
208
@memoize
@@ -229,43 +230,45 @@ def _compile_theano_function(param, vars, givens=None):
229
230
allow_input_downcast = True )
230
231
231
232
232
- def draw_value (param , point = None , givens = ()):
233
- if hasattr (param , 'name' ):
234
- if hasattr (param , 'model' ):
235
- if point is not None and param .name in point :
236
- value = point [param .name ]
237
- elif hasattr (param , 'random' ) and param .random is not None :
238
- value = param .random (point = point , size = None )
239
- else :
240
- value = param .tag .test_value
241
- else :
242
- input_pairs = ([g [0 ] for g in givens ],
243
- [g [1 ] for g in givens ])
233
+ def _draw_value (param , point = None , givens = None ):
234
+ """Draw a random value from a distribution or return a constant.
244
235
245
- value = _compile_theano_function (param ,
246
- input_pairs [0 ])(* input_pairs [1 ])
236
+ Parameters
237
+ ----------
238
+ param : number, array like, theano variable or pymc3 random variable
239
+ The value or distribution. Constants or shared variables
240
+ will be converted to an array and returned. Theano variables
241
+ are evaluated. If `param` is a pymc3 random variables, draw
242
+ a new value from it and return that, unless a value is specified
243
+ in `point`.
244
+ point : dict, optional
245
+ A dictionary from pymc3 variable names to their values.
246
+ givens : dict, optional
247
+ A dictionary from theano variables to their values. These values
248
+ are used to evaluate `param` if it is a theano variable.
249
+ """
250
+ if isinstance (param , numbers .Number ):
251
+ return param
252
+ elif isinstance (param , np .ndarray ):
253
+ return param
254
+ elif isinstance (param , tt .TensorConstant ):
255
+ return param .value
256
+ elif isinstance (param , tt .sharedvar .SharedVariable ):
257
+ return param .get_value ()
258
+ elif isinstance (param , tt .TensorVariable ):
259
+ if point and hasattr (param , 'model' ) and param .name in point :
260
+ return point [param .name ]
261
+ elif hasattr (param , 'random' ) and param .random is not None :
262
+ return param .random (point = point , size = None )
263
+ else :
264
+ if givens :
265
+ variables , values = list (zip (* givens ))
266
+ else :
267
+ variables = values = []
268
+ func = _compile_theano_function (param , variables )
269
+ return func (* values )
247
270
else :
248
- value = param
249
-
250
- # Sanitising values may be necessary.
251
- if hasattr (value , 'value' ):
252
- value = value .value
253
- elif hasattr (value , 'get_value' ):
254
- value = value .get_value ()
255
-
256
- if hasattr (param , 'dtype' ):
257
- value = np .atleast_1d (value ).astype (param .dtype )
258
- if hasattr (param , 'shape' ):
259
- try :
260
- shape = param .shape .tag .test_value
261
- except AttributeError :
262
- try :
263
- shape = param .shape .eval ()
264
- except AttributeError :
265
- shape = param .shape
266
- if len (shape ) == 0 and len (value ) == 1 :
267
- value = value [0 ]
268
- return value
271
+ raise ValueError ('Unexpected type in draw_value: %s' % type (param ))
269
272
270
273
271
274
def broadcast_shapes (* args ):
@@ -490,8 +493,8 @@ class Bound(object):
490
493
# or within the model context
491
494
NegativeNormal = pm.Bound(pm.Normal, upper=0.0)
492
495
par2 = NegativeNormal('par2', mu=0.0, sd=1.0, testval=1.0)
493
-
494
- # or you can define it implicitly within the model context
496
+
497
+ # or you can define it implicitly within the model context
495
498
par3 = pm.Bound(pm.Normal, lower=-1.0, upper=1.0)(
496
499
'par3', mu=0.0, sd=1.0, testval=1.0)
497
500
"""
0 commit comments