diff --git a/aesara/compile/debugmode.py b/aesara/compile/debugmode.py index 39d3cf4c3b..c3c116b091 100644 --- a/aesara/compile/debugmode.py +++ b/aesara/compile/debugmode.py @@ -848,17 +848,17 @@ def _get_preallocated_maps( or "ALL" in prealloc_modes ): max_ndim = 0 - rev_out_broadcastable = [] + rev_out_shape = [] for r in considered_outputs: if isinstance(r.type, TensorType): if max_ndim < r.ndim: - rev_out_broadcastable += [True] * (r.ndim - max_ndim) + rev_out_shape += [1] * (r.ndim - max_ndim) max_ndim = r.ndim - assert len(rev_out_broadcastable) == max_ndim + assert len(rev_out_shape) == max_ndim - for i, b in enumerate(r.broadcastable[::-1]): - rev_out_broadcastable[i] = rev_out_broadcastable[i] and b - out_broadcastable = rev_out_broadcastable[::-1] + for i, s in enumerate(r.type.shape[::-1]): + rev_out_shape[i] = 1 if rev_out_shape[i] == 1 and s == 1 else None + out_shape = rev_out_shape[::-1] if "strided" in prealloc_modes or "ALL" in prealloc_modes: check_ndim = config.DebugMode__check_preallocated_output_ndim @@ -887,14 +887,14 @@ def _get_preallocated_maps( # Moreover, to avoid memory problems, we do not test with strides # 2 and -2 on those dimensions. step_signs_list = [] - for b in out_broadcastable[-check_ndim:]: - if b: + for s in out_shape[-check_ndim:]: + if s == 1: step_signs_list.append((1,)) else: step_signs_list.append((-1, 1)) # Use the same step on all dimensions before the last check_ndim. - if all(out_broadcastable[:-check_ndim]): + if all(s == 1 for s in out_shape[:-check_ndim]): step_signs_list = [(1,)] + step_signs_list else: step_signs_list = [(-1, 1)] + step_signs_list @@ -905,7 +905,7 @@ def _get_preallocated_maps( # First, the dimensions above check_ndim, then the other ones # Do not test with 2 or -2 for dimensions above check_ndim - steps = [step_signs[0]] * len(out_broadcastable[:-check_ndim]) + steps = [step_signs[0]] * len(out_shape[:-check_ndim]) steps += [s * step_size for s in step_signs[1:]] name = f"strided{tuple(steps)}" @@ -932,8 +932,8 @@ def _get_preallocated_maps( if "wrong_size" in prealloc_modes or "ALL" in prealloc_modes: # For each dimension, try size-1, size, size+1 - for dim, b in enumerate(out_broadcastable): - if b: + for dim, s in enumerate(out_shape): + if s == 1: # The shape has to be 1 continue @@ -947,11 +947,11 @@ def _get_preallocated_maps( for r in considered_outputs: if isinstance(r.type, TensorType): r_shape_diff = shape_diff[: r.ndim] - out_shape = [ + new_buf_shape = [ max((s + sd), 0) for s, sd in zip(r_vals[r].shape, r_shape_diff) ] - new_buf = np.empty(out_shape, dtype=r.type.dtype) + new_buf = np.empty(new_buf_shape, dtype=r.type.dtype) new_buf[...] = np.asarray(def_val).astype(r.type.dtype) wrong_size[r] = new_buf diff --git a/aesara/gradient.py b/aesara/gradient.py index 51b2bb77ad..7391a50ae0 100644 --- a/aesara/gradient.py +++ b/aesara/gradient.py @@ -1802,13 +1802,11 @@ def verify_grad( mode=mode, ) - tensor_pt = [ - aesara.tensor.type.TensorType( - aesara.tensor.as_tensor_variable(p).dtype, - aesara.tensor.as_tensor_variable(p).broadcastable, - )(name=f"input {i}") - for i, p in enumerate(pt) - ] + tensor_pt = [] + for i, p in enumerate(pt): + p_t = aesara.tensor.as_tensor_variable(p).type() + p_t.name = f"input {i}" + tensor_pt.append(p_t) # fun can be either a function or an actual Op instance o_output = fun(*tensor_pt) diff --git a/aesara/link/c/params_type.py b/aesara/link/c/params_type.py index c48db53fc5..928b92ed2c 100644 --- a/aesara/link/c/params_type.py +++ b/aesara/link/c/params_type.py @@ -29,7 +29,7 @@ .. code-block:: python - params_type = ParamsType(attr1=TensorType('int32', (False, False)), attr2=ScalarType('float64')) + params_type = ParamsType(attr1=TensorType('int32', shape=(None, None)), attr2=ScalarType('float64')) If your op contains attributes ``attr1`` **and** ``attr2``, the default ``op.get_params()`` implementation will automatically try to look for it and generate an appropriate Params object. @@ -324,7 +324,7 @@ class ParamsType(CType): `ParamsType` constructor takes key-value args. Key will be the name of the attribute in the struct. Value is the Aesara type of this attribute, ie. an instance of (a subclass of) :class:`CType` - (eg. ``TensorType('int64', (False,))``). + (eg. ``TensorType('int64', (None,))``). In a Python code any attribute named ``key`` will be available via:: diff --git a/aesara/sandbox/multinomial.py b/aesara/sandbox/multinomial.py index fc72ca8c6d..6e15d6b57c 100644 --- a/aesara/sandbox/multinomial.py +++ b/aesara/sandbox/multinomial.py @@ -44,7 +44,9 @@ def make_node(self, pvals, unis, n=1): odtype = pvals.dtype else: odtype = self.odtype - out = at.tensor(dtype=odtype, shape=pvals.type.broadcastable) + out = at.tensor( + dtype=odtype, shape=tuple(1 if s == 1 else None for s in pvals.type.shape) + ) return Apply(self, [pvals, unis, as_scalar(n)], [out]) def grad(self, ins, outgrads): diff --git a/aesara/sandbox/rng_mrg.py b/aesara/sandbox/rng_mrg.py index a1afeb3d5d..5c1c252ce4 100644 --- a/aesara/sandbox/rng_mrg.py +++ b/aesara/sandbox/rng_mrg.py @@ -379,20 +379,23 @@ def make_node(self, rstate, size): # this op should not be called directly. # # call through MRG_RandomStream instead. - broad = [] + out_shape = () for i in range(self.output_type.ndim): - broad.append(at.extract_constant(size[i]) == 1) - output_type = self.output_type.clone(shape=broad)() + if at.extract_constant(size[i]) == 1: + out_shape += (1,) + else: + out_shape += (None,) + output_var = self.output_type.clone(shape=out_shape)() rstate = as_tensor_variable(rstate) size = as_tensor_variable(size) - return Apply(self, [rstate, size], [rstate.type(), output_type]) + return Apply(self, [rstate, size], [rstate.type(), output_var]) @classmethod def new(cls, rstate, ndim, dtype, size): v_size = as_tensor_variable(size) if ndim is None: ndim = get_vector_length(v_size) - op = cls(TensorType(dtype, (False,) * ndim)) + op = cls(TensorType(dtype, shape=(None,) * ndim)) return op(rstate, v_size) def perform(self, node, inp, out, params): diff --git a/aesara/sparse/basic.py b/aesara/sparse/basic.py index 6f5bb22b0a..21d0fa7bea 100644 --- a/aesara/sparse/basic.py +++ b/aesara/sparse/basic.py @@ -592,7 +592,7 @@ def make_node(self, csm): csm = as_sparse_variable(csm) assert csm.format in ("csr", "csc") - data = TensorType(dtype=csm.type.dtype, shape=(False,))() + data = TensorType(dtype=csm.type.dtype, shape=(None,))() return Apply(self, [csm], [data, ivector(), ivector(), ivector()]) def perform(self, node, inputs, out): @@ -994,7 +994,7 @@ def make_node(self, x): return Apply( self, [x], - [TensorType(dtype=x.type.dtype, shape=(False, False))()], + [TensorType(dtype=x.type.dtype, shape=(None, None))()], ) def perform(self, node, inputs, outputs): @@ -1753,11 +1753,13 @@ def __init__(self, axis=None, sparse_grad=True): def make_node(self, x): x = as_sparse_variable(x) assert x.format in ("csr", "csc") - b = () + if self.axis is not None: - b = (False,) + out_shape = (None,) + else: + out_shape = () - z = TensorType(shape=b, dtype=x.dtype)() + z = TensorType(dtype=x.dtype, shape=out_shape)() return Apply(self, [x], [z]) def perform(self, node, inputs, outputs): @@ -1872,7 +1874,7 @@ def make_node(self, x): """ x = as_sparse_variable(x) assert x.format in ("csr", "csc") - return Apply(self, [x], [tensor(shape=(False,), dtype=x.dtype)]) + return Apply(self, [x], [tensor(dtype=x.dtype, shape=(None,))]) def perform(self, node, inputs, outputs): (x,) = inputs @@ -2138,7 +2140,7 @@ def make_node(self, x, y): return Apply( self, [x, y], - [TensorType(dtype=out_dtype, shape=y.type.broadcastable)()], + [TensorType(dtype=out_dtype, shape=y.type.shape)()], ) def perform(self, node, inputs, outputs): @@ -2621,7 +2623,7 @@ def make_node(self, x, y): x, y = as_sparse_variable(x), at.as_tensor_variable(y) assert y.type.ndim == 2 - out = TensorType(dtype="uint8", shape=(False, False))() + out = TensorType(dtype="uint8", shape=(None, None))() return Apply(self, [x, y], [out]) def perform(self, node, inputs, outputs): @@ -3462,7 +3464,7 @@ def make_node(self, a, b): return Apply( self, [a, b], - [tensor(dtype_out, (False, b.type.broadcastable[1]))], + [tensor(dtype_out, shape=(None, 1 if b.type.shape[1] == 1 else None))], ) def perform(self, node, inputs, outputs): @@ -3593,7 +3595,7 @@ class StructuredDotGradCSC(COp): def make_node(self, a_indices, a_indptr, b, g_ab): return Apply( - self, [a_indices, a_indptr, b, g_ab], [tensor(g_ab.dtype, (False,))] + self, [a_indices, a_indptr, b, g_ab], [tensor(g_ab.dtype, shape=(None,))] ) def perform(self, node, inputs, outputs): @@ -3726,7 +3728,9 @@ class StructuredDotGradCSR(COp): __props__ = () def make_node(self, a_indices, a_indptr, b, g_ab): - return Apply(self, [a_indices, a_indptr, b, g_ab], [tensor(b.dtype, (False,))]) + return Apply( + self, [a_indices, a_indptr, b, g_ab], [tensor(b.dtype, shape=(None,))] + ) def perform(self, node, inputs, outputs): (a_indices, a_indptr, b, g_ab) = inputs @@ -3967,6 +3971,7 @@ def make_node(self, x, y): x = as_sparse_variable(x) if isinstance(y, scipy.sparse.spmatrix): y = as_sparse_variable(y) + x_is_sparse_var = _is_sparse_variable(x) y_is_sparse_var = _is_sparse_variable(y) @@ -3978,34 +3983,35 @@ def make_node(self, x, y): ) if x_is_sparse_var: - broadcast_x = (False,) * x.ndim + shape_x = (None,) * x.type.ndim else: x = at.as_tensor_variable(x) - broadcast_x = x.type.broadcastable + shape_x = x.type.shape assert y.format in ("csr", "csc") if x.ndim not in (1, 2): raise TypeError( "Input 0 (0-indexed) must have ndim of " - f"1 or 2, {int(x.ndim)} given." + f"1 or 2, {int(x.type.ndim)} given." ) if y_is_sparse_var: - broadcast_y = (False,) * y.ndim + shape_y = (None,) * y.type.ndim else: y = at.as_tensor_variable(y) - broadcast_y = y.type.broadcastable + shape_y = y.type.shape assert x.format in ("csr", "csc") if y.ndim not in (1, 2): raise TypeError( "Input 1 (1-indexed) must have ndim of " - f"1 or 2, {int(y.ndim)} given." + f"1 or 2, {int(y.type.ndim)} given." ) - if len(broadcast_y) == 2: - broadcast_out = broadcast_x[:-1] + broadcast_y[1:] - elif len(broadcast_y) == 1: - broadcast_out = broadcast_x[:-1] - return Apply(self, [x, y], [tensor(dtype=dtype_out, shape=broadcast_out)]) + if len(shape_y) == 2: + shape_out = shape_x[:-1] + shape_y[1:] + elif len(shape_y) == 1: + shape_out = shape_x[:-1] + + return Apply(self, [x, y], [tensor(dtype=dtype_out, shape=shape_out)]) def perform(self, node, inputs, out): x, y = inputs @@ -4126,21 +4132,21 @@ def make_node(self, alpha, x, y, z): alpha = at.as_tensor_variable(alpha) z = at.as_tensor_variable(z) - assert z.ndim == 2 - assert alpha.type.broadcastable == (True,) * alpha.ndim + assert z.type.ndim == 2 + assert alpha.type.shape == (1,) * alpha.type.ndim if not _is_sparse_variable(x): x = at.as_tensor_variable(x) assert y.format in ("csr", "csc") - assert x.ndim == 2 + assert x.type.ndim == 2 if not _is_sparse_variable(y): y = at.as_tensor_variable(y) assert x.format in ("csr", "csc") - assert y.ndim == 2 + assert y.type.ndim == 2 return Apply( self, [alpha, x, y, z], - [tensor(dtype=dtype_out, shape=(False, False))], + [tensor(dtype=dtype_out, shape=(None, None))], ) def perform(self, node, inputs, outputs): diff --git a/aesara/sparse/rewriting.py b/aesara/sparse/rewriting.py index fde57a30ac..69865c7fe8 100644 --- a/aesara/sparse/rewriting.py +++ b/aesara/sparse/rewriting.py @@ -126,7 +126,9 @@ def make_node(self, x, y): # The magic number two here arises because L{scipy.sparse} # objects must be matrices (have dimension 2) assert y.type.ndim == 2 - out = TensorType(dtype=out_dtype, shape=y.type.broadcastable)() + out = TensorType( + dtype=out_dtype, shape=tuple(1 if s == 1 else None for s in y.type.shape) + )() return Apply(self, [data, indices, indptr, y], [out]) def c_code(self, node, name, inputs, outputs, sub): @@ -268,7 +270,7 @@ def make_node(self, a_val, a_ind, a_ptr, a_nrows, b): r = Apply( self, [a_val, a_ind, a_ptr, a_nrows, b], - [tensor(dtype_out, (False, b.type.broadcastable[1]))], + [tensor(dtype_out, shape=(None, 1 if b.type.shape[1] == 1 else None))], ) return r @@ -463,7 +465,7 @@ def make_node(self, a_val, a_ind, a_ptr, b): r = Apply( self, [a_val, a_ind, a_ptr, b], - [tensor(self.dtype_out, (False, b.type.broadcastable[1]))], + [tensor(self.dtype_out, shape=(None, 1 if b.type.shape[1] == 1 else None))], ) return r @@ -675,7 +677,7 @@ def make_node(self, alpha, x_val, x_ind, x_ptr, x_nrows, y, z): assert x_ind.dtype == "int32" assert x_ptr.dtype == "int32" assert x_nrows.dtype == "int32" - assert alpha.ndim == 2 and alpha.type.broadcastable == (True, True) + assert alpha.ndim == 2 and alpha.type.shape == (1, 1) assert x_val.ndim == 1 assert y.ndim == 2 assert z.ndim == 2 @@ -703,7 +705,7 @@ def make_node(self, alpha, x_val, x_ind, x_ptr, x_nrows, y, z): r = Apply( self, [alpha, x_val, x_ind, x_ptr, x_nrows, y, z], - [tensor(dtype_out, (False, y.type.broadcastable[1]))], + [tensor(dtype_out, shape=(None, 1 if y.type.shape[1] == 1 else None))], ) return r @@ -903,7 +905,7 @@ def c_code_cache_version(self): { "pattern": "alpha", "constraint": lambda expr: ( - all(expr.type.broadcastable) and config.blas__ldflags + all(s == 1 for s in expr.type.shape) and config.blas__ldflags ), }, (sparse._dot, "x", "y"), @@ -1140,7 +1142,7 @@ def make_node(self, a_data, a_indices, a_indptr, b): """ assert b.type.ndim == 2 return Apply( - self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, (False,))] + self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, shape=(None,))] ) def c_code_cache_version(self): @@ -1278,7 +1280,7 @@ def make_node(self, a_data, a_indices, a_indptr, b): """ assert b.type.ndim == 2 return Apply( - self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, (False,))] + self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, shape=(None,))] ) def c_code_cache_version(self): @@ -1468,7 +1470,7 @@ def make_node(self, a_data, a_indices, a_indptr, b): """ assert b.type.ndim == 1 return Apply( - self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, (False,))] + self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, shape=(None,))] ) def c_code_cache_version(self): @@ -1640,7 +1642,7 @@ def make_node(self, a_data, a_indices, a_indptr, b): assert a_indptr.type.ndim == 1 assert b.type.ndim == 1 return Apply( - self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, (False,))] + self, [a_data, a_indices, a_indptr, b], [tensor(b.dtype, shape=(None,))] ) def c_code_cache_version(self): @@ -1851,9 +1853,9 @@ def make_node(self, x, y, p_data, p_ind, p_ptr, p_ncols): self, [x, y, p_data, p_ind, p_ptr, p_ncols], [ - tensor(dtype=dtype_out, shape=(False,)), - tensor(dtype=p_ind.type.dtype, shape=(False,)), - tensor(dtype=p_ptr.type.dtype, shape=(False,)), + tensor(dtype=dtype_out, shape=(None,)), + tensor(dtype=p_ind.type.dtype, shape=(None,)), + tensor(dtype=p_ptr.type.dtype, shape=(None,)), ], ) diff --git a/aesara/sparse/sandbox/sp.py b/aesara/sparse/sandbox/sp.py index 1f95d01758..6015006848 100644 --- a/aesara/sparse/sandbox/sp.py +++ b/aesara/sparse/sandbox/sp.py @@ -181,7 +181,7 @@ def evaluate(inshp, kshp, strides=(1, 1), nkern=1, mode="valid", ws=True): # taking into account multiple # input features - col = ( + col = int( iy * inshp[2] + ix + fmapi * np.prod(inshp[1:]) ) @@ -196,13 +196,13 @@ def evaluate(inshp, kshp, strides=(1, 1), nkern=1, mode="valid", ws=True): # convert to row index of sparse matrix if ws: - row = ( + row = int( (y * outshp[1] + x) * inshp[0] * ksize + l + fmapi * ksize ) else: - row = y * outshp[1] + x + row = int(y * outshp[1] + x) # Store something at that location # in sparse matrix. The written diff --git a/aesara/tensor/__init__.py b/aesara/tensor/__init__.py index 1f63c30644..d726da3241 100644 --- a/aesara/tensor/__init__.py +++ b/aesara/tensor/__init__.py @@ -80,8 +80,9 @@ def get_vector_length(v: TensorLike) -> int: if v.type.ndim != 1: raise TypeError(f"Argument must be a vector; got {v.type}") - if v.type.broadcastable[0]: - return 1 + static_shape: Optional[int] = v.type.shape[0] + if static_shape is not None: + return static_shape return _get_vector_length(getattr(v.owner, "op", v), v) diff --git a/aesara/tensor/basic.py b/aesara/tensor/basic.py index f629bfb095..4762d903d2 100644 --- a/aesara/tensor/basic.py +++ b/aesara/tensor/basic.py @@ -28,7 +28,7 @@ from aesara.graph.fg import FunctionGraph from aesara.graph.op import Op from aesara.graph.rewriting.utils import rewrite_graph -from aesara.graph.type import Type +from aesara.graph.type import HasShape, Type from aesara.link.c.op import COp from aesara.link.c.params_type import ParamsType from aesara.misc.safe_asarray import _asarray @@ -110,10 +110,12 @@ def _as_tensor_Variable(x, name, ndim, **kwargs): if x.type.ndim > ndim: # Strip off leading broadcastable dimensions - non_broadcastables = [idx for idx in range(x.ndim) if not x.broadcastable[idx]] + non_broadcastables = tuple( + idx for idx in range(x.type.ndim) if x.type.shape[idx] != 1 + ) if non_broadcastables: - x = x.dimshuffle(list(range(x.ndim))[non_broadcastables[0] :]) + x = x.dimshuffle(list(range(x.type.ndim))[non_broadcastables[0] :]) else: x = x.dimshuffle() @@ -346,8 +348,8 @@ def get_scalar_constant_value( if isinstance(inp, Constant): return np.asarray(np.shape(inp.data)[i]) # The shape of a broadcastable dimension is 1 - if hasattr(inp.type, "broadcastable") and inp.type.broadcastable[i]: - return np.asarray(1) + if isinstance(inp.type, HasShape) and inp.type.shape[i] is not None: + return np.asarray(inp.type.shape[i]) # Don't act as the constant_folding optimization here as this # fct is used too early in the optimization phase. This would @@ -500,21 +502,16 @@ def get_scalar_constant_value( owner.inputs[1], max_recur=max_recur ) grandparent = leftmost_parent.owner.inputs[0] - gp_broadcastable = grandparent.type.broadcastable + gp_shape = grandparent.type.shape ndim = grandparent.type.ndim if grandparent.owner and isinstance( grandparent.owner.op, Unbroadcast ): - ggp_broadcastable = grandparent.owner.inputs[0].broadcastable - l = [ - b1 or b2 - for b1, b2 in zip(ggp_broadcastable, gp_broadcastable) - ] - gp_broadcastable = tuple(l) - - assert ndim == len(gp_broadcastable) + ggp_shape = grandparent.owner.inputs[0].type.shape + l = [s1 == 1 or s2 == 1 for s1, s2 in zip(ggp_shape, gp_shape)] + gp_shape = tuple(l) - if not (idx < len(gp_broadcastable)): + if not (idx < ndim): msg = ( "get_scalar_constant_value detected " f"deterministic IndexError: x.shape[{int(idx)}] " @@ -526,8 +523,9 @@ def get_scalar_constant_value( msg += f" x={v}" raise ValueError(msg) - if gp_broadcastable[idx]: - return np.asarray(1) + gp_shape_val = gp_shape[idx] + if gp_shape_val is not None and gp_shape_val > -1: + return np.asarray(gp_shape_val) if isinstance(grandparent, Constant): return np.asarray(np.shape(grandparent.data)[idx]) @@ -862,7 +860,7 @@ def make_node(self, a): a = as_tensor_variable(a) if a.ndim == 0: raise ValueError("Nonzero only supports non-scalar arrays.") - output = [TensorType(dtype="int64", shape=(False,))() for i in range(a.ndim)] + output = [TensorType(dtype="int64", shape=(None,))() for i in range(a.ndim)] return Apply(self, [a], output) def perform(self, node, inp, out_): @@ -993,7 +991,7 @@ def make_node(self, N, M, k): return Apply( self, [N, M, k], - [TensorType(dtype=self.dtype, shape=(False, False))()], + [TensorType(dtype=self.dtype, shape=(None, None))()], ) def perform(self, node, inp, out_): @@ -1272,7 +1270,7 @@ def make_node(self, n, m, k): return Apply( self, [n, m, k], - [TensorType(dtype=self.dtype, shape=(False, False))()], + [TensorType(dtype=self.dtype, shape=(None, None))()], ) def perform(self, node, inp, out_): @@ -1509,15 +1507,16 @@ def grad(self, inputs, grads): axis_kept = [] for i, (ib, gb) in enumerate( zip( - inputs[0].broadcastable, + inputs[0].type.shape, # We need the dimensions corresponding to x - grads[0].broadcastable[-inputs[0].ndim :], + grads[0].type.shape[-inputs[0].ndim :], ) ): - if ib and not gb: + if ib == 1 and gb != 1: axis_broadcasted.append(i + n_axes_to_sum) else: axis_kept.append(i) + gx = gz.sum(axis=axis + axis_broadcasted) if axis_broadcasted: new_order = ["x"] * x.ndim @@ -1663,7 +1662,7 @@ def make_node(self, *inputs): else: dtype = self.dtype - otype = TensorType(dtype, (len(inputs),)) + otype = TensorType(dtype, shape=(len(inputs),)) return Apply(self, inputs, [otype()]) def perform(self, node, inputs, out_): @@ -1863,11 +1862,14 @@ def transpose(x, axes=None): """ _x = as_tensor_variable(x) + if axes is None: - axes = list(range((_x.ndim - 1), -1, -1)) - ret = DimShuffle(_x.broadcastable, axes)(_x) - if _x.name and axes == list(range((_x.ndim - 1), -1, -1)): + axes = list(range((_x.type.ndim - 1), -1, -1)) + ret = DimShuffle(tuple(s == 1 for s in _x.type.shape), axes)(_x) + + if _x.name and axes == list(range((_x.type.ndim - 1), -1, -1)): ret.name = _x.name + ".T" + return ret @@ -1918,7 +1920,7 @@ def make_node(self, x, axis, splits): raise TypeError("`axis` parameter must be an integer scalar") inputs = [x, axis, splits] - out_type = TensorType(dtype=x.dtype, shape=[None] * x.type.ndim) + out_type = TensorType(dtype=x.dtype, shape=(None,) * x.type.ndim) outputs = [out_type() for i in range(self.len_splits)] return Apply(self, inputs, outputs) @@ -2210,9 +2212,9 @@ def make_node(self, axis, *tensors): "Join cannot handle arguments of dimension 0." " Use `stack` to join scalar values." ) - # Handle single-tensor joins immediately. + if len(tensors) == 1: - bcastable = list(tensors[0].type.broadcastable) + out_shape = tensors[0].type.shape else: # When the axis is fixed, a dimension should be # broadcastable if at least one of the inputs is @@ -2220,8 +2222,8 @@ def make_node(self, axis, *tensors): # except for the axis dimension. # Initialize bcastable all false, and then fill in some trues with # the loops. - bcastable = [False] * len(tensors[0].type.broadcastable) - ndim = len(bcastable) + ndim = tensors[0].type.ndim + out_shape = [None] * ndim if not isinstance(axis, int): try: @@ -2246,15 +2248,15 @@ def make_node(self, axis, *tensors): axis += ndim for x in tensors: - for current_axis, bflag in enumerate(x.type.broadcastable): + for current_axis, s in enumerate(x.type.shape): # Constant negative axis can no longer be negative at # this point. It safe to compare this way. if current_axis == axis: continue - if bflag: - bcastable[current_axis] = True + if s == 1: + out_shape[current_axis] = 1 try: - bcastable[axis] = False + out_shape[axis] = None except IndexError: raise ValueError( f"Axis value {axis} is out of range for the given input dimensions" @@ -2262,9 +2264,9 @@ def make_node(self, axis, *tensors): else: # When the axis may vary, no dimension can be guaranteed to be # broadcastable. - bcastable = [False] * len(tensors[0].type.broadcastable) + out_shape = [None] * tensors[0].type.ndim - if not builtins.all(x.ndim == len(bcastable) for x in tensors): + if not builtins.all(x.ndim == len(out_shape) for x in tensors): raise TypeError( "Only tensors with the same number of dimensions can be joined" ) @@ -2274,7 +2276,7 @@ def make_node(self, axis, *tensors): if inputs[0].type.dtype not in int_dtypes: raise TypeError(f"Axis value {inputs[0]} must be an integer type") - return Apply(self, inputs, [tensor(dtype=out_dtype, shape=bcastable)]) + return Apply(self, inputs, [tensor(dtype=out_dtype, shape=out_shape)]) def perform(self, node, axis_and_tensors, out_): (out,) = out_ @@ -2387,9 +2389,9 @@ def grad(self, axis_and_tensors, grads): # read it if needed. split_gz = [ g - if g.type.broadcastable == t.type.broadcastable + if g.type.shape == t.type.shape == 1 else specify_broadcastable( - g, *(ax for (ax, b) in enumerate(t.type.broadcastable) if b) + g, *(ax for (ax, s) in enumerate(t.type.shape) if s == 1) ) for t, g in zip(tens, split_gz) ] @@ -2770,13 +2772,13 @@ def flatten(x, ndim=1): dims = tuple(_x.shape[: ndim - 1]) + (-1,) else: dims = (-1,) + x_reshaped = _x.reshape(dims) - bcast_kept_dims = _x.broadcastable[: ndim - 1] - bcast_new_dim = builtins.all(_x.broadcastable[ndim - 1 :]) - broadcastable = bcast_kept_dims + (bcast_new_dim,) - x_reshaped = specify_broadcastable( - x_reshaped, *[i for i in range(ndim) if broadcastable[i]] - ) + shape_kept_dims = _x.type.shape[: ndim - 1] + bcast_new_dim = builtins.all(s == 1 for s in _x.type.shape[ndim - 1 :]) + out_shape = shape_kept_dims + (1 if bcast_new_dim else None,) + bcasted_indices = tuple(i for i in range(ndim) if out_shape[i] == 1) + x_reshaped = specify_broadcastable(x_reshaped, *bcasted_indices) return x_reshaped @@ -2882,7 +2884,7 @@ def make_node(self, start, stop, step): assert step.ndim == 0 inputs = [start, stop, step] - outputs = [tensor(self.dtype, (False,))] + outputs = [tensor(self.dtype, shape=(None,))] return Apply(self, inputs, outputs) @@ -3158,11 +3160,11 @@ def make_node(self, x, y, inverse): elif x_dim < y_dim: x = shape_padleft(x, n_ones=(y_dim - x_dim)) - # Compute the broadcastable pattern of the output - out_broadcastable = [ - xb and yb for xb, yb in zip(x.type.broadcastable, y.type.broadcastable) + out_shape = [ + 1 if xb == 1 and yb == 1 else None + for xb, yb in zip(x.type.shape, y.type.shape) ] - out_type = tensor(dtype=x.type.dtype, shape=out_broadcastable) + out_type = tensor(dtype=x.type.dtype, shape=out_shape) inputlist = [x, y, inverse] outputlist = [out_type] @@ -3205,11 +3207,11 @@ def _rec_perform(self, node, x, y, inverse, out, curdim): if xs0 == ys0: for i in range(xs0): self._rec_perform(node, x[i], y[i], inverse, out[i], curdim + 1) - elif ys0 == 1 and node.inputs[1].type.broadcastable[curdim]: + elif ys0 == 1 and node.inputs[1].type.shape[curdim] == 1: # Broadcast y for i in range(xs0): self._rec_perform(node, x[i], y[0], inverse, out[i], curdim + 1) - elif xs0 == 1 and node.inputs[0].type.broadcastable[curdim]: + elif xs0 == 1 and node.inputs[0].type.shape[curdim] == 1: # Broadcast x for i in range(ys0): self._rec_perform(node, x[0], y[i], inverse, out[i], curdim + 1) @@ -3268,7 +3270,7 @@ def grad(self, inp, grads): broadcasted_dims = [ dim for dim in range(gz.type.ndim) - if x.type.broadcastable[dim] and not gz.type.broadcastable[dim] + if x.type.shape[dim] == 1 and gz.type.shape[dim] != 1 ] gx = Sum(axis=broadcasted_dims)(gx) @@ -3283,8 +3285,13 @@ def grad(self, inp, grads): newdims.append(i) i += 1 - gx = DimShuffle(gx.type.broadcastable, newdims)(gx) - assert gx.type.broadcastable == x.type.broadcastable + gx = DimShuffle(tuple(s == 1 for s in gx.type.shape), newdims)(gx) + assert gx.type.ndim == x.type.ndim + assert all( + s1 == s2 + for s1, s2 in zip(gx.type.shape, x.type.shape) + if s1 == 1 or s2 == 1 + ) # if x is an integer type, then so is the output. # this means f(x+eps) = f(x) so the gradient with respect @@ -3394,7 +3401,7 @@ def make_node(self, x): return Apply( self, [x], - [x.type.__class__(dtype=x.dtype, shape=[False] * (x.ndim - 1))()], + [x.type.clone(dtype=x.dtype, shape=(None,) * (x.ndim - 1))()], ) def perform(self, node, inputs, outputs): @@ -3516,7 +3523,7 @@ def make_node(self, diag): return Apply( self, [diag], - [diag.type.clone(shape=[False] * (diag.ndim + 1))()], + [diag.type.clone(shape=(None,) * (diag.ndim + 1))()], ) def perform(self, node, inputs, outputs): @@ -3799,11 +3806,12 @@ def make_node(self, a, choices): choice = aesara.typed_list.make_list(choices) else: choice = as_tensor_variable(choices) + (out_shape,) = self.infer_shape( None, None, [shape_tuple(a), shape_tuple(choice)] ) - bcast = [] + static_out_shape = () for s in out_shape: try: s_val = aesara.get_scalar_constant_value(s) @@ -3811,11 +3819,11 @@ def make_node(self, a, choices): s_val = None if s_val == 1: - bcast.append(True) + static_out_shape += (1,) else: - bcast.append(False) + static_out_shape += (None,) - o = TensorType(choice.dtype, bcast) + o = TensorType(choice.dtype, shape=static_out_shape) return Apply(self, [a, choice], [o()]) def perform(self, node, inputs, outputs): diff --git a/aesara/tensor/blas.py b/aesara/tensor/blas.py index ee478b6a8a..a866b6f85a 100644 --- a/aesara/tensor/blas.py +++ b/aesara/tensor/blas.py @@ -167,6 +167,7 @@ from aesara.tensor.shape import specify_broadcastable from aesara.tensor.type import ( DenseTensorType, + TensorType, integer_dtypes, tensor, values_eq_approx_remove_inf_nan, @@ -1204,11 +1205,11 @@ def _as_scalar(res, dtype=None): """Return ``None`` or a `TensorVariable` of float type""" if dtype is None: dtype = config.floatX - if all(res.type.broadcastable): + if all(s == 1 for s in res.type.shape): while res.owner and isinstance(res.owner.op, DimShuffle): res = res.owner.inputs[0] # may still have some number of True's - if res.type.broadcastable: + if res.type.ndim > 0: rval = res.dimshuffle() else: rval = res @@ -1230,8 +1231,8 @@ def _is_real_matrix(res): return ( res.type.dtype in ("float16", "float32", "float64") and res.type.ndim == 2 - and res.type.broadcastable[0] is False - and res.type.broadcastable[1] is False + and res.type.shape[0] != 1 + and res.type.shape[1] != 1 ) # cope with tuple vs. list @@ -1239,7 +1240,7 @@ def _is_real_vector(res): return ( res.type.dtype in ("float16", "float32", "float64") and res.type.ndim == 1 - and res.type.broadcastable[0] is False + and res.type.shape[0] != 1 ) @@ -1298,9 +1299,7 @@ def scaled(thing): else: return scale * thing - try: - r.type.broadcastable - except Exception: + if not isinstance(r.type, TensorType): return None if (r.type.ndim not in (1, 2)) or r.type.dtype not in ( @@ -1333,10 +1332,10 @@ def scaled(thing): vectors = [] matrices = [] for i in r.owner.inputs: - if all(i.type.broadcastable): + if all(s == 1 for s in i.type.shape): while i.owner and isinstance(i.owner.op, DimShuffle): i = i.owner.inputs[0] - if i.type.broadcastable: + if i.type.ndim > 0: scalars.append(i.dimshuffle()) else: scalars.append(i) @@ -1681,8 +1680,7 @@ def make_node(self, x, y): raise TypeError(y) if y.type.dtype != x.type.dtype: raise TypeError("dtype mismatch to Dot22") - bz = (x.type.broadcastable[0], y.type.broadcastable[1]) - outputs = [tensor(x.type.dtype, bz)] + outputs = [tensor(x.type.dtype, shape=(x.type.shape[0], y.type.shape[1]))] return Apply(self, [x, y], outputs) def perform(self, node, inp, out): @@ -1986,8 +1984,8 @@ def make_node(self, x, y, a): if not a.dtype.startswith("float") and not a.dtype.startswith("complex"): raise TypeError("Dot22Scalar requires float or complex args", a.dtype) - bz = [x.type.broadcastable[0], y.type.broadcastable[1]] - outputs = [tensor(x.type.dtype, bz)] + sz = (x.type.shape[0], y.type.shape[1]) + outputs = [tensor(x.type.dtype, shape=sz)] return Apply(self, [x, y, a], outputs) def perform(self, node, inp, out): @@ -2213,12 +2211,17 @@ def make_node(self, *inputs): dtype = aesara.scalar.upcast(*[input.type.dtype for input in inputs]) # upcast inputs to common dtype if needed upcasted_inputs = [at.cast(input, dtype) for input in inputs] - broadcastable = ( - (inputs[0].type.broadcastable[0] or inputs[1].type.broadcastable[0],) - + inputs[0].type.broadcastable[1:-1] - + inputs[1].type.broadcastable[2:] + out_shape = ( + ( + 1 + if inputs[0].type.shape[0] == 1 or inputs[1].type.shape[0] == 1 + else None, + ) + + inputs[0].type.shape[1:-1] + + inputs[1].type.shape[2:] ) - return Apply(self, upcasted_inputs, [tensor(dtype, broadcastable)]) + out_shape = tuple(1 if s == 1 else None for s in out_shape) + return Apply(self, upcasted_inputs, [tensor(dtype, shape=out_shape)]) def perform(self, node, inp, out): x, y = inp diff --git a/aesara/tensor/elemwise.py b/aesara/tensor/elemwise.py index 34f9ea5459..4a3571a995 100644 --- a/aesara/tensor/elemwise.py +++ b/aesara/tensor/elemwise.py @@ -62,17 +62,17 @@ class DimShuffle(ExternalCOp): If `j = new_order[i]` is an index, the output's ith dimension will be the input's jth dimension. If `new_order[i]` is `x`, the output's ith dimension will - be 1 and Broadcast operations will be allowed to do broadcasting + be 1 and broadcast operations will be allowed to do broadcasting over that dimension. - If `input.broadcastable[i] == False` then `i` must be found in new_order. + If `input.type.shape[i] != 1` then `i` must be found in `new_order`. Broadcastable dimensions, on the other hand, can be discarded. .. code-block:: python DimShuffle((False, False, False), ['x', 2, 'x', 0, 1]) - This op will only work on 3d tensors with no broadcastable + This `Op` will only work on 3d tensors with no broadcastable dimensions. The first dimension will be broadcastable, then we will have the third dimension of the input tensor as the second of the resulting tensor, etc. If the tensor has @@ -83,7 +83,7 @@ class DimShuffle(ExternalCOp): DimShuffle((True, False), [1]) - This op will only work on 2d tensors with the first dimension + This `Op` will only work on 2d tensors with the first dimension broadcastable. The second dimension of the input tensor will be the first dimension of the resulting tensor. @@ -186,7 +186,7 @@ def __setstate__(self, state): def make_node(self, _input): input = as_tensor_variable(_input) - ib = tuple(input.type.broadcastable) + ib = tuple(s == 1 for s in input.type.shape) if ib != self.input_broadcastable: if len(ib) != len(self.input_broadcastable): raise TypeError( @@ -258,7 +258,7 @@ def grad(self, inp, grads): (x,) = inp (gz,) = grads gz = as_tensor_variable(gz) - grad_order = ["x"] * len(x.type.broadcastable) + grad_order = ["x"] * x.type.ndim for i, v in enumerate(self.new_order): if v != "x": grad_order[v] = i @@ -269,7 +269,7 @@ def grad(self, inp, grads): return [inp[0].zeros_like(dtype=config.floatX)] else: return [ - DimShuffle(gz.type.broadcastable, grad_order)( + DimShuffle(tuple(s == 1 for s in gz.type.shape), grad_order)( Elemwise(scalar_identity)(gz) ) ] @@ -406,7 +406,7 @@ def get_output_info(self, dim_shuffle, *inputs): # TODO: use LComplete instead args.append( dim_shuffle( - input.type.broadcastable, + tuple(1 if s == 1 else None for s in input.type.shape), ["x"] * difference + list(range(length)), )(input) ) @@ -452,11 +452,11 @@ def get_most_specialized_shape(shapes): inplace_pattern = self.inplace_pattern if inplace_pattern: for overwriter, overwritten in inplace_pattern.items(): - for ob, ib in zip( + for out_s, in_s in zip( out_shapes[overwriter], - inputs[overwritten].type.broadcastable, + inputs[overwritten].type.shape, ): - if ib and not ob == 1: + if in_s == 1 and out_s != 1: raise ValueError( "Operation cannot be done inplace on an input " "with broadcasted dimensions." @@ -578,8 +578,8 @@ def L_op(self, inputs, outs, ograds): # TODO: only count dimensions that were effectively broadcasted to_sum = [ j - for j, bcast in enumerate(ipt.type.broadcastable) - if bcast and not outs[0].broadcastable[j] + for j, in_s in enumerate(ipt.type.shape) + if in_s == 1 and outs[0].type.shape[j] != 1 ] if to_sum: @@ -614,7 +614,7 @@ def as_scalar(t): f"{str(self.scalar_op)}.grad returned {str(type(scalar_igrads))} instead of list or tuple" ) - nd = len(inputs[0].type.broadcastable) # this is the same for everyone + nd = inputs[0].type.ndim # this is the same for everyone def transform(r): # From a graph of ScalarOps, make a graph of Broadcast ops. @@ -897,7 +897,7 @@ def _c_all(self, node, nodename, inames, onames, sub): # for each input: # same as range(ndim), but with 'x' at all broadcastable positions orders = [ - [x and "x" or i for i, x in enumerate(input.type.broadcastable)] + [s == 1 and "x" or i for i, s in enumerate(input.type.shape)] for input in inputs ] @@ -920,7 +920,7 @@ def _c_all(self, node, nodename, inames, onames, sub): [ f"PyArray_ISFORTRAN({arr})" for arr, var in z - if not all(var.broadcastable) + if not all(s == 1 for s in var.type.shape) ] ) # If it is a scalar, make it c contig to prevent problem with @@ -1005,7 +1005,7 @@ def _c_all(self, node, nodename, inames, onames, sub): or # Use simpler code when output ndim == 0 or 1 # or for broadcated scalar. - all(node.outputs[0].broadcastable) + all(s == 1 for s in node.outputs[0].type.shape) ): if nnested: all_code = [("", "")] * (nnested - 1) + [("", code)] + [""] @@ -1077,7 +1077,7 @@ def _c_all(self, node, nodename, inames, onames, sub): all(o.ndim >= 1 for o in node.outputs) and # Don't use the contig code for broadcasted scalar. - not all(node.outputs[0].broadcastable) + not all(s == 1 for s in node.outputs[0].type.shape) ): contig = None try: @@ -1110,7 +1110,7 @@ def _c_all(self, node, nodename, inames, onames, sub): """ index = "" for x, var in zip(inames + onames, inputs + node.outputs): - if not all(var.broadcastable): + if not all(s == 1 for s in var.type.shape): contig += ( """ dtype_%(x)s * %(x)s_ptr = (dtype_%(x)s*) PyArray_DATA(%(x)s); @@ -1144,18 +1144,19 @@ def _c_all(self, node, nodename, inames, onames, sub): ) if contig is not None: z = list(zip(inames + onames, inputs + node.outputs)) + all_broadcastable = all(s == 1 for s in var.type.shape) cond1 = " && ".join( [ "PyArray_ISCONTIGUOUS(%s)" % arr for arr, var in z - if not all(var.broadcastable) + if not all_broadcastable ] ) cond2 = " && ".join( [ "PyArray_ISFORTRAN(%s)" % arr for arr, var in z - if not all(var.broadcastable) + if not all_broadcastable ] ) loop = ( @@ -1305,8 +1306,6 @@ def _output_dtype(self, input_dtype): def make_node(self, input): input = as_tensor_variable(input) inp_dims = input.type.ndim - inp_bdcast = input.type.broadcastable - inp_dtype = input.type.dtype axis = self.axis if axis is None: @@ -1329,9 +1328,12 @@ def make_node(self, input): else: op = self - broadcastable = [x for i, x in enumerate(inp_bdcast) if i not in axis] + shape = [x for i, x in enumerate(input.type.shape) if i not in axis] - output = TensorType(dtype=self._output_dtype(inp_dtype), shape=broadcastable)() + output = TensorType( + dtype=self._output_dtype(input.type.dtype), + shape=shape, + )() return Apply(op, [input], [output]) @@ -1387,13 +1389,7 @@ def infer_shape(self, fgraph, node, shapes): axis = self.axis if axis is None: return ((),) - return ( - [ - ishape[i] - for (i, b) in enumerate(node.inputs[0].type.broadcastable) - if i not in axis - ], - ) + return ([ishape[i] for i in range(node.inputs[0].type.ndim) if i not in axis],) def _c_all(self, node, name, inames, onames, sub): @@ -1411,14 +1407,14 @@ def _c_all(self, node, name, inames, onames, sub): if acc_dtype is not None: if acc_dtype == "float16": raise MethodNotDefined("no c_code for float16") - acc_type = TensorType(shape=node.outputs[0].broadcastable, dtype=acc_dtype) + acc_type = TensorType(shape=node.outputs[0].type.shape, dtype=acc_dtype) adtype = acc_type.dtype_specs()[1] else: adtype = odtype axis = self.axis if axis is None: - axis = list(range(len(input.type.broadcastable))) + axis = list(range(input.type.ndim)) if len(axis) == 0: # The acc_dtype is never a downcast compared to the input dtype diff --git a/aesara/tensor/extra_ops.py b/aesara/tensor/extra_ops.py index ca3e720339..397ff876d0 100644 --- a/aesara/tensor/extra_ops.py +++ b/aesara/tensor/extra_ops.py @@ -668,19 +668,21 @@ def make_node(self, x, repeats): ) if self.axis is None: - broadcastable = [False] + out_shape = [None] else: try: const_reps = at.get_scalar_constant_value(repeats) except NotScalarConstantError: const_reps = None if const_reps == 1: - broadcastable = x.broadcastable + out_shape = x.type.shape else: - broadcastable = list(x.broadcastable) - broadcastable[self.axis] = False + out_shape = list(x.type.shape) + out_shape[self.axis] = None - out_type = TensorType(x.dtype, broadcastable) + out_type = TensorType( + x.dtype, shape=tuple(1 if s == 1 else None for s in out_shape) + ) return Apply(self, [x, repeats], [out_type()]) @@ -1178,33 +1180,26 @@ def __init__( self.return_inverse = return_inverse self.return_counts = return_counts self.axis = axis - numpy_ver = [int(n) for n in np.__version__.split(".")[:2]] - if self.axis is not None and bool(numpy_ver < [1, 13]): - raise RuntimeError( - "Numpy version = " - + np.__version__ - + f". Option 'axis={axis}' works starting from version 1.13.0." - ) def make_node(self, x): x = at.as_tensor_variable(x) self_axis = self.axis if self_axis is None: - broadcastable = [False] + out_shape = (None,) else: if self_axis < 0: - self_axis += len(x.broadcastable) - if self_axis < 0 or self_axis >= len(x.broadcastable): - raise RuntimeError( - "Unique axis `{}` is outside of input ndim = " - "{}.".format(self.axis, len(x.broadcastable)) + self_axis += x.type.ndim + if self_axis < 0 or self_axis >= x.type.ndim: + raise ValueError( + f"Unique axis {self.axis} is outside of input ndim = {x.type.ndim}" ) - broadcastable = [ - b if axis != self_axis else False - for axis, b in enumerate(x.broadcastable) - ] - outputs = [TensorType(shape=broadcastable, dtype=x.dtype)()] - typ = TensorType(shape=[False], dtype="int64") + out_shape = tuple( + s if s == 1 and axis != self_axis else None + for axis, s in enumerate(x.type.shape) + ) + + outputs = [TensorType(dtype=x.dtype, shape=out_shape)()] + typ = TensorType(dtype="int64", shape=(None,)) if self.return_index: outputs.append(typ()) if self.return_inverse: @@ -1310,7 +1305,7 @@ def make_node(self, indices, dims): self, [indices, dims], [ - TensorType(dtype="int64", shape=(False,) * indices.ndim)() + TensorType(dtype="int64", shape=(None,) * indices.type.ndim)() for i in range(at.get_vector_length(dims)) ], ) @@ -1389,7 +1384,7 @@ def make_node(self, *inp): return Apply( self, multi_index + [dims], - [TensorType(dtype="int64", shape=(False,) * multi_index[0].ndim)()], + [TensorType(dtype="int64", shape=(None,) * multi_index[0].type.ndim)()], ) def infer_shape(self, fgraph, node, input_shapes): diff --git a/aesara/tensor/fft.py b/aesara/tensor/fft.py index 0fcdfbdeec..7cc2a9df45 100644 --- a/aesara/tensor/fft.py +++ b/aesara/tensor/fft.py @@ -15,7 +15,7 @@ class RFFTOp(Op): def output_type(self, inp): # add extra dim for real/imag - return TensorType(inp.dtype, shape=[False] * (inp.type.ndim + 1)) + return TensorType(inp.dtype, shape=(None,) * (inp.type.ndim + 1)) def make_node(self, a, s=None): a = as_tensor_variable(a) @@ -76,7 +76,7 @@ class IRFFTOp(Op): def output_type(self, inp): # remove extra dim for real/imag - return TensorType(inp.dtype, shape=[False] * (inp.type.ndim - 1)) + return TensorType(inp.dtype, shape=(None,) * (inp.type.ndim - 1)) def make_node(self, a, s=None): a = as_tensor_variable(a) diff --git a/aesara/tensor/fourier.py b/aesara/tensor/fourier.py index bc069b31e2..2bcc87ba0e 100644 --- a/aesara/tensor/fourier.py +++ b/aesara/tensor/fourier.py @@ -59,27 +59,22 @@ class Fourier(Op): def make_node(self, a, n, axis): a = as_tensor_variable(a) if a.ndim < 1: - raise TypeError( - f"{self.__class__.__name__}: input must be an array, not a scalar" - ) + raise TypeError("Input must be an array, not a scalar") if axis is None: axis = a.ndim - 1 axis = as_tensor_variable(axis) else: axis = as_tensor_variable(axis) if axis.dtype not in integer_dtypes: - raise TypeError( - "%s: index of the transformed axis must be" - " of type integer" % self.__class__.__name__ - ) + raise TypeError("Index of the transformed axis must be of type integer") elif axis.ndim != 0 or ( isinstance(axis, TensorConstant) and (axis.data < 0 or axis.data > a.ndim - 1) ): raise TypeError( - f"{self.__class__.__name__}: index of the transformed axis must be" - " a scalar not smaller than 0 and smaller than" - " dimension of array" + "Index of the transformed axis must be " + "a scalar not smaller than 0 and smaller than " + "dimension of array" ) if n is None: n = a.shape[axis] @@ -88,18 +83,21 @@ def make_node(self, a, n, axis): n = as_tensor_variable(n) if n.dtype not in integer_dtypes: raise TypeError( - "%s: length of the transformed axis must be" - " of type integer" % self.__class__.__name__ + "Length of the transformed axis must be of type integer" ) elif n.ndim != 0 or (isinstance(n, TensorConstant) and n.data < 1): raise TypeError( - "%s: length of the transformed axis must be a" - " strictly positive scalar" % self.__class__.__name__ + "Length of the transformed axis must be a strictly positive scalar" ) return Apply( self, [a, n, axis], - [TensorType("complex128", a.type.broadcastable)()], + [ + TensorType( + "complex128", + shape=tuple(1 if s == 1 else None for s in a.type.shape), + )() + ], ) def infer_shape(self, fgraph, node, in_shapes): diff --git a/aesara/tensor/io.py b/aesara/tensor/io.py index ab670b4bb2..4ddafe398e 100644 --- a/aesara/tensor/io.py +++ b/aesara/tensor/io.py @@ -21,11 +21,11 @@ class LoadFromDisk(Op): """ - __props__ = ("dtype", "broadcastable", "mmap_mode") + __props__ = ("dtype", "shape", "mmap_mode") - def __init__(self, dtype, broadcastable, mmap_mode=None): + def __init__(self, dtype, shape, mmap_mode=None): self.dtype = np.dtype(dtype) # turn "float64" into np.float64 - self.broadcastable = broadcastable + self.shape = shape if mmap_mode not in (None, "c"): raise ValueError( "The only supported values for mmap_mode " @@ -36,7 +36,7 @@ def __init__(self, dtype, broadcastable, mmap_mode=None): def make_node(self, path): if isinstance(path, str): path = Constant(Generic(), path) - return Apply(self, [path], [tensor(self.dtype, shape=self.broadcastable)]) + return Apply(self, [path], [tensor(self.dtype, shape=self.shape)]) def perform(self, node, inp, out): path = inp[0] @@ -50,14 +50,14 @@ def perform(self, node, inp, out): out[0][0] = result def __str__(self): - return "Load{{dtype: {}, broadcastable: {}, mmep: {}}}".format( + return "Load{{dtype: {}, shape: {}, mmep: {}}}".format( self.dtype, - self.broadcastable, + self.shape, self.mmap_mode, ) -def load(path, dtype, broadcastable, mmap_mode=None): +def load(path, dtype, shape, mmap_mode=None): """ Load an array from an .npy file. @@ -67,10 +67,8 @@ def load(path, dtype, broadcastable, mmap_mode=None): A Generic symbolic variable, that will contain a string dtype : data-type The data type of the array to be read. - broadcastable - The broadcastable pattern of the loaded array, for instance, - (False,) for a vector, (False, True) for a column, - (False, False) for a matrix. + shape + The static shape information of the loaded array. mmap_mode How the file will be loaded. None means that the data will be copied into an array in memory, 'c' means that the file @@ -83,7 +81,7 @@ def load(path, dtype, broadcastable, mmap_mode=None): -------- >>> from aesara import * >>> path = Variable(Generic(), None) - >>> x = tensor.load(path, 'int64', (False,)) + >>> x = tensor.load(path, 'int64', (None,)) >>> y = x*2 >>> fn = function([path], y) >>> fn("stored-array.npy") # doctest: +SKIP @@ -91,7 +89,7 @@ def load(path, dtype, broadcastable, mmap_mode=None): """ - return LoadFromDisk(dtype, broadcastable, mmap_mode)(path) + return LoadFromDisk(dtype, shape, mmap_mode)(path) ########################## @@ -129,7 +127,7 @@ def __init__(self, source, tag, shape, dtype): self.tag = tag self.shape = shape self.dtype = np.dtype(dtype) # turn "float64" into numpy.float64 - self.broadcastable = (False,) * len(shape) + self.static_shape = (None,) * len(shape) def make_node(self): return Apply( @@ -137,7 +135,7 @@ def make_node(self): [], [ Variable(Generic(), None), - tensor(self.dtype, shape=self.broadcastable), + tensor(self.dtype, shape=self.static_shape), ], ) @@ -182,7 +180,7 @@ def make_node(self, request, data): return Apply( self, [request, data], - [tensor(data.dtype, shape=data.broadcastable)], + [tensor(data.dtype, shape=data.type.shape)], ) def perform(self, node, inp, out): diff --git a/aesara/tensor/math.py b/aesara/tensor/math.py index 2b6724aa4b..c16661b9e7 100644 --- a/aesara/tensor/math.py +++ b/aesara/tensor/math.py @@ -151,13 +151,15 @@ def make_node(self, x): # We keep the original broadcastable flags for dimensions on which # we do not perform the max / argmax. all_axes = set(self.axis) - broadcastable = [ - b for i, b in enumerate(x.type.broadcastable) if i not in all_axes - ] inputs = [x] + out_shape = tuple( + 1 if s == 1 else None + for i, s in enumerate(x.type.shape) + if i not in all_axes + ) outputs = [ - tensor(x.type.dtype, broadcastable, name="max"), - tensor("int64", broadcastable, name="argmax"), + tensor(x.type.dtype, shape=out_shape, name="max"), + tensor("int64", shape=out_shape, name="argmax"), ] return Apply(self, inputs, outputs) @@ -375,10 +377,8 @@ def make_node(self, x, axis=None): # We keep the original broadcastable flags for dimensions on which # we do not perform the argmax. - broadcastable = [ - b for i, b in enumerate(x.type.broadcastable) if i not in all_axes - ] - outputs = [tensor("int64", broadcastable, name="argmax")] + out_shape = tuple(s for i, s in enumerate(x.type.shape) if i not in all_axes) + outputs = [tensor("int64", shape=out_shape, name="argmax")] return Apply(self, inputs, outputs) def prepare_node(self, node, storage_map, compute_map, impl): @@ -1911,15 +1911,14 @@ def make_node(self, *inputs): "aesara.tensor.dot instead." ) - i_broadcastables = [input.type.broadcastable for input in inputs] - bx, by = i_broadcastables - if len(by) == 2: # y is a matrix - bz = bx[:-1] + by[-1:] - elif len(by) == 1: # y is vector - bz = bx[:-1] + sx, sy = [input.type.shape for input in inputs] + if len(sy) == 2: + sz = sx[:-1] + sy[-1:] + elif len(sy) == 1: + sz = sx[:-1] i_dtypes = [input.type.dtype for input in inputs] - outputs = [tensor(aes.upcast(*i_dtypes), bz)] + outputs = [tensor(aes.upcast(*i_dtypes), shape=sz)] return Apply(self, inputs, outputs) def perform(self, node, inp, out): diff --git a/aesara/tensor/nnet/abstract_conv.py b/aesara/tensor/nnet/abstract_conv.py index dbfc0b7b69..f27b85620e 100644 --- a/aesara/tensor/nnet/abstract_conv.py +++ b/aesara/tensor/nnet/abstract_conv.py @@ -2492,10 +2492,11 @@ def make_node(self, img, kern): "filters does not match given kshp.", ) - broadcastable = [img.broadcastable[0], kern.broadcastable[0]] + ( - [False] * self.convdim - ) - output = img.type.clone(shape=broadcastable)() + out_shape = ( + 1 if img.type.shape[0] == 1 else None, + 1 if kern.type.shape[0] == 1 else None, + ) + ((None,) * self.convdim) + output = img.type.clone(shape=out_shape)() return Apply(self, [img, kern], [output]) def perform(self, node, inp, out_): @@ -2817,17 +2818,18 @@ def make_node(self, img, topgrad, shape, add_assert_shape=True): shape = as_tensor_variable(shape) if self.unshared: - broadcastable = ( - [topgrad.broadcastable[1]] - + ([False] * self.convdim) - + [img.broadcastable[1]] - + ([False] * self.convdim) + out_shape = ( + (topgrad.type.shape[1],) + + ((None,) * self.convdim) + + (img.type.shape[1],) + + ((None,) * self.convdim) ) else: - broadcastable = [topgrad.broadcastable[1], img.broadcastable[1]] + ( - [False] * self.convdim + out_shape = (topgrad.type.shape[1], img.type.shape[1]) + ( + (None,) * self.convdim ) - output = img.type.clone(shape=broadcastable)() + out_shape = tuple(1 if s == 1 else None for s in out_shape) + output = img.type.clone(shape=out_shape)() return Apply(self, [img, topgrad, shape], [output]) def perform(self, node, inp, out_): @@ -3146,7 +3148,10 @@ def make_node(self, kern, topgrad, shape, add_assert_shape=True): kern = as_tensor_variable(kern) if not isinstance(topgrad, Variable): topgrad = as_tensor_variable(topgrad) - gtype = kern.type.clone(dtype=topgrad.dtype, shape=topgrad.broadcastable) + gtype = kern.type.clone( + dtype=topgrad.dtype, + shape=tuple(1 if s == 1 else None for s in topgrad.type.shape), + ) topgrad = gtype.filter_variable(topgrad) if self.unshared: @@ -3175,15 +3180,13 @@ def make_node(self, kern, topgrad, shape, add_assert_shape=True): shape = as_tensor_variable(shape) if self.num_groups > 1: - broadcastable = [topgrad.type.broadcastable[0], False] + ( - [False] * self.convdim - ) + out_shape = (topgrad.type.shape[0], None) + ((None,) * self.convdim) else: - broadcastable = [ - topgrad.type.broadcastable[0], - kern.type.broadcastable[-self.convdim - 1], - ] + ([False] * self.convdim) - output = kern.type.clone(shape=broadcastable)() + out_shape = (topgrad.type.shape[0], kern.type.shape[-self.convdim - 1]) + ( + (None,) * self.convdim + ) + out_shape = tuple(1 if s == 1 else None for s in out_shape) + output = kern.type.clone(shape=out_shape)() return Apply(self, [kern, topgrad, shape], [output]) def perform(self, node, inp, out_): diff --git a/aesara/tensor/nnet/basic.py b/aesara/tensor/nnet/basic.py index 888350877d..61eaf4584c 100644 --- a/aesara/tensor/nnet/basic.py +++ b/aesara/tensor/nnet/basic.py @@ -507,8 +507,8 @@ def make_node(self, x, b, y_idx): raise ValueError("y_idx must be 1-d tensor of [u]ints", y_idx.type) # TODO: Is this correct? It used to be y, not y_idx - nll = TensorType(x.type.dtype, y_idx.type.broadcastable).make_variable() - # nll = TensorType(x.dtype, y.broadcastable) + out_shape = tuple(1 if s == 1 else None for s in y_idx.type.shape) + nll = TensorType(x.type.dtype, shape=out_shape).make_variable() sm = x.type() am = y_idx.type() return Apply(self, [x, b, y_idx], [nll, sm, am]) @@ -986,7 +986,7 @@ def make_node(self, coding_dist, true_one_of_n): return Apply( self, [_coding_dist, _true_one_of_n], - [TensorType(dtype=_coding_dist.dtype, shape=[False])()], + [TensorType(dtype=_coding_dist.dtype, shape=(None,))()], ) def perform(self, node, inp, out): diff --git a/aesara/tensor/nnet/conv.py b/aesara/tensor/nnet/conv.py index 0dbb0240c1..b0c391cef4 100644 --- a/aesara/tensor/nnet/conv.py +++ b/aesara/tensor/nnet/conv.py @@ -739,10 +739,16 @@ def make_node(self, inputs, kerns): "The image and the kernel must have the same type." "inputs({_inputs.dtype}), kerns({_kerns.dtype})" ) - bcastable23 = [self.outshp[0] == 1, self.outshp[1] == 1] + out_shape = ( + _inputs.type.shape[0], + _kerns.type.shape[0], + self.outshp[0], + self.outshp[1], + ) + out_shape = tuple(1 if s == 1 else None for s in out_shape) output = tensor( dtype=_inputs.type.dtype, - shape=[_inputs.broadcastable[0], _kerns.broadcastable[0]] + bcastable23, + shape=out_shape, ) return Apply(self, [_inputs, _kerns], [output]) diff --git a/aesara/tensor/nnet/corr.py b/aesara/tensor/nnet/corr.py index c6758a11e1..e89054d29f 100644 --- a/aesara/tensor/nnet/corr.py +++ b/aesara/tensor/nnet/corr.py @@ -692,14 +692,14 @@ def make_node(self, img, kern): if kern.type.ndim != 4: raise TypeError("kern must be 4D tensor") - broadcastable = [ - img.type.broadcastable[0], - kern.type.broadcastable[0], - False, - False, - ] + out_shape = tuple( + 1 if img.type.shape[0] == 1 else None, + 1 if kern.type.shape[0] == 1 else None, + None, + None, + ) dtype = img.type.dtype - return Apply(self, [img, kern], [TensorType(dtype, broadcastable)()]) + return Apply(self, [img, kern], [TensorType(dtype, shape=out_shape)()]) def infer_shape(self, fgraph, node, input_shape): imshp = input_shape[0] @@ -770,24 +770,25 @@ def make_node(self, img, topgrad, shape=None): ] if self.unshared is True: - broadcastable = [ - topgrad.type.broadcastable[1], - False, - False, - img.type.broadcastable[1], - False, - False, + out_shape = [ + 1 if topgrad.type.shape[1] == 1 else None, + None, + None, + 1 if img.type.shape[1] == 1 else None, + None, + None, ] else: - broadcastable = [ - topgrad.type.broadcastable[1], - img.type.broadcastable[1], - False, - False, + out_shape = [ + 1 if topgrad.type.shape[1] == 1 else None, + 1 if img.type.shape[1] == 1 else None, + None, + None, ] + dtype = img.type.dtype return Apply( - self, [img, topgrad] + height_width, [TensorType(dtype, broadcastable)()] + self, [img, topgrad] + height_width, [TensorType(dtype, shape=out_shape)()] ) def infer_shape(self, fgraph, node, input_shape): @@ -905,17 +906,17 @@ def make_node(self, kern, topgrad, shape=None): ] if self.num_groups > 1: - broadcastable = [topgrad.type.broadcastable[0], False, False, False] + out_shape = [1 if topgrad.type.shape[0] == 1 else None, None, None, None] else: - broadcastable = [ - topgrad.type.broadcastable[0], - kern.type.broadcastable[-3], - False, - False, + out_shape = [ + 1 if topgrad.type.shape[0] == 1 else None, + 1 if kern.type.shape[-3] == 1 else None, + None, + None, ] dtype = kern.type.dtype return Apply( - self, [kern, topgrad] + height_width, [TensorType(dtype, broadcastable)()] + self, [kern, topgrad] + height_width, [TensorType(dtype, shape=out_shape)()] ) def infer_shape(self, fgraph, node, input_shape): diff --git a/aesara/tensor/nnet/corr3d.py b/aesara/tensor/nnet/corr3d.py index dc2585b132..fa9d146777 100644 --- a/aesara/tensor/nnet/corr3d.py +++ b/aesara/tensor/nnet/corr3d.py @@ -631,15 +631,15 @@ def make_node(self, img, kern): if kern.type.ndim != 5: raise TypeError("kern must be 5D tensor") - broadcastable = [ - img.type.broadcastable[0], - kern.type.broadcastable[0], - False, - False, - False, + out_shape = [ + 1 if img.type.shape[0] == 1 else None, + 1 if kern.type.shape[0] == 1 else None, + None, + None, + None, ] dtype = img.type.dtype - return Apply(self, [img, kern], [TensorType(dtype, broadcastable)()]) + return Apply(self, [img, kern], [TensorType(dtype, shape=out_shape)()]) def infer_shape(self, fgraph, node, input_shape): imshp = input_shape[0] @@ -708,18 +708,18 @@ def make_node(self, img, topgrad, shape=None): as_tensor_variable(shape[2]).astype("int64"), ] - broadcastable = [ - topgrad.type.broadcastable[1], - img.type.broadcastable[1], - False, - False, - False, + out_shape = [ + 1 if topgrad.type.shape[1] == 1 else None, + 1 if img.type.shape[1] == 1 else None, + None, + None, + None, ] dtype = img.type.dtype return Apply( self, [img, topgrad] + height_width_depth, - [TensorType(dtype, broadcastable)()], + [TensorType(dtype, shape=out_shape)()], ) def infer_shape(self, fgraph, node, input_shape): @@ -829,11 +829,17 @@ def make_node(self, kern, topgrad, shape=None): ] if self.num_groups > 1: - broadcastable = [topgrad.type.broadcastable[0], False, False, False, False] + out_shape = [ + 1 if topgrad.type.shape[0] == 1 else None, + None, + None, + None, + None, + ] else: - broadcastable = [ - topgrad.type.broadcastable[0], - kern.type.broadcastable[1], + out_shape = [ + 1 if topgrad.type.shape[0] == 1 else None, + 1 if kern.type.shape[1] == 1 else None, False, False, False, @@ -842,7 +848,7 @@ def make_node(self, kern, topgrad, shape=None): return Apply( self, [kern, topgrad] + height_width_depth, - [TensorType(dtype, broadcastable)()], + [TensorType(dtype, shape=out_shape)()], ) def infer_shape(self, fgraph, node, input_shape): diff --git a/aesara/tensor/rewriting/basic.py b/aesara/tensor/rewriting/basic.py index 7cb095a346..831324b27b 100644 --- a/aesara/tensor/rewriting/basic.py +++ b/aesara/tensor/rewriting/basic.py @@ -1155,7 +1155,7 @@ def constant_folding(fgraph, node): if isinstance(output.type, DenseTensorType): output_type = TensorType( output.type.dtype, - tuple(s == 1 for s in data.shape), + shape=data.shape, name=output.type.name, ) else: diff --git a/aesara/tensor/rewriting/shape.py b/aesara/tensor/rewriting/shape.py index a3b30177f0..87d77b1322 100644 --- a/aesara/tensor/rewriting/shape.py +++ b/aesara/tensor/rewriting/shape.py @@ -364,8 +364,8 @@ def set_shape(self, r, s, override=False): else: shape_vars.append(self.unpack(s[i], r)) assert all( - not hasattr(r.type, "broadcastable") - or not r.type.broadcastable[i] + not hasattr(r.type, "shape") + or r.type.shape[i] != 1 or self.lscalar_one.equals(shape_vars[i]) or self.lscalar_one.equals(extract_constant(shape_vars[i])) for i in range(r.type.ndim) @@ -447,9 +447,9 @@ def update_shape(self, r, other_r): merged_shape.append(other_shape[i]) assert all( ( - not hasattr(r.type, "broadcastable") - or not r.type.broadcastable[i] - and not other_r.type.broadcastable[i] + not hasattr(r.type, "shape") + or r.type.shape[i] != 1 + and other_r.type.shape[i] != 1 ) or self.lscalar_one.equals(merged_shape[i]) or self.lscalar_one.equals( @@ -474,8 +474,8 @@ def set_shape_i(self, r, i, s_i): else: new_shape.append(s_j) assert all( - not hasattr(r.type, "broadcastable") - or not r.type.broadcastable[idx] + not hasattr(r.type, "shape") + or r.type.shape[idx] != 1 or self.lscalar_one.equals(new_shape[idx]) or self.lscalar_one.equals(extract_constant(new_shape[idx])) for idx in range(r.type.ndim) @@ -781,7 +781,11 @@ def f(fgraph, node): # We should try to figure out why we lost the information about this # constant value... but in the meantime, better not apply this # rewrite. - if rval.broadcastable == node.outputs[0].broadcastable: + if rval.type.ndim == node.outputs[0].type.ndim and all( + s1 == s1 + for s1, s2 in zip(rval.type.shape, node.outputs[0].type.shape) + if s1 == 1 or s2 == 1 + ): return [rval] else: return False @@ -797,27 +801,31 @@ def f(fgraph, node): @register_stabilize @node_rewriter([Reshape]) def local_useless_reshape(fgraph, node): - """ - Remove two kinds of useless reshape. + """Remove two kinds of useless `Reshape`. - Remove Reshape when both the input and output have a single dimension. - Remove Reshape when reshaping to the shape of the input. + - Remove `Reshape` when both the input and output have a single dimension. + - Remove `Reshape` when reshaping to the shape of the input. """ - op = node.op - if not isinstance(op, Reshape): - return False - inp = node.inputs[0] output = node.outputs[0] output_shape = node.inputs[1] - if inp.ndim != output.ndim: + if inp.type.ndim != output.type.ndim: return False # Simple case: both input and output have a single dimension. - # This could hide errors if the user provides inconsistent shapes. - if inp.ndim == 1 and output.ndim == 1 and inp.broadcastable == output.broadcastable: + # TODO FIXME XXX: This could hide errors if the user provides inconsistent + # shapes. + if ( + inp.type.ndim == 1 + and output.type.ndim == 1 + and all( + s1 == s2 + for s1, s2 in zip(inp.type.shape, output.type.shape) + if s1 == 1 or s2 == 1 + ) + ): return [inp] # Second case: all the shapes match the input shape @@ -835,8 +843,8 @@ def local_useless_reshape(fgraph, node): shape_feature = getattr(fgraph, "shape_feature", None) nb_m1 = 0 - shape_match = [False] * inp.ndim - for dim in range(inp.ndim): + shape_match = [False] * inp.type.ndim + for dim in range(inp.type.ndim): outshp_i = output_shape_is[dim] # Match Shape_i{dim}(input) if ( @@ -862,9 +870,9 @@ def local_useless_reshape(fgraph, node): shape_match[dim] = True continue - # Match 1 if input.broadcastable[dim] is True + # Match 1 if input.type.shape[dim] == 1 cst_outshp_i = extract_constant(outshp_i, only_process_constants=1) - if inp.broadcastable[dim] and cst_outshp_i == 1: + if inp.type.shape[dim] == 1 and cst_outshp_i == 1: shape_match[dim] = True continue @@ -895,22 +903,18 @@ def local_useless_reshape(fgraph, node): @register_canonicalize @node_rewriter([Reshape]) def local_reshape_to_dimshuffle(fgraph, node): - """ - Broadcastable dimensions in Reshape are replaced with dimshuffle. + r"""Replace broadcastable dimensions in `Reshape` nodes with `DimShuffle`\s. - The goal is to avoid using reshape to add or remove broadcastable - dimensions, but use dimshuffle instead, so dimshuffles can cancel out - or be removed later on. + The goal is to avoid using `Reshape` to add or remove broadcastable + dimensions, and to use `DimShuffle` instead, since `DimShuffle`\s can + cancel out and/or be removed later on. For example: - - reshape(x, (1, n)) --> dimshuffle{x,0}(reshape(x, (n,)) + - reshape(x, (1, n)) -> DimShuffle{x,0}(Reshape(x, (n,)) - reshape(x, (1, m, 1, n, 1, 1)) - --> dimshuffle{x,0,x,1,x,x}(reshape(x, (m, n))) + -> DimShuffle{x,0,x,1,x,x}(Reshape(x, (m, n))) """ op = node.op - if not isinstance(op, Reshape): - return False - inp = node.inputs[0] output = node.outputs[0] output_shape = node.inputs[1] @@ -931,10 +935,15 @@ def local_reshape_to_dimshuffle(fgraph, node): dimshuffle_new_order.append(index) new_output_shape.append(dim) index = index + 1 - if index != output.ndim: + + if index != output.type.ndim: inner = op.__class__(len(new_output_shape))(inp, new_output_shape) copy_stack_trace(output, inner) - new_node = [DimShuffle(inner.type.broadcastable, dimshuffle_new_order)(inner)] + new_node = [ + DimShuffle(tuple(s == 1 for s in inner.type.shape), dimshuffle_new_order)( + inner + ) + ] copy_stack_trace(output, new_node) return new_node @@ -1023,8 +1032,8 @@ def local_Shape_of_SpecifyShape(fgraph, node): @register_useless @register_canonicalize @node_rewriter([Shape_i]) -def local_Shape_i_of_broadcastable(fgraph, node): - """Replace ``shape_i(x, i)`` with ``1`` when ``x.broadcastable[i]`` is ``True``.""" +def local_Shape_i_ground(fgraph, node): + """Replace ``shape_i(x, i)`` with ``s`` when ``x.type.shape[i] == s``.""" if not isinstance(node.op, Shape_i): return False @@ -1034,8 +1043,9 @@ def local_Shape_i_of_broadcastable(fgraph, node): if not isinstance(shape_arg.type, TensorType): return False - if shape_arg.broadcastable[node.op.i]: - return [as_tensor_variable(1, dtype=np.int64)] + s_val = shape_arg.type.shape[node.op.i] + if s_val is not None: + return [as_tensor_variable(s_val, dtype=np.int64)] @register_specialize @@ -1098,10 +1108,9 @@ def local_useless_dimshuffle_in_reshape(fgraph, node): new_order = node.inputs[0].owner.op.new_order inp = node.inputs[0].owner.inputs[0] - broadcastables = node.inputs[0].broadcastable new_order_of_nonbroadcast = [] - for i, bd in zip(new_order, broadcastables): - if not bd: + for i, s in zip(new_order, node.inputs[0].type.shape): + if s != 1: new_order_of_nonbroadcast.append(i) no_change_in_order = all( new_order_of_nonbroadcast[i] <= new_order_of_nonbroadcast[i + 1] @@ -1125,7 +1134,11 @@ def local_useless_unbroadcast(fgraph, node): """ if isinstance(node.op, Unbroadcast): x = node.inputs[0] - if x.broadcastable == node.outputs[0].broadcastable: + if x.type.ndim == node.outputs[0].type.ndim and all( + s1 == s2 + for s1, s2 in zip(x.type.shape, node.outputs[0].type.shape) + if s1 == 1 or s2 == 1 + ): # No broadcastable flag was modified # No need to copy over stack trace, # because x should already have a stack trace. diff --git a/aesara/tensor/shape.py b/aesara/tensor/shape.py index f6ed3590c5..065a9d7b35 100644 --- a/aesara/tensor/shape.py +++ b/aesara/tensor/shape.py @@ -8,6 +8,7 @@ import aesara from aesara.gradient import DisconnectedType from aesara.graph.basic import Apply, Variable +from aesara.graph.type import HasShape from aesara.link.c.op import COp from aesara.link.c.params_type import ParamsType from aesara.misc.safe_asarray import _asarray @@ -158,18 +159,28 @@ def _get_vector_length_Shape(op, var): def shape_tuple(x: TensorVariable) -> Tuple[Variable, ...]: - """Get a tuple of symbolic shape values. + r"""Get a tuple of symbolic shape values. + + This will return `ScalarConstant`\s for static shape values. - This will return a `ScalarConstant` with the value ``1`` wherever - broadcastable is ``True``. """ - one_at = aesara.scalar.ScalarConstant(aesara.scalar.int64, 1) - return tuple( - one_at if getattr(sh, "value", sh) == 1 or bcast else sh - for sh, bcast in zip( - shape(x), getattr(x, "broadcastable", (False,) * x.type.ndim) - ) - ) + if not isinstance(x.type, HasShape): + # We assume/call it a scalar + return () + + res = () + symbolic_shape = shape(x) + static_shape = x.type.shape + for i in range(x.type.ndim): + shape_val = static_shape[i] + + if shape_val is not None: + # TODO: Why not use uint64? + res += (aesara.scalar.ScalarConstant(aesara.scalar.int64, shape_val),) + else: + res += (symbolic_shape[i],) + + return res class Shape_i(COp): @@ -536,7 +547,8 @@ def specify_shape( ): """Specify a fixed shape for a `Variable`. - If a dimension's shape value is ``None``, the size of that dimension is not considered fixed/static at runtime. + If a dimension's shape value is ``None``, the size of that dimension is not + considered fixed/static at runtime. """ if not isinstance(shape, (tuple, list)): @@ -608,28 +620,27 @@ def make_node(self, x, shp): # except when shp is constant and empty # (in this case, shp.dtype does not matter anymore). raise TypeError(f"Shape must be integers; got {shp.dtype}") + assert shp.ndim == 1 + if isinstance(shp, TensorConstant): - bcast = [s == 1 for s in shp.data] - return Apply(self, [x, shp], [tensor(x.type.dtype, bcast)]) + out_shape = tuple(int(s) if s >= 0 else None for s in shp.data) else: - bcasts = [False] * self.ndim + out_shape = [None] * self.ndim shp_list = shp_orig if hasattr(shp_orig, "ndim") and shp_orig.ndim == 0: shp_list = [shp_orig] for index in range(self.ndim): y = shp_list[index] y = at.as_tensor_variable(y) - # Try to see if we can infer that y has a constant value of 1. - # If so, that dimension should be broadcastable. try: - bcasts[index] = ( - hasattr(y, "get_scalar_constant_value") - and y.get_scalar_constant_value() == 1 - ) + s_val = at.get_scalar_constant_value(y).item() + if s_val >= 0: + out_shape[index] = s_val except NotScalarConstantError: pass - return Apply(self, [x, shp], [tensor(x.type.dtype, bcasts)]) + + return Apply(self, [x, shp], [tensor(x.type.dtype, shape=out_shape)]) def perform(self, node, inp, out_, params): x, shp = inp @@ -769,7 +780,7 @@ def c_code(self, node, name, inputs, outputs, sub): def reshape(x, newshape, ndim=None): if ndim is None: newshape = at.as_tensor_variable(newshape) - if newshape.ndim != 1: + if newshape.type.ndim != 1: raise TypeError( "New shape in reshape must be a vector or a list/tuple of" f" scalar. Got {newshape} after conversion to a vector." @@ -894,8 +905,7 @@ def shape_padaxis(t, axis): def specify_broadcastable(x, *axes): - """ - Specify the input as being broadcastable in the specified axes. + """Specify the input as being broadcastable in the specified axes. For example, specify_broadcastable(x, 0) will make the first dimension of x broadcastable. When performing the function, if the length of @@ -924,7 +934,7 @@ def specify_broadcastable(x, *axes): if max(axes) >= x.type.ndim: raise ValueError("Trying to specify broadcastable of non-existent dimension") - shape_info = [1 if i in axes else None for i in range(len(x.type.shape))] + shape_info = [1 if i in axes else s for i, s in enumerate(x.type.shape)] return specify_shape(x, shape_info) diff --git a/aesara/tensor/sharedvar.py b/aesara/tensor/sharedvar.py index 76d9f3148b..947127d2e1 100644 --- a/aesara/tensor/sharedvar.py +++ b/aesara/tensor/sharedvar.py @@ -68,7 +68,7 @@ def tensor_constructor( # the value might be resized in any dimension in the future. # if shape is None: - shape = (False,) * len(value.shape) + shape = (None,) * len(value.shape) type = TensorType(value.dtype, shape=shape) return TensorSharedVariable( type=type, diff --git a/aesara/tensor/signal/pool.py b/aesara/tensor/signal/pool.py index bb46501244..543896a022 100755 --- a/aesara/tensor/signal/pool.py +++ b/aesara/tensor/signal/pool.py @@ -542,8 +542,10 @@ def make_node(self, x, ws, stride=None, pad=None): if pad.dtype not in int_dtypes: raise TypeError("Padding parameters must be ints.") # If the input shape are broadcastable we can have 0 in the output shape - broad = x.broadcastable[:-nd] + (False,) * nd - out = TensorType(x.dtype, broad) + out_shape = tuple( + 1 if s == 1 else None for s in x.type.shape[:-nd] + (None,) * nd + ) + out = TensorType(x.dtype, shape=out_shape) return Apply(self, [x, ws, stride, pad], [out()]) def perform(self, node, inp, out, params): @@ -2208,8 +2210,10 @@ def make_node(self, x, eval_point, ws, stride=None, pad=None): if not pad.dtype.startswith("int"): raise TypeError("Padding parameters must be ints.") # If the input shape are broadcastable we can have 0 in the output shape - broad = x.broadcastable[:-nd] + (False,) * nd - out = TensorType(eval_point.dtype, broad) + out_shape = tuple( + 1 if s == 1 else None for s in x.type.shape[:-nd] + (None,) * nd + ) + out = TensorType(eval_point.dtype, shape=out_shape) return Apply(self, [x, eval_point, ws, stride, pad], [out()]) def perform(self, node, inp, out, params): diff --git a/aesara/tensor/slinalg.py b/aesara/tensor/slinalg.py index 8bcd353a72..cd3674f1c6 100644 --- a/aesara/tensor/slinalg.py +++ b/aesara/tensor/slinalg.py @@ -215,7 +215,7 @@ def make_node(self, C, b): o_dtype = scipy.linalg.solve( np.eye(1).astype(C.dtype), np.eye(1).astype(b.dtype) ).dtype - x = tensor(shape=b.broadcastable, dtype=o_dtype) + x = tensor(dtype=o_dtype, shape=b.type.shape) return Apply(self, [C, b], [x]) def perform(self, node, inputs, output_storage): @@ -292,7 +292,7 @@ def make_node(self, A, b): o_dtype = scipy.linalg.solve( np.eye(1).astype(A.dtype), np.eye(1).astype(b.dtype) ).dtype - x = tensor(shape=b.broadcastable, dtype=o_dtype) + x = tensor(dtype=o_dtype, shape=b.type.shape) return Apply(self, [A, b], [x]) def infer_shape(self, fgraph, node, shapes): diff --git a/aesara/tensor/sort.py b/aesara/tensor/sort.py index 20bd23fcfc..9d3f870dcf 100644 --- a/aesara/tensor/sort.py +++ b/aesara/tensor/sort.py @@ -414,9 +414,13 @@ def make_node(self, inp, kth): _check_tensor_is_scalar(kth) outs = [] if self.return_values: - outs.append(inp.type()) + outs.append( + TensorType(dtype=inp.type.dtype, shape=(None,) * inp.type.ndim)() + ) if self.return_indices: - outs.append(TensorType(dtype=self.idx_dtype, shape=inp.type.shape)()) + outs.append( + TensorType(dtype=self.idx_dtype, shape=(None,) * inp.type.ndim)() + ) return Apply(self, [inp, kth], outs) def perform(self, node, inputs, output_storage): diff --git a/aesara/tensor/subtensor.py b/aesara/tensor/subtensor.py index f9abfaf784..4260fb444c 100644 --- a/aesara/tensor/subtensor.py +++ b/aesara/tensor/subtensor.py @@ -724,10 +724,11 @@ def make_node(self, x, *inputs): padded = get_constant_idx( self.idx_list, (None,) + inputs, allow_partial=True ) + [slice(None, None, None)] * (x.type.ndim - len(idx_list)) - broadcastable = [] - for i, (p, bc) in enumerate(zip(padded, x.type.broadcastable)): + + out_shape = [] + for i, (p, s) in enumerate(zip(padded, x.type.shape)): if isinstance(p, slice): - if bc: + if s == 1: start = p.start try: start = get_scalar_constant_value(start) @@ -741,15 +742,15 @@ def make_node(self, x, *inputs): isinstance(p.stop, (int, np.integer, np.ndarray)) and p.stop > start ): - broadcastable.append(True) + out_shape.append(1) continue - broadcastable.append(False) + out_shape.append(None) return Apply( self, (x,) + inputs, - [tensor(dtype=x.type.dtype, shape=broadcastable)], + [tensor(dtype=x.type.dtype, shape=out_shape)], ) def perform(self, node, inputs, out_): @@ -1948,8 +1949,9 @@ def make_node(self, x, ilist): raise TypeError("index must be vector") if x_.type.ndim == 0: raise TypeError("cannot index into a scalar") - bcast = (ilist_.broadcastable[0],) + x_.broadcastable[1:] - return Apply(self, [x_, ilist_], [TensorType(dtype=x.dtype, shape=bcast)()]) + out_shape = (ilist_.type.shape[0],) + x_.type.shape[1:] + out_shape = tuple(1 if s == 1 else None for s in out_shape) + return Apply(self, [x_, ilist_], [TensorType(dtype=x.dtype, shape=out_shape)()]) def perform(self, node, inp, out_): x, i = inp @@ -2551,17 +2553,14 @@ def make_node(self, x, *index): x = as_tensor_variable(x) index = tuple(map(as_index_variable, index)) - # We only want the broadcast information, and we don't need recursive - # `Subtensor` calls, so we create a fake symbolic shape tuple and - # identify the broadcast dimensions from the shape result of this - # entire subtensor operation. + # We create a fake symbolic shape tuple and identify the broadcast + # dimensions from the shape result of this entire subtensor operation. with config.change_flags(compute_test_value="off"): fake_shape = tuple( - tensor(dtype="int64", shape=()) if not bcast else 1 - for bcast in x.broadcastable + tensor(dtype="int64", shape=()) if s != 1 else 1 for s in x.type.shape ) - bcast_index = tuple( + fake_index = tuple( chain.from_iterable( aesara.tensor.basic.nonzero(idx) if getattr(idx, "ndim", 0) > 0 @@ -2571,15 +2570,15 @@ def make_node(self, x, *index): ) ) - bcast = [ - getattr(i, "value", i) == 1 - for i in indexed_result_shape(fake_shape, bcast_index) - ] + out_shape = tuple( + i.value if isinstance(i, Constant) else None + for i in indexed_result_shape(fake_shape, fake_index) + ) return Apply( self, (x,) + index, - [tensor(dtype=x.type.dtype, shape=bcast)], + [tensor(dtype=x.type.dtype, shape=out_shape)], ) def R_op(self, inputs, eval_points): @@ -2682,7 +2681,12 @@ def make_node(self, x, y, *inputs): return Apply( self, (x, y) + tuple(new_inputs), - [tensor(dtype=x.type.dtype, shape=x.type.broadcastable)], + [ + tensor( + dtype=x.type.dtype, + shape=tuple(1 if s == 1 else None for s in x.type.shape), + ) + ], ) def perform(self, node, inputs, out_): diff --git a/aesara/tensor/type.py b/aesara/tensor/type.py index df6fafa983..5890b6e22e 100644 --- a/aesara/tensor/type.py +++ b/aesara/tensor/type.py @@ -1,6 +1,6 @@ import logging import warnings -from typing import Iterable, Optional, Tuple, Union +from typing import TYPE_CHECKING, Iterable, Optional, Tuple, Union import numpy as np @@ -15,6 +15,12 @@ from aesara.utils import apply_across_args +if TYPE_CHECKING: + from numpy.typing import DTypeLike + + from aesara.tensor.var import TensorVariable + + _logger = logging.getLogger("aesara.tensor.type") @@ -380,7 +386,18 @@ def __str__(self): if self.name: return self.name else: - return f"TensorType({self.dtype}, {self.shape})" + + def shape_str(s): + if s is None: + return "?" + else: + return str(s) + + formatted_shape = ", ".join([shape_str(s) for s in self.shape]) + if len(self.shape) == 1: + formatted_shape += "," + + return f"TensorType({self.dtype}, ({formatted_shape}))" def __repr__(self): return str(self) @@ -805,14 +822,14 @@ def scalar(name=None, dtype=None): float_scalar_types = float_types complex_scalar_types = complex_types -cvector = TensorType("complex64", (False,)) -zvector = TensorType("complex128", (False,)) -fvector = TensorType("float32", (False,)) -dvector = TensorType("float64", (False,)) -bvector = TensorType("int8", (False,)) -wvector = TensorType("int16", (False,)) -ivector = TensorType("int32", (False,)) -lvector = TensorType("int64", (False,)) +cvector = TensorType("complex64", shape=(None,)) +zvector = TensorType("complex128", shape=(None,)) +fvector = TensorType("float32", shape=(None,)) +dvector = TensorType("float64", shape=(None,)) +bvector = TensorType("int8", shape=(None,)) +wvector = TensorType("int16", shape=(None,)) +ivector = TensorType("int32", shape=(None,)) +lvector = TensorType("int64", shape=(None,)) def vector(name=None, dtype=None): @@ -828,7 +845,7 @@ def vector(name=None, dtype=None): """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False,)) + type = TensorType(dtype, shape=(None,)) return type(name) @@ -840,14 +857,14 @@ def vector(name=None, dtype=None): float_vector_types = fvector, dvector complex_vector_types = cvector, zvector -cmatrix = TensorType("complex64", (False, False)) -zmatrix = TensorType("complex128", (False, False)) -fmatrix = TensorType("float32", (False, False)) -dmatrix = TensorType("float64", (False, False)) -bmatrix = TensorType("int8", (False, False)) -wmatrix = TensorType("int16", (False, False)) -imatrix = TensorType("int32", (False, False)) -lmatrix = TensorType("int64", (False, False)) +cmatrix = TensorType("complex64", shape=(None, None)) +zmatrix = TensorType("complex128", shape=(None, None)) +fmatrix = TensorType("float32", shape=(None, None)) +dmatrix = TensorType("float64", shape=(None, None)) +bmatrix = TensorType("int8", shape=(None, None)) +wmatrix = TensorType("int16", shape=(None, None)) +imatrix = TensorType("int32", shape=(None, None)) +lmatrix = TensorType("int64", shape=(None, None)) def matrix(name=None, dtype=None): @@ -863,7 +880,7 @@ def matrix(name=None, dtype=None): """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False, False)) + type = TensorType(dtype, shape=(None, None)) return type(name) @@ -875,18 +892,18 @@ def matrix(name=None, dtype=None): float_matrix_types = fmatrix, dmatrix complex_matrix_types = cmatrix, zmatrix -crow = TensorType("complex64", (True, False)) -zrow = TensorType("complex128", (True, False)) -frow = TensorType("float32", (True, False)) -drow = TensorType("float64", (True, False)) -brow = TensorType("int8", (True, False)) -wrow = TensorType("int16", (True, False)) -irow = TensorType("int32", (True, False)) -lrow = TensorType("int64", (True, False)) +crow = TensorType("complex64", shape=(1, None)) +zrow = TensorType("complex128", shape=(1, None)) +frow = TensorType("float32", shape=(1, None)) +drow = TensorType("float64", shape=(1, None)) +brow = TensorType("int8", shape=(1, None)) +wrow = TensorType("int16", shape=(1, None)) +irow = TensorType("int32", shape=(1, None)) +lrow = TensorType("int64", shape=(1, None)) def row(name=None, dtype=None): - """Return a symbolic row variable (ndim=2, shape=[True,False]). + """Return a symbolic row variable (i.e. shape ``(1, None)``). Parameters ---------- @@ -898,65 +915,69 @@ def row(name=None, dtype=None): """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (True, False)) + type = TensorType(dtype, shape=(1, None)) return type(name) rows, frows, drows, irows, lrows = apply_across_args(row, frow, drow, irow, lrow) -ccol = TensorType("complex64", (False, True)) -zcol = TensorType("complex128", (False, True)) -fcol = TensorType("float32", (False, True)) -dcol = TensorType("float64", (False, True)) -bcol = TensorType("int8", (False, True)) -wcol = TensorType("int16", (False, True)) -icol = TensorType("int32", (False, True)) -lcol = TensorType("int64", (False, True)) +ccol = TensorType("complex64", shape=(None, 1)) +zcol = TensorType("complex128", shape=(None, 1)) +fcol = TensorType("float32", shape=(None, 1)) +dcol = TensorType("float64", shape=(None, 1)) +bcol = TensorType("int8", shape=(None, 1)) +wcol = TensorType("int16", shape=(None, 1)) +icol = TensorType("int32", shape=(None, 1)) +lcol = TensorType("int64", shape=(None, 1)) -def col(name=None, dtype=None): - """Return a symbolic column variable (ndim=2, shape=[False,True]). +def col( + name: Optional[str] = None, dtype: Optional["DTypeLike"] = None +) -> "TensorVariable": + """Return a symbolic column variable (i.e. shape ``(None, 1)``). Parameters ---------- - dtype : numeric - None means to use aesara.config.floatX. name A name to attach to this variable. + dtype + ``None`` means to use `aesara.config.floatX`. """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False, True)) + type = TensorType(dtype, shape=(None, 1)) return type(name) cols, fcols, dcols, icols, lcols = apply_across_args(col, fcol, dcol, icol, lcol) -ctensor3 = TensorType("complex64", ((False,) * 3)) -ztensor3 = TensorType("complex128", ((False,) * 3)) -ftensor3 = TensorType("float32", ((False,) * 3)) -dtensor3 = TensorType("float64", ((False,) * 3)) -btensor3 = TensorType("int8", ((False,) * 3)) -wtensor3 = TensorType("int16", ((False,) * 3)) -itensor3 = TensorType("int32", ((False,) * 3)) -ltensor3 = TensorType("int64", ((False,) * 3)) +ctensor3 = TensorType("complex64", shape=((None,) * 3)) +ztensor3 = TensorType("complex128", shape=((None,) * 3)) +ftensor3 = TensorType("float32", shape=((None,) * 3)) +dtensor3 = TensorType("float64", shape=((None,) * 3)) +btensor3 = TensorType("int8", shape=((None,) * 3)) +wtensor3 = TensorType("int16", shape=((None,) * 3)) +itensor3 = TensorType("int32", shape=((None,) * 3)) +ltensor3 = TensorType("int64", shape=((None,) * 3)) -def tensor3(name=None, dtype=None): - """Return a symbolic 3-D variable. +def tensor3( + name: Optional[str] = None, dtype: Optional["DTypeLike"] = None +) -> "TensorVariable": + """Return a symbolic 3D variable. Parameters ---------- - dtype: numeric type - None means to use aesara.config.floatX. name A name to attach to this variable. + dtype + ``None`` means to use `aesara.config.floatX`. """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False, False, False)) + type = TensorType(dtype, shape=(None, None, None)) return type(name) @@ -964,30 +985,32 @@ def tensor3(name=None, dtype=None): tensor3, ftensor3, dtensor3, itensor3, ltensor3 ) -ctensor4 = TensorType("complex64", ((False,) * 4)) -ztensor4 = TensorType("complex128", ((False,) * 4)) -ftensor4 = TensorType("float32", ((False,) * 4)) -dtensor4 = TensorType("float64", ((False,) * 4)) -btensor4 = TensorType("int8", ((False,) * 4)) -wtensor4 = TensorType("int16", ((False,) * 4)) -itensor4 = TensorType("int32", ((False,) * 4)) -ltensor4 = TensorType("int64", ((False,) * 4)) +ctensor4 = TensorType("complex64", shape=((None,) * 4)) +ztensor4 = TensorType("complex128", shape=((None,) * 4)) +ftensor4 = TensorType("float32", shape=((None,) * 4)) +dtensor4 = TensorType("float64", shape=((None,) * 4)) +btensor4 = TensorType("int8", shape=((None,) * 4)) +wtensor4 = TensorType("int16", shape=((None,) * 4)) +itensor4 = TensorType("int32", shape=((None,) * 4)) +ltensor4 = TensorType("int64", shape=((None,) * 4)) -def tensor4(name=None, dtype=None): - """Return a symbolic 4-D variable. +def tensor4( + name: Optional[str] = None, dtype: Optional["DTypeLike"] = None +) -> "TensorVariable": + """Return a symbolic 4D variable. Parameters ---------- - dtype: numeric type - None means to use aesara.config.floatX. name A name to attach to this variable. + dtype + ``None`` means to use `aesara.config.floatX`. """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False, False, False, False)) + type = TensorType(dtype, shape=(None, None, None, None)) return type(name) @@ -995,30 +1018,32 @@ def tensor4(name=None, dtype=None): tensor4, ftensor4, dtensor4, itensor4, ltensor4 ) -ctensor5 = TensorType("complex64", ((False,) * 5)) -ztensor5 = TensorType("complex128", ((False,) * 5)) -ftensor5 = TensorType("float32", ((False,) * 5)) -dtensor5 = TensorType("float64", ((False,) * 5)) -btensor5 = TensorType("int8", ((False,) * 5)) -wtensor5 = TensorType("int16", ((False,) * 5)) -itensor5 = TensorType("int32", ((False,) * 5)) -ltensor5 = TensorType("int64", ((False,) * 5)) +ctensor5 = TensorType("complex64", shape=((None,) * 5)) +ztensor5 = TensorType("complex128", shape=((None,) * 5)) +ftensor5 = TensorType("float32", shape=((None,) * 5)) +dtensor5 = TensorType("float64", shape=((None,) * 5)) +btensor5 = TensorType("int8", shape=((None,) * 5)) +wtensor5 = TensorType("int16", shape=((None,) * 5)) +itensor5 = TensorType("int32", shape=((None,) * 5)) +ltensor5 = TensorType("int64", shape=((None,) * 5)) -def tensor5(name=None, dtype=None): - """Return a symbolic 5-D variable. +def tensor5( + name: Optional[str] = None, dtype: Optional["DTypeLike"] = None +) -> "TensorVariable": + """Return a symbolic 5D variable. Parameters ---------- - dtype: numeric type - None means to use aesara.config.floatX. name A name to attach to this variable. + dtype + ``None`` means to use `aesara.config.floatX`. """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False, False, False, False, False)) + type = TensorType(dtype, shape=(None, None, None, None, None)) return type(name) @@ -1026,30 +1051,32 @@ def tensor5(name=None, dtype=None): tensor5, ftensor5, dtensor5, itensor5, ltensor5 ) -ctensor6 = TensorType("complex64", ((False,) * 6)) -ztensor6 = TensorType("complex128", ((False,) * 6)) -ftensor6 = TensorType("float32", ((False,) * 6)) -dtensor6 = TensorType("float64", ((False,) * 6)) -btensor6 = TensorType("int8", ((False,) * 6)) -wtensor6 = TensorType("int16", ((False,) * 6)) -itensor6 = TensorType("int32", ((False,) * 6)) -ltensor6 = TensorType("int64", ((False,) * 6)) +ctensor6 = TensorType("complex64", shape=((None,) * 6)) +ztensor6 = TensorType("complex128", shape=((None,) * 6)) +ftensor6 = TensorType("float32", shape=((None,) * 6)) +dtensor6 = TensorType("float64", shape=((None,) * 6)) +btensor6 = TensorType("int8", shape=((None,) * 6)) +wtensor6 = TensorType("int16", shape=((None,) * 6)) +itensor6 = TensorType("int32", shape=((None,) * 6)) +ltensor6 = TensorType("int64", shape=((None,) * 6)) -def tensor6(name=None, dtype=None): - """Return a symbolic 6-D variable. +def tensor6( + name: Optional[str] = None, dtype: Optional["DTypeLike"] = None +) -> "TensorVariable": + """Return a symbolic 6D variable. Parameters ---------- - dtype: numeric type - None means to use aesara.config.floatX. name A name to attach to this variable. + dtype + ``None`` means to use `aesara.config.floatX`. """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False,) * 6) + type = TensorType(dtype, shape=(None,) * 6) return type(name) @@ -1057,30 +1084,32 @@ def tensor6(name=None, dtype=None): tensor6, ftensor6, dtensor6, itensor6, ltensor6 ) -ctensor7 = TensorType("complex64", ((False,) * 7)) -ztensor7 = TensorType("complex128", ((False,) * 7)) -ftensor7 = TensorType("float32", ((False,) * 7)) -dtensor7 = TensorType("float64", ((False,) * 7)) -btensor7 = TensorType("int8", ((False,) * 7)) -wtensor7 = TensorType("int16", ((False,) * 7)) -itensor7 = TensorType("int32", ((False,) * 7)) -ltensor7 = TensorType("int64", ((False,) * 7)) +ctensor7 = TensorType("complex64", shape=((None,) * 7)) +ztensor7 = TensorType("complex128", shape=((None,) * 7)) +ftensor7 = TensorType("float32", shape=((None,) * 7)) +dtensor7 = TensorType("float64", shape=((None,) * 7)) +btensor7 = TensorType("int8", shape=((None,) * 7)) +wtensor7 = TensorType("int16", shape=((None,) * 7)) +itensor7 = TensorType("int32", shape=((None,) * 7)) +ltensor7 = TensorType("int64", shape=((None,) * 7)) -def tensor7(name=None, dtype=None): +def tensor7( + name: Optional[str] = None, dtype: Optional["DTypeLike"] = None +) -> "TensorVariable": """Return a symbolic 7-D variable. Parameters ---------- - dtype: numeric type - None means to use aesara.config.floatX. name A name to attach to this variable. + dtype + ``None`` means to use `aesara.config.floatX`. """ if dtype is None: dtype = config.floatX - type = TensorType(dtype, (False,) * 7) + type = TensorType(dtype, shape=(None,) * 7) return type(name) diff --git a/doc/extending/creating_a_c_op.rst b/doc/extending/creating_a_c_op.rst index 3c0a56736b..423d84c7f9 100644 --- a/doc/extending/creating_a_c_op.rst +++ b/doc/extending/creating_a_c_op.rst @@ -618,7 +618,7 @@ C code. # Create an output variable of the same type as x output_var = aesara.tensor.type.TensorType( dtype=aesara.scalar.upcast(x.dtype, y.dtype), - shape=[False])() + shape=(None,))() return Apply(self, [x, y], [output_var]) @@ -767,7 +767,7 @@ The new :class:`Op` is defined inside a Python file with the following code : # Create an output variable of the same type as x output_var = aesara.tensor.type.TensorType( dtype=aesara.scalar.upcast(x.dtype, y.dtype), - shape=[False])() + shape=(None,))() return Apply(self, [x, y], [output_var]) diff --git a/doc/extending/creating_a_numba_jax_op.rst b/doc/extending/creating_a_numba_jax_op.rst index 108d3c8494..d64f25f1c8 100644 --- a/doc/extending/creating_a_numba_jax_op.rst +++ b/doc/extending/creating_a_numba_jax_op.rst @@ -30,7 +30,7 @@ For example, the :class:`Eye`\ :class:`Op` current has an :meth:`Op.make_node` a return Apply( self, [n, m, k], - [TensorType(dtype=self.dtype, shape=(False, False))()], + [TensorType(dtype=self.dtype, shape=(None, None))()], ) diff --git a/doc/extending/extending_aesara_solution_1.py b/doc/extending/extending_aesara_solution_1.py index d232756ebd..f30562a9e9 100755 --- a/doc/extending/extending_aesara_solution_1.py +++ b/doc/extending/extending_aesara_solution_1.py @@ -16,9 +16,9 @@ class ProdOp(Op): def make_node(self, x, y): x = at.as_tensor_variable(x) y = at.as_tensor_variable(y) - outdim = x.ndim + outdim = x.type.ndim output = TensorType( - dtype=aesara.scalar.upcast(x.dtype, y.dtype), shape=[False] * outdim + dtype=aesara.scalar.upcast(x.dtype, y.dtype), shape=(None,) * outdim )() return Apply(self, inputs=[x, y], outputs=[output]) @@ -41,12 +41,12 @@ class SumDiffOp(Op): def make_node(self, x, y): x = at.as_tensor_variable(x) y = at.as_tensor_variable(y) - outdim = x.ndim + outdim = x.type.ndim output1 = TensorType( - dtype=aesara.scalar.upcast(x.dtype, y.dtype), shape=[False] * outdim + dtype=aesara.scalar.upcast(x.dtype, y.dtype), shape=(None,) * outdim )() output2 = TensorType( - dtype=aesara.scalar.upcast(x.dtype, y.dtype), shape=[False] * outdim + dtype=aesara.scalar.upcast(x.dtype, y.dtype), shape=(None,) * outdim )() return Apply(self, inputs=[x, y], outputs=[output1, output2]) diff --git a/doc/extending/graphstructures.rst b/doc/extending/graphstructures.rst index 41f16504f5..2b28eec2da 100644 --- a/doc/extending/graphstructures.rst +++ b/doc/extending/graphstructures.rst @@ -217,7 +217,7 @@ For example, :ref:`aesara.tensor.irow ` is an instance o >>> from aesara.tensor import irow >>> irow() - + As the string print-out shows, `irow` specifies the following information about the :class:`Variable`\s it constructs: diff --git a/doc/extending/type.rst b/doc/extending/type.rst index 39accfc687..473af43e90 100644 --- a/doc/extending/type.rst +++ b/doc/extending/type.rst @@ -90,7 +90,7 @@ For example, let's say we have two :class:`Variable`\s with the following >>> from aesara.tensor.type import TensorType >>> v1 = TensorType("float64", (2, None))() >>> v1.type -TensorType(float64, (2, None)) +TensorType(float64, (2, ?)) >>> v2 = TensorType("float64", (2, 1))() >>> v2.type TensorType(float64, (2, 1)) @@ -145,7 +145,7 @@ SpecifyShape.0 >>> import aesara >>> aesara.dprint(v3, print_type=True) SpecifyShape [id A] - | [id B] + | [id B] |TensorConstant{2} [id C] |TensorConstant{1} [id D] diff --git a/doc/library/scan.rst b/doc/library/scan.rst index 0abcbcd6ed..86b59d119f 100644 --- a/doc/library/scan.rst +++ b/doc/library/scan.rst @@ -406,7 +406,7 @@ Using the original Gibbs sampling example, with ``strict=True`` added to the Traceback (most recent call last): ... MissingInputError: An input of the graph, used to compute - DimShuffle{1,0}(), was not provided and + DimShuffle{1,0}(), was not provided and not given a value.Use the Aesara flag exception_verbosity='high',for more information on this error. diff --git a/doc/library/tensor/basic.rst b/doc/library/tensor/basic.rst index b9e52e6684..153e731f63 100644 --- a/doc/library/tensor/basic.rst +++ b/doc/library/tensor/basic.rst @@ -409,7 +409,7 @@ them perfectly, but a `dscalar` otherwise. broadcast over the middle dimension of a 3-dimensional tensor when adding them together, we would define it like this: - >>> middle_broadcaster = TensorType('complex64', [False, True, False]) + >>> middle_broadcaster = TensorType('complex64', shape=(None, 1, None)) .. attribute:: ndim diff --git a/doc/tutorial/debug_faq.rst b/doc/tutorial/debug_faq.rst index 7e4d6a12e9..5bb53d7eb3 100644 --- a/doc/tutorial/debug_faq.rst +++ b/doc/tutorial/debug_faq.rst @@ -44,8 +44,8 @@ Running the code above we see: Traceback (most recent call last): ... ValueError: Input dimension mismatch. (input[0].shape[0] = 3, input[1].shape[0] = 2) - Apply node that caused the error: Elemwise{add,no_inplace}(, , ) - Inputs types: [TensorType(float64, (None,)), TensorType(float64, (None,)), TensorType(float64, (None,))] + Apply node that caused the error: Elemwise{add,no_inplace}(, , ) + Inputs types: [TensorType(float64, (?,)), TensorType(float64, (?,)), TensorType(float64, (?,))] Inputs shapes: [(3,), (2,), (2,)] Inputs strides: [(8,), (8,), (8,)] Inputs scalar values: ['not scalar', 'not scalar', 'not scalar'] @@ -73,11 +73,11 @@ message becomes : z = z + y Debugprint of the apply node: - Elemwise{add,no_inplace} [id A] '' - |Elemwise{add,no_inplace} [id B] '' - | | [id C] - | | [id C] - | [id D] + Elemwise{add,no_inplace} [id A] '' + |Elemwise{add,no_inplace} [id B] '' + | | [id C] + | | [id C] + | [id D] We can here see that the error can be traced back to the line ``z = z + y``. For this example, using ``optimizer=fast_compile`` worked. If it did not, @@ -145,18 +145,18 @@ Running the above code generates the following error message: outputs = self.vm() ValueError: Shape mismatch: x has 10 cols (and 5 rows) but y has 20 rows (and 10 cols) Apply node that caused the error: Dot22(x, DimShuffle{1,0}.0) - Inputs types: [TensorType(float64, (None, None)), TensorType(float64, (None, None))] + Inputs types: [TensorType(float64, (?, ?)), TensorType(float64, (?, ?))] Inputs shapes: [(5, 10), (20, 10)] Inputs strides: [(80, 8), (8, 160)] Inputs scalar values: ['not scalar', 'not scalar'] Debugprint of the apply node: - Dot22 [id A] '' - |x [id B] - |DimShuffle{1,0} [id C] '' - |Flatten{2} [id D] '' - |DimShuffle{2,0,1} [id E] '' - |W1 [id F] + Dot22 [id A] '' + |x [id B] + |DimShuffle{1,0} [id C] '' + |Flatten{2} [id D] '' + |DimShuffle{2,0,1} [id E] '' + |W1 [id F] HINT: Re-running with most Aesara optimization disabled could give you a back-traces when this node was created. This can be done with by setting the Aesara flags 'optimizer=fast_compile'. If that does not work, Aesara optimization can be disabled with 'optimizer=None'. @@ -483,7 +483,7 @@ Consider this example script (``ex.py``): ValueError: Input dimension mismatch. (input[0].shape[0] = 3, input[1].shape[0] = 5) Apply node that caused the error: Elemwise{mul,no_inplace}(a, b) Toposort index: 0 - Inputs types: [TensorType(float64, (None, None)), TensorType(float64, (None, None))] + Inputs types: [TensorType(float64, (?, ?)), TensorType(float64, (?, ?))] Inputs shapes: [(3, 4), (5, 5)] Inputs strides: [(32, 8), (40, 8)] Inputs values: ['not shown', 'not shown'] diff --git a/tests/compile/test_builders.py b/tests/compile/test_builders.py index b770121134..0ca4cabf53 100644 --- a/tests/compile/test_builders.py +++ b/tests/compile/test_builders.py @@ -580,10 +580,10 @@ def test_debugprint(): OpFromGraph{inline=False} [id A] >Elemwise{add,no_inplace} [id E] - > |*0- [id F] + > |*0- [id F] > |Elemwise{mul,no_inplace} [id G] - > |*1- [id H] - > |*2- [id I] + > |*1- [id H] + > |*2- [id I] """ for truth, out in zip(exp_res.split("\n"), lines): diff --git a/tests/compile/test_debugmode.py b/tests/compile/test_debugmode.py index c9c59a463f..2bfc45a444 100644 --- a/tests/compile/test_debugmode.py +++ b/tests/compile/test_debugmode.py @@ -716,8 +716,8 @@ def make_node(self, v): v = at.as_tensor_variable(v) assert v.type.ndim == 1 type_class = type(v.type) - out_r_type = type_class(dtype=v.dtype, shape=(True, False)) - out_c_type = type_class(dtype=v.dtype, shape=(False, True)) + out_r_type = type_class(dtype=v.dtype, shape=(1, None)) + out_c_type = type_class(dtype=v.dtype, shape=(None, 1)) return Apply(self, [v], [out_r_type(), out_c_type()]) def perform(self, node, inp, out): diff --git a/tests/compile/test_shared.py b/tests/compile/test_shared.py index 49058a7fee..714d30ab77 100644 --- a/tests/compile/test_shared.py +++ b/tests/compile/test_shared.py @@ -36,11 +36,11 @@ def test_ctors(self): # test tensor constructor b = shared(np.zeros((5, 5), dtype="int32")) - assert b.type == TensorType("int32", shape=[False, False]) + assert b.type == TensorType("int32", shape=(None, None)) b = shared(np.random.random((4, 5))) - assert b.type == TensorType("float64", shape=[False, False]) + assert b.type == TensorType("float64", shape=(None, None)) b = shared(np.random.random((5, 1, 2))) - assert b.type == TensorType("float64", shape=[False, False, False]) + assert b.type == TensorType("float64", shape=(None, None, None)) assert shared([]).type == generic @@ -67,7 +67,7 @@ def test_create_numpy_strict_false(self): # so creation should work SharedVariable( name="u", - type=TensorType(shape=[False], dtype="float64"), + type=TensorType(dtype="float64", shape=(None,)), value=np.asarray([1.0, 2.0]), strict=False, ) @@ -76,7 +76,7 @@ def test_create_numpy_strict_false(self): # so creation should work SharedVariable( name="u", - type=TensorType(shape=[False], dtype="float64"), + type=TensorType(dtype="float64", shape=(None,)), value=[1.0, 2.0], strict=False, ) @@ -85,7 +85,7 @@ def test_create_numpy_strict_false(self): # so creation should work SharedVariable( name="u", - type=TensorType(shape=[False], dtype="float64"), + type=TensorType(dtype="float64", shape=(None,)), value=[1, 2], # different dtype and not a numpy array strict=False, ) @@ -95,7 +95,7 @@ def test_create_numpy_strict_false(self): try: SharedVariable( name="u", - type=TensorType(shape=[False], dtype="float64"), + type=TensorType(dtype="float64", shape=(None,)), value=dict(), # not an array by any stretch strict=False, ) @@ -109,7 +109,7 @@ def test_use_numpy_strict_false(self): # so creation should work u = SharedVariable( name="u", - type=TensorType(shape=[False], dtype="float64"), + type=TensorType(dtype="float64", shape=(None,)), value=np.asarray([1.0, 2.0]), strict=False, ) diff --git a/tests/graph/rewriting/test_unify.py b/tests/graph/rewriting/test_unify.py index 6ce1284794..899e4e3166 100644 --- a/tests/graph/rewriting/test_unify.py +++ b/tests/graph/rewriting/test_unify.py @@ -72,7 +72,7 @@ def test_cons(): assert car(op1) == CustomOp assert cdr(op1) == (1,) - tt1 = TensorType("float32", [True, False]) + tt1 = TensorType("float32", shape=(1, None)) assert car(tt1) == TensorType assert cdr(tt1) == ("float32", (1, None)) @@ -247,8 +247,8 @@ def test_unify_Constant(): def test_unify_Type(): - t1 = TensorType(np.float64, (True, False)) - t2 = TensorType(np.float64, (True, False)) + t1 = TensorType(np.float64, shape=(1, None)) + t2 = TensorType(np.float64, shape=(1, None)) # `Type`, `Type` s = unify(t1, t2) diff --git a/tests/link/c/test_params_type.py b/tests/link/c/test_params_type.py index 7053c054c7..65ba3e6bc1 100644 --- a/tests/link/c/test_params_type.py +++ b/tests/link/c/test_params_type.py @@ -12,7 +12,7 @@ from tests import unittest_tools as utt -tensor_type_0d = TensorType("float64", tuple()) +tensor_type_0d = TensorType("float64", shape=tuple()) scalar_type = ScalarType("float64") generic_type = Generic() @@ -127,15 +127,15 @@ class TestParamsType: def test_hash_and_eq_params(self): wp1 = ParamsType( a=Generic(), - array=TensorType("int64", (False,)), + array=TensorType("int64", shape=(None,)), floatting=ScalarType("float64"), - npy_scalar=TensorType("float64", tuple()), + npy_scalar=TensorType("float64", shape=tuple()), ) wp2 = ParamsType( a=Generic(), - array=TensorType("int64", (False,)), + array=TensorType("int64", shape=(None,)), floatting=ScalarType("float64"), - npy_scalar=TensorType("float64", tuple()), + npy_scalar=TensorType("float64", shape=tuple()), ) w1 = Params( wp1, @@ -157,9 +157,9 @@ def test_hash_and_eq_params(self): # Changing attributes names only (a -> other_name). wp2_other = ParamsType( other_name=Generic(), - array=TensorType("int64", (False,)), + array=TensorType("int64", shape=(None,)), floatting=ScalarType("float64"), - npy_scalar=TensorType("float64", tuple()), + npy_scalar=TensorType("float64", shape=tuple()), ) w2 = Params( wp2_other, @@ -190,13 +190,13 @@ def test_hash_and_eq_params(self): def test_hash_and_eq_params_type(self): w1 = ParamsType( - a1=TensorType("int64", (False, False)), - a2=TensorType("int64", (False, True, False, False, True)), + a1=TensorType("int64", shape=(None, None)), + a2=TensorType("int64", shape=(None, 1, None, None, 1)), a3=Generic(), ) w2 = ParamsType( - a1=TensorType("int64", (False, False)), - a2=TensorType("int64", (False, True, False, False, True)), + a1=TensorType("int64", shape=(None, None)), + a2=TensorType("int64", shape=(None, 1, None, None, 1)), a3=Generic(), ) assert w1 == w2 @@ -205,24 +205,24 @@ def test_hash_and_eq_params_type(self): assert w1.name == w2.name # Changing attributes names only. w2 = ParamsType( - a1=TensorType("int64", (False, False)), + a1=TensorType("int64", shape=(None, None)), other_name=TensorType( - "int64", (False, True, False, False, True) + "int64", shape=(None, 1, None, None, 1) ), # a2 -> other_name a3=Generic(), ) assert w1 != w2 # Changing attributes types only. w2 = ParamsType( - a1=TensorType("int64", (False, False)), + a1=TensorType("int64", shape=(None, None)), a2=Generic(), # changing class a3=Generic(), ) assert w1 != w2 # Changing attributes types characteristics only. w2 = ParamsType( - a1=TensorType("int64", (False, True)), # changing broadcasting - a2=TensorType("int64", (False, True, False, False, True)), + a1=TensorType("int64", shape=(None, 1)), # changing broadcasting + a2=TensorType("int64", shape=(None, 1, None, None, 1)), a3=Generic(), ) assert w1 != w2 @@ -239,8 +239,8 @@ def test_params_type_filtering(self): random_tensor = np.random.normal(size=size_tensor5).reshape(shape_tensor5) w = ParamsType( - a1=TensorType("int32", (False, False)), - a2=TensorType("float64", (False, False, False, False, False)), + a1=TensorType("int32", shape=(None, None)), + a2=TensorType("float64", shape=(None, None, None, None, None)), a3=Generic(), ) diff --git a/tests/link/c/test_type.py b/tests/link/c/test_type.py index aedf00c9a7..603dfb28d3 100644 --- a/tests/link/c/test_type.py +++ b/tests/link/c/test_type.py @@ -44,7 +44,7 @@ class GetOp(COp): __props__ = () def make_node(self, c): - return Apply(self, [c], [TensorType("float32", (False,))()]) + return Apply(self, [c], [TensorType("float32", shape=(None,))()]) def c_support_code(self, **kwargs): return """ @@ -73,7 +73,7 @@ def perform(self, *args, **kwargs): not aesara.config.cxx, reason="G++ not available, so we need to skip this test." ) def test_cdata(): - i = TensorType("float32", (False,))() + i = TensorType("float32", shape=(None,))() c = ProdOp()(i) i2 = GetOp()(c) mode = None diff --git a/tests/link/jax/test_elemwise.py b/tests/link/jax/test_elemwise.py index 4f6a7343ad..49acc6b807 100644 --- a/tests/link/jax/test_elemwise.py +++ b/tests/link/jax/test_elemwise.py @@ -24,12 +24,12 @@ def test_jax_Dimshuffle(): x_fg = FunctionGraph([a_at], [x]) compare_jax_and_py(x_fg, [np.c_[[1.0, 2.0], [3.0, 4.0]].astype(config.floatX)]) - a_at = tensor(dtype=config.floatX, shape=[False, True]) + a_at = tensor(dtype=config.floatX, shape=(None, 1)) x = a_at.dimshuffle((0,)) x_fg = FunctionGraph([a_at], [x]) compare_jax_and_py(x_fg, [np.c_[[1.0, 2.0, 3.0, 4.0]].astype(config.floatX)]) - a_at = tensor(dtype=config.floatX, shape=[False, True]) + a_at = tensor(dtype=config.floatX, shape=(None, 1)) x = at_elemwise.DimShuffle([False, True], (0,))(a_at) x_fg = FunctionGraph([a_at], [x]) compare_jax_and_py(x_fg, [np.c_[[1.0, 2.0, 3.0, 4.0]].astype(config.floatX)]) diff --git a/tests/link/numba/test_elemwise.py b/tests/link/numba/test_elemwise.py index d5457a4733..1302624b48 100644 --- a/tests/link/numba/test_elemwise.py +++ b/tests/link/numba/test_elemwise.py @@ -140,7 +140,7 @@ def test_Elemwise(inputs, input_vals, output_fn, exc): # `{'drop': [1], 'shuffle': [2, 0], 'augment': [0, 2, 4]}` ( set_test_value( - at.tensor(config.floatX, [False, True, False], name="a"), + at.tensor(config.floatX, shape=(None, 1, None), name="a"), np.array([[[1.0, 2.0]], [[3.0, 4.0]]], dtype=config.floatX), ), ("x", 2, "x", 0, "x"), @@ -149,21 +149,21 @@ def test_Elemwise(inputs, input_vals, output_fn, exc): # `{'drop': [1], 'shuffle': [0], 'augment': []}` ( set_test_value( - at.tensor(config.floatX, [False, True], name="a"), + at.tensor(config.floatX, shape=(None, 1), name="a"), np.array([[1.0], [2.0], [3.0], [4.0]], dtype=config.floatX), ), (0,), ), ( set_test_value( - at.tensor(config.floatX, [False, True], name="a"), + at.tensor(config.floatX, shape=(None, 1), name="a"), np.array([[1.0], [2.0], [3.0], [4.0]], dtype=config.floatX), ), (0,), ), ( set_test_value( - at.tensor(config.floatX, [True, True, True], name="a"), + at.tensor(config.floatX, shape=(1, 1, 1), name="a"), np.array([[[1.0]]], dtype=config.floatX), ), (), diff --git a/tests/link/numba/test_random.py b/tests/link/numba/test_random.py index b859919829..6f554d297f 100644 --- a/tests/link/numba/test_random.py +++ b/tests/link/numba/test_random.py @@ -270,7 +270,7 @@ np.array([[1, 2], [3, 4]], dtype=np.float64), ), set_test_value( - at.tensor("float64", [True, False, False]), + at.tensor("float64", shape=(1, None, None)), np.eye(2)[None, ...], ), ], diff --git a/tests/scan/test_printing.py b/tests/scan/test_printing.py index 8ff4175147..f02a37bf6b 100644 --- a/tests/scan/test_printing.py +++ b/tests/scan/test_printing.py @@ -58,8 +58,8 @@ def test_debugprint_sitsot(): for{cpu,scan_fn} [id C] (outer_out_sit_sot-0) >Elemwise{mul,no_inplace} [id W] (inner_out_sit_sot-0) - > |*0- [id X] -> [id E] (inner_in_sit_sot-0) - > |*1- [id Y] -> [id M] (inner_in_non_seqs-0)""" + > |*0- [id X] -> [id E] (inner_in_sit_sot-0) + > |*1- [id Y] -> [id M] (inner_in_non_seqs-0)""" for truth, out in zip(expected_output.split("\n"), lines): assert truth.strip() == out.strip() @@ -113,8 +113,8 @@ def test_debugprint_sitsot_no_extra_info(): for{cpu,scan_fn} [id C] >Elemwise{mul,no_inplace} [id W] - > |*0- [id X] -> [id E] - > |*1- [id Y] -> [id M]""" + > |*0- [id X] -> [id E] + > |*1- [id Y] -> [id M]""" for truth, out in zip(expected_output.split("\n"), lines): assert truth.strip() == out.strip() @@ -264,7 +264,7 @@ def compute_A_k(A, k): > | | | | | | | |Unbroadcast{0} [id BL] > | | | | | | | |InplaceDimShuffle{x,0} [id BM] > | | | | | | | |Elemwise{second,no_inplace} [id BN] - > | | | | | | | |*2- [id BO] -> [id W] (inner_in_non_seqs-0) + > | | | | | | | |*2- [id BO] -> [id W] (inner_in_non_seqs-0) > | | | | | | | |InplaceDimShuffle{x} [id BP] > | | | | | | | |TensorConstant{1.0} [id BQ] > | | | | | | |ScalarConstant{0} [id BR] @@ -275,7 +275,7 @@ def compute_A_k(A, k): > | | | | |Unbroadcast{0} [id BL] > | | | | |ScalarFromTensor [id BV] > | | | | |Subtensor{int64} [id BJ] - > | | | |*2- [id BO] -> [id W] (inner_in_non_seqs-0) (outer_in_non_seqs-0) + > | | | |*2- [id BO] -> [id W] (inner_in_non_seqs-0) (outer_in_non_seqs-0) > | | |ScalarConstant{1} [id BW] > | |ScalarConstant{-1} [id BX] > |InplaceDimShuffle{x} [id BY] @@ -283,8 +283,8 @@ def compute_A_k(A, k): for{cpu,scan_fn} [id BE] (outer_out_sit_sot-0) >Elemwise{mul,no_inplace} [id CA] (inner_out_sit_sot-0) - > |*0- [id CB] -> [id BG] (inner_in_sit_sot-0) - > |*1- [id CC] -> [id BO] (inner_in_non_seqs-0)""" + > |*0- [id CB] -> [id BG] (inner_in_sit_sot-0) + > |*1- [id CC] -> [id BO] (inner_in_non_seqs-0)""" for truth, out in zip(expected_output.split("\n"), lines): assert truth.strip() == out.strip() @@ -334,7 +334,7 @@ def compute_A_k(A, k): for{cpu,scan_fn} [id E] (outer_out_nit_sot-0) -*0- [id Y] -> [id U] (inner_in_seqs-0) -*1- [id Z] -> [id W] (inner_in_seqs-1) - -*2- [id BA] -> [id C] (inner_in_non_seqs-0) + -*2- [id BA] -> [id C] (inner_in_non_seqs-0) -*3- [id BB] -> [id B] (inner_in_non_seqs-1) >Elemwise{mul,no_inplace} [id BC] (inner_out_nit_sot-0) > |InplaceDimShuffle{x} [id BD] @@ -353,7 +353,7 @@ def compute_A_k(A, k): > | | | | | | | |Unbroadcast{0} [id BN] > | | | | | | | |InplaceDimShuffle{x,0} [id BO] > | | | | | | | |Elemwise{second,no_inplace} [id BP] - > | | | | | | | |*2- [id BA] (inner_in_non_seqs-0) + > | | | | | | | |*2- [id BA] (inner_in_non_seqs-0) > | | | | | | | |InplaceDimShuffle{x} [id BQ] > | | | | | | | |TensorConstant{1.0} [id BR] > | | | | | | |ScalarConstant{0} [id BS] @@ -364,18 +364,18 @@ def compute_A_k(A, k): > | | | | |Unbroadcast{0} [id BN] > | | | | |ScalarFromTensor [id BW] > | | | | |Subtensor{int64} [id BL] - > | | | |*2- [id BA] (inner_in_non_seqs-0) (outer_in_non_seqs-0) + > | | | |*2- [id BA] (inner_in_non_seqs-0) (outer_in_non_seqs-0) > | | |ScalarConstant{1} [id BX] > | |ScalarConstant{-1} [id BY] > |InplaceDimShuffle{x} [id BZ] > |*1- [id Z] (inner_in_seqs-1) for{cpu,scan_fn} [id BH] (outer_out_sit_sot-0) - -*0- [id CA] -> [id BI] (inner_in_sit_sot-0) - -*1- [id CB] -> [id BA] (inner_in_non_seqs-0) + -*0- [id CA] -> [id BI] (inner_in_sit_sot-0) + -*1- [id CB] -> [id BA] (inner_in_non_seqs-0) >Elemwise{mul,no_inplace} [id CC] (inner_out_sit_sot-0) - > |*0- [id CA] (inner_in_sit_sot-0) - > |*1- [id CB] (inner_in_non_seqs-0)""" + > |*0- [id CA] (inner_in_sit_sot-0) + > |*1- [id CB] (inner_in_non_seqs-0)""" for truth, out in zip(expected_output.split("\n"), lines): assert truth.strip() == out.strip() @@ -413,7 +413,7 @@ def fn(a_m2, a_m1, b_m2, b_m1): | | | | |Subtensor{int64} [id H] | | | | |Shape [id I] | | | | | |Subtensor{:int64:} [id J] - | | | | | | [id K] + | | | | | | [id K] | | | | | |ScalarConstant{2} [id L] | | | | |ScalarConstant{0} [id M] | | | |Subtensor{:int64:} [id J] @@ -426,7 +426,7 @@ def fn(a_m2, a_m1, b_m2, b_m1): | | | |Subtensor{int64} [id R] | | | |Shape [id S] | | | | |Subtensor{:int64:} [id T] - | | | | | [id U] + | | | | | [id U] | | | | |ScalarConstant{2} [id V] | | | |ScalarConstant{0} [id W] | | |Subtensor{:int64:} [id T] @@ -562,19 +562,19 @@ def test_debugprint_mitmot(): for{cpu,grad_of_scan_fn}.1 [id B] (outer_out_sit_sot-0) >Elemwise{add,no_inplace} [id CM] (inner_out_mit_mot-0-0) > |Elemwise{mul} [id CN] - > | |*2- [id CO] -> [id BL] (inner_in_mit_mot-0-0) - > | |*5- [id CP] -> [id P] (inner_in_non_seqs-0) - > |*3- [id CQ] -> [id BL] (inner_in_mit_mot-0-1) + > | |*2- [id CO] -> [id BL] (inner_in_mit_mot-0-0) + > | |*5- [id CP] -> [id P] (inner_in_non_seqs-0) + > |*3- [id CQ] -> [id BL] (inner_in_mit_mot-0-1) >Elemwise{add,no_inplace} [id CR] (inner_out_sit_sot-0) > |Elemwise{mul} [id CS] - > | |*2- [id CO] -> [id BL] (inner_in_mit_mot-0-0) - > | |*0- [id CT] -> [id Z] (inner_in_seqs-0) - > |*4- [id CU] -> [id CE] (inner_in_sit_sot-0) + > | |*2- [id CO] -> [id BL] (inner_in_mit_mot-0-0) + > | |*0- [id CT] -> [id Z] (inner_in_seqs-0) + > |*4- [id CU] -> [id CE] (inner_in_sit_sot-0) for{cpu,scan_fn} [id F] (outer_out_sit_sot-0) >Elemwise{mul,no_inplace} [id CV] (inner_out_sit_sot-0) - > |*0- [id CT] -> [id H] (inner_in_sit_sot-0) - > |*1- [id CW] -> [id P] (inner_in_non_seqs-0)""" + > |*0- [id CT] -> [id H] (inner_in_sit_sot-0) + > |*1- [id CW] -> [id P] (inner_in_non_seqs-0)""" for truth, out in zip(expected_output.split("\n"), lines): assert truth.strip() == out.strip() diff --git a/tests/sparse/test_basic.py b/tests/sparse/test_basic.py index a3fd87ec47..0f4def3435 100644 --- a/tests/sparse/test_basic.py +++ b/tests/sparse/test_basic.py @@ -693,7 +693,7 @@ def fn(m): def test_err(self): for ndim in [1, 3]: - t = TensorType(dtype=config.floatX, shape=(False,) * ndim)() + t = TensorType(dtype=config.floatX, shape=(None,) * ndim)() v = ivector() sub = t[v] @@ -1084,7 +1084,7 @@ def test_todense(self): @staticmethod def check_format_ndim(format, ndim): - x = tensor(dtype=config.floatX, shape=([False] * ndim), name="x") + x = tensor(dtype=config.floatX, shape=(None,) * ndim, name="x") s = SparseFromDense(format)(x) s_m = -s @@ -1171,7 +1171,7 @@ def test_csm_sparser(self): for format in ("csc", "csr"): for dtype in ("float32", "float64"): - x = tensor(dtype=dtype, shape=(False,)) + x = tensor(dtype=dtype, shape=(None,)) y = ivector() z = ivector() s = ivector() @@ -1224,7 +1224,7 @@ def test_csm(self): for format in ("csc", "csr"): for dtype in ("float32", "float64"): - x = tensor(dtype=dtype, shape=(False,)) + x = tensor(dtype=dtype, shape=(None,)) y = ivector() z = ivector() s = ivector() @@ -1334,7 +1334,7 @@ def test_opt_unpack(self): return # - kerns = TensorType(dtype="int64", shape=[False])("kerns") + kerns = TensorType(dtype="int64", shape=(None,))("kerns") spmat = sp.sparse.lil_matrix((4, 6), dtype="int64") for i in range(5): # set non-zeros in random locations (row x, col y) @@ -1343,7 +1343,7 @@ def test_opt_unpack(self): spmat[x, y] = np.random.random() * 10 spmat = sp.sparse.csc_matrix(spmat) - images = TensorType(dtype="float32", shape=[False, False])("images") + images = TensorType(dtype="float32", shape=(None, None))("images") cscmat = CSC(kerns, spmat.indices[: spmat.size], spmat.indptr, spmat.shape) f = aesara.function([kerns, images], structured_dot(cscmat, images.T)) @@ -3275,7 +3275,7 @@ def test_op_sd(self): variable, data = sparse_random_inputs( format, shape=(10, 10), out_dtype=dtype, n=2, p=0.1 ) - variable[1] = TensorType(dtype=dtype, shape=(False, False))() + variable[1] = TensorType(dtype=dtype, shape=(None, None))() data[1] = data[1].toarray() f = aesara.function(variable, self.op(*variable)) diff --git a/tests/tensor/nnet/speed_test_conv.py b/tests/tensor/nnet/speed_test_conv.py index 0a413c9848..8a9676933e 100644 --- a/tests/tensor/nnet/speed_test_conv.py +++ b/tests/tensor/nnet/speed_test_conv.py @@ -39,7 +39,7 @@ def flip(kern, kshp): global_rng = np.random.default_rng(3423489) -dmatrix4 = TensorType("float64", (False, False, False, False)) +dmatrix4 = TensorType("float64", shape=(None, None, None, None)) def exec_multilayer_conv_nnet_old( diff --git a/tests/tensor/nnet/test_abstract_conv.py b/tests/tensor/nnet/test_abstract_conv.py index 31a3df7aa3..70d78d976a 100644 --- a/tests/tensor/nnet/test_abstract_conv.py +++ b/tests/tensor/nnet/test_abstract_conv.py @@ -2529,7 +2529,7 @@ def setup_method(self): self.ref_mode = "FAST_RUN" def test_fwd(self): - tensor6 = TensorType(config.floatX, (False,) * 6) + tensor6 = TensorType(config.floatX, shape=(None,) * 6) img_sym = tensor4("img") kern_sym = tensor6("kern") ref_kern_sym = tensor4("ref_kern") @@ -2652,7 +2652,7 @@ def conv_gradweight(inputs_val, output_val): utt.verify_grad(conv_gradweight, [img, top], mode=self.mode, eps=1) def test_gradinput(self): - tensor6 = TensorType(config.floatX, (False,) * 6) + tensor6 = TensorType(config.floatX, shape=(None,) * 6) kern_sym = tensor6("kern") top_sym = tensor4("top") ref_kern_sym = tensor4("ref_kern") diff --git a/tests/tensor/nnet/test_batchnorm.py b/tests/tensor/nnet/test_batchnorm.py index b5c57d6117..751375d87a 100644 --- a/tests/tensor/nnet/test_batchnorm.py +++ b/tests/tensor/nnet/test_batchnorm.py @@ -495,7 +495,7 @@ def test_batch_normalization_train_broadcast(): params_dimshuffle[axis] = i # construct non-broadcasted parameter variables - param_type = TensorType(x.dtype, (False,) * len(non_bc_axes)) + param_type = TensorType(x.dtype, shape=(None,) * len(non_bc_axes)) scale, bias, running_mean, running_var = ( param_type(n) for n in ("scale", "bias", "running_mean", "running_var") ) diff --git a/tests/tensor/random/test_basic.py b/tests/tensor/random/test_basic.py index 42104a293f..69a5e6bc40 100644 --- a/tests/tensor/random/test_basic.py +++ b/tests/tensor/random/test_basic.py @@ -607,7 +607,7 @@ def test_mvnormal_ShapeFeature(): assert M_at in graph_inputs([s2]) # Test broadcasted shapes - mean = tensor(config.floatX, [True, False]) + mean = tensor(config.floatX, shape=(1, None)) mean.tag.test_value = np.array([[0, 1, 2]], dtype=config.floatX) test_covar = np.diag(np.array([1, 10, 100], dtype=config.floatX)) diff --git a/tests/tensor/random/test_op.py b/tests/tensor/random/test_op.py index a645b8a474..8e18dcec65 100644 --- a/tests/tensor/random/test_op.py +++ b/tests/tensor/random/test_op.py @@ -125,9 +125,9 @@ def test_RandomVariable_basics(): def test_RandomVariable_bcast(): rv = RandomVariable("normal", 0, [0, 0], config.floatX, inplace=True) - mu = tensor(config.floatX, [True, False, False]) + mu = tensor(config.floatX, shape=(1, None, None)) mu.tag.test_value = np.zeros((1, 2, 3)).astype(config.floatX) - sd = tensor(config.floatX, [False, False]) + sd = tensor(config.floatX, shape=(None, None)) sd.tag.test_value = np.ones((2, 3)).astype(config.floatX) s1 = iscalar() @@ -160,14 +160,14 @@ def test_RandomVariable_bcast_specify_shape(): s3 = Assert("testing")(s3, eq(s1, 1)) size = specify_shape(at.as_tensor([s1, s3, s2, s2, s1]), (5,)) - mu = tensor(config.floatX, [False, False, True]) + mu = tensor(config.floatX, shape=(None, None, 1)) mu.tag.test_value = np.random.normal(size=(2, 2, 1)).astype(config.floatX) - std = tensor(config.floatX, [False, True, True]) + std = tensor(config.floatX, shape=(None, 1, 1)) std.tag.test_value = np.ones((2, 1, 1)).astype(config.floatX) res = rv(mu, std, size=size) - assert res.broadcastable == (True, False, False, False, True) + assert res.type.shape == (1, None, None, None, 1) def test_RandomVariable_floatX(): diff --git a/tests/tensor/random/test_utils.py b/tests/tensor/random/test_utils.py index 18a7650147..bce218c27f 100644 --- a/tests/tensor/random/test_utils.py +++ b/tests/tensor/random/test_utils.py @@ -69,7 +69,7 @@ def test_broadcast_params(): # Try it in Aesara with config.change_flags(compute_test_value="raise"): - mean = tensor(config.floatX, [False, True]) + mean = tensor(config.floatX, shape=(None, 1)) mean.tag.test_value = np.array([[0], [10], [100]], dtype=config.floatX) cov = matrix() cov.tag.test_value = np.diag(np.array([1e-6], dtype=config.floatX)) diff --git a/tests/tensor/rewriting/test_basic.py b/tests/tensor/rewriting/test_basic.py index b835fe79ec..9bc2caad5a 100644 --- a/tests/tensor/rewriting/test_basic.py +++ b/tests/tensor/rewriting/test_basic.py @@ -614,8 +614,8 @@ def test_eq(self): f2 = function([x], eq(x, x), mode=self.mode) assert np.all(f2(vx) == np.ones((5, 4))) topo2 = f2.maker.fgraph.toposort() - # Shape_i{1}(), - # Shape_i{0}(), Alloc([[1]], Shape_i{0}.0, + # Shape_i{1}(), + # Shape_i{0}(), Alloc([[1]], Shape_i{0}.0, # Shape_i{1}.0 assert len(topo2) == 3 assert isinstance(topo2[-1].op, Alloc) @@ -1693,8 +1693,8 @@ def verify_op_count(f, count, cls): ], ) def test_basic(self, expr, x_shape, y_shape): - x = at.tensor("int64", (False,) * len(x_shape), name="x") - y = at.tensor("int64", (False,) * len(y_shape), name="y") + x = at.tensor("int64", shape=(None,) * len(x_shape), name="x") + y = at.tensor("int64", shape=(None,) * len(y_shape), name="y") z = expr(x, y) z_opt = aesara.function( @@ -1872,7 +1872,7 @@ def test_multi_input_single_alloc(self): def test_misc(self): x = row(dtype=self.dtype) - y = tensor(dtype=self.dtype, shape=(False, False, True)) + y = tensor(dtype=self.dtype, shape=(None, None, 1)) out = at.alloc(x, 5, 5).dimshuffle(0, 1, "x") + y func = function([y, x], out, mode=self.fast_run_mode) diff --git a/tests/tensor/rewriting/test_elemwise.py b/tests/tensor/rewriting/test_elemwise.py index cfb9b6a61d..ec1525ff43 100644 --- a/tests/tensor/rewriting/test_elemwise.py +++ b/tests/tensor/rewriting/test_elemwise.py @@ -71,9 +71,9 @@ def ds(x, y): def inputs(xbc=(0, 0), ybc=(0, 0), zbc=(0, 0)): - x = TensorType(shape=xbc, dtype="float64")("x") - y = TensorType(shape=ybc, dtype="float64")("y") - z = TensorType(shape=zbc, dtype="float64")("z") + x = TensorType(dtype="float64", shape=xbc)("x") + y = TensorType(dtype="float64", shape=ybc)("y") + z = TensorType(dtype="float64", shape=zbc)("z") return x, y, z @@ -82,6 +82,7 @@ def test_double_transpose(self): x, y, z = inputs() e = ds(ds(x, (1, 0)), (1, 0)) g = FunctionGraph([x], [e]) + # TODO FIXME: Construct these graphs and compare them. assert ( str(g) == "FunctionGraph(InplaceDimShuffle{1,0}(InplaceDimShuffle{1,0}(x)))" ) @@ -93,6 +94,7 @@ def test_merge2(self): x, y, z = inputs() e = ds(ds(x, (1, "x", 0)), (2, 0, "x", 1)) g = FunctionGraph([x], [e]) + # TODO FIXME: Construct these graphs and compare them. assert ( str(g) == "FunctionGraph(InplaceDimShuffle{2,0,x,1}(InplaceDimShuffle{1,x,0}(x)))" @@ -106,6 +108,7 @@ def test_elim3(self): x, y, z = inputs() e = ds(ds(ds(x, (0, "x", 1)), (2, 0, "x", 1)), (1, 0)) g = FunctionGraph([x], [e]) + # TODO FIXME: Construct these graphs and compare them. assert str(g) == ( "FunctionGraph(InplaceDimShuffle{1,0}(InplaceDimShuffle{2,0,x,1}" "(InplaceDimShuffle{0,x,1}(x))))" @@ -119,6 +122,7 @@ def test_lift(self): e = x + y + z g = FunctionGraph([x, y, z], [e]) + # TODO FIXME: Construct these graphs and compare them. # It does not really matter if the DimShuffles are inplace # or not. init_str_g_inplace = ( @@ -149,13 +153,14 @@ def test_recursive_lift(self): m = matrix(dtype="float64") out = ((v + 42) * (m + 84)).T g = FunctionGraph([v, m], [out]) + # TODO FIXME: Construct these graphs and compare them. init_str_g = ( "FunctionGraph(InplaceDimShuffle{1,0}(Elemwise{mul,no_inplace}" "(InplaceDimShuffle{x,0}(Elemwise{add,no_inplace}" - "(, " + "(, " "InplaceDimShuffle{x}(TensorConstant{42}))), " "Elemwise{add,no_inplace}" - "(, " + "(, " "InplaceDimShuffle{x,x}(TensorConstant{84})))))" ) assert str(g) == init_str_g @@ -163,10 +168,10 @@ def test_recursive_lift(self): new_g = FunctionGraph(g.inputs, [new_out]) rewrite_str_g = ( "FunctionGraph(Elemwise{mul,no_inplace}(Elemwise{add,no_inplace}" - "(InplaceDimShuffle{0,x}(), " + "(InplaceDimShuffle{0,x}(), " "InplaceDimShuffle{x,x}(TensorConstant{42})), " "Elemwise{add,no_inplace}(InplaceDimShuffle{1,0}" - "(), " + "(), " "InplaceDimShuffle{x,x}(TensorConstant{84}))))" ) assert str(new_g) == rewrite_str_g @@ -177,6 +182,7 @@ def test_useless_dimshuffle(self): x, _, _ = inputs() e = ds(x, (0, 1)) g = FunctionGraph([x], [e]) + # TODO FIXME: Construct these graphs and compare them. assert str(g) == "FunctionGraph(InplaceDimShuffle{0,1}(x))" dimshuffle_lift.rewrite(g) assert str(g) == "FunctionGraph(x)" @@ -191,6 +197,7 @@ def test_dimshuffle_on_broadcastable(self): ds_z = ds(z, (2, 1, 0)) # useful ds_u = ds(u, ("x")) # useful g = FunctionGraph([x, y, z, u], [ds_x, ds_y, ds_z, ds_u]) + # TODO FIXME: Construct these graphs and compare them. assert ( str(g) == "FunctionGraph(InplaceDimShuffle{0,x}(x), InplaceDimShuffle{2,1,0}(y), InplaceDimShuffle{2,1,0}(z), InplaceDimShuffle{x}(TensorConstant{1}))" @@ -205,10 +212,10 @@ def test_dimshuffle_on_broadcastable(self): def test_local_useless_dimshuffle_in_reshape(): - vec = TensorType(shape=(False,), dtype="float64")("vector") - mat = TensorType(shape=(False, False), dtype="float64")("mat") - row = TensorType(shape=(True, False), dtype="float64")("row") - col = TensorType(shape=(False, True), dtype="float64")("col") + vec = TensorType(dtype="float64", shape=(None,))("vector") + mat = TensorType(dtype="float64", shape=(None, None))("mat") + row = TensorType(dtype="float64", shape=(1, None))("row") + col = TensorType(dtype="float64", shape=(None, 1))("col") reshape_dimshuffle_vector = reshape(vec.dimshuffle("x", 0), vec.shape) reshape_dimshuffle_mat = reshape(mat.dimshuffle("x", 0, "x", 1), mat.shape) @@ -225,6 +232,7 @@ def test_local_useless_dimshuffle_in_reshape(): ], ) + # TODO FIXME: Construct these graphs and compare them. assert str(g) == ( "FunctionGraph(Reshape{1}(InplaceDimShuffle{x,0}(vector), Shape(vector)), " "Reshape{2}(InplaceDimShuffle{x,0,x,1}(mat), Shape(mat)), " @@ -270,12 +278,12 @@ def my_init(dtype="float64", num=0): return np.zeros((5, 5), dtype=dtype) + num fw, fx, fy, fz = [ - tensor(dtype="float32", shape=[False] * 2, name=n) for n in "wxyz" + tensor(dtype="float32", shape=(None,) * 2, name=n) for n in "wxyz" ] dw, dx, dy, dz = [ - tensor(dtype="float64", shape=[False] * 2, name=n) for n in "wxyz" + tensor(dtype="float64", shape=(None,) * 2, name=n) for n in "wxyz" ] - ix, iy, iz = [tensor(dtype="int32", shape=[False] * 2, name=n) for n in "xyz"] + ix, iy, iz = [tensor(dtype="int32", shape=(None,) * 2, name=n) for n in "xyz"] fv = fvector("v") fs = fscalar("s") fwv = my_init("float32", 1) diff --git a/tests/tensor/rewriting/test_math.py b/tests/tensor/rewriting/test_math.py index aaad958556..73b5bb1a81 100644 --- a/tests/tensor/rewriting/test_math.py +++ b/tests/tensor/rewriting/test_math.py @@ -161,9 +161,9 @@ def rewrite(g, level="fast_run"): def inputs(xbc=(0, 0), ybc=(0, 0), zbc=(0, 0)): - x = TensorType(shape=xbc, dtype="float64")("x") - y = TensorType(shape=ybc, dtype="float64")("y") - z = TensorType(shape=zbc, dtype="float64")("z") + x = TensorType(dtype="float64", shape=xbc)("x") + y = TensorType(dtype="float64", shape=ybc)("y") + z = TensorType(dtype="float64", shape=zbc)("z") return x, y, z @@ -959,11 +959,11 @@ def test_canonicalize_nan(self): def test_mismatching_types(self): a = at.as_tensor([[0.0]], dtype=np.float64) - b = tensor("float64", (None,)).dimshuffle("x", 0) + b = tensor("float64", shape=(None,)).dimshuffle("x", 0) z = add(a, b) # Construct a node with the wrong output `Type` z = Apply( - z.owner.op, z.owner.inputs, [tensor("float64", (None, None))] + z.owner.op, z.owner.inputs, [tensor("float64", shape=(None, None))] ).outputs[0] z_rewritten = rewrite_graph( @@ -1098,13 +1098,13 @@ def my_init(shp, dtype="float64", num=0): return ret fw, fx, fy, fz = [ - tensor(dtype="float32", shape=[False] * len(shp), name=n) for n in "wxyz" + tensor(dtype="float32", shape=(None,) * len(shp), name=n) for n in "wxyz" ] dw, dx, dy, dz = [ - tensor(dtype="float64", shape=[False] * len(shp), name=n) for n in "wxyz" + tensor(dtype="float64", shape=(None,) * len(shp), name=n) for n in "wxyz" ] ix, iy, iz = [ - tensor(dtype="int32", shape=[False] * len(shp), name=n) for n in "xyz" + tensor(dtype="int32", shape=(None,) * len(shp), name=n) for n in "xyz" ] fv = fvector("v") fs = fscalar("s") @@ -3558,7 +3558,7 @@ def test_local_reduce_broadcast_all_0(self): at_max, at_min, ]: - x = TensorType("int64", (True, True, True))() + x = TensorType("int64", shape=(1, 1, 1))() f = function([x], [fct(x)], mode=self.mode) assert not any( isinstance(node.op, CAReduce) for node in f.maker.fgraph.toposort() @@ -3573,7 +3573,7 @@ def test_local_reduce_broadcast_all_1(self): at_max, at_min, ]: - x = TensorType("int64", (True, True))() + x = TensorType("int64", shape=(1, 1))() f = function([x], [fct(x, axis=[0, 1])], mode=self.mode) assert not any( isinstance(node.op, CAReduce) for node in f.maker.fgraph.toposort() @@ -3588,7 +3588,7 @@ def test_local_reduce_broadcast_some_0(self): at_max, at_min, ]: - x = TensorType("int64", (True, False, True))() + x = TensorType("int64", shape=(1, None, 1))() f = function([x], [fct(x, axis=[0, 1])], mode=self.mode) order = f.maker.fgraph.toposort() @@ -3613,7 +3613,7 @@ def test_local_reduce_broadcast_some_1(self): at_max, at_min, ]: - x = TensorType("int64", (True, True, True))() + x = TensorType("int64", shape=(1, 1, 1))() f = function([x], [fct(x, axis=[0, 2])], mode=self.mode) assert not any( isinstance(node.op, CAReduce) for node in f.maker.fgraph.toposort() @@ -4097,7 +4097,7 @@ def test_local_log_sum_exp_maximum(): check_max_log_sum_exp(x, axis=2, dimshuffle_op=transpose_op) # If the sum is performed with keepdims=True - x = TensorType(dtype="floatX", shape=(False, True, False))("x") + x = TensorType(dtype="floatX", shape=(None, 1, None))("x") sum_keepdims_op = x.sum(axis=(0, 1), keepdims=True).owner.op check_max_log_sum_exp(x, axis=(0, 1), dimshuffle_op=sum_keepdims_op) diff --git a/tests/tensor/rewriting/test_shape.py b/tests/tensor/rewriting/test_shape.py index 09dc0585d0..c7281dd80c 100644 --- a/tests/tensor/rewriting/test_shape.py +++ b/tests/tensor/rewriting/test_shape.py @@ -9,7 +9,7 @@ from aesara.compile.mode import get_default_mode, get_mode from aesara.compile.ops import deep_copy_op from aesara.configdefaults import config -from aesara.graph.basic import Apply, Variable +from aesara.graph.basic import Apply, Variable, equal_computations from aesara.graph.fg import FunctionGraph from aesara.graph.op import Op from aesara.graph.rewriting.basic import check_stack_trace, node_rewriter, out2in @@ -324,7 +324,7 @@ class TestLocalReshapeToDimshuffle: def setup_method(self): self.rng = np.random.default_rng(utt.fetch_seed()) - def test_1(self): + def test_basic(self): reshape_lift = out2in(local_reshape_to_dimshuffle) useless_reshape = out2in(local_useless_reshape) x = shared(self.rng.standard_normal((4,))) @@ -332,27 +332,27 @@ def test_1(self): reshape_x = reshape(x, (1, 4)) reshape_y = reshape(y, (1, 5, 1, 6, 1, 1)) - g = FunctionGraph([x, y], [reshape_x, reshape_y]) - assert str(g) == ( - "FunctionGraph(Reshape{2}" - "(, " - "TensorConstant{[1 4]}), " - "Reshape{6}" - "(, " - "TensorConstant{[1 5 1 6 1 1]}))" + g = FunctionGraph([x, y], [reshape_x, reshape_y], clone=False) + + assert equal_computations( + g.outputs, + [ + Reshape(2)(x, as_tensor_variable((1, 4), ndim=1)), + Reshape(6)(y, as_tensor_variable((1, 5, 1, 6, 1, 1), ndim=1)), + ], ) reshape_lift.rewrite(g) useless_reshape.rewrite(g) - assert str(g) == ( - "FunctionGraph(InplaceDimShuffle{x,0}" - "(), " - "InplaceDimShuffle{x,0,x,1,x,x}" - "(Reshape{2}(, " - "TensorConstant{[5 6]})))" + + exp_x = SpecifyShape()(x, 4).dimshuffle("x", 0) + assert equal_computations([g.outputs[0]], [exp_x]) + + exp_y = Reshape(2)(y, as_tensor_variable((5, 6), ndim=1)).dimshuffle( + "x", 0, "x", 1, "x", "x" ) + assert equal_computations([g.outputs[1]], [exp_y]) - # Check stacktrace was copied over correctly after the rewrite was applied assert check_stack_trace(g, ops_to_check=(DimShuffle, Reshape)) @@ -493,15 +493,15 @@ def test_local_Shape_of_SpecifyShape_partial(s1): assert not any(isinstance(apply.op, SpecifyShape) for apply in fgraph.apply_nodes) -def test_local_Shape_i_of_broadcastable(): - x = tensor(np.float64, [False, True]) +def test_local_Shape_i_ground(): + x = tensor(np.float64, shape=(None, 2)) s = Shape_i(1)(x) fgraph = FunctionGraph(outputs=[s], clone=False) _ = rewrite_graph(fgraph, clone=False) assert x not in fgraph.variables - assert fgraph.outputs[0].data == 1 + assert fgraph.outputs[0].data == 2 # A test for a non-`TensorType` class MyType(Type): diff --git a/tests/tensor/rewriting/test_subtensor.py b/tests/tensor/rewriting/test_subtensor.py index 754dfc6995..8aab0aa35a 100644 --- a/tests/tensor/rewriting/test_subtensor.py +++ b/tests/tensor/rewriting/test_subtensor.py @@ -86,7 +86,7 @@ def test_local_replace_AdvancedSubtensor(indices, is_none): X_val = np.random.normal(size=(4, 4, 4)) - X = tensor(np.float64, [False, False, False], name="X") + X = tensor(np.float64, shape=(None, None, None), name="X") X.tag.test_value = X_val Y = X[indices] @@ -1858,7 +1858,10 @@ def test_local_subtensor_of_alloc(): # DebugMode should detect if something goes wrong. # test shape combination of odd and event shape. for s in [(3, 5), (4, 6), (3, 8), (4, 7), (1, 5), (5, 1)]: - x = tensor(dtype=config.floatX, shape=(s[0] == 1, s[1] == 1)) + x = tensor( + dtype=config.floatX, + shape=(1 if s[0] == 1 else None, 1 if s[1] == 1 else None), + ) xval = np.zeros(s, dtype=config.floatX) yval = np.arange(s[1], dtype=config.floatX) @@ -1902,7 +1905,7 @@ def test_local_subtensor_of_alloc(): def test_local_subtensor_shape_constant(): - x = tensor(np.float64, [True, False]).shape[0] + x = tensor(np.float64, shape=(1, None)).shape[0] (res,) = local_subtensor_shape_constant.transform(None, x.owner) assert isinstance(res, Constant) assert res.data == 1 @@ -1912,21 +1915,21 @@ def test_local_subtensor_shape_constant(): assert isinstance(res, Constant) assert res.data == 1 - x = _shape(tensor(np.float64, [True, False]))[lscalar()] + x = _shape(tensor(np.float64, shape=(1, None)))[lscalar()] assert not local_subtensor_shape_constant.transform(None, x.owner) - x = _shape(tensor(np.float64, [True, False]))[0:] + x = _shape(tensor(np.float64, shape=(1, None)))[0:] assert not local_subtensor_shape_constant.transform(None, x.owner) - x = _shape(tensor(np.float64, [True, False]))[lscalar() :] + x = _shape(tensor(np.float64, shape=(1, None)))[lscalar() :] assert not local_subtensor_shape_constant.transform(None, x.owner) - x = _shape(tensor(np.float64, [True, True]))[1:] + x = _shape(tensor(np.float64, shape=(1, 1)))[1:] (res,) = local_subtensor_shape_constant.transform(None, x.owner) assert isinstance(res, Constant) assert np.array_equal(res.data, [1]) - x = _shape(tensor(np.float64, [False, True, True]))[1:] + x = _shape(tensor(np.float64, shape=(None, 1, 1)))[1:] (res,) = local_subtensor_shape_constant.transform(None, x.owner) assert isinstance(res, Constant) assert np.array_equal(res.data, [1, 1]) diff --git a/tests/tensor/rewriting/test_uncanonicalize.py b/tests/tensor/rewriting/test_uncanonicalize.py index 0f0bcd8534..b4de1e3866 100644 --- a/tests/tensor/rewriting/test_uncanonicalize.py +++ b/tests/tensor/rewriting/test_uncanonicalize.py @@ -192,7 +192,7 @@ def test_local_dimshuffle_subtensor(): assert not all(isinstance(x, DimShuffle) for x in topo) # Test dimshuffle remove dimensions the subtensor don't "see". - x = tensor(shape=(False, True, False), dtype="float64") + x = tensor(dtype="float64", shape=(None, 1, None)) out = x[i].dimshuffle(1) g = FunctionGraph([x, i], [out]) @@ -203,7 +203,7 @@ def test_local_dimshuffle_subtensor(): # Test dimshuffle remove dimensions the subtensor don't "see" but # have in between dimensions. - x = tensor(shape=(False, True, False, True), dtype="float64") + x = tensor(dtype="float64", shape=(None, 1, None, 1)) out = x[i].dimshuffle(1) f = aesara.function([x, i], out) diff --git a/tests/tensor/signal/test_conv.py b/tests/tensor/signal/test_conv.py index 62cfbb0cc1..8217989002 100644 --- a/tests/tensor/signal/test_conv.py +++ b/tests/tensor/signal/test_conv.py @@ -16,8 +16,8 @@ def validate(self, image_shape, filter_shape, out_dim, verify_grad=True): image_dim = len(image_shape) filter_dim = len(filter_shape) - input = TensorType("float64", [False] * image_dim)() - filters = TensorType("float64", [False] * filter_dim)() + input = TensorType("float64", shape=(None,) * image_dim)() + filters = TensorType("float64", shape=(None,) * filter_dim)() bsize = image_shape[0] if image_dim != 3: diff --git a/tests/tensor/signal/test_pool.py b/tests/tensor/signal/test_pool.py index 4539090236..c3318cb38e 100644 --- a/tests/tensor/signal/test_pool.py +++ b/tests/tensor/signal/test_pool.py @@ -1122,7 +1122,7 @@ def test_max_pool_2d_6D(self): rng = np.random.default_rng(utt.fetch_seed()) maxpoolshps = [(3, 2)] imval = rng.random((2, 1, 1, 1, 3, 4)) - images = TensorType("float64", [False] * 6)() + images = TensorType("float64", shape=(None,) * 6)() for maxpoolshp, ignore_border, mode in product( maxpoolshps, @@ -1204,7 +1204,7 @@ def test_infer_shape(self): warn=False, ) # checking with broadcastable input - image = tensor(dtype="float64", shape=(False, False, True, True)) + image = tensor(dtype="float64", shape=(None, None, 1, 1)) image_val = rng.random((4, 6, 1, 1)) self._compile_and_check( [image], diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index 9c123f4c3a..a38c4fa1da 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -458,10 +458,10 @@ def test_make_vector_fail(self): res = MakeVector("int32")(a, b) res = MakeVector()(a) - assert res.broadcastable == (True,) + assert res.type.shape == (1,) res = MakeVector()() - assert res.broadcastable == (False,) + assert res.type.shape == (0,) def test_infer_shape(self): adscal = dscalar() @@ -511,7 +511,7 @@ def perform(self, *args, **kwargs): def test_constant(): - int8_vector_type = TensorType(dtype="int8", shape=(False,)) + int8_vector_type = TensorType(dtype="int8", shape=(None,)) # Make sure we return a `TensorConstant` unchanged x = TensorConstant(int8_vector_type, [1, 2]) @@ -575,17 +575,17 @@ def test_list(self): as_tensor_variable(bad_apply_var) def test_ndim_strip_leading_broadcastable(self): - x = TensorType(config.floatX, (True, False))("x") + x = TensorType(config.floatX, shape=(1, None))("x") x = as_tensor_variable(x, ndim=1) assert x.ndim == 1 def test_ndim_all_broadcastable(self): - x = TensorType(config.floatX, (True, True))("x") + x = TensorType(config.floatX, shape=(1, 1))("x") res = as_tensor_variable(x, ndim=0) assert res.ndim == 0 def test_ndim_incompatible(self): - x = TensorType(config.floatX, (True, False))("x") + x = TensorType(config.floatX, shape=(1, None))("x") with pytest.raises(ValueError, match="^Tensor of type.*"): as_tensor_variable(x, ndim=0) @@ -661,7 +661,7 @@ def test_constant_identity(self): assert x_scalar is a_scalar x_vector = TensorConstant( - TensorType(dtype="int8", shape=(False,)), + TensorType(dtype="int8", shape=(None,)), np.array([1, 2], dtype="int8"), ) a_vector = as_tensor_variable(x_vector) @@ -975,7 +975,7 @@ class TestNonzero: @config.change_flags(compute_test_value="raise") def test_nonzero(self): def check(m): - m_symb = tensor(dtype=m.dtype, shape=(False,) * m.ndim) + m_symb = tensor(dtype=m.dtype, shape=(None,) * m.ndim) m_symb.tag.test_value = m res_tuple_at = nonzero(m_symb, return_matrix=False) @@ -1004,7 +1004,7 @@ def check(m): @config.change_flags(compute_test_value="raise") def test_flatnonzero(self): def check(m): - m_symb = tensor(dtype=m.dtype, shape=(False,) * m.ndim) + m_symb = tensor(dtype=m.dtype, shape=(None,) * m.ndim) m_symb.tag.test_value = m res_at = flatnonzero(m_symb) @@ -1033,7 +1033,7 @@ def check(m): @config.change_flags(compute_test_value="raise") def test_nonzero_values(self): def check(m): - m_symb = tensor(dtype=m.dtype, shape=(False,) * m.ndim) + m_symb = tensor(dtype=m.dtype, shape=(None,) * m.ndim) m_symb.tag.test_value = m res_at = nonzero_values(m_symb) @@ -1177,6 +1177,8 @@ def test_get_vector_length(): # Test `Alloc`s assert 3 == get_vector_length(alloc(0, 3)) + assert 5 == get_vector_length(tensor(np.float64, shape=(5,))) + class TestJoinAndSplit: # Split is tested by each verify_grad method. @@ -1660,21 +1662,21 @@ def test_broadcastable_flag_assignment_mixed_otheraxes(self): a_val = rng.random((1, 4, 1)).astype(self.floatX) b_val = rng.random((1, 3, 1)).astype(self.floatX) - a = self.shared(a_val, shape=(False, False, True)) - b = self.shared(b_val, shape=(True, False, True)) + a = self.shared(a_val, shape=(None, None, 1)) + b = self.shared(b_val, shape=(1, None, 1)) c = self.join_op(1, a, b) - assert c.type.broadcastable[0] and c.type.broadcastable[2] - assert not c.type.broadcastable[1] + assert c.type.shape[0] == 1 and c.type.shape[2] == 1 + assert c.type.shape[1] != 1 # Opt can remplace the int by an Aesara constant c = self.join_op(constant(1), a, b) - assert c.type.broadcastable[0] and c.type.broadcastable[2] - assert not c.type.broadcastable[1] + assert c.type.shape[0] == 1 and c.type.shape[2] == 1 + assert c.type.shape[1] != 1 # In case futur opt insert other useless stuff c = self.join_op(cast(constant(1), dtype="int32"), a, b) - assert c.type.broadcastable[0] and c.type.broadcastable[2] - assert not c.type.broadcastable[1] + assert c.type.shape[0] == 1 and c.type.shape[2] == 1 + assert c.type.shape[1] != 1 f = function([], c, mode=self.mode) topo = f.maker.fgraph.toposort() @@ -1698,10 +1700,10 @@ def test_broadcastable_flag_assignment_mixed_thisaxes(self): a_val = rng.random((2, 4, 1)).astype(self.floatX) b_val = rng.random((1, 4, 1)).astype(self.floatX) - a = self.shared(a_val, shape=(False, False, True)) - b = self.shared(b_val, shape=(True, False, True)) + a = self.shared(a_val, shape=(None, None, 1)) + b = self.shared(b_val, shape=(1, None, 1)) c = self.join_op(0, a, b) - assert not c.type.broadcastable[0] + assert c.type.shape[0] != 1 f = function([], c, mode=self.mode) topo = f.maker.fgraph.toposort() @@ -1715,8 +1717,8 @@ def test_broadcastable_flag_assignment_mixed_thisaxes(self): # We can't set the value| with pytest.raises(TypeError): b.set_value(rng.random((3, 4, 1)).astype(self.floatX)) - a = TensorType(dtype=self.floatX, shape=[False, False, True])() - b = TensorType(dtype=self.floatX, shape=[True, False, True])() + a = TensorType(dtype=self.floatX, shape=(None, None, 1))() + b = TensorType(dtype=self.floatX, shape=(1, None, 1))() c = self.join_op(0, a, b) f = function([a, b], c, mode=self.mode) bad_b_val = rng.random((3, 4, 1)).astype(self.floatX) @@ -1731,10 +1733,10 @@ def test_broadcastable_flags_all_broadcastable_on_joinaxis(self): a_val = rng.random((1, 4, 1)).astype(self.floatX) b_val = rng.random((1, 4, 1)).astype(self.floatX) - a = self.shared(a_val, shape=(True, False, True)) - b = self.shared(b_val, shape=(True, False, True)) + a = self.shared(a_val, shape=(1, None, 1)) + b = self.shared(b_val, shape=(1, None, 1)) c = self.join_op(0, a, b) - assert not c.type.broadcastable[0] + assert c.type.shape[0] != 1 f = function([], c, mode=self.mode) topo = f.maker.fgraph.toposort() @@ -1750,11 +1752,11 @@ def test_broadcastable_single_input_broadcastable_dimension(self): # single-input join. rng = np.random.default_rng(seed=utt.fetch_seed()) a_val = rng.random((1, 4, 1)).astype(self.floatX) - a = self.shared(a_val, shape=(True, False, True)) + a = self.shared(a_val, shape=(1, None, 1)) b = self.join_op(0, a) - assert b.type.broadcastable[0] - assert b.type.broadcastable[2] - assert not b.type.broadcastable[1] + assert b.type.shape[0] == 1 + assert b.type.shape[2] == 1 + assert b.type.shape[1] != 1 f = function([], b, mode=self.mode) topo = f.maker.fgraph.toposort() @@ -1774,29 +1776,19 @@ def test_broadcastable_single_input_broadcastable_dimension(self): def test_broadcastable_flags_many_dims_and_inputs(self): # Test that the right broadcastable flags get set for a join # with many inputs and many input dimensions. - a = TensorType( - dtype=self.floatX, shape=[True, False, True, False, False, False] - )() - b = TensorType( - dtype=self.floatX, shape=[True, True, True, False, False, False] - )() - c = TensorType( - dtype=self.floatX, shape=[True, False, False, False, False, False] - )() - d = TensorType( - dtype=self.floatX, shape=[True, False, True, True, False, True] - )() - e = TensorType( - dtype=self.floatX, shape=[True, False, True, False, False, True] - )() + a = TensorType(dtype=self.floatX, shape=(1, None, 1, None, None, None))() + b = TensorType(dtype=self.floatX, shape=(1, 1, 1, None, None, None))() + c = TensorType(dtype=self.floatX, shape=(1, None, None, None, None, None))() + d = TensorType(dtype=self.floatX, shape=(1, None, 1, 1, None, 1))() + e = TensorType(dtype=self.floatX, shape=(1, None, 1, None, None, 1))() f = self.join_op(0, a, b, c, d, e) - fb = f.type.broadcastable + fb = tuple(s == 1 for s in f.type.shape) assert not fb[0] and fb[1] and fb[2] and fb[3] and not fb[4] and fb[5] g = self.join_op(1, a, b, c, d, e) - gb = g.type.broadcastable + gb = tuple(s == 1 for s in g.type.shape) assert gb[0] and not gb[1] and gb[2] and gb[3] and not gb[4] and gb[5] h = self.join_op(4, a, b, c, d, e) - hb = h.type.broadcastable + hb = tuple(s == 1 for s in h.type.shape) assert hb[0] and hb[1] and hb[2] and hb[3] and not hb[4] and hb[5] f = function([a, b, c, d, e], f, mode=self.mode) @@ -1881,8 +1873,8 @@ def get_mat(s1, s2): def test_rebroadcast(self): # Regression test for a crash that used to happen when rebroadcasting. - x = TensorType(self.floatX, [False, False, True])() - u = TensorType(self.floatX, [False, False, True])() + x = TensorType(self.floatX, shape=(None, None, 1))() + u = TensorType(self.floatX, shape=(None, None, 1))() # This line used to crash. at.concatenate([x, -u], axis=2) @@ -1989,8 +1981,8 @@ def test_TensorFromScalar(): s = aes.constant(56) t = tensor_from_scalar(s) assert t.owner.op is tensor_from_scalar - assert t.type.broadcastable == (), t.type.broadcastable - assert t.type.ndim == 0, t.type.ndim + assert t.type.shape == () + assert t.type.ndim == 0 assert t.type.dtype == s.type.dtype v = eval_outputs([t]) @@ -2118,7 +2110,7 @@ def test_flatten_ndim2(): def test_flatten_ndim2_of_3(): - a = TensorType("float64", (False, False, False))() + a = TensorType("float64", shape=(None, None, None))() c = flatten(a, 2) f = inplace_func([a], c) a_val = _asarray([[[0, 1], [2, 3]], [[4, 5], [6, 7]]], dtype="float64") @@ -2135,25 +2127,25 @@ def test_flatten_broadcastable(): # Ensure that the broadcastable pattern of the output is coherent with # that of the input - inp = TensorType("float64", (False, False, False, False))() + inp = TensorType("float64", shape=(None, None, None, None))() out = flatten(inp, ndim=2) - assert out.broadcastable == (False, False) + assert out.type.shape == (None, None) - inp = TensorType("float64", (False, False, False, True))() + inp = TensorType("float64", shape=(None, None, None, 1))() out = flatten(inp, ndim=2) - assert out.broadcastable == (False, False) + assert out.type.shape == (None, None) - inp = TensorType("float64", (False, True, False, True))() + inp = TensorType("float64", shape=(None, 1, None, 1))() out = flatten(inp, ndim=2) - assert out.broadcastable == (False, False) + assert out.type.shape == (None, None) - inp = TensorType("float64", (False, True, True, True))() + inp = TensorType("float64", shape=(None, 1, 1, 1))() out = flatten(inp, ndim=2) - assert out.broadcastable == (False, True) + assert out.type.shape == (None, 1) - inp = TensorType("float64", (True, False, True, True))() + inp = TensorType("float64", shape=(1, None, 1, 1))() out = flatten(inp, ndim=3) - assert out.broadcastable == (True, False, True) + assert out.type.shape == (1, None, 1) def test_flatten_ndim_invalid(): @@ -2946,10 +2938,10 @@ def permute_fixed(s_input): def test_3b_2(self): # Test permute_row_elements on a more complex broadcasting pattern: - # input.type.broadcastable = (False, True, False), - # p.type.broadcastable = (False, False). + # input.type.shape = (None, 1, None), + # p.type.shape = (None, None). - input = TensorType("floatX", (False, True, False))() + input = TensorType("floatX", shape=(None, 1, None))() p = imatrix() out = permute_row_elements(input, p) permute = function([input, p], out) @@ -3185,7 +3177,7 @@ def test_too_big(self): def test_len(): for shape_ in [(5,), (3, 4), (7, 4, 6)]: - x = tensor(dtype="floatX", shape=(False,) * len(shape_)) + x = tensor(dtype="floatX", shape=(None,) * len(shape_)) with pytest.raises(TypeError): len(x) @@ -3327,7 +3319,7 @@ def test_shape_i(self): assert get_scalar_constant_value(s) == 3 s = Shape_i(1)(c) assert get_scalar_constant_value(s) == 4 - d = aesara.shared(np.random.standard_normal((1, 1)), shape=(True, True)) + d = aesara.shared(np.random.standard_normal((1, 1)), shape=(1, 1)) f = ScalarFromTensor()(Shape_i(0)(d)) assert get_scalar_constant_value(f) == 1 @@ -3532,7 +3524,7 @@ def _generator(self): for d in range(1, dims + 1): # Create a TensorType of the same dimensions as # as the data we want to test. - x = TensorType(dtype=config.floatX, shape=(False,) * d)("x") + x = TensorType(dtype=config.floatX, shape=(None,) * d)("x") # Make a slice of the test data that has the # dimensions we need by doing xv[0,...,0] @@ -4054,7 +4046,7 @@ def test_broadcasted(self): B = np.asarray(np.random.random((4, 1)), dtype="float32") for m in self.modes: f = function([a, b], choose(a, b, mode=m)) - assert choose(a, b, mode=m).broadcastable[0] + assert choose(a, b, mode=m).type.shape[0] == 1 t_c = f(A, B) n_c = np.choose(A, B, mode=m) assert np.allclose(t_c, n_c) @@ -4117,8 +4109,10 @@ def test_infer_shape(self): ((4,), (1,)), ((1,), (1,)), ]: - a = tensor(dtype="int32", shape=[n == 1 for n in shp1]) - c = tensor(dtype="float32", shape=[n == 1 for n in shp2]) + a = tensor(dtype="int32", shape=tuple(1 if s == 1 else None for s in shp1)) + c = tensor( + dtype="float32", shape=tuple(1 if s == 1 else None for s in shp2) + ) A = np.asarray(np.random.random(shp1) * shp2[0], dtype="int32") C = np.asarray(np.random.random(shp2) * shp2[0], dtype="float32") self._compile_and_check( @@ -4268,8 +4262,12 @@ def test_take_along_axis(self, shape, axis, samples): indices_size[axis or 0] = samples indices = rng.integers(low=0, high=shape[axis or 0], size=indices_size) - arr_in = at.tensor(config.floatX, [s == 1 for s in arr.shape]) - indices_in = at.tensor(np.int64, [s == 1 for s in indices.shape]) + arr_in = at.tensor( + config.floatX, shape=tuple(1 if s == 1 else None for s in arr.shape) + ) + indices_in = at.tensor( + np.int64, shape=tuple(1 if s == 1 else None for s in indices.shape) + ) out = at.take_along_axis(arr_in, indices_in, axis) @@ -4280,12 +4278,12 @@ def test_take_along_axis(self, shape, axis, samples): ) def test_ndim_dtype_failures(self): - arr = at.tensor(config.floatX, [False] * 2) - indices = at.tensor(np.int64, [False] * 3) + arr = at.tensor(config.floatX, shape=(None,) * 2) + indices = at.tensor(np.int64, shape=(None,) * 3) with pytest.raises(ValueError): at.take_along_axis(arr, indices) - indices = at.tensor(np.float64, [False] * 2) + indices = at.tensor(np.float64, shape=(None,) * 2) with pytest.raises(IndexError): at.take_along_axis(arr, indices) diff --git a/tests/tensor/test_blas.py b/tests/tensor/test_blas.py index 96de2667ab..9c15a017c7 100644 --- a/tests/tensor/test_blas.py +++ b/tests/tensor/test_blas.py @@ -1469,7 +1469,7 @@ def test_gemv_broadcast(self): v2 = shared(v2_orig) m = shared( np.array(rng.uniform(size=(1, 2)), dtype="float32"), - shape=(True, False), + shape=(1, None), ) o = aesara.tensor.dot(m, v1) f = function([], o + v2, mode=mode_blas_opt) @@ -1779,20 +1779,20 @@ class TestDgemv(BaseGemv, unittest_tools.OptimizationTestMixin): class TestGerMakeNode: def setup_method(self): - self.iv = tensor(dtype="int32", shape=(False,)) - self.fv = tensor(dtype="float32", shape=(False,)) - self.fv1 = tensor(dtype="float32", shape=(True,)) - self.dv = tensor(dtype="float64", shape=(False,)) - self.dv1 = tensor(dtype="float64", shape=(True,)) - self.cv = tensor(dtype="complex64", shape=(False,)) - self.zv = tensor(dtype="complex128", shape=(False,)) - - self.fv_2 = tensor(dtype="float32", shape=(False,)) - self.fv1_2 = tensor(dtype="float32", shape=(True,)) - self.dv_2 = tensor(dtype="float64", shape=(False,)) - self.dv1_2 = tensor(dtype="float64", shape=(True,)) - self.cv_2 = tensor(dtype="complex64", shape=(False,)) - self.zv_2 = tensor(dtype="complex128", shape=(False,)) + self.iv = tensor(dtype="int32", shape=(None,)) + self.fv = tensor(dtype="float32", shape=(None,)) + self.fv1 = tensor(dtype="float32", shape=(1,)) + self.dv = tensor(dtype="float64", shape=(None,)) + self.dv1 = tensor(dtype="float64", shape=(1,)) + self.cv = tensor(dtype="complex64", shape=(None,)) + self.zv = tensor(dtype="complex128", shape=(None,)) + + self.fv_2 = tensor(dtype="float32", shape=(None,)) + self.fv1_2 = tensor(dtype="float32", shape=(1,)) + self.dv_2 = tensor(dtype="float64", shape=(None,)) + self.dv1_2 = tensor(dtype="float64", shape=(1,)) + self.cv_2 = tensor(dtype="complex64", shape=(None,)) + self.zv_2 = tensor(dtype="complex128", shape=(None,)) self.fm = fmatrix() self.dm = dmatrix() @@ -1866,10 +1866,10 @@ def setup_method(self): self.mode = aesara.compile.get_default_mode().including("fast_run") self.mode = self.mode.excluding("c_blas", "scipy_blas") dtype = self.dtype = "float64" # optimization isn't dtype-dependent - self.A = tensor(dtype=dtype, shape=(False, False)) + self.A = tensor(dtype=dtype, shape=(None, None)) self.a = tensor(dtype=dtype, shape=()) - self.x = tensor(dtype=dtype, shape=(False,)) - self.y = tensor(dtype=dtype, shape=(False,)) + self.x = tensor(dtype=dtype, shape=(None,)) + self.y = tensor(dtype=dtype, shape=(None,)) self.ger = ger self.ger_destructive = ger_destructive self.gemm = gemm_no_inplace @@ -2000,9 +2000,9 @@ def given_dtype(self, dtype, M, N, *, destructive=True): # test corner case shape and dtype rng = np.random.default_rng(unittest_tools.fetch_seed()) - A = tensor(dtype=dtype, shape=(False, False)) - x = tensor(dtype=dtype, shape=(False,)) - y = tensor(dtype=dtype, shape=(False,)) + A = tensor(dtype=dtype, shape=(None, None)) + x = tensor(dtype=dtype, shape=(None,)) + y = tensor(dtype=dtype, shape=(None,)) f = self.function([A, x, y], A + 0.1 * outer(x, y)) self.assertFunctionContains( diff --git a/tests/tensor/test_blas_c.py b/tests/tensor/test_blas_c.py index af6c5f761d..4205badb0b 100644 --- a/tests/tensor/test_blas_c.py +++ b/tests/tensor/test_blas_c.py @@ -41,10 +41,10 @@ def manual_setup_method(self, dtype="float64"): # This tests can run even when aesara.config.blas__ldflags is empty. self.dtype = dtype self.mode = aesara.compile.get_default_mode().including("fast_run") - self.A = tensor(dtype=dtype, shape=(False, False)) + self.A = tensor(dtype=dtype, shape=(None, None)) self.a = tensor(dtype=dtype, shape=()) - self.x = tensor(dtype=dtype, shape=(False,)) - self.y = tensor(dtype=dtype, shape=(False,)) + self.x = tensor(dtype=dtype, shape=(None,)) + self.y = tensor(dtype=dtype, shape=(None,)) self.Aval = np.ones((2, 3), dtype=dtype) self.xval = np.asarray([1, 2], dtype=dtype) self.yval = np.asarray([1.5, 2.7, 3.9], dtype=dtype) @@ -131,12 +131,12 @@ def setup_method(self): self.dtype = dtype self.mode = aesara.compile.get_default_mode().including("fast_run") # matrix - self.A = tensor(dtype=dtype, shape=(False, False)) + self.A = tensor(dtype=dtype, shape=(None, None)) self.Aval = np.ones((2, 3), dtype=dtype) # vector - self.x = tensor(dtype=dtype, shape=(False,)) - self.y = tensor(dtype=dtype, shape=(False,)) + self.x = tensor(dtype=dtype, shape=(None,)) + self.y = tensor(dtype=dtype, shape=(None,)) self.xval = np.asarray([1, 2], dtype=dtype) self.yval = np.asarray([1.5, 2.7, 3.9], dtype=dtype) diff --git a/tests/tensor/test_blas_scipy.py b/tests/tensor/test_blas_scipy.py index 25fe5316a7..2d81d87bb6 100644 --- a/tests/tensor/test_blas_scipy.py +++ b/tests/tensor/test_blas_scipy.py @@ -17,10 +17,10 @@ def setup_method(self): self.mode = self.mode.including("fast_run") self.mode = self.mode.excluding("c_blas") # c_blas trumps scipy Ops dtype = self.dtype = "float64" # optimization isn't dtype-dependent - self.A = tensor(dtype=dtype, shape=(False, False)) + self.A = tensor(dtype=dtype, shape=(None, None)) self.a = tensor(dtype=dtype, shape=()) - self.x = tensor(dtype=dtype, shape=(False,)) - self.y = tensor(dtype=dtype, shape=(False,)) + self.x = tensor(dtype=dtype, shape=(None,)) + self.y = tensor(dtype=dtype, shape=(None,)) self.Aval = np.ones((2, 3), dtype=dtype) self.xval = np.asarray([1, 2], dtype=dtype) self.yval = np.asarray([1.5, 2.7, 3.9], dtype=dtype) diff --git a/tests/tensor/test_casting.py b/tests/tensor/test_casting.py index e7f4e63fc5..3477897179 100644 --- a/tests/tensor/test_casting.py +++ b/tests/tensor/test_casting.py @@ -75,7 +75,7 @@ def test_illegal(self): ), ) def test_basic(self, type1, type2, converter): - x = TensorType(dtype=type1, shape=(False,))() + x = TensorType(dtype=type1, shape=(None,))() y = converter(x) f = function([In(x, strict=True)], y) a = np.arange(10, dtype=type1) @@ -86,8 +86,8 @@ def test_convert_to_complex(self): val64 = np.ones(3, dtype="complex64") + 0.5j val128 = np.ones(3, dtype="complex128") + 0.5j - vec64 = TensorType("complex64", (False,))() - vec128 = TensorType("complex128", (False,))() + vec64 = TensorType("complex64", shape=(None,))() + vec128 = TensorType("complex128", shape=(None,))() f = function([vec64], _convert_to_complex128(vec64)) # we need to compare with the same type. diff --git a/tests/tensor/test_elemwise.py b/tests/tensor/test_elemwise.py index 6bd514f277..1c8c4b2ad6 100644 --- a/tests/tensor/test_elemwise.py +++ b/tests/tensor/test_elemwise.py @@ -56,13 +56,14 @@ def with_linker(self, linker): ((1, 1, 1), (), ()), ((1,), ("x", "x"), (1, 1)), ]: - ib = [(entry == 1) for entry in xsh] - x = self.type(self.dtype, ib)("x") + i_shape = [entry if entry == 1 else None for entry in xsh] + ib = [entry == 1 for entry in i_shape] + x = self.type(self.dtype, shape=i_shape)("x") e = self.op(ib, shuffle)(x) f = aesara.function([x], e, mode=Mode(linker=linker)) assert f(np.ones(xsh, dtype=self.dtype)).shape == zsh # test that DimShuffle.infer_shape work correctly - x = self.type(self.dtype, ib)("x") + x = self.type(self.dtype, shape=i_shape)("x") e = self.op(ib, shuffle)(x) f = aesara.function( [x], e.shape, mode=Mode(linker=linker), on_unused_input="ignore" @@ -71,13 +72,13 @@ def with_linker(self, linker): # Test when we drop a axis that is not broadcastable ib = [False, True, False] - x = self.type(self.dtype, ib)("x") + x = self.type(self.dtype, shape=(None, 1, None))("x") with pytest.raises(ValueError): self.op(ib, shuffle) # Test when we drop a axis that don't have shape 1 ib = [True, True, False] - x = self.type(self.dtype, ib)("x") + x = self.type(self.dtype, shape=(1, 1, None))("x") e = self.op(ib, (1, 2))(x) f = aesara.function([x], e.shape, mode=Mode(linker=linker)) with pytest.raises(TypeError): @@ -86,7 +87,7 @@ def with_linker(self, linker): # Test that we can't take a dimensions multiple time xsh, shuffle, zsh = ((1, 1, 4), (0, 1, 2, 0), (1, 4)) ib = [False, True, False] - x = self.type(self.dtype, ib)("x") + x = self.type(self.dtype, shape=(None, 1, None))("x") with pytest.raises(ValueError): DimShuffle(ib, shuffle) @@ -111,8 +112,9 @@ def test_infer_shape(self): ((1, 1, 1), ()), ((1,), ("x", "x")), ]: + i_shape = [entry if entry == 1 else None for entry in xsh] ib = [(entry == 1) for entry in xsh] - adtens = self.type(self.dtype, ib)("x") + adtens = self.type(self.dtype, shape=i_shape)("x") adtens_val = np.ones(xsh, dtype=self.dtype) self._compile_and_check( [adtens], @@ -234,11 +236,11 @@ def with_linker(self, linker, op, type, rand_val): # type shape provided by Aesara was broadcastable/non-broadcastable x_type = type( aesara.config.floatX, - broadcastable=[(entry == 1) for entry in xsh], + shape=tuple(s if s == 1 else None for s in xsh), ) y_type = type( aesara.config.floatX, - broadcastable=[(entry == 1) for entry in ysh], + shape=tuple(s if s == 1 else None for s in ysh), ) else: x_type = type(aesara.config.floatX, shape=[None for _ in xsh]) @@ -285,11 +287,11 @@ def with_linker_inplace(self, linker, op, type, rand_val): # type shape provided by Aesara was broadcastable/non-broadcastable x_type = type( aesara.config.floatX, - broadcastable=[(entry == 1) for entry in xsh], + shape=tuple(s if s == 1 else None for s in xsh), ) y_type = type( aesara.config.floatX, - broadcastable=[(entry == 1) for entry in ysh], + shape=tuple(s if s == 1 else None for s in ysh), ) else: x_type = type(aesara.config.floatX, shape=[None for _ in xsh]) @@ -349,8 +351,8 @@ def test_fill(self): [self.type, self.ctype], [self.rand_val, self.rand_cval], ): - x = t(aesara.config.floatX, (False, False))("x") - y = t(aesara.config.floatX, (True, True))("y") + x = t(aesara.config.floatX, shape=(None, None))("x") + y = t(aesara.config.floatX, shape=(1, 1))("y") e = op(aes.Second(aes.transfer_type(0)), {0: 0})(x, y) f = make_function(linker().accept(FunctionGraph([x, y], [e]))) xv = rval((5, 5)) @@ -363,11 +365,10 @@ def test_fill_var(self): x.fill(3) def test_fill_grad(self): - # Fix bug reported at - # https://groups.google.com/d/topic/theano-users/nQshB8gUA6k/discussion - x = TensorType(config.floatX, (False, True, False))("x") - y = TensorType(config.floatX, (False, True, False))("y") + x = TensorType(config.floatX, shape=(None, 1, None))("x") + y = TensorType(config.floatX, shape=(None, 1, None))("y") e = second(x, y) + # TODO FIXME: Make this a real test and assert something here! aesara.grad(e.sum(), y) @pytest.mark.skipif( @@ -380,8 +381,8 @@ def test_weird_strides(self): [self.type, self.ctype], [self.rand_val, self.rand_cval], ): - x = t(aesara.config.floatX, (False,) * 5)("x") - y = t(aesara.config.floatX, (False,) * 5)("y") + x = t(aesara.config.floatX, shape=(None,) * 5)("x") + y = t(aesara.config.floatX, shape=(None,) * 5)("y") e = op(aes.add)(x, y) f = make_function(linker().accept(FunctionGraph([x, y], [e]))) xv = rval((2, 2, 2, 2, 2)) @@ -399,7 +400,7 @@ def test_same_inputs(self): [self.type, self.ctype], [self.rand_val, self.rand_cval], ): - x = t(aesara.config.floatX, (False,) * 2)("x") + x = t(aesara.config.floatX, shape=(None,) * 2)("x") e = op(aes.add)(x, x) f = make_function(linker().accept(FunctionGraph([x], [e]))) xv = rval((2, 2)) @@ -440,7 +441,9 @@ def with_mode( for xsh, tosum in self.cases: if dtype == "floatX": dtype = aesara.config.floatX - x = self.type(dtype, [(entry == 1) for entry in xsh])("x") + x = self.type( + dtype, shape=tuple(entry if entry == 1 else None for entry in xsh) + )("x") d = {} if pre_scalar_op is not None: d = {"pre_scalar_op": pre_scalar_op} @@ -548,7 +551,9 @@ def with_mode( # GpuCAReduce don't implement all cases when size is 0 assert xv.size == 0 - x = self.type(dtype, [(entry == 1) for entry in xsh])("x") + x = self.type( + dtype, shape=tuple(entry if entry == 1 else None for entry in xsh) + )("x") if tensor_op is None: e = self.op(scalar_op, axis=tosum)(x) else: @@ -653,7 +658,9 @@ def test_infer_shape(self, dtype=None, pre_scalar_op=None): if dtype is None: dtype = aesara.config.floatX for xsh, tosum in self.cases: - x = self.type(dtype, [(entry == 1) for entry in xsh])("x") + x = self.type( + dtype, shape=tuple(entry if entry == 1 else None for entry in xsh) + )("x") if pre_scalar_op is not None: x = pre_scalar_op(x) if tosum is None: @@ -749,8 +756,12 @@ def test_infer_shape(self): ((2, 3, 4, 1), (2, 3, 4, 5)), ]: dtype = aesara.config.floatX - t_left = TensorType(dtype, [(entry == 1) for entry in s_left])() - t_right = TensorType(dtype, [(entry == 1) for entry in s_right])() + t_left = TensorType( + dtype, shape=tuple(entry if entry == 1 else None for entry in s_left) + )() + t_right = TensorType( + dtype, shape=tuple(entry if entry == 1 else None for entry in s_right) + )() t_left_val = np.zeros(s_left, dtype=dtype) t_right_val = np.zeros(s_right, dtype=dtype) self._compile_and_check( @@ -857,7 +868,7 @@ def test_shape_types(self): def test_static_shape_unary(self): x = tensor("float64", shape=(None, 0, 1, 5)) - exp(x).type.shape == (None, 0, 1, 5) + assert exp(x).type.shape == (None, 0, 1, 5) def test_static_shape_binary(self): x = tensor("float64", shape=(None, 5)) diff --git a/tests/tensor/test_extra_ops.py b/tests/tensor/test_extra_ops.py index 9c88453420..f56e5b0358 100644 --- a/tests/tensor/test_extra_ops.py +++ b/tests/tensor/test_extra_ops.py @@ -337,10 +337,10 @@ def test_perform(self, axis, n): @pytest.mark.parametrize( "x_type", ( - at.TensorType("float64", (None, None)), - at.TensorType("float64", (None, 30)), - at.TensorType("float64", (10, None)), - at.TensorType("float64", (10, 30)), + at.TensorType("float64", shape=(None, None)), + at.TensorType("float64", shape=(None, 30)), + at.TensorType("float64", shape=(10, None)), + at.TensorType("float64", shape=(10, 30)), ), ) @pytest.mark.parametrize("axis", (-2, -1, 0, 1)) @@ -363,19 +363,19 @@ def setup_method(self): self.op = squeeze @pytest.mark.parametrize( - "shape, broadcast", + "shape, var_shape", zip( [(1, 3), (1, 2, 3), (1, 5, 1, 1, 6)], [ - [True, False], - [True, False, False], - [True, False, True, True, False], + [1, None], + [1, None, None], + [1, None, 1, 1, None], ], ), ) - def test_op(self, shape, broadcast): + def test_op(self, shape, var_shape): data = np.random.random(size=shape).astype(config.floatX) - variable = TensorType(config.floatX, broadcast)() + variable = TensorType(config.floatX, shape=var_shape)() f = aesara.function([variable], self.op(variable)) @@ -386,19 +386,19 @@ def test_op(self, shape, broadcast): assert np.allclose(tested, expected) @pytest.mark.parametrize( - "shape, broadcast", + "shape, var_shape", zip( [(1, 3), (1, 2, 3), (1, 5, 1, 1, 6)], [ - [True, False], - [True, False, False], - [True, False, True, True, False], + [1, None], + [1, None, None], + [1, None, 1, 1, None], ], ), ) - def test_infer_shape(self, shape, broadcast): + def test_infer_shape(self, shape, var_shape): data = np.random.random(size=shape).astype(config.floatX) - variable = TensorType(config.floatX, broadcast)() + variable = TensorType(config.floatX, shape=var_shape)() self._compile_and_check( [variable], [self.op(variable)], [data], DimShuffle, warn=False @@ -420,20 +420,20 @@ def test_grad(self, shape, broadcast): utt.verify_grad(self.op, [data]) @pytest.mark.parametrize( - "shape, broadcast", + "shape, var_shape", zip( [(1, 3), (1, 2, 3), (1, 5, 1, 1, 6)], [ - [True, False], - [True, False, False], - [True, False, True, True, False], + [1, None], + [1, None, None], + [1, None, 1, 1, None], ], ), ) - def test_var_interface(self, shape, broadcast): + def test_var_interface(self, shape, var_shape): # same as test_op, but use a_aesara_var.squeeze. data = np.random.random(size=shape).astype(config.floatX) - variable = TensorType(config.floatX, broadcast)() + variable = TensorType(config.floatX, shape=var_shape)() f = aesara.function([variable], variable.squeeze()) @@ -444,29 +444,29 @@ def test_var_interface(self, shape, broadcast): assert np.allclose(tested, expected) def test_axis(self): - variable = TensorType(config.floatX, [False, True, False])() + variable = TensorType(config.floatX, shape=(None, 1, None))() res = squeeze(variable, axis=1) assert res.broadcastable == (False, False) - variable = TensorType(config.floatX, [False, True, False])() + variable = TensorType(config.floatX, shape=(None, 1, None))() res = squeeze(variable, axis=(1,)) assert res.broadcastable == (False, False) - variable = TensorType(config.floatX, [False, True, False, True])() + variable = TensorType(config.floatX, shape=(None, 1, None, 1))() res = squeeze(variable, axis=(1, 3)) assert res.broadcastable == (False, False) - variable = TensorType(config.floatX, [True, False, True, False, True])() + variable = TensorType(config.floatX, shape=(1, None, 1, None, 1))() res = squeeze(variable, axis=(0, -1)) assert res.broadcastable == (False, True, False) def test_invalid_axis(self): # Test that trying to squeeze a non broadcastable dimension raises error - variable = TensorType(config.floatX, [True, False])() + variable = TensorType(config.floatX, shape=(1, None))() with pytest.raises( ValueError, match="Cannot drop a non-broadcastable dimension" ): @@ -540,7 +540,7 @@ def setup_method(self): def test_basic(self, ndim, dtype): rng = np.random.default_rng(4282) - x = TensorType(config.floatX, [False] * ndim)() + x = TensorType(config.floatX, (None,) * ndim)() a = rng.random((10,) * ndim).astype(config.floatX) for axis in self._possible_axis(ndim): @@ -579,7 +579,7 @@ def test_basic(self, ndim, dtype): ) # check when r is aesara tensortype that broadcastable is (True,) - r_var = TensorType(shape=(True,), dtype=dtype)() + r_var = TensorType(dtype=dtype, shape=(1,))() r = rng.integers(1, 6, size=(1,)).astype(dtype) f = aesara.function([x, r_var], repeat(x, r_var, axis=axis)) assert np.allclose(np.repeat(a, r[0], axis=axis), f(a, r)) @@ -593,7 +593,7 @@ def test_basic(self, ndim, dtype): def test_infer_shape(self, ndim, dtype): rng = np.random.default_rng(4282) - x = TensorType(config.floatX, [False] * ndim)() + x = TensorType(config.floatX, shape=(None,) * ndim)() shp = (np.arange(ndim) + 1) * 3 a = rng.random(shp).astype(config.floatX) @@ -635,7 +635,7 @@ def test_grad(self, ndim): utt.verify_grad(lambda x: Repeat(axis=axis)(x, 3), [a]) def test_broadcastable(self): - x = TensorType(config.floatX, [False, True, False])() + x = TensorType(config.floatX, shape=(None, 1, None))() r = Repeat(axis=1)(x, 2) assert r.broadcastable == (False, False, False) r = Repeat(axis=1)(x, 1) @@ -1333,7 +1333,7 @@ def test_gradient(self, fn, input_dims): def test_infer_shape(self): rng = np.random.default_rng(43) - a = tensor(config.floatX, [False, True, False]) + a = tensor(config.floatX, shape=(None, 1, None)) shape = list(a.shape) out = self.op(a, shape) @@ -1344,7 +1344,7 @@ def test_infer_shape(self): self.op_class, ) - a = tensor(config.floatX, [False, True, False]) + a = tensor(config.floatX, shape=(None, 1, None)) shape = [iscalar() for i in range(4)] self._compile_and_check( [a] + shape, diff --git a/tests/tensor/test_io.py b/tests/tensor/test_io.py index addc0a54bf..64cad51b0d 100644 --- a/tests/tensor/test_io.py +++ b/tests/tensor/test_io.py @@ -20,7 +20,7 @@ def test_basic(self): path = Variable(Generic(), None) # Not specifying mmap_mode defaults to None, and the data is # copied into main memory - x = load(path, "int32", (False,)) + x = load(path, "int32", (None,)) y = x * 2 fn = function([path], y) assert (fn(self.filename) == (self.data * 2)).all() @@ -32,14 +32,14 @@ def test_invalid_modes(self): path = Variable(Generic(), None) for mmap_mode in ("r+", "r", "w+", "toto"): with pytest.raises(ValueError): - load(path, "int32", (False,), mmap_mode) + load(path, "int32", (None,), mmap_mode) - def test1(self): + def test_copy_on_write(self): path = Variable(Generic(), None) # 'c' means "copy-on-write", which allow the array to be overwritten # by an inplace Op in the graph, without modifying the underlying # file. - x = load(path, "int32", (False,), "c") + x = load(path, "int32", (None,), "c") # x ** 2 has been chosen because it will work inplace. y = (x**2).sum() fn = function([path], y) @@ -49,7 +49,7 @@ def test1(self): def test_memmap(self): path = Variable(Generic(), None) - x = load(path, "int32", (False,), mmap_mode="c") + x = load(path, "int32", (None,), mmap_mode="c") fn = function([path], x) assert type(fn(self.filename)) == np.core.memmap diff --git a/tests/tensor/test_math.py b/tests/tensor/test_math.py index 71114a03dd..2d1d12ddf2 100644 --- a/tests/tensor/test_math.py +++ b/tests/tensor/test_math.py @@ -562,7 +562,7 @@ def test_maximum_minimum_grad(): def test_py_c_match(): - a = TensorType(dtype="int8", shape=(False,))() + a = TensorType(dtype="int8", shape=(None,))() f = function([a], arccos(a), mode="DebugMode") # This can fail in DebugMode f(np.asarray([1, 0, -1], dtype="int8")) @@ -1460,8 +1460,8 @@ class TestOuter: def test_outer(self): for m in range(4): for n in range(4): - x = tensor(dtype="floatX", shape=(False,) * m) - y = tensor(dtype="floatX", shape=(False,) * n) + x = tensor(dtype="floatX", shape=(None,) * m) + y = tensor(dtype="floatX", shape=(None,) * n) s1 = self.rng.integers(1, 10, m) s2 = self.rng.integers(1, 10, n) v1 = np.asarray(self.rng.random(s1)).astype(config.floatX) @@ -1927,21 +1927,21 @@ def is_super_shape(var1, var2): for dtype0 in ("float32", "float64", "complex64"): for dtype1 in ("float32", "complex64", "complex128"): for bc0 in ( - (True,), - (False,), - (True, True), - (True, False), - (False, True), - (False, False), + (1,), + (None,), + (1, 1), + (1, None), + (None, 1), + (None, None), ): x = TensorType(dtype=dtype0, shape=bc0)() for bc1 in ( - (True,), - (False,), - (True, True), - (True, False), - (False, True), - (False, False), + (1,), + (None,), + (1, 1), + (1, None), + (None, 1), + (None, None), ): y = TensorType(dtype=dtype1, shape=bc1)() @@ -2117,7 +2117,7 @@ def test_scalar0(self): def test_broadcastable1(self): rng = np.random.default_rng(seed=utt.fetch_seed()) - x = TensorType(dtype=config.floatX, shape=(True, False, False))("x") + x = TensorType(dtype=config.floatX, shape=(1, None, None))("x") y = tensor3("y") z = tensordot(x, y) assert z.broadcastable == (True, False) @@ -2129,7 +2129,7 @@ def test_broadcastable1(self): def test_broadcastable2(self): rng = np.random.default_rng(seed=utt.fetch_seed()) - x = TensorType(dtype=config.floatX, shape=(True, False, False))("x") + x = TensorType(dtype=config.floatX, shape=(1, None, None))("x") y = tensor3("y") axes = [[2, 1], [0, 1]] z = tensordot(x, y, axes=axes) @@ -2156,7 +2156,7 @@ def test_smallest(): def test_var(): - a = TensorType(dtype="float64", shape=[False, False, False])() + a = TensorType(dtype="float64", shape=(None, None, None))() f = function([a], var(a)) a_val = np.arange(6).reshape(1, 2, 3) @@ -2206,7 +2206,7 @@ def test_var(): class TestSum: def test_sum_overflow(self): # Ensure that overflow errors are a little bit harder to get - a = TensorType(dtype="int8", shape=[False])() + a = TensorType(dtype="int8", shape=(None,))() f = function([a], at_sum(a)) assert f([1] * 300) == 300 @@ -3262,7 +3262,7 @@ def test_grad_useless_sum(): mode = get_default_mode().including("canonicalize") mode.check_isfinite = False - x = TensorType(config.floatX, (True,))("x") + x = TensorType(config.floatX, shape=(1,))("x") l = log(1.0 - sigmoid(x))[0] g = grad(l, x) @@ -3287,8 +3287,8 @@ def test_tanh_grad_broadcast(): # FIXME: This is not a real test. # This crashed in the past. - x = tensor(dtype="float32", shape=(True, False, False, False)) - y = tensor(dtype="float32", shape=(True, True, False, False)) + x = tensor(dtype="float32", shape=(1, None, None, None)) + y = tensor(dtype="float32", shape=(1, 1, None, None)) # TODO FIXME: This is a bad test grad(tanh(x).sum(), x) diff --git a/tests/tensor/test_shape.py b/tests/tensor/test_shape.py index 1db5d510ec..e93829d6d2 100644 --- a/tests/tensor/test_shape.py +++ b/tests/tensor/test_shape.py @@ -9,6 +9,7 @@ from aesara.graph.fg import FunctionGraph from aesara.graph.type import Type from aesara.misc.safe_asarray import _asarray +from aesara.scalar.basic import ScalarConstant from aesara.tensor import as_tensor_variable, get_vector_length, row from aesara.tensor.basic import MakeVector, constant from aesara.tensor.elemwise import DimShuffle, Elemwise @@ -22,6 +23,7 @@ reshape, shape, shape_i, + shape_tuple, specify_broadcastable, specify_shape, unbroadcast, @@ -46,19 +48,20 @@ from aesara.tensor.var import TensorVariable from aesara.typed_list import make_list from tests import unittest_tools as utt +from tests.graph.utils import MyType2 from tests.tensor.utils import eval_outputs, random from tests.test_rop import RopLopChecker def test_shape_basic(): s = shape([]) - assert s.type.broadcastable == (True,) + assert s.type.shape == (1,) s = shape([10]) - assert s.type.broadcastable == (True,) + assert s.type.shape == (1,) s = shape(lscalar()) - assert s.type.broadcastable == (False,) + assert s.type.shape == (0,) class MyType(Type): def filter(self, *args, **kwargs): @@ -68,7 +71,7 @@ def __eq__(self, other): return isinstance(other, MyType) and other.thingy == self.thingy s = shape(Variable(MyType(), None)) - assert s.type.broadcastable == (False,) + assert s.type.shape == (None,) s = shape(np.array(1)) assert np.array_equal(eval_outputs([s]), []) @@ -116,15 +119,14 @@ def test_basics(self): b = dmatrix() d = dmatrix() - # basic to 1 dim(without list) - c = reshape(b, as_tensor_variable(6), ndim=1) - f = self.function([b], c) - b_val1 = np.asarray([[0, 1, 2], [3, 4, 5]]) c_val1 = np.asarray([0, 1, 2, 3, 4, 5]) b_val2 = b_val1.T c_val2 = np.asarray([0, 3, 1, 4, 2, 5]) + # basic to 1 dim(without list) + c = reshape(b, as_tensor_variable(6), ndim=1) + f = self.function([b], c) f_out1 = f(b_val1) f_out2 = f(b_val2) assert np.array_equal(f_out1, c_val1), (f_out1, c_val1) @@ -188,10 +190,10 @@ def just_vals(v): f(np.asarray([[0, 1, 2], [3, 4, 5]])), np.asarray([[[0], [1], [2]], [[3], [4], [5]]]), ) - assert f.maker.fgraph.toposort()[-1].outputs[0].type.broadcastable == ( - False, - False, - True, + assert f.maker.fgraph.toposort()[-1].outputs[0].type.shape == ( + None, + None, + 1, ) # test broadcast flag for constant value of 1 if it cannot be @@ -202,10 +204,10 @@ def just_vals(v): f(np.asarray([[0, 1, 2], [3, 4, 5]])), np.asarray([[[0], [1]], [[2], [3]], [[4], [5]]]), ) - assert f.maker.fgraph.toposort()[-1].outputs[0].type.broadcastable == ( - False, - False, - True, + assert f.maker.fgraph.toposort()[-1].outputs[0].type.shape == ( + None, + None, + 1, ) def test_m1(self): @@ -657,3 +659,18 @@ def test_basic(self): Unbroadcast, warn=False, ) + + +def test_shape_tuple(): + + x = Variable(MyType2(), None, None) + assert shape_tuple(x) == () + + x = tensor(np.float64, shape=(1, 2, None)) + res = shape_tuple(x) + assert isinstance(res, tuple) + assert isinstance(res[0], ScalarConstant) + assert res[0].data == 1 + assert isinstance(res[1], ScalarConstant) + assert res[1].data == 2 + assert not isinstance(res[2], ScalarConstant) diff --git a/tests/tensor/test_sharedvar.py b/tests/tensor/test_sharedvar.py index 7dba717209..145a473753 100644 --- a/tests/tensor/test_sharedvar.py +++ b/tests/tensor/test_sharedvar.py @@ -513,7 +513,7 @@ def test_specify_shape_inplace(self): ) topo = f.maker.fgraph.toposort() f() - # [Gemm{inplace}(, 0.01, , , 2e-06)] + # [Gemm{inplace}(, 0.01, , , 2e-06)] if aesara.config.mode != "FAST_COMPILE": assert ( sum( @@ -658,10 +658,3 @@ def test_scalar_shared_options(): def test_get_vector_length(): x = aesara.shared(np.array((2, 3, 4, 5))) assert get_vector_length(x) == 4 - - -def test_deprecated_kwargs(): - with pytest.warns(DeprecationWarning, match=".*broadcastable.*"): - res = aesara.shared(np.array([[1.0]]), broadcastable=(True, False)) - - assert res.type.shape == (1, None) diff --git a/tests/tensor/test_slinalg.py b/tests/tensor/test_slinalg.py index 13acf1febc..ea8bb0e4d1 100644 --- a/tests/tensor/test_slinalg.py +++ b/tests/tensor/test_slinalg.py @@ -178,13 +178,13 @@ class TestSolveBase(utt.InferShapeTester): [ (vector, matrix, "`A` must be a matrix.*"), ( - functools.partial(tensor, dtype="floatX", shape=(False,) * 3), + functools.partial(tensor, dtype="floatX", shape=(None,) * 3), matrix, "`A` must be a matrix.*", ), ( matrix, - functools.partial(tensor, dtype="floatX", shape=(False,) * 3), + functools.partial(tensor, dtype="floatX", shape=(None,) * 3), "`b` must be a matrix or a vector.*", ), ], @@ -523,12 +523,12 @@ def setup_method(self): def test_perform(self): for shp0 in [(2,), (2, 3), (2, 3, 4), (2, 3, 4, 5)]: - x = tensor(dtype="floatX", shape=(False,) * len(shp0)) + x = tensor(dtype="floatX", shape=(None,) * len(shp0)) a = np.asarray(self.rng.random(shp0)).astype(config.floatX) for shp1 in [(6,), (6, 7), (6, 7, 8), (6, 7, 8, 9)]: if len(shp0) + len(shp1) == 2: continue - y = tensor(dtype="floatX", shape=(False,) * len(shp1)) + y = tensor(dtype="floatX", shape=(None,) * len(shp1)) f = function([x, y], kron(x, y)) b = self.rng.random(shp1).astype(config.floatX) out = f(a, b) @@ -542,12 +542,12 @@ def test_perform(self): def test_numpy_2d(self): for shp0 in [(2, 3)]: - x = tensor(dtype="floatX", shape=(False,) * len(shp0)) + x = tensor(dtype="floatX", shape=(None,) * len(shp0)) a = np.asarray(self.rng.random(shp0)).astype(config.floatX) for shp1 in [(6, 7)]: if len(shp0) + len(shp1) == 2: continue - y = tensor(dtype="floatX", shape=(False,) * len(shp1)) + y = tensor(dtype="floatX", shape=(None,) * len(shp1)) f = function([x, y], kron(x, y)) b = self.rng.random(shp1).astype(config.floatX) out = f(a, b) diff --git a/tests/tensor/test_sort.py b/tests/tensor/test_sort.py index 0b82e6e979..8a3e3b23e3 100644 --- a/tests/tensor/test_sort.py +++ b/tests/tensor/test_sort.py @@ -459,7 +459,7 @@ def test_argtopk_nd(self, shp, k_, dtype, sorted, idx_dtype): if k == 0: continue - x = tensor(name="x", shape=(False,) * len(shp), dtype=dtype) + x = tensor(name="x", shape=(None,) * len(shp), dtype=dtype) y = argtopk(x, k, axis=axis, sorted=sorted, idx_dtype=idx_dtype) fn = aesara.function([x], y, mode=self.mode) assert any( @@ -515,7 +515,7 @@ def test_combined_infer_shape(self, shp, k_): if k == 0: continue - x = tensor(name="x", shape=(False,) * len(shp), dtype=aesara.config.floatX) + x = tensor(name="x", shape=(None,) * len(shp), dtype=aesara.config.floatX) yv, yi = topk_and_argtopk(x, k, axis=axis, sorted=False, idx_dtype="int32") size = reduce(int.__mul__, shp) xval = gen_unique_vector(size, aesara.config.floatX).reshape(shp) diff --git a/tests/tensor/test_subtensor.py b/tests/tensor/test_subtensor.py index 1af4e50ccd..1e6a3e99da 100644 --- a/tests/tensor/test_subtensor.py +++ b/tests/tensor/test_subtensor.py @@ -465,7 +465,7 @@ def test_ok_elem_2(self): def test_ok_row(self): n = self.shared(np.arange(6, dtype=self.dtype).reshape((2, 3))) t = n[1] - assert not any(n.type.broadcastable) + assert not any(s == 1 for s in n.type.shape) assert isinstance(t.owner.op, Subtensor) tval = self.eval_output_and_check(t) assert tval.shape == (3,) @@ -475,7 +475,7 @@ def test_ok_col(self): n = self.shared(np.arange(6, dtype=self.dtype).reshape((2, 3))) t = n[:, 0] assert isinstance(t.owner.op, Subtensor) - assert not any(n.type.broadcastable) + assert not any(s == 1 for s in n.type.shape) tval = self.eval_output_and_check(t) assert tval.shape == (2,) assert np.all(tval == [0, 3]) @@ -877,7 +877,7 @@ def test_err_bound_list(self): def test_adv_sub1_broadcast(self): v = np.arange(3, dtype=self.dtype).reshape((1, 3)) - n = self.shared(v * 5, shape=(True, False)) + n = self.shared(v * 5, shape=(1, None)) idx = lvector() t = n[idx] @@ -960,8 +960,8 @@ def test_adv_sub1_idx_broadcast(self): # The idx can be a broadcastable vector. ones = np.ones((4, 3), dtype=self.dtype) n = self.shared(ones * 5) - idx = TensorType(dtype="int64", shape=(True,))() - assert idx.type.broadcastable == (True,) + idx = TensorType(dtype="int64", shape=(1,))() + assert idx.type.shape == (1,) t = n[idx] f = self.function([idx], t, op=AdvancedSubtensor1) @@ -1167,7 +1167,7 @@ def test_advanced1_inc_and_set(self): # We create a new one every time in order not to # have duplicated variables in the function's inputs data_var = TensorType( - shape=[False] * data_n_dims, dtype=self.dtype + shape=(None,) * data_n_dims, dtype=self.dtype )() # Symbolic variable with rows to be incremented. idx_var = vector(dtype="int64") @@ -1190,7 +1190,7 @@ def test_advanced1_inc_and_set(self): idx_num = idx_num.astype("int64") # Symbolic variable with increment value. inc_var = TensorType( - shape=[False] * inc_n_dims, dtype=self.dtype + shape=(None,) * inc_n_dims, dtype=self.dtype )() # Trick for the case where `inc_shape` is the same as # `data_shape`: what we actually want is the first @@ -1715,7 +1715,7 @@ def test_advinc_subtensor(self, inplace): def check(idx, y_val, x_val, true): x = self.shared(x_val, name="x") - y = tensor(dtype="float32", shape=(False,) * len(y_val.shape), name="y") + y = tensor(dtype="float32", shape=(None,) * len(y_val.shape), name="y") sym_idx = [at.as_tensor_variable(ix) for ix in idx] expr = AdvancedIncSubtensor(inplace=inplace)(x, y, *sym_idx) f = aesara.function( @@ -1773,15 +1773,17 @@ def test_index_into_vec_w_vec(self): def test_index_into_vec_w_matrix(self): a = self.v[self.ix2] assert a.dtype == self.v.dtype, (a.dtype, self.v.dtype) - assert a.broadcastable == self.ix2.broadcastable, ( - a.broadcastable, - self.ix2.broadcastable, + assert a.type.ndim == self.ix2.type.ndim + assert all( + s1 == s2 + for s1, s2 in zip(a.type.shape, self.ix2.type.shape) + if s1 == 1 or s2 == 1 ) def test_index_into_mat_w_row(self): a = self.m[self.ixr] assert a.dtype == self.m.dtype, (a.dtype, self.m.dtype) - assert a.broadcastable == (True, False, False) + assert a.type.shape == (1, None, None) def test_index_w_int_and_vec(self): # like test_ok_list, but with a single index on the first one @@ -1879,7 +1881,10 @@ def test_inc_adv_subtensor_w_2vec(self, ignore_duplicates): subt = self.m[self.ix1, self.ix12] a = inc_subtensor(subt, subt, ignore_duplicates=ignore_duplicates) - typ = TensorType(self.m.type.dtype, self.ix2.type.broadcastable) + typ = TensorType( + self.m.type.dtype, + shape=tuple(1 if s == 1 else None for s in self.ix2.type.shape), + ) assert a.type == typ f = aesara.function( @@ -2071,7 +2076,7 @@ def test_adv_grouped(self): def test_grad(self): ones = np.ones((1, 3), dtype=self.dtype) - n = self.shared(ones * 5, shape=(True, False)) + n = self.shared(ones * 5, shape=(1, None)) idx = lvector() idx2 = lvector() t = n[idx, idx2] @@ -2444,7 +2449,7 @@ def test_AdvancedSubtensor_bool(self): ) abs_res = n[~isinf(n)] - assert abs_res.broadcastable == (False,) + assert abs_res.type.shape == (None,) @config.change_flags(compute_test_value="raise") @@ -2465,9 +2470,7 @@ def idx_as_tensor(x): def bcast_shape_tuple(x): if not hasattr(x, "shape"): return x - return tuple( - s if not bcast else 1 for s, bcast in zip(tuple(x.shape), x.broadcastable) - ) + return tuple(s if ss != 1 else 1 for s, ss in zip(tuple(x.shape), x.type.shape)) test_idx = np.ix_(np.array([True, True]), np.array([True]), np.array([True, True])) diff --git a/tests/tensor/test_type.py b/tests/tensor/test_type.py index 3c8a5194ef..3df380dd03 100644 --- a/tests/tensor/test_type.py +++ b/tests/tensor/test_type.py @@ -25,30 +25,34 @@ def test_numpy_dtype(dtype, exp_dtype): def test_in_same_class(): - test_type = TensorType(config.floatX, [False, False]) - test_type2 = TensorType(config.floatX, [False, True]) + test_type = TensorType(config.floatX, shape=(None, None)) + test_type2 = TensorType(config.floatX, shape=(None, 1)) assert test_type.in_same_class(test_type) assert not test_type.in_same_class(test_type2) + test_type = TensorType(config.floatX, shape=()) + test_type2 = TensorType(config.floatX, shape=(None,)) + assert not test_type.in_same_class(test_type2) + def test_is_super(): - test_type = TensorType(config.floatX, [False, False]) - test_type2 = TensorType(config.floatX, [False, True]) + test_type = TensorType(config.floatX, shape=(None, None)) + test_type2 = TensorType(config.floatX, shape=(None, 1)) assert test_type.is_super(test_type) assert test_type.is_super(test_type2) assert not test_type2.is_super(test_type) - test_type3 = TensorType(config.floatX, [False, False, False]) + test_type3 = TensorType(config.floatX, shape=(None, None, None)) assert not test_type3.is_super(test_type) def test_convert_variable(): - test_type = TensorType(config.floatX, [False, False]) + test_type = TensorType(config.floatX, shape=(None, None)) test_var = test_type() - test_type2 = TensorType(config.floatX, [True, False]) + test_type2 = TensorType(config.floatX, shape=(1, None)) test_var2 = test_type2() res = test_type.convert_variable(test_var) @@ -60,7 +64,7 @@ def test_convert_variable(): res = test_type2.convert_variable(test_var) assert res.type == test_type2 - test_type3 = TensorType(config.floatX, [True, False, True]) + test_type3 = TensorType(config.floatX, shape=(1, None, 1)) test_var3 = test_type3() res = test_type2.convert_variable(test_var3) @@ -84,12 +88,12 @@ def test_convert_variable_mixed_specificity(): def test_filter_variable(): - test_type = TensorType(config.floatX, []) + test_type = TensorType(config.floatX, shape=()) with pytest.raises(TypeError): test_type.filter(test_type()) - test_type = TensorType(config.floatX, [True, False]) + test_type = TensorType(config.floatX, shape=(1, None)) with pytest.raises(TypeError): test_type.filter(np.empty((0, 1), dtype=config.floatX)) @@ -103,7 +107,7 @@ def test_filter_variable(): test_type.filter_checks_isfinite = True test_type.filter(np.full((1, 2), np.inf, dtype=config.floatX)) - test_type2 = TensorType(config.floatX, [False, False]) + test_type2 = TensorType(config.floatX, shape=(None, None)) test_var = test_type() test_var2 = test_type2() @@ -120,7 +124,7 @@ def test_filter_variable(): def test_filter_strict(): - test_type = TensorType(config.floatX, []) + test_type = TensorType(config.floatX, shape=()) with pytest.raises(TypeError): test_type.filter(1, strict=True) @@ -131,7 +135,7 @@ def test_filter_strict(): def test_filter_ndarray_subclass(): """Make sure `TensorType.filter` can handle NumPy `ndarray` subclasses.""" - test_type = TensorType(config.floatX, [False]) + test_type = TensorType(config.floatX, shape=(None,)) class MyNdarray(np.ndarray): pass @@ -147,7 +151,7 @@ class MyNdarray(np.ndarray): def test_filter_float_subclass(): """Make sure `TensorType.filter` can handle `float` subclasses.""" with config.change_flags(floatX="float64"): - test_type = TensorType("float64", shape=[]) + test_type = TensorType("float64", shape=()) nan = np.array([np.nan], dtype="float64")[0] assert isinstance(nan, float) and not isinstance(nan, np.ndarray) @@ -157,7 +161,7 @@ def test_filter_float_subclass(): with config.change_flags(floatX="float32"): # Try again, except this time `nan` isn't a `float` - test_type = TensorType("float32", shape=[]) + test_type = TensorType("float32", shape=()) nan = np.array([np.nan], dtype="float32")[0] assert isinstance(nan, np.floating) and not isinstance(nan, np.ndarray) @@ -173,7 +177,7 @@ def test_filter_memmap(): filename = path.join(mkdtemp(), "newfile.dat") fp = np.memmap(filename, dtype=config.floatX, mode="w+", shape=(3, 4)) - test_type = TensorType(config.floatX, [False, False]) + test_type = TensorType(config.floatX, shape=(None, None)) res = test_type.filter(fp) assert res is fp @@ -219,25 +223,25 @@ def test_tensor_values_eq_approx(): def test_fixed_shape_basic(): - t1 = TensorType("float64", (1, 1)) + t1 = TensorType("float64", shape=(1, 1)) assert t1.shape == (1, 1) assert t1.broadcastable == (True, True) - t1 = TensorType("float64", (0,)) + t1 = TensorType("float64", shape=(0,)) assert t1.shape == (0,) assert t1.broadcastable == (False,) - t1 = TensorType("float64", (False, False)) + t1 = TensorType("float64", shape=(None, None)) assert t1.shape == (None, None) assert t1.broadcastable == (False, False) - t1 = TensorType("float64", (2, 3)) + t1 = TensorType("float64", shape=(2, 3)) assert t1.shape == (2, 3) assert t1.broadcastable == (False, False) assert str(t1) == "TensorType(float64, (2, 3))" - t1 = TensorType("float64", (1,)) + t1 = TensorType("float64", shape=(1,)) assert t1.shape == (1,) assert t1.broadcastable == (True,) @@ -256,13 +260,13 @@ def test_fixed_shape_clone(): t2 = t1.clone(dtype="float32", shape=(2, 4)) assert t2.shape == (2, 4) - t2 = t1.clone(dtype="float32", shape=(False, False)) + t2 = t1.clone(dtype="float32", shape=(None, None)) assert t2.shape == (None, None) def test_fixed_shape_comparisons(): - t1 = TensorType("float64", (True, True)) - t2 = TensorType("float64", (1, 1)) + t1 = TensorType("float64", shape=(1, 1)) + t2 = TensorType("float64", shape=(1, 1)) assert t1 == t2 assert t1.is_super(t2) @@ -270,19 +274,19 @@ def test_fixed_shape_comparisons(): assert hash(t1) == hash(t2) - t3 = TensorType("float64", (True, False)) - t4 = TensorType("float64", (1, 2)) + t3 = TensorType("float64", shape=(1, None)) + t4 = TensorType("float64", shape=(1, 2)) assert t3 != t4 - t1 = TensorType("float64", (True, True)) - t2 = TensorType("float64", ()) + t1 = TensorType("float64", shape=(1, 1)) + t2 = TensorType("float64", shape=()) assert t1 != t2 def test_fixed_shape_convert_variable(): # These are equivalent types - t1 = TensorType("float64", (True, True)) - t2 = TensorType("float64", (1, 1)) + t1 = TensorType("float64", shape=(1, 1)) + t2 = TensorType("float64", shape=(1, 1)) assert t1 == t2 assert t1.shape == t2.shape @@ -298,13 +302,13 @@ def test_fixed_shape_convert_variable(): res = t2.convert_variable(t1_var) assert res is t1_var - t3 = TensorType("float64", (False, True)) + t3 = TensorType("float64", shape=(None, 1)) t3_var = t3() res = t2.convert_variable(t3_var) assert isinstance(res.owner.op, SpecifyShape) - t3 = TensorType("float64", (False, False)) - t4 = TensorType("float64", (3, 2)) + t3 = TensorType("float64", shape=(None, None)) + t4 = TensorType("float64", shape=(3, 2)) t4_var = t4() assert t3.shape == (None, None) res = t3.convert_variable(t4_var) diff --git a/tests/tensor/test_var.py b/tests/tensor/test_var.py index 05127cb3d2..f7d1a4ddc5 100644 --- a/tests/tensor/test_var.py +++ b/tests/tensor/test_var.py @@ -155,18 +155,18 @@ def test__getitem__Subtensor(): def test__getitem__AdvancedSubtensor_bool(): x = matrix("x") - i = TensorType("bool", (False, False))("i") + i = TensorType("bool", shape=(None, None))("i") z = x[i] op_types = [type(node.op) for node in aesara.graph.basic.io_toposort([x, i], [z])] assert op_types[-1] == AdvancedSubtensor - i = TensorType("bool", (False,))("i") + i = TensorType("bool", shape=(None,))("i") z = x[:, i] op_types = [type(node.op) for node in aesara.graph.basic.io_toposort([x, i], [z])] assert op_types[-1] == AdvancedSubtensor - i = TensorType("bool", (False,))("i") + i = TensorType("bool", shape=(None,))("i") z = x[..., i] op_types = [type(node.op) for node in aesara.graph.basic.io_toposort([x, i], [z])] assert op_types[-1] == AdvancedSubtensor @@ -244,23 +244,25 @@ def test__getitem__newaxis(x, indices, new_order): def test_fixed_shape_variable_basic(): - x = TensorVariable(TensorType("int64", (4,)), None) + x = TensorVariable(TensorType("int64", shape=(4,)), None) assert isinstance(x.shape, Constant) assert np.array_equal(x.shape.data, (4,)) - x = TensorConstant(TensorType("int64", (False, False)), np.array([[1, 2], [2, 3]])) + x = TensorConstant( + TensorType("int64", shape=(None, None)), np.array([[1, 2], [2, 3]]) + ) assert x.type.shape == (2, 2) with pytest.raises(ValueError): - TensorConstant(TensorType("int64", (True, False)), np.array([[1, 2], [2, 3]])) + TensorConstant(TensorType("int64", shape=(1, None)), np.array([[1, 2], [2, 3]])) def test_get_vector_length(): - x = TensorVariable(TensorType("int64", (4,)), None) + x = TensorVariable(TensorType("int64", shape=(4,)), None) res = get_vector_length(x) assert res == 4 - x = TensorVariable(TensorType("int64", (None,)), None) + x = TensorVariable(TensorType("int64", shape=(None,)), None) with pytest.raises(ValueError): get_vector_length(x) diff --git a/tests/tensor/utils.py b/tests/tensor/utils.py index c59c99d99d..d92b9b066d 100644 --- a/tests/tensor/utils.py +++ b/tests/tensor/utils.py @@ -449,7 +449,9 @@ def test_good(self): inputrs = [ TensorType( dtype=input.dtype, - shape=[shape_elem == 1 for shape_elem in input.shape], + shape=tuple( + 1 if shape_elem == 1 else None for shape_elem in input.shape + ), )() for input in inputs ] @@ -611,7 +613,9 @@ def test_grad_none(self): inputrs = [ TensorType( dtype=input.dtype, - shape=[shape_elem == 1 for shape_elem in input.shape], + shape=tuple( + 1 if shape_elem == 1 else None for shape_elem in input.shape + ), )() for input in inputs ] @@ -632,8 +636,10 @@ def test_grad_none(self): dtype = config.floatX else: dtype = str(out.dtype) - bcast = [shape_elem == 1 for shape_elem in out.shape] - var = TensorType(dtype=dtype, shape=bcast)() + out_shape = tuple( + 1 if shape_elem == 1 else None for shape_elem in out.shape + ) + var = TensorType(dtype=dtype, shape=out_shape)() out_grad_vars.append(var) try: diff --git a/tests/test_printing.py b/tests/test_printing.py index db7d4cd3c6..414be0b555 100644 --- a/tests/test_printing.py +++ b/tests/test_printing.py @@ -282,7 +282,7 @@ def test_debugprint(): | | |B | |TensorConstant{1.0} | |B - | | + | | | |TensorConstant{0.0} |D """ @@ -306,9 +306,9 @@ def test_debugprint_id_type(): exp_res = f"""Elemwise{{add,no_inplace}} [id {e_at.auto_name}] |dot [id {d_at.auto_name}] - | | [id {b_at.auto_name}] - | | [id {a_at.auto_name}] - | [id {a_at.auto_name}] + | | [id {b_at.auto_name}] + | | [id {a_at.auto_name}] + | [id {a_at.auto_name}] """ assert [l.strip() for l in s.split("\n")] == [ @@ -319,7 +319,7 @@ def test_debugprint_id_type(): def test_pprint(): x = dvector() y = x[1] - assert pp(y) == "[1]" + assert pp(y) == "[1]" def test_debugprint_inner_graph(): diff --git a/tests/typed_list/test_basic.py b/tests/typed_list/test_basic.py index 554f120843..52b4d94012 100644 --- a/tests/typed_list/test_basic.py +++ b/tests/typed_list/test_basic.py @@ -57,7 +57,7 @@ class TestGetItem: def test_sanity_check_slice(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicSlice = SliceType()() @@ -75,7 +75,7 @@ def test_sanity_check_slice(self): def test_sanity_check_single(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicScalar = scalar(dtype="int64") @@ -90,7 +90,7 @@ def test_sanity_check_single(self): def test_interface(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicScalar = scalar(dtype="int64") @@ -110,7 +110,7 @@ def test_interface(self): def test_wrong_input(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicMatrix = matrix() @@ -119,7 +119,7 @@ def test_wrong_input(self): def test_constant_input(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = GetItem()(mySymbolicMatricesList, 0) @@ -140,7 +140,7 @@ def test_constant_input(self): class TestAppend: def test_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -156,7 +156,7 @@ def test_inplace(self): def test_sanity_check(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -172,7 +172,7 @@ def test_sanity_check(self): def test_interfaces(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -190,10 +190,10 @@ def test_interfaces(self): class TestExtend: def test_inplace(self): mySymbolicMatricesList1 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicMatricesList2 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Extend(True)(mySymbolicMatricesList1, mySymbolicMatricesList2) @@ -210,10 +210,10 @@ def test_inplace(self): def test_sanity_check(self): mySymbolicMatricesList1 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicMatricesList2 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Extend()(mySymbolicMatricesList1, mySymbolicMatricesList2) @@ -228,10 +228,10 @@ def test_sanity_check(self): def test_interface(self): mySymbolicMatricesList1 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicMatricesList2 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = mySymbolicMatricesList1.extend(mySymbolicMatricesList2) @@ -248,7 +248,7 @@ def test_interface(self): class TestInsert: def test_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() myScalar = scalar(dtype="int64") @@ -267,7 +267,7 @@ def test_inplace(self): def test_sanity_check(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() myScalar = scalar(dtype="int64") @@ -284,7 +284,7 @@ def test_sanity_check(self): def test_interface(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() myScalar = scalar(dtype="int64") @@ -303,7 +303,7 @@ def test_interface(self): class TestRemove: def test_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -319,7 +319,7 @@ def test_inplace(self): def test_sanity_check(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -335,7 +335,7 @@ def test_sanity_check(self): def test_interface(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -353,7 +353,7 @@ def test_interface(self): class TestReverse: def test_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Reverse(True)(mySymbolicMatricesList) @@ -368,7 +368,7 @@ def test_inplace(self): def test_sanity_check(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Reverse()(mySymbolicMatricesList) @@ -383,7 +383,7 @@ def test_sanity_check(self): def test_interface(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = mySymbolicMatricesList.reverse() @@ -400,7 +400,7 @@ def test_interface(self): class TestIndex: def test_sanity_check(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -416,7 +416,7 @@ def test_sanity_check(self): def test_interface(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -432,10 +432,10 @@ def test_interface(self): def test_non_tensor_type(self): mySymbolicNestedMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)), 1 + TensorType(aesara.config.floatX, shape=(None, None)), 1 )() mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Index()(mySymbolicNestedMatricesList, mySymbolicMatricesList) @@ -468,7 +468,7 @@ def test_sparse(self): class TestCount: def test_sanity_check(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -484,7 +484,7 @@ def test_sanity_check(self): def test_interface(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() myMatrix = matrix() @@ -500,10 +500,10 @@ def test_interface(self): def test_non_tensor_type(self): mySymbolicNestedMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)), 1 + TensorType(aesara.config.floatX, shape=(None, None)), 1 )() mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Count()(mySymbolicNestedMatricesList, mySymbolicMatricesList) @@ -536,7 +536,7 @@ def test_sparse(self): class TestLength: def test_sanity_check(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Length()(mySymbolicMatricesList) @@ -549,7 +549,7 @@ def test_sanity_check(self): def test_interface(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = mySymbolicMatricesList.__len__() diff --git a/tests/typed_list/test_rewriting.py b/tests/typed_list/test_rewriting.py index 167424cfb8..9e1244e63f 100644 --- a/tests/typed_list/test_rewriting.py +++ b/tests/typed_list/test_rewriting.py @@ -13,7 +13,7 @@ class TestInplace: def test_reverse_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Reverse()(mySymbolicMatricesList) @@ -36,7 +36,7 @@ def test_reverse_inplace(self): def test_append_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicMatrix = matrix() z = Append()(mySymbolicMatricesList, mySymbolicMatrix) @@ -62,11 +62,11 @@ def test_append_inplace(self): def test_extend_inplace(self): mySymbolicMatricesList1 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicMatricesList2 = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() z = Extend()(mySymbolicMatricesList1, mySymbolicMatricesList2) @@ -91,7 +91,7 @@ def test_extend_inplace(self): def test_insert_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicIndex = scalar(dtype="int64") mySymbolicMatrix = matrix() @@ -121,7 +121,7 @@ def test_insert_inplace(self): def test_remove_inplace(self): mySymbolicMatricesList = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() mySymbolicMatrix = matrix() z = Remove()(mySymbolicMatricesList, mySymbolicMatrix) diff --git a/tests/typed_list/test_type.py b/tests/typed_list/test_type.py index 4ee1b76e02..e0b53dfdb2 100644 --- a/tests/typed_list/test_type.py +++ b/tests/typed_list/test_type.py @@ -24,7 +24,7 @@ def test_wrong_input_on_filter(self): # specified on creation # list of matrices - myType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) with pytest.raises(TypeError): myType.filter([4]) @@ -34,7 +34,7 @@ def test_not_a_list_on_filter(self): # if no iterable variable is given on input # list of matrices - myType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) with pytest.raises(TypeError): myType.filter(4) @@ -45,11 +45,11 @@ def test_type_equality(self): # variables # list of matrices - myType1 = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType1 = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) # list of matrices - myType2 = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType2 = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) # list of scalars - myType3 = TypedListType(TensorType(aesara.config.floatX, ())) + myType3 = TypedListType(TensorType(aesara.config.floatX, shape=())) assert myType2 == myType1 assert myType3 != myType1 @@ -57,7 +57,7 @@ def test_type_equality(self): def test_filter_sanity_check(self): # Simple test on typed list type filter - myType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) x = random_ranged(-1000, 1000, [100, 100]) @@ -68,14 +68,14 @@ def test_intern_filter(self): # filtered. If they weren't this code would raise # an exception. - myType = TypedListType(TensorType("float64", (False, False))) + myType = TypedListType(TensorType("float64", shape=(None, None))) x = np.asarray([[4, 5], [4, 5]], dtype="float32") assert np.array_equal(myType.filter([x]), [x]) def test_load_alot(self): - myType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) x = random_ranged(-1000, 1000, [10, 10]) testList = [] @@ -87,7 +87,9 @@ def test_load_alot(self): def test_basic_nested_list(self): # Testing nested list with one level of depth - myNestedType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myNestedType = TypedListType( + TensorType(aesara.config.floatX, shape=(None, None)) + ) myType = TypedListType(myNestedType) @@ -98,7 +100,9 @@ def test_basic_nested_list(self): def test_comparison_different_depth(self): # Nested list with different depth aren't the same - myNestedType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myNestedType = TypedListType( + TensorType(aesara.config.floatX, shape=(None, None)) + ) myNestedType2 = TypedListType(myNestedType) @@ -110,10 +114,10 @@ def test_nested_list_arg(self): # test for the 'depth' optional argument myNestedType = TypedListType( - TensorType(aesara.config.floatX, (False, False)), 3 + TensorType(aesara.config.floatX, shape=(None, None)), 3 ) - myType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) myManualNestedType = TypedListType(TypedListType(TypedListType(myType))) @@ -122,7 +126,7 @@ def test_nested_list_arg(self): def test_get_depth(self): # test case for get_depth utilitary function - myType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) myManualNestedType = TypedListType(TypedListType(TypedListType(myType))) @@ -131,7 +135,7 @@ def test_get_depth(self): def test_comparison_uneven_nested(self): # test for comparison between uneven nested list - myType = TypedListType(TensorType(aesara.config.floatX, (False, False))) + myType = TypedListType(TensorType(aesara.config.floatX, shape=(None, None))) myManualNestedType1 = TypedListType(TypedListType(TypedListType(myType))) @@ -142,7 +146,7 @@ def test_comparison_uneven_nested(self): def test_variable_is_Typed_List_variable(self): mySymbolicVariable = TypedListType( - TensorType(aesara.config.floatX, (False, False)) + TensorType(aesara.config.floatX, shape=(None, None)) )() assert isinstance(mySymbolicVariable, TypedListVariable)