提交 91c7197c authored 作者: Pascal Lamblin's avatar Pascal Lamblin

PEP8/flake8 fixes in tensor/basic.py

Remaining errors are lines too long in comments or C code.
上级 55693fb0
......@@ -7,7 +7,6 @@ import warnings
from itertools import izip
import numpy
from copy import copy as python_copy
import theano
from theano.configparser import config
......@@ -26,7 +25,7 @@ from theano.gof.utils import hashtype
from theano import compile, printing
from theano.printing import pprint, min_informative_str
#For history
from theano.compile import Rebroadcast, Shape, shape, SpecifyShape, specify_shape
from theano.compile import Rebroadcast, Shape, shape
# We use these exceptions as well.
......@@ -138,7 +137,8 @@ def as_tensor_variable(x, name=None, ndim=None):
:Exceptions:
- `ValueError`: raised if an `Apply` with more then one output is fetched
- `AsTensorError`: raised if `x` cannot be converted to a TensorType Variable
- `AsTensorError`: raised if `x` cannot be converted to a TensorType
Variable
"""
if hasattr(x, '_as_TensorVariable'):
......@@ -166,11 +166,12 @@ def as_tensor_variable(x, name=None, ndim=None):
if (x.type.ndim > ndim):
# strip off leading broadcastable dimensions
first_non_broadcastable = [idx for idx in range(x.ndim)
if x.broadcastable[idx] == False][0]
if not x.broadcastable[idx]][0]
x = x.dimshuffle(range(x.ndim)[first_non_broadcastable:])
if x.ndim > ndim:
raise ValueError(
'TensorType could not be cast to have %i dimensions' % ndim, x.type
'TensorType could not be cast to have %i dimensions'
% ndim, x.type
)
return x
elif (x.type.ndim < ndim):
......@@ -251,9 +252,9 @@ class NumpyAutocaster(object):
return numpy.asarray(x)
elif config.cast_policy == 'numpy+floatX':
rval = numpy.asarray(x)
if (rval.dtype == 'float64' and # numpy wants float64
if ((rval.dtype == 'float64' and # numpy wants float64
config.floatX == 'float32' and # but we prefer float32
not hasattr(x, 'dtype')): # and `x` was not typed
not hasattr(x, 'dtype'))): # and `x` was not typed
rval = theano._asarray(rval, dtype='float32')
return rval
......@@ -275,9 +276,9 @@ class NumpyAutocaster(object):
# unsafe downcast of float64 variables when config.floatX == 'float32'
# recall: float is numpy.float
if (isinstance(x, float) and
if ((isinstance(x, float) and
config.floatX in self.dtypes and
config.floatX == 'float32'):
config.floatX == 'float32')):
return theano._asarray(x, dtype='float32')
......@@ -313,7 +314,7 @@ class autocast_float_as(object):
For example:
>>> with autocast_float_as('float32') as _dummy:
>>> assert (fvector() + 1.1).dtype == 'float32' # temporary downcasting
... assert (fvector() + 1.1).dtype == 'float32' # temporary downcasting
>>> assert (fvector() + 1.1).dtype == 'float64' # back to default behaviour
This class might be convenient in some code, but it definitely
......@@ -407,17 +408,17 @@ def constant_or_value(x, rtype, name=None, ndim=None, dtype=None):
raise TypeError("Could not convert %s to TensorType" % x, type(x))
constant_cache = {}
def constant(x, name=None, ndim=None, dtype=None):
ret = constant_or_value(x, rtype=TensorConstant, name=name, ndim=ndim,
dtype=dtype)
#We create a small cache of frequently used constant.
#This speed up the Merge optimization for big graph.
#We want to cache all scalar to don't merge as frequently constants.
#But we don't want to cache too much stuff
#So we cache integer with dtype [u]int and float where the value is between -10 and 10
#We want to cache all broadcast pattern for scalar.
# We create a small cache of frequently used constant.
# This speed up the Merge optimization for big graph.
# We want to cache all scalar to don't merge as frequently constants.
# But we don't want to cache too much stuff
# So we cache integer with dtype [u]int and float where the value is
# between -10 and 10
# We want to cache all broadcast pattern for scalar.
if not constant.enable:
return ret
sig = ret.signature()
......@@ -431,6 +432,7 @@ def constant(x, name=None, ndim=None, dtype=None):
return constant_cache.get(sig, ret)
constant.enable = True
constant_cache = {}
def _obj_is_wrappable_as_tensor(x):
......@@ -520,8 +522,9 @@ def numpy_scalar(data):
"""
# handle case where data is numpy.array([])
if data.ndim > 0 and (len(data.shape) == 0 or
__builtins__['max'](data.shape) == 0):
if (data.ndim > 0 and
(len(data.shape) == 0 or
__builtins__['max'](data.shape) == 0)):
assert numpy.all(numpy.array([]) == data)
raise EmptyConstantError()
try:
......@@ -539,6 +542,8 @@ get_scalar_constant_value_elemwises = (
scal.LT, scal.GT, scal.LE, scal.GE,
scal.Sub, scal.Add, scal.Mod, scal.Mul,
scal.IntDiv, scal.TrueDiv, scal.Minimum, scal.Maximum)
def get_scalar_constant_value(orig_v, elemwise=True):
"""return the constant scalar(0-D) value underlying variable `v`
......@@ -557,8 +562,8 @@ def get_scalar_constant_value(orig_v, elemwise=True):
v = orig_v
while True:
if v is None:
# None is not a scalar (and many uses of this function seem to depend
# on passing it None)
# None is not a scalar (and many uses of this function seem
# to depend on passing it None)
raise NotScalarConstantError()
if isinstance(v, (numpy.integer, int, float)):
......@@ -591,7 +596,7 @@ def get_scalar_constant_value(orig_v, elemwise=True):
elif isinstance(v.owner.op, scal.ScalarOp):
if isinstance(v.owner.op, scal.Second):
# We don't need both input to be constant for second
shape, val = v.owner.inputs
shp, val = v.owner.inputs
v = val
continue
if isinstance(v.owner.op, get_scalar_constant_value_elemwises):
......@@ -603,16 +608,18 @@ def get_scalar_constant_value(orig_v, elemwise=True):
elif elemwise and isinstance(v.owner.op, Elemwise):
if isinstance(v.owner.op.scalar_op, scal.Second):
# We don't need both input to be constant for second
shape, val = v.owner.inputs
shp, val = v.owner.inputs
v = val
continue
elif isinstance(v.owner.op.scalar_op,
get_scalar_constant_value_elemwises):
const = [get_scalar_constant_value(i) for i in v.owner.inputs]
const = [get_scalar_constant_value(i)
for i in v.owner.inputs]
ret = [[None]]
v.owner.op.perform(v.owner, const, ret)
return ret[0][0]
elif isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and v.ndim == 0:
elif (isinstance(v.owner.op, theano.tensor.subtensor.Subtensor)
and v.ndim == 0):
if isinstance(v.owner.inputs[0], TensorConstant):
cdata = tuple(v.owner.op.get_constant_idx(v.owner.inputs))
try:
......@@ -628,21 +635,22 @@ def get_scalar_constant_value(orig_v, elemwise=True):
# TODO: implement the case where we take a scalar in a matrix
assert len(v.owner.op.idx_list) == v.owner.inputs[0].ndim
# Needed to make better graph in this test in theano/tensor/tests:
# test_sharedvar.py:test_shared_options.test_specify_shape_partial
if (v.owner.inputs[0].owner and
# Needed to make better graph in this test in
# theano/tensor/tests/test_sharedvar.py:
# test_shared_options.test_specify_shape_partial
if ((v.owner.inputs[0].owner and
isinstance(v.owner.inputs[0].owner.op, Join) and
len(v.owner.op.idx_list) == 1):
len(v.owner.op.idx_list) == 1)):
# Ensure the Join is joining only scalar variables (so that
# the constant value can be found at the same index as the one
# used in the sub-tensor).
# the constant value can be found at the same index as the
# one used in the sub-tensor).
if python_all(var.ndim == 0 for var in
v.owner.inputs[0].owner.inputs[1:]):
idx = v.owner.op.idx_list[0]
if isinstance(idx, gof.Type):
idx = get_scalar_constant_value(v.owner.inputs[1])
# Note the '+ 1' is because the first argument to Join is the
# axis.
# Note the '+ 1' is because the first argument to Join
# is the axis.
ret = v.owner.inputs[0].owner.inputs[idx + 1]
ret = get_scalar_constant_value(ret)
# join can cast implicitly its input in some case.
......@@ -658,7 +666,8 @@ def get_scalar_constant_value(orig_v, elemwise=True):
for joined in v.owner.inputs[0].owner.inputs[1:]:
ll = get_vector_length(joined)
if idx < length + ll:
return get_scalar_constant_value(joined[idx-length])
return get_scalar_constant_value(
joined[idx - length])
length += ll
except TypeError:
pass
......@@ -673,6 +682,7 @@ def get_scalar_constant_value(orig_v, elemwise=True):
python_all(var.ndim == 0 for var in
v.owner.inputs[0].owner.inputs) and
len(v.owner.op.idx_list) == 1):
idx = v.owner.op.idx_list[0]
if isinstance(idx, gof.Type):
idx = get_scalar_constant_value(v.owner.inputs[1])
......@@ -1039,7 +1049,8 @@ class ScalarFromTensor(Op):
assert t.type.broadcastable == ()
return Apply(self,
[t],
[scal.get_scalar_type(dtype=t.type.dtype).make_variable()])
[scal.get_scalar_type(dtype=t.type.dtype).make_variable()]
)
def perform(self, node, inp, out_):
s, = inp
......@@ -1235,7 +1246,8 @@ class MaxAndArgmax(Op):
elif isinstance(axis, Variable):
if not isinstance(axis, TensorConstant):
raise TypeError("MaxAndArgmax needs a constant axis")
assert axis.dtype.startswith("int") or axis.dtype.startswith("uint")
assert (axis.dtype.startswith("int")
or axis.dtype.startswith("uint"))
axis = int(axis.data)
# we make the axis all positive to make the infer_shape work
# with negative axis
......@@ -1389,7 +1401,8 @@ class MaxAndArgmax(Op):
if g_max_disconnected and g_max_idx_disconnected:
return [DisconnectedType()(), DisconnectedType()()]
axis_grad = grad_undefined(self, 1, axis,
axis_grad = grad_undefined(
self, 1, axis,
"argmax is not defined for non-integer axes so"
" argmax(x, axis+eps) is undefined")
......@@ -1449,7 +1462,8 @@ def makeKeepDims(x, y, axis):
newaxis = []
for a in axis:
if not isinstance(a, int):
raise ValueError("keepdims option can be used only with constant axis")
raise ValueError(
"keepdims option can be used only with constant axis")
if a < 0:
a += x.type.ndim
newaxis.append(a)
......@@ -1931,6 +1945,7 @@ def gammaln(a):
def psi(a):
"""derivative of log gamma function"""
@_scal_elemwise
def chi2sf(x, k):
"""chi squared survival function"""
......@@ -2001,26 +2016,26 @@ def zeros_like(model, dtype=None):
return fill(model, constant(0.0, dtype=dtype))
def zeros(shape, dtype=None):
def zeros(shp, dtype=None):
"""
Create a Tensor filled with zeros, closer to Numpy's syntax than ``alloc``.
"""
if not isinstance(shape, (list, tuple, TensorVariable)):
shape = [shape]
if not isinstance(shp, (list, tuple, TensorVariable)):
shp = [shp]
if dtype is None:
dtype = config.floatX
return alloc(numpy.array(0, dtype=dtype), *shape)
return alloc(numpy.array(0, dtype=dtype), *shp)
def ones(shape, dtype=None):
def ones(shp, dtype=None):
"""
Create a Tensor filled with ones, closer to Numpy's syntax than ``alloc``.
"""
if not isinstance(shape, (list, tuple, TensorVariable)):
shape = [shape]
if not isinstance(shp, (list, tuple, TensorVariable)):
shp = [shp]
if dtype is None:
dtype = config.floatX
return alloc(numpy.array(1, dtype=dtype), *shape)
return alloc(numpy.array(1, dtype=dtype), *shp)
class Nonzero(gof.Op):
......@@ -2198,7 +2213,9 @@ class Tri(gof.Op):
N = as_tensor_variable(N)
M = as_tensor_variable(M)
k = as_tensor_variable(k)
return gof.Apply(self, [N, M, k],
return gof.Apply(
self,
[N, M, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()])
def perform(self, node, inp, out_):
......@@ -2307,7 +2324,9 @@ class Eye(gof.Op):
assert n.ndim == 0
assert m.ndim == 0
assert k.ndim == 0
return gof.Apply(self, [n, m, k],
return gof.Apply(
self,
[n, m, k],
[TensorType(dtype=self.dtype, broadcastable=(False, False))()])
def perform(self, node, inp, out_):
......@@ -2370,8 +2389,9 @@ class Alloc(gof.Op):
Returns an N-dimensional tensor initialized by `value` using something
equivalent to
>>> z = numpy.zeros(shape, value.dtype)
>>> z += value
z = numpy.zeros(shape, value.dtype)
z += value
The result has N dimensions, has the dtype of `value` and is obtained by
broadcasting value over the output ndarray.
......@@ -2555,16 +2575,17 @@ class Alloc(gof.Op):
# If the output is a constant, it will have to be deepcopied
# each time the function is called. So we do not fold.
return False
elif (#The following ops work inplace of their input id 0.
elif (
# The following ops work inplace of their input id 0.
client[1] == 0 and
isinstance(client[0].op, (
#Ops that will work inplace on the Alloc. So if they
#get constant_folded, they would copy the
#constant and this is less efficients.
# Ops that will work inplace on the Alloc. So if they
# get constant_folded, they would copy the
# constant and this is less efficients.
#Not doing the constant folding could also lower
#the peak memory usage, as we the "constant" won't
#always exists.
# Not doing the constant folding could also lower
# the peak memory usage, as we the "constant" won't
# always exists.
theano.tensor.subtensor.IncSubtensor,
theano.tensor.subtensor.AdvancedIncSubtensor1,
theano.tensor.subtensor.AdvancedIncSubtensor,
......@@ -2572,8 +2593,7 @@ class Alloc(gof.Op):
theano.tensor.blas_c.CGemv,
theano.tensor.blas.Ger,
theano.tensor.blas_c.CGer,
theano.tensor.blas_scipy.ScipyGer
))):
theano.tensor.blas_scipy.ScipyGer))):
return False
#If the clients is a transfer to the GPU, we don't want to
#fold. We let the Alloc being moved to the GPU, then we
......@@ -2951,8 +2971,8 @@ def ceil_intdiv(a, b):
def mod_check(x, y):
"""Make sure we do not try to use complex numbers."""
if (as_tensor_variable(x).dtype in complex_dtypes or
as_tensor_variable(y).dtype in complex_dtypes):
if ((as_tensor_variable(x).dtype in complex_dtypes or
as_tensor_variable(y).dtype in complex_dtypes)):
# Currently forbidden.
raise scal.Mod.complex_error
else:
......@@ -3006,8 +3026,8 @@ def extract_constant(x, elemwise=True):
x = get_scalar_constant_value(x, elemwise=elemwise)
except NotScalarConstantError:
pass
if (isinstance(x, scal.ScalarVariable) or
isinstance(x, scal.sharedvar.ScalarSharedVariable)):
if ((isinstance(x, scal.ScalarVariable) or
isinstance(x, scal.sharedvar.ScalarSharedVariable))):
if x.owner and isinstance(x.owner.op, ScalarFromTensor):
x = x.owner.inputs[0]
else:
......@@ -3046,7 +3066,8 @@ def batched_dot(x, y):
But numpy einsum is slower than dot or tensordot:
http://mail.scipy.org/pipermail/numpy-discussion/2012-October/064259.html
"""
result, updates = theano.scan(fn=lambda x_mat, y_mat:
result, updates = theano.scan(
fn=lambda x_mat, y_mat:
theano.tensor.dot(x_mat, y_mat),
outputs_info=None,
sequences=[x, y],
......@@ -3085,10 +3106,13 @@ def batched_tensordot(x, y, axes=2):
axes = numpy.asarray(axes)
else:
axes = axes.copy()
assert numpy.greater(axes,0).all(), "All axes should be greater than one, as the first axis is iterated over (batch-wise scan)"
assert numpy.greater(axes, 0).all(), (
"All axes should be greater than one, as the "
"first axis is iterated over (batch-wise scan)")
axes -= 1
result, updates = theano.scan(fn=lambda x_mat, y_mat:
result, updates = theano.scan(
fn=lambda x_mat, y_mat:
theano.tensor.tensordot(x_mat, y_mat, axes),
outputs_info=None,
sequences=[x, y],
......@@ -3327,8 +3351,8 @@ class Join(Op):
output_maker = lambda bcastable: tensor(dtype=out_dtype,
broadcastable=bcastable)
return self._make_node_internal(axis, tensors,
as_tensor_variable_args, output_maker)
return self._make_node_internal(
axis, tensors, as_tensor_variable_args, output_maker)
def _make_node_internal(self, axis, tensors,
as_tensor_variable_args, output_maker):
......@@ -3387,7 +3411,8 @@ class Join(Op):
if not python_all([x.ndim == len(bcastable)
for x in as_tensor_variable_args[1:]]):
raise TypeError("Join() can only join tensor with the same number of dimensions.")
raise TypeError("Join() can only join tensors with the same "
"number of dimensions.")
inputs = [as_tensor_variable(axis)] + list(as_tensor_variable_args)
if inputs[0].type not in int_types:
......@@ -3617,8 +3642,8 @@ def stack(*tensors):
# And DebugMode can't detect error in this code as it is not in an
# optimization.
# See ticket #660
if numpy.all([
# in case there is direct int in tensors.
if numpy.all(
[ # in case there is direct int in tensors.
isinstance(t, (numpy.number, float, int, python_complex,
long)) or
(isinstance(t, Variable) and
......@@ -3649,7 +3674,8 @@ def concatenate(tensor_list, axis=0):
# instead of
# c = concatenate((x, y))
if not isinstance(tensor_list, (tuple, list)):
raise TypeError("The 'tensors' argument must be either a tuple "
raise TypeError(
"The 'tensors' argument must be either a tuple "
"or a list, make sure you did not forget () or [] around "
"arguments of concatenate.", tensor_list)
return join(axis, *tensor_list)
......@@ -3682,10 +3708,10 @@ def get_vector_length(v):
if v.owner and isinstance(v.owner.op, Shape):
return v.owner.inputs[0].type.ndim
# If we take this slice: var[:0], we know it will have 0 elements.
if (v.owner and
if ((v.owner and
isinstance(v.owner.op, theano.tensor.subtensor.Subtensor) and
isinstance(v.owner.op.idx_list[0], slice) and
v.owner.op.idx_list[0].start in [None, 0]):
v.owner.op.idx_list[0].start in [None, 0])):
stop = theano.tensor.subtensor.get_idx_list(
v.owner.inputs, v.owner.op.idx_list)[0].stop
if extract_constant(stop) == 0:
......@@ -3911,7 +3937,8 @@ def reshape(x, newshape, ndim=None, name=None):
try:
ndim = get_vector_length(newshape)
except ValueError:
raise ValueError("The length of the provided shape (%s) cannot "
raise ValueError(
"The length of the provided shape (%s) cannot "
"be automatically determined, so Theano is not able "
"to know what the number of dimensions of the reshaped "
"variable will be. You can provide the 'ndim' keyword "
......@@ -4231,7 +4258,8 @@ def arange(start, stop=None, step=1, dtype=None):
config.floatX == 'float32' and
numpy_dtype == 'float64' and
# No explicit float64 in the three arguments?
python_all(dt != 'float64'
python_all(
dt != 'float64'
for dt in [s.dtype for s in (start, stop, step)])):
# We use float32 instead.
assert dtype != 'float64'
......@@ -4283,9 +4311,9 @@ class PermuteRowElements(Op):
assert (y.type.dtype.startswith('int') or
y.type.dtype.startswith('uint'))
# Inverse should be an integer scalar
assert inverse.type.ndim == 0 and\
(inverse.type.dtype.startswith('int') or\
inverse.type.dtype.startswith('uint'))
assert (inverse.type.ndim == 0 and
(inverse.type.dtype.startswith('int') or
inverse.type.dtype.startswith('uint')))
# Match shapes of x and y
x_dim = x.type.ndim
......@@ -4571,7 +4599,6 @@ class Dot(Op):
# R_op for a \dot b evaluted at c for a and d for b is
# simply c \dot b + a \dot d
assert len(inputs) == 2
assert len(eval_points) == 2
if eval_points[0] is None and eval_points[1] is None:
......@@ -4599,14 +4626,16 @@ class Dot(Op):
ev0 = gof.op.get_test_value(eval_points[0])
except AttributeError:
gof.op.missing_test_message(
'first eval point passed to Dot.R_op has no test value')
'first eval point passed to Dot.R_op '
'has no test value')
debugger_available = False
if eval_points[1]:
try:
ev1 = gof.op.get_test_value(eval_points[1])
except AttributeError:
gof.op.missing_test_message(
'second eval point passed to Dot.R_op has no test value')
'second eval point passed to Dot.R_op '
'has no test value')
debugger_available = False
if debugger_available:
......@@ -4616,11 +4645,10 @@ class Dot(Op):
for i in xrange(2):
if eval_point_values[i] is not None and \
input_values[i].shape != eval_point_values[i].shape:
raise ValueError('input ' + str(i) + ' and eval_point ' +
str(i) + ' to Dot.R_op '
'should have the '
'same shape, but their shapes are'
' %s and %s, respectively' % (
raise ValueError(
'input ' + str(i) + ' and eval_point ' + str(i)
+ ' to Dot.R_op should have the same shape, but '
'their shapes are %s and %s, respectively' % (
str(input_values[i].shape),
str(eval_point_values[i].shape)))
if eval_points[0]:
......@@ -4888,8 +4916,9 @@ def tensordot(a, b, axes=2):
a_order = (tuple(x for x in tuple(xrange(a.ndim)) if x not in a_axes)
+ a_axes)
b_order = (b_axes
+ tuple(x for x in tuple(xrange(b.ndim)) if x not in b_axes))
b_order = (b_axes + tuple(x
for x in tuple(xrange(b.ndim))
if x not in b_axes))
a_shuffled = a.dimshuffle(a_order)
b_shuffled = b.dimshuffle(b_order)
......@@ -5082,7 +5111,7 @@ def ptp(a, axis=None):
def power(x, y):
return x**y
return x ** y
def swapaxes(y, axis1, axis2):
......@@ -5098,25 +5127,48 @@ def choose(a, choices, out=None, mode='raise'):
"""
Construct an array from an index array and a set of arrays to choose from.
First of all, if confused or uncertain, definitely look at the Examples - in its full generality, this function is less simple than it might seem from the following code description (below ndi = numpy.lib.index_tricks):
First of all, if confused or uncertain, definitely look at the Examples -
in its full generality, this function is less simple than it might seem
from the following code description (below ndi = numpy.lib.index_tricks):
np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)]).
But this omits some subtleties. Here is a fully general summary:
Given an ``index`` array (a) of integers and a sequence of n arrays (choices), a and each choice array are first broadcast, as necessary, to arrays of a common shape; calling these Ba and Bchoices[i], i = 0,...,n-1 we have that, necessarily, Ba.shape == Bchoices[i].shape for each i. Then, a new array with shape Ba.shape is created as follows:
if mode=raise (the default), then, first of all, each element of a (and thus Ba) must be in the range [0, n-1]; now, suppose that i (in that range) is the value at the (j0, j1, ..., jm) position in Ba - then the value at the same position in the new array is the value in Bchoices[i] at that same position;
if mode=wrap, values in a (and thus Ba) may be any (signed) integer; modular arithmetic is used to map integers outside the range [0, n-1] back into that range; and then the new array is constructed as above;
if mode=clip, values in a (and thus Ba) may be any (signed) integer; negative integers are mapped to 0; values greater than n-1 are mapped to n-1; and then the new array is constructed as above.
:Parameters: *a* - int array
This array must contain integers in [0, n-1], where n is the number of choices, unless mode=wrap or mode=clip, in which cases any integers are permissible.
:Parameters: *choices* - sequence of arrays
Choice arrays. a and all of the choices must be broadcastable to the same shape. If choices is itself an array (not recommended), then its outermost dimension (i.e., the one corresponding to choices.shape[0]) is taken as defining the ``sequence``.
:Parameters: *out* - array, optional
If provided, the result will be inserted into this array. It should be of the appropriate shape and dtype.
:Parameters: *mode* - {``raise`` (default), ``wrap``, ``clip``}, optional
Given an ``index`` array (a) of integers and a sequence of n arrays
(choices), a and each choice array are first broadcast, as necessary,
to arrays of a common shape; calling these Ba and
Bchoices[i], i = 0,...,n-1 we have that, necessarily,
Ba.shape == Bchoices[i].shape for each i.
Then, a new array with shape Ba.shape is created as follows:
- if mode=raise (the default), then, first of all, each element of a
(and thus Ba) must be in the range [0, n-1]; now, suppose that
i (in that range) is the value at the (j0, j1, ..., jm) position in Ba -
then the value at the same position in the new array is the value in
Bchoices[i] at that same position;
- if mode=wrap, values in a (and thus Ba) may be any (signed) integer;
modular arithmetic is used to map integers outside the range [0, n-1]
back into that range; and then the new array is constructed as above;
- if mode=clip, values in a (and thus Ba) may be any (signed) integer;
negative integers are mapped to 0; values greater than n-1 are mapped
to n-1; and then the new array is constructed as above.
:Parameter: *a* - int array
This array must contain integers in [0, n-1], where n is the number of
choices, unless mode=wrap or mode=clip, in which cases any integers
are permissible.
:Parameter: *choices* - sequence of arrays
Choice arrays. a and all of the choices must be broadcastable to
the same shape. If choices is itself an array (not recommended),
then its outermost dimension (i.e., the one corresponding to
choices.shape[0]) is taken as defining the ``sequence``.
:Parameter: *out* - array, optional
If provided, the result will be inserted into this array.
It should be of the appropriate shape and dtype.
:Parameter: *mode* - {``raise`` (default), ``wrap``, ``clip``}, optional
Specifies how indices outside [0, n-1] will be treated:
``raise`` : an exception is raised
``wrap`` : value becomes value mod n
......@@ -5145,17 +5197,18 @@ class Choose(Op):
return[(shapes[0])]
else:
import theano.typed_list
assert isinstance(node.inputs[1], theano.typed_list.TypedListVariable)
assert isinstance(node.inputs[1],
theano.typed_list.TypedListVariable)
raise ShapeError("Case not implemented")
shape = shapes[0]
for i in range(len(shapes[0])-1):
for i in range(len(shapes[0]) - 1):
shape[i] = shapes[1][i]
return [(shape)]
def make_node(self, a, choices):
# Import here as it isn't imported by default and we can't
# import at the top as it would cause circular import.
from theano import typed_list
import theano.typed_list
a = as_tensor_variable(a)
if isinstance(choices, (tuple, list)):
choice = theano.typed_list.make_list(choices)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论