1from __future__ import absolute_import, print_function, division
2
3from copy import copy, deepcopy
4from functools import partial
5import itertools
6import logging
7from nose.plugins.skip import SkipTest
8from nose.tools import assert_raises
9import operator
10import os
11import sys
12from tempfile import mkstemp
13import unittest
14import warnings
15
16from six import iteritems
17from six.moves import StringIO, reduce
18from six.moves import xrange
19# Import builtin min to be able to use it after importing the tensor version.
20from six.moves.builtins import min as builtin_min
21
22import numpy as np
23from numpy.testing import dec, assert_array_equal, assert_allclose
24
25import theano
26from theano.compat import izip
27from theano.compat import PY3, exc_message, operator_div
28from theano import compile, config, function, gof, tensor, shared
29from theano.compile import DeepCopyOp
30from theano.compile.mode import get_default_mode
31from theano.scalar import autocast_float_as, autocast_float
32from theano.tensor import (
33    wvector, bvector,
34    argmin, max_and_argmax, cscalar, join,
35    horizontal_stack, vertical_stack, argmax, get_vector_length,
36    fscalar, sum, tensor3, vector, add, addbroadcast,
37    alloc, as_tensor_variable, tensor_from_scalar, ARange,
38    clip, constant, default, diag, dot, batched_dot,
39    dmatrix, dscalar, dvector, eq, eye, fill, flatten, inverse_permutation,
40    tensor4, permute_row_elements, fmatrix, fscalars, grad,
41    inplace, iscalar, matrix, minimum, matrices, maximum, mul, neq,
42    Reshape, row, scalar, scalars, second, smallest, stack, sub, Tensor,
43    tensor_copy, tensordot, TensorType, Tri, tri, tril, triu, unbroadcast,
44    var, Argmax, Join, shape, MaxAndArgmax, lscalar, zvector, exp,
45    get_scalar_constant_value, ivector, reshape, scalar_from_tensor, scal,
46    iscalars, arange, dscalars, fvector, imatrix, numeric_grad,
47    opt, lvector, true_div, max, min, Split, roll,
48    tile, patternbroadcast, Eye, Shape, Dot, PermuteRowElements,
49    ScalarFromTensor, TensorFromScalar, dtensor4, Rebroadcast, Alloc,
50    dtensor3, SpecifyShape, Mean,
51    itensor3, Tile, switch, ExtractDiag, AllocDiag,
52    nonzero, flatnonzero, nonzero_values,
53    stacklists, DimShuffle, hessian, ptp, power,
54    swapaxes, choose, Choose, NoneConst, AllocEmpty,
55    isclose, allclose, mgrid, ogrid, extract_constant,
56    )
57
58from theano.tests import unittest_tools as utt
59from theano.tests.unittest_tools import attr
60from theano import change_flags
61
62imported_scipy_special = False
63mode_no_scipy = get_default_mode()
64try:
65    import scipy.special
66    import scipy.stats
67    imported_scipy_special = True
68except ImportError:
69    if config.mode == "FAST_COMPILE":
70        mode_no_scipy = "FAST_RUN"
71floatX = config.floatX
72
73if config.mode == "FAST_COMPILE":
74    mode_opt = "FAST_RUN"
75else:
76    mode_opt = get_default_mode()
77
78
79# Use a seeded random number generator so that unittests are deterministic
80utt.seed_rng()
81test_rng = np.random.RandomState(seed=utt.fetch_seed())
82# In order to check random values close to the boundaries when designing
83# new tests, you can use utt.MockRandomState, for instance:
84# test_rng = MockRandomState(0)
85# test_rng = MockRandomState(0.99999982)
86# test_rng = MockRandomState(1)
87
88
89if PY3:
90    def L(i):
91        return i
92else:
93    def L(i):
94        return long(i)  # noqa for Python 3
95
96
97def inplace_func(inputs, outputs, mode=None, allow_input_downcast=False,
98                 on_unused_input='raise', name=None):
99    if mode is None:
100        mode = get_default_mode()
101    return function(inputs, outputs,
102                    mode=mode,
103                    allow_input_downcast=allow_input_downcast,
104                    accept_inplace=True,
105                    on_unused_input=on_unused_input,
106                    name=name)
107
108
109def eval_outputs(outputs, ops=(), mode=None):
110    f = inplace_func([], outputs, mode=mode)
111    variables = f()
112    if ops:
113        assert any(isinstance(node.op, ops) for node in f.maker.fgraph.apply_nodes)
114    if isinstance(variables, (tuple, list)) and len(variables) == 1:
115        return variables[0]
116    return variables
117
118
119def get_numeric_subclasses(cls=np.number, ignore=None):
120    # Return subclasses of `cls` in the numpy scalar hierarchy.
121    #
122    # We only return subclasses that correspond to unique data types.
123    # The hierarchy can be seen here:
124    #     http://docs.scipy.org/doc/numpy/reference/arrays.scalars.html
125    if ignore is None:
126        ignore = []
127    rval = []
128    dtype = np.dtype(cls)
129    dtype_num = dtype.num
130    if dtype_num not in ignore:
131        # Safety check: we should be able to represent 0 with this data type.
132        np.array(0, dtype=dtype)
133        rval.append(cls)
134        ignore.append(dtype_num)
135    for sub_ in cls.__subclasses__():
136        rval += [c for c in get_numeric_subclasses(sub_, ignore=ignore)]
137    return rval
138
139
140def get_numeric_types(with_int=True, with_float=True, with_complex=False,
141                      only_theano_types=True):
142    # Return numpy numeric data types.
143    #
144    # :param with_int: Whether to include integer types.
145    #
146    # :param with_float: Whether to include floating point types.
147    #
148    # :param with_complex: Whether to include complex types.
149    #
150    # :param only_theano_types: If True, then numpy numeric data types that are
151    # not supported by Theano are ignored (i.e. those that are not declared in
152    # scalar/basic.py).
153    #
154    # :returns: A list of unique data type objects. Note that multiple data types
155    # may share the same string representation, but can be differentiated through
156    # their `num` attribute.
157    #
158    # Note that when `only_theano_types` is True we could simply return the list
159    # of types defined in the `scalar` module. However with this function we can
160    # test more unique dtype objects, and in the future we may use it to
161    # automatically detect new data types introduced in numpy.
162    if only_theano_types:
163        theano_types = [d.dtype for d in theano.scalar.all_types]
164    rval = []
165
166    def is_within(cls1, cls2):
167        # Return True if scalars defined from `cls1` are within the hierarchy
168        # starting from `cls2`.
169        # The third test below is to catch for instance the fact that
170        # one can use ``dtype=numpy.number`` and obtain a float64 scalar, even
171        # though `numpy.number` is not under `numpy.floating` in the class
172        # hierarchy.
173        return (cls1 is cls2 or
174                issubclass(cls1, cls2) or
175                isinstance(np.array([0], dtype=cls1)[0], cls2))
176
177    for cls in get_numeric_subclasses():
178        dtype = np.dtype(cls)
179        if ((not with_complex and is_within(cls, np.complexfloating)) or
180                (not with_int and is_within(cls, np.integer)) or
181                (not with_float and is_within(cls, np.floating)) or
182                (only_theano_types and dtype not in theano_types)):
183            # Ignore this class.
184            continue
185        rval.append([str(dtype), dtype, dtype.num])
186    # We sort it to be deterministic, then remove the string and num elements.
187    return [x[1] for x in sorted(rval, key=str)]
188
189
190def _numpy_checker(x, y):
191    # Checks if x.data and y.data have the same contents.
192    # Used in DualLinker to compare C version with Python version.
193    x, y = x[0], y[0]
194    if (x.dtype != y.dtype or x.shape != y.shape or
195            np.any(np.abs(x - y) > 1e-10)):
196        raise Exception("Output mismatch.", {'performlinker': x, 'clinker': y})
197
198
199def safe_make_node(op, *inputs):
200    # Emulate the behaviour of make_node when op is a function.
201    #
202    # Normally op in an instead of the Op class.
203    node = op(*inputs)
204    if isinstance(node, list):
205        return node[0].owner
206    else:
207        return node.owner
208
209
210def upcast_float16_ufunc(fn):
211    # Decorator that enforces computation is not done in float16 by NumPy.
212    #
213    # Some ufuncs in NumPy will compute float values on int8 and uint8
214    # in half-precision (float16), which is not enough, and not compatible
215    # with the C code.
216    #
217    # :param fn: numpy ufunc
218    # :returns: function similar to fn.__call__, computing the same
219    #     value with a minimum floating-point precision of float32
220    def ret(*args, **kwargs):
221        out_dtype = np.find_common_type(
222            [a.dtype for a in args], [np.float16])
223        if out_dtype == 'float16':
224            # Force everything to float32
225            sig = 'f' * fn.nin + '->' + 'f' * fn.nout
226            kwargs.update(sig=sig)
227        return fn(*args, **kwargs)
228
229    return ret
230
231
232def upcast_int8_nfunc(fn):
233    # Decorator that upcasts input of dtype int8 to float32.
234    #
235    # This is so that floating-point computation is not carried using
236    # half-precision (float16), as some NumPy functions do.
237    #
238    # :param fn: function computing a floating-point value from inputs
239    # :returns: function similar to fn, but upcasting its uint8 and int8
240    #     inputs before carrying out the computation.
241    def ret(*args, **kwargs):
242        args = list(args)
243        for i, a in enumerate(args):
244            if getattr(a, 'dtype', None) in ('int8', 'uint8'):
245                args[i] = a.astype('float32')
246
247        return fn(*args, **kwargs)
248
249    return ret
250
251
252def makeTester(name, op, expected, checks=None, good=None, bad_build=None,
253               bad_runtime=None, grad=None, mode=None, grad_rtol=None,
254               eps=1e-10, skip=False, test_memmap=True, check_name=True,
255               grad_eps=None):
256    # :param check_name:
257    #     Use only for tester that aren't in Theano.
258    if checks is None:
259        checks = {}
260    if good is None:
261        good = {}
262    if bad_build is None:
263        bad_build = {}
264    if bad_runtime is None:
265        bad_runtime = {}
266    if grad is None:
267        grad = {}
268    if grad is True:
269        grad = good
270
271    _op, _expected, _checks, _good = op, expected, checks, good
272    _bad_build, _bad_runtime, _grad = bad_build, bad_runtime, grad
273    _mode, _grad_rtol, _eps, skip_ = mode, grad_rtol, eps, skip
274    _test_memmap = test_memmap
275    _check_name = check_name
276    _grad_eps = grad_eps
277
278    class Checker(unittest.TestCase):
279
280        op = staticmethod(_op)
281        expected = staticmethod(_expected)
282        checks = _checks
283        check_name = _check_name
284        good = _good
285        bad_build = _bad_build
286        bad_runtime = _bad_runtime
287        grad = _grad
288        mode = _mode
289        skip = skip_
290        test_memmap = _test_memmap
291
292        def setUp(self):
293            # Verify that the test's name is correctly set.
294            # Some tests reuse it outside this module.
295            if self.check_name:
296                eval(self.__class__.__module__ + '.' + self.__class__.__name__)
297
298            # We keep a list of temporary files created in add_memmap_values,
299            # to remove them at the end of the test.
300            self.tmp_files = []
301
302        def add_memmap_values(self, val_dict):
303            # If test_memmap is True, we create a temporary file
304            # containing a copy of the data passed in the "val_dict" dict,
305            # then open it as a memmapped array, and we can use the result as a
306            # new test value.
307            if not self.test_memmap:
308                return val_dict
309
310            # Copy dict before modifying them
311            val_dict = val_dict.copy()
312
313            # Note that we sort items in the dictionary to ensure tests are
314            # deterministic (since the loop below will break on the first valid
315            # item that can be memmapped).
316            for k, v in sorted(val_dict.items()):
317                new_k = '_'.join((k, 'memmap'))
318                if new_k in val_dict:
319                    # A corresponding key was already provided
320                    break
321
322                new_v = []
323                for inp in v:
324                    if type(inp) is np.ndarray and inp.size > 0:
325                        f, fname = mkstemp()
326                        self.tmp_files.append((f, fname))
327                        new_inp = np.memmap(fname, dtype=inp.dtype,
328                                            mode='w+', shape=inp.shape)
329                        new_inp[...] = inp[...]
330                        new_v.append(new_inp)
331                    else:
332                        new_v.append(inp)
333                val_dict[new_k] = new_v
334
335                # We only need one value, no need to copy all of them
336                break
337            return val_dict
338
339        def tearDown(self):
340            # This is to avoid a problem with deleting memmap files on windows.
341            import gc
342            gc.collect()
343            for f, fname in self.tmp_files:
344                os.close(f)
345                os.remove(fname)
346
347        def test_good(self):
348            if skip:
349                raise SkipTest(skip)
350
351            good = self.add_memmap_values(self.good)
352
353            for testname, inputs in iteritems(good):
354                inputs = [copy(input) for input in inputs]
355                inputrs = [TensorType(
356                    dtype=input.dtype,
357                    broadcastable=[shape_elem == 1
358                                   for shape_elem in input.shape]
359                    )() for input in inputs]
360                try:
361                    node = safe_make_node(self.op, *inputrs)
362                except Exception as exc:
363                    err_msg = ("Test %s::%s: Error occurred while"
364                               " making a node with inputs %s") % (
365                                   self.op, testname, inputs)
366                    exc.args += (err_msg,)
367                    raise
368
369                try:
370                    f = inplace_func(inputrs, node.outputs, mode=mode, name='test_good')
371                except Exception as exc:
372                    err_msg = ("Test %s::%s: Error occurred while"
373                               " trying to make a Function") % (self.op, testname)
374                    exc.args += (err_msg,)
375                    raise
376                if (isinstance(self.expected, dict) and
377                        testname in self.expected):
378                    expecteds = self.expected[testname]
379                    # with numpy version, when we print a number and read it
380                    # back, we don't get exactly the same result, so we accept
381                    # rounding error in that case.
382                    eps = 5e-9
383                else:
384                    expecteds = self.expected(*inputs)
385                    eps = 1e-10
386
387                if any([i.dtype in ('float32', 'int8', 'uint8', 'uint16')
388                        for i in inputs]):
389                    eps = 1e-6
390                eps = np.max([eps, _eps])
391
392                try:
393                    variables = f(*inputs)
394                except Exception as exc:
395                    err_msg = ("Test %s::%s: Error occurred while calling"
396                               " the Function on the inputs %s") % (
397                                   self.op, testname, inputs)
398                    exc.args += (err_msg,)
399                    raise
400
401                if not isinstance(expecteds, (list, tuple)):
402                    expecteds = (expecteds, )
403
404                for i, (variable, expected) in enumerate(
405                        izip(variables, expecteds)):
406                    if (variable.dtype != expected.dtype or
407                            variable.shape != expected.shape or
408                            not np.allclose(variable, expected,
409                                            atol=eps, rtol=eps)):
410                        self.fail(("Test %s::%s: Output %s gave the wrong"
411                                   " value. With inputs %s, expected %s (dtype %s),"
412                                   " got %s (dtype %s). eps=%f"
413                                   " np.allclose returns %s %s") % (
414                            self.op,
415                            testname,
416                            i,
417                            inputs,
418                            expected,
419                            expected.dtype,
420                            variable,
421                            variable.dtype,
422                            eps,
423                            np.allclose(variable, expected,
424                                        atol=eps, rtol=eps),
425                            np.allclose(variable, expected)))
426
427                for description, check in iteritems(self.checks):
428                    if not check(inputs, variables):
429                        self.fail(("Test %s::%s: Failed check: %s (inputs"
430                                   " were %s, outputs were %s)") % (
431                            self.op, testname, description,
432                            inputs, variables))
433
434        def test_bad_build(self):
435            if skip:
436                raise SkipTest(skip)
437            for testname, inputs in iteritems(self.bad_build):
438                inputs = [copy(input) for input in inputs]
439                inputrs = [shared(input) for input in inputs]
440                self.assertRaises(Exception,
441                                  safe_make_node, self.op, *inputrs)
442                # The old error string was ("Test %s::%s: %s was successfully
443                # instantiated on the following bad inputs: %s"
444                # % (self.op, testname, node, inputs))
445
446        @change_flags(compute_test_value='off')
447        def test_bad_runtime(self):
448            if skip:
449                raise SkipTest(skip)
450            for testname, inputs in iteritems(self.bad_runtime):
451                inputrs = [shared(input) for input in inputs]
452                try:
453                    node = safe_make_node(self.op, *inputrs)
454                except Exception as exc:
455                    err_msg = ("Test %s::%s: Error occurred while trying"
456                               " to make a node with inputs %s") % (
457                        self.op, testname, inputs)
458                    exc.args += (err_msg,)
459                    raise
460
461                try:
462                    f = inplace_func([], node.outputs, mode=mode, name="test_bad_runtime")
463                except Exception as exc:
464                    err_msg = ("Test %s::%s: Error occurred while trying"
465                               " to make a Function") % (self.op, testname)
466                    exc.args += (err_msg,)
467                    raise
468
469                # Add tester return a ValueError. Should we catch only this
470                # one?
471                # TODO: test that only this one is raised and catch only this
472                # one or the subset that get raised.
473                self.assertRaises(Exception, f, [])
474
475        def test_grad(self):
476            if skip:
477                raise SkipTest(skip)
478            # Disable old warning that may be triggered by this test.
479            backup = config.warn.sum_div_dimshuffle_bug
480            config.warn.sum_div_dimshuffle_bug = False
481            try:
482                for testname, inputs in iteritems(self.grad):
483                    inputs = [copy(input) for input in inputs]
484                    try:
485                        utt.verify_grad(self.op, inputs,
486                                        mode=self.mode,
487                                        rel_tol=_grad_rtol,
488                                        eps=_grad_eps)
489                    except Exception as exc:
490                        err_msg = ("Test %s::%s: Error occurred while"
491                                   " computing the gradient on the following"
492                                   " inputs: %s") % (self.op, testname, inputs)
493                        exc.args += (err_msg,)
494                        raise
495            finally:
496                config.warn.sum_div_dimshuffle_bug = backup
497
498        def test_grad_none(self):
499            # Check that None is never returned as input gradient
500            # when calling self.op.grad
501            # We use all values in self.good because this has to be true
502            # whether or not the values work for utt.verify_grad.
503            if skip:
504                raise SkipTest(skip)
505
506            if not hasattr(self.op, 'grad'):
507                # This is not actually an Op
508                return
509
510            for testname, inputs in iteritems(self.good):
511                inputs = [copy(input) for input in inputs]
512                inputrs = [TensorType(
513                    dtype=input.dtype,
514                    broadcastable=[shape_elem == 1
515                                   for shape_elem in input.shape]
516                    )() for input in inputs]
517
518                if (isinstance(self.expected, dict) and
519                        testname in self.expected):
520                    expecteds = self.expected[testname]
521                    # with numpy version, when we print a number and read it
522                    # back, we don't get exactly the same result, so we accept
523                    # rounding error in that case.
524                else:
525                    expecteds = self.expected(*inputs)
526                if not isinstance(expecteds, (list, tuple)):
527                    expecteds = (expecteds, )
528
529                out_grad_vars = []
530                for out in expecteds:
531                    if str(out.dtype) in tensor.discrete_dtypes:
532                        dtype = floatX
533                    else:
534                        dtype = str(out.dtype)
535                    bcast = [shape_elem == 1 for shape_elem in out.shape]
536                    var = TensorType(dtype=dtype, broadcastable=bcast)()
537                    out_grad_vars.append(var)
538
539                try:
540                    in_grad_vars = self.op.grad(inputrs, out_grad_vars)
541                except (gof.utils.MethodNotDefined, NotImplementedError):
542                    pass
543                else:
544                    assert None not in in_grad_vars
545
546    Checker.__name__ = name
547    if hasattr(Checker, '__qualname__'):
548        Checker.__qualname__ = name
549    return Checker
550
551
552def rand(*shape):
553    r = test_rng.rand(*shape) * 2 - 1
554    return np.asarray(r, dtype=config.floatX)
555
556
557def rand_nonzero(shape, eps=3e-4):
558    # Like rand, but the absolute value has to be at least eps
559    # covers [0, 1)
560    r = np.asarray(test_rng.rand(*shape), dtype=config.floatX)
561    # covers [0, (1 - eps) / 2) U [(1 + eps) / 2, 1)
562    r = r * (1 - eps) + eps * (r >= 0.5)
563    # covers [-1, -eps) U [eps, 1)
564    r = r * 2 - 1
565    return r
566
567
568def randint(*shape):
569    return test_rng.randint(-5, 6, shape)
570
571
572def randuint32(*shape):
573    return np.array(test_rng.randint(5, size=shape), dtype=np.uint32)
574
575
576def randuint16(*shape):
577    return np.array(test_rng.randint(5, size=shape), dtype=np.uint16)
578
579
580# XXX: this so-called complex random array as all-zero imaginary parts
581def randcomplex(*shape):
582    r = np.asarray(test_rng.rand(*shape), dtype=config.floatX)
583    return np.complex128(2 * r - 1)
584
585
586def randcomplex_nonzero(shape, eps=1e-4):
587    return np.complex128(rand_nonzero(shape, eps))
588
589
590def randint_nonzero(*shape):
591    r = test_rng.randint(-5, 5, shape)
592    return r + (r == 0) * 5
593
594
595def rand_ranged(min, max, shape):
596    return np.asarray(test_rng.rand(*shape) * (max - min) + min,
597                      dtype=config.floatX)
598
599
600def randint_ranged(min, max, shape):
601    return test_rng.randint(min, max + 1, shape)
602
603
604def randc128_ranged(min, max, shape):
605    return np.asarray(test_rng.rand(*shape) * (max - min) + min,
606                      dtype='complex128')
607
608
609def rand_of_dtype(shape, dtype):
610    if dtype in tensor.discrete_dtypes:
611        return randint(*shape).astype(dtype)
612    elif dtype in tensor.float_dtypes:
613        return rand(*shape).astype(dtype)
614    elif dtype in tensor.complex_dtypes:
615        return randcomplex(*shape).astype(dtype)
616    else:
617        raise TypeError()
618
619# Used to exclude random numbers too close to certain values
620_eps = 1e-2
621
622
623def makeBroadcastTester(op, expected, checks=None, name=None, **kwargs):
624    if checks is None:
625        checks = {}
626    if name is None:
627        name = str(op)
628    # Here we ensure the test name matches the name of the variable defined in
629    # this script. This is needed to properly identify the test e.g. with the
630    # --with-id option of nosetests, or simply to rerun a specific test that
631    # failed.
632    capitalize = False
633    if name.startswith('Elemwise{') and name.endswith(',no_inplace}'):
634        # For instance: Elemwise{add,no_inplace} -> Add
635        name = name[9:-12]
636        capitalize = True
637    elif name.endswith('_inplace'):
638        # For instance: sub_inplace -> SubInplace
639        capitalize = True
640    if capitalize:
641        name = ''.join([x.capitalize() for x in name.split('_')])
642    # Some tests specify a name that already ends with 'Tester', while in other
643    # cases we need to add it manually.
644    if not name.endswith('Tester'):
645        name += "Tester"
646    if 'inplace' in kwargs:
647        if kwargs['inplace']:
648            _expected = expected
649            if not isinstance(_expected, dict):
650                def expected(*inputs):
651                    return np.array(_expected(*inputs), dtype=inputs[0].dtype)
652
653            def inplace_check(inputs, outputs):
654                # this used to be inputs[0] is output[0]
655                # I changed it so that it was easier to satisfy by the
656                # DebugMode
657                return np.all(inputs[0] == outputs[0])
658
659            checks = dict(checks, inplace_check=inplace_check)
660        del kwargs['inplace']
661    return makeTester(name, op, expected, checks, **kwargs)
662
663
664_good_broadcast_binary_normal = dict(
665    same_shapes=(rand(2, 3), rand(2, 3)),
666    not_same_dimensions=(rand(2, 2), rand(2)),
667    scalar=(rand(2, 3), rand(1, 1)),
668    row=(rand(2, 3), rand(1, 3)),
669    column=(rand(2, 3), rand(2, 1)),
670    integers=(randint(2, 3), randint(2, 3)),
671    uint32=(randuint32(2, 3), randuint32(2, 3)),
672    uint16=(randuint16(2, 3), randuint16(2, 3)),
673    dtype_mixup_1=(rand(2, 3), randint(2, 3)),
674    dtype_mixup_2=(randint(2, 3), rand(2, 3)),
675    complex1=(randcomplex(2, 3), randcomplex(2, 3)),
676    complex2=(randcomplex(2, 3), rand(2, 3)),
677    # Disabled as we test the case where we reuse the same output as the
678    # first inputs.
679    # complex3=(rand(2,3),randcomplex(2,3)),
680    empty=(np.asarray([], dtype=config.floatX),
681           np.asarray([1], dtype=config.floatX)),
682    )
683
684_bad_build_broadcast_binary_normal = dict()
685
686_bad_runtime_broadcast_binary_normal = dict(
687    bad_shapes=(rand(2, 3), rand(3, 2)),
688    bad_row=(rand(2, 3), rand(1, 2)))
689
690_grad_broadcast_binary_normal = dict(
691    same_shapes=(rand(2, 3), rand(2, 3)),
692    scalar=(rand(2, 3), rand(1, 1)),
693    row=(rand(2, 3), rand(1, 3)),
694    column=(rand(2, 3), rand(2, 1)),
695    # This don't work as verify grad don't support that
696    # empty=(np.asarray([]), np.asarray([1]))
697    # complex1=(randcomplex(2,3),randcomplex(2,3)),
698    # complex2=(randcomplex(2,3),rand(2,3)),
699    # Disabled as we test the case where we reuse the same output as the
700    # first inputs.
701    # complex3=(rand(2,3),randcomplex(2,3)),
702    )
703
704
705def check_floatX(inputs, rval):
706    # :param inputs: Inputs to a function that returned `rval` with these inputs.
707    #
708    # :param rval: Value returned by a function with inputs set to `inputs`.
709    #
710    # :returns: Either `rval` unchanged, or `rval` cast in float32. The idea is
711    # that when a numpy function would have returned a float64, Theano may prefer
712    # to return a float32 instead when `config.cast_policy` is set to
713    # 'numpy+floatX' and config.floatX to 'float32', and there was no float64
714    # input.
715    if (isinstance(rval, np.ndarray) and
716            rval.dtype == 'float64' and
717            config.cast_policy == 'numpy+floatX' and
718            config.floatX == 'float32' and
719            all(x.dtype != 'float64' for x in inputs)):
720        # Then we expect float32 instead of float64.
721        return rval.astype('float32')
722    else:
723        return rval
724
725
726AddTester = makeBroadcastTester(
727    op=add,
728    expected=lambda *inputs: check_floatX(
729        inputs, reduce(lambda x, y: x + y, inputs)),
730    good=dict(
731        three_inputs_same_shapes=(rand(2, 3),
732                                  rand(2, 3),
733                                  rand(2, 3)),
734        three_inputs_same_shapes_uint=(randuint32(2, 3),
735                                       randuint32(2, 3),
736                                       randuint32(2, 3)),
737        four_inputs_broadcast=(rand(2, 3),
738                               rand(1, 3),
739                               rand(2, 1),
740                               rand(1, 1)),
741        **_good_broadcast_binary_normal),
742    bad_build=_bad_build_broadcast_binary_normal,
743    bad_runtime=_bad_runtime_broadcast_binary_normal)
744
745
746AddInplaceTester = makeBroadcastTester(
747    op=inplace.add_inplace,
748    expected=lambda x, y: x + y,
749    good=_good_broadcast_binary_normal,
750    bad_build=_bad_build_broadcast_binary_normal,
751    bad_runtime=_bad_runtime_broadcast_binary_normal,
752    inplace=True)
753
754SubTester = makeBroadcastTester(
755    op=sub,
756    expected=lambda x, y: check_floatX((x, y), x - y),
757    good=_good_broadcast_binary_normal,
758    bad_build=_bad_build_broadcast_binary_normal,
759    bad_runtime=_bad_runtime_broadcast_binary_normal,
760    grad=_grad_broadcast_binary_normal)
761
762SubInplaceTester = makeBroadcastTester(op=inplace.sub_inplace,
763                                       expected=lambda x, y: x - y,
764                                       good=_good_broadcast_binary_normal,
765                                       bad_build=_bad_build_broadcast_binary_normal,
766                                       bad_runtime=_bad_runtime_broadcast_binary_normal,
767                                       inplace=True)
768
769
770SwitchTester = makeBroadcastTester(
771    op=switch,
772    expected=np.where,
773    good=dict(all_true=(np.asarray(1, dtype=config.floatX),
774                        rand(4, 5), rand(4, 5)),
775              false_true=(np.asarray(0, dtype=config.floatX),
776                          rand(4, 5), rand(4, 5)),
777              mixed=(randint_ranged(0, 1, (4, 5)),
778                     rand(4, 5), rand(4, 5))
779              ),
780    bad_build=dict(all_true=(np.asarray(1, dtype=config.floatX),
781                             rand(4, 5))),
782    bad_runtime=dict(all_true=(np.asarray(1, dtype=config.floatX),
783                               rand(3, 5), rand(4, 5)),
784                     false_true=(np.asarray(0, dtype=config.floatX),
785                                 rand(4, 6), rand(4, 5)),
786                     ),
787    # We suppose that cond+eps do not switch branch in switch.grad()
788    # So we can't call verify_grad with cond 0.
789    grad=dict(all_true=(np.asarray(1, dtype=config.floatX),
790                        rand(4, 5), rand(4, 5)),
791              # false_true=(np.asarray(0, dtype=config.floatX),
792              #             rand(4, 5), rand(4, 5)),
793              # mixed=(randint_ranged(0, 1, (4, 5)).astype(config.floatX),
794              #        rand(4, 5), rand(4, 5))
795              ),
796)
797
798
799MaximumTester = makeBroadcastTester(
800    op=maximum,
801    expected=lambda *inputs: check_floatX(inputs, np.maximum(*inputs)),
802    good=_good_broadcast_binary_normal,
803    bad_build=_bad_build_broadcast_binary_normal,
804    bad_runtime=_bad_runtime_broadcast_binary_normal,
805    grad=_grad_broadcast_binary_normal)
806
807MaximumInplaceTester = makeBroadcastTester(
808    op=inplace.maximum_inplace,
809    expected=np.maximum,
810    good=_good_broadcast_binary_normal,
811    bad_build=_bad_build_broadcast_binary_normal,
812    bad_runtime=_bad_runtime_broadcast_binary_normal,
813    inplace=True)
814
815
816def test_maximum_minimum_grad():
817    # Test the discontinuity point.
818    # We decided that we only pass the gradient to the first input in that case.
819    x, y = tensor.vectors('xy')
820    for op in [tensor.maximum, tensor.minimum]:
821        o = op(x, y)
822        g = theano.grad(o.sum(), [x, y])
823
824        f = theano.function([x, y], g)
825        assert np.allclose(f([1], [1]), [[1], [0]])
826
827
828MinimumTester = makeBroadcastTester(
829    op=minimum,
830    expected=lambda *inputs: check_floatX(inputs, np.minimum(*inputs)),
831    good=_good_broadcast_binary_normal,
832    bad_build=_bad_build_broadcast_binary_normal,
833    bad_runtime=_bad_runtime_broadcast_binary_normal,
834    grad=_grad_broadcast_binary_normal)
835
836MinimumInplaceTester = makeBroadcastTester(
837    op=inplace.minimum_inplace,
838    expected=np.minimum,
839    good=_good_broadcast_binary_normal,
840    bad_build=_bad_build_broadcast_binary_normal,
841    bad_runtime=_bad_runtime_broadcast_binary_normal,
842    inplace=True)
843
844MulTester = makeBroadcastTester(
845    op=mul,
846    expected=lambda *inputs: check_floatX(inputs, reduce(lambda x, y: x * y, inputs)),
847    good=dict(three_inputs_same_shapes=(rand(2, 3), rand(2, 3), rand(2, 3)),
848              four_inputs_broadcast=(rand(2, 3), rand(1, 3), rand(2, 1), rand(1, 1)),
849              **_good_broadcast_binary_normal),
850    bad_build=_bad_build_broadcast_binary_normal,
851    bad_runtime=_bad_runtime_broadcast_binary_normal,
852    grad=dict(three_inputs_same_shapes=(rand(2, 3), rand(2, 3), rand(2, 3)),
853              four_inputs_broadcast=(rand(2, 3), rand(1, 3), rand(2, 1), rand(1, 1)),
854              **_grad_broadcast_binary_normal))
855
856MulInplaceTester = makeBroadcastTester(
857    op=inplace.mul_inplace,
858    expected=lambda x, y: x * y,
859    good=_good_broadcast_binary_normal,
860    bad_build=_bad_build_broadcast_binary_normal,
861    bad_runtime=_bad_runtime_broadcast_binary_normal,
862    inplace=True)
863
864
865def copymod(dct, without=None, **kwargs):
866    # Return dct but with the keys named by args removed, and with
867    # kwargs added.
868    if without is None:
869        without = []
870    rval = copy(dct)
871    for a in without:
872        if a in rval:
873            del rval[a]
874    for kw, val in iteritems(kwargs):
875        rval[kw] = val
876    return rval
877
878_good_broadcast_div_mod_normal_float_no_complex = dict(
879    same_shapes=(rand(2, 3), rand_nonzero((2, 3))),
880    scalar=(rand(2, 3), rand_nonzero((1, 1))),
881    row=(rand(2, 3), rand_nonzero((1, 3))),
882    column=(rand(2, 3), rand_nonzero((2, 1))),
883    dtype_mixup_1=(rand(2, 3), randint_nonzero(2, 3)),
884    dtype_mixup_2=(randint_nonzero(2, 3), rand_nonzero((2, 3))),
885    integer=(randint(2, 3), randint_nonzero(2, 3)),
886    uint8=(randint(2, 3).astype("uint8"),
887           randint_nonzero(2, 3).astype("uint8")),
888    uint16=(randint(2, 3).astype("uint16"),
889            randint_nonzero(2, 3).astype("uint16")),
890    int8=[np.tile(np.arange(-127, 128, dtype='int8'), [254, 1]).T,
891          np.tile(np.array(list(range(-127, 0)) + list(range(1, 128)),
892                           dtype='int8'),
893                  [255, 1])],
894    # This empty2 doesn't work for some tests. I don't remember why
895    # empty2=(np.asarray([0]), np.asarray([])),
896    )
897
898if PY3:
899    _good_broadcast_div_mod_normal_float_inplace = copymod(
900        _good_broadcast_div_mod_normal_float_no_complex,
901        empty1=(np.asarray([]), np.asarray([1])),
902        # No complex floor division in python 3.x
903        )
904else:
905    _good_broadcast_div_mod_normal_float_inplace = copymod(
906        _good_broadcast_div_mod_normal_float_no_complex,
907        empty1=(np.asarray([], dtype=config.floatX),
908                np.asarray([1], dtype=config.floatX)),
909        complex1=(randcomplex(2, 3), randcomplex_nonzero((2, 3))),
910        complex2=(randcomplex(2, 3), rand_nonzero((2, 3))),
911        # Inplace on the first element. Must have the same type.
912        # complex3=(rand(2, 3) ,randcomplex(2, 3)),
913        )
914
915_good_broadcast_div_mod_normal_float = copymod(
916    _good_broadcast_div_mod_normal_float_inplace,
917    empty2=(np.asarray([0], dtype=config.floatX),
918            np.asarray([], dtype=config.floatX))
919    )
920
921
922_grad_broadcast_div_mod_normal = dict(
923    same_shapes=(rand(2, 3), rand_nonzero((2, 3))),
924    scalar=(rand(2, 3), rand_nonzero((1, 1))),
925    row=(rand(2, 3), rand_nonzero((1, 3))),
926    column=(rand(2, 3), rand_nonzero((2, 1))),
927    # complex1=(randcomplex(2, 3), randcomplex_nonzero((2, 3))),
928    # complex2=(randcomplex(2, 3), rand_nonzero((2, 3))),
929    # complex3=(rand(2, 3), randcomplex_nonzero((2, 3))),
930    # dtype_mixup_1=(rand(2, 3), randint_nonzero(2, 3)),
931    # dtype_mixup_2=(randint_nonzero(2, 3), rand_nonzero((2, 3))),
932    # empty1=(np.asarray([]), np.asarray([1.])),
933    # empty2=(np.asarray([0]), np.asarray([])),
934    )
935
936div_grad_rtol = None
937if config.floatX == 'float32':
938    # We raise the relative tolerance for the grad as there can be errors in
939    # float32.
940    # This is probably caused by our way of computing the gradient error.
941    div_grad_rtol = 0.025
942
943
944def _numpy_true_div(x, y):
945    # Performs true division, and cast the result in the type we expect.
946    #
947    # We define that function so we can use it in TrueDivTester.expected,
948    # because simply calling np.true_divide could cause a dtype mismatch.
949    out = np.true_divide(x, y)
950    # Use floatX as the result of int / int
951    if x.dtype in tensor.discrete_dtypes and y.dtype in tensor.discrete_dtypes:
952        out = theano._asarray(out, dtype=config.floatX)
953    return out
954
955TrueDivTester = makeBroadcastTester(
956    op=tensor.true_div,
957    expected=_numpy_true_div,
958    good=_good_broadcast_div_mod_normal_float_no_complex,
959    grad=_grad_broadcast_div_mod_normal,
960    grad_rtol=div_grad_rtol,
961    )
962
963TrueDivInplaceTester = makeBroadcastTester(
964    op=inplace.true_div_inplace,
965    expected=_numpy_true_div,
966    good=copymod(
967        _good_broadcast_div_mod_normal_float_inplace,
968        # The output is now in float, we cannot work inplace on an int.
969        without=['integer', 'uint8', 'uint16', 'int8']),
970    grad_rtol=div_grad_rtol,
971    inplace=True)
972
973
974_good_inv = dict(
975    normal=[5 * rand_nonzero((2, 3))],
976    integers=[randint_nonzero(2, 3)],
977    int8=[np.array(list(range(-127, 0)) + list(range(1, 127)), dtype='int8')],
978    uint8=[np.array(list(range(0, 255)), dtype='uint8')],
979    uint16=[np.array(list(range(0, 65535)), dtype='uint16')],
980    complex=[randcomplex_nonzero((2, 3))],
981    empty=[np.asarray([], dtype=config.floatX)])
982
983_good_inv_inplace = copymod(_good_inv, without=['integers', 'int8', 'uint8', 'uint16', 'complex'])
984_grad_inv = copymod(_good_inv,
985                    without=['integers', 'int8', 'uint8', 'uint16', 'complex', 'empty'])
986
987_bad_runtime_inv = dict(
988    float=[np.zeros((2, 3))],
989    integers=[np.zeros((2, 3), dtype='int64')],
990    int8=[np.zeros((2, 3), dtype='int8')],
991    complex=[np.zeros((2, 3), dtype='complex128')])
992
993
994InvTester = makeBroadcastTester(
995    op=tensor.inv,
996    expected=lambda x: upcast_int8_nfunc(np.true_divide)(np.int8(1), x),
997    good=_good_inv,
998    bad_runtime=_bad_runtime_inv,
999    grad=_grad_inv,
1000    grad_rtol=div_grad_rtol)
1001
1002InvInplaceTester = makeBroadcastTester(
1003    op=inplace.inv_inplace,
1004    expected=lambda x: _numpy_true_div(np.int8(1), x),
1005    good=_good_inv_inplace,
1006    bad_runtime=_bad_runtime_inv,
1007    grad_rtol=div_grad_rtol,
1008    inplace=True)
1009
1010
1011CeilIntDivTester = makeBroadcastTester(
1012    op=tensor.ceil_intdiv,
1013    expected=lambda x, y: check_floatX((x, y), (x // y) + ((x % y) != 0)),
1014    good=_good_broadcast_div_mod_normal_float_no_complex,
1015    name='CeilIntDiv',
1016    # As we implement this function with neq, the gradient returned is always 0.
1017    # grad=_grad_broadcast_div_mod_normal,
1018    # grad_rtol=div_grad_rtol,
1019    )
1020
1021ModTester = makeBroadcastTester(
1022    op=tensor.mod,
1023    expected=lambda x, y: np.asarray(
1024        x % y, dtype=theano.scalar.basic.upcast(x.dtype, y.dtype)),
1025    good=copymod(_good_broadcast_div_mod_normal_float,
1026                 ['complex1', 'complex2']),
1027    grad=_grad_broadcast_div_mod_normal,
1028    grad_eps=1e-5,
1029    )
1030
1031
1032ModInplaceTester = makeBroadcastTester(
1033    op=inplace.mod_inplace,
1034    expected=lambda x, y: np.asarray(
1035        x % y, dtype=theano.scalar.basic.upcast(x.dtype, y.dtype)),
1036    good=copymod(_good_broadcast_div_mod_normal_float_inplace,
1037                 ["complex1", "complex2"]),
1038    grad_eps=1e-5,
1039    inplace=True)
1040
1041_good_broadcast_pow_normal_float = dict(
1042    same_shapes=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (2, 3))),
1043    scalar=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (1, 1))),
1044    row=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (1, 3))),
1045    column=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (2, 1))),
1046    dtype_mixup=(rand_ranged(-3, 3, (2, 3)), randint_ranged(-3, 3, (2, 3))),
1047    complex1=(randcomplex(2, 3), randcomplex(2, 3)),
1048    complex2=(randcomplex(2, 3), rand(2, 3)),
1049    # complex3 = (rand(2,3),randcomplex(2,3)), # Inplace on the first element.
1050    empty1=(np.asarray([], dtype=config.floatX),
1051            np.asarray([1], dtype=config.floatX)),
1052    empty2=(np.asarray([0], dtype=config.floatX),
1053            np.asarray([], dtype=config.floatX)),
1054    empty3=(np.asarray([], dtype=config.floatX),
1055            np.asarray([], dtype=config.floatX)),
1056    )
1057_grad_broadcast_pow_normal = dict(
1058    same_shapes=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (2, 3))),
1059    scalar=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (1, 1))),
1060    row=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (1, 3))),
1061    column=(rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (2, 1))),
1062    # complex1 = (randcomplex(2,3),randcomplex(2,3)),
1063    # complex2 = (randcomplex(2,3),rand(2,3)),
1064    # complex3 = (rand(2,3),randcomplex(2,3)),
1065    # empty1 = (np.asarray([]), np.asarray([1])),
1066    # empty2 = (np.asarray([0]), np.asarray([])),
1067    x_eq_zero=(
1068        np.asarray([0.], dtype=config.floatX),
1069        np.asarray([2.], dtype=config.floatX)
1070        ),  # Test for issue 1780
1071    )
1072# empty2 case is not supported by numpy.
1073_good_broadcast_pow_normal_float_pow = copy(_good_broadcast_pow_normal_float)
1074del _good_broadcast_pow_normal_float_pow["empty2"]
1075
1076# Disable NAN checking for pow operator per issue #1780
1077m = copy(theano.compile.get_default_mode())
1078m.check_isfinite = False
1079
1080PowTester = makeBroadcastTester(
1081    op=pow,
1082    expected=lambda x, y: check_floatX((x, y), x ** y),
1083    good=_good_broadcast_pow_normal_float,
1084    grad=_grad_broadcast_pow_normal,
1085    name='Pow',
1086    mode=m
1087)
1088
1089PowInplaceTester = makeBroadcastTester(
1090    op=inplace.pow_inplace,
1091    expected=lambda x, y: x ** y,
1092    good=_good_broadcast_pow_normal_float_pow,
1093    inplace=True,
1094    mode=m
1095)
1096
1097# Those are corner case when rounding. Their is many rounding algo.
1098# c round() fct and numpy round are not the same!
1099corner_case = np.asarray(
1100    [-2.5, -2., -1.5, -1., -0.5, -.51, -.49, 0,
1101     0.49, 0.5, 0.9, 1, 1.5, 2, 2.5],
1102    dtype=floatX)
1103
1104# we remove 0 here as the grad is not always computable numerically.
1105corner_case_grad = np.asarray(
1106    [-2.5, -2., -1.5, -1., -0.5, -.51, -.49,
1107     0.49, 0.5, 0.9, 1, 1.5, 2, 2.5],
1108    dtype=floatX)
1109
1110_good_broadcast_unary_normal_float = dict(
1111    normal=[rand_ranged(-5, 5, (2, 3))],
1112    corner_case=[corner_case],
1113    complex=[randcomplex(2, 3)],
1114    empty=[np.asarray([], dtype=config.floatX)])
1115
1116_good_broadcast_unary_normal_float_no_empty = copymod(
1117    _good_broadcast_unary_normal_float,
1118    without=['empty'])
1119
1120_good_broadcast_unary_normal_float_no_empty_no_complex = copymod(
1121    _good_broadcast_unary_normal_float_no_empty,
1122    without=['complex'])
1123
1124_good_broadcast_unary_normal_float_no_complex = copymod(
1125    _good_broadcast_unary_normal_float,
1126    without=['complex'])
1127
1128_good_broadcast_unary_normal_float_no_complex_small_neg_range = dict(
1129    normal=[rand_ranged(-2, 5, (2, 3))],
1130    corner_case=[corner_case],
1131    empty=[np.asarray([], dtype=config.floatX)])
1132
1133_good_broadcast_unary_normal = dict(
1134    normal=[np.asarray(rand_ranged(-5, 5, (2, 3)),
1135                       dtype=config.floatX)],
1136    integers=[randint_ranged(-5, 5, (2, 3))],
1137    # not using -128 because np.allclose would return False
1138    int8=[np.arange(-127, 128, dtype='int8')],
1139    uint8=[np.arange(0, 255, dtype='uint8')],
1140    uint16=[np.arange(0, 65535, dtype='uint16')],
1141    corner_case=[corner_case],
1142    complex=[randcomplex(2, 3)],
1143    empty=[np.asarray([], dtype=config.floatX)],
1144    )
1145
1146_good_broadcast_unary_normal_no_complex = dict(
1147    normal=[np.asarray(rand_ranged(-5, 5, (2, 3)), dtype=floatX)],
1148    integers=[randint_ranged(-5, 5, (2, 3))],
1149    int8=[np.arange(-127, 128, dtype='int8')],
1150    uint8=[np.arange(0, 89, dtype='uint8')],
1151    uint16=[np.arange(0, 89, dtype='uint16')],
1152    corner_case=[corner_case],
1153    empty=[np.asarray([], dtype=config.floatX)],
1154    )
1155
1156_grad_broadcast_unary_normal_no_complex = dict(
1157    normal=[np.asarray(rand_ranged(-5, 5, (2, 3)), dtype=floatX)],
1158    corner_case=[corner_case_grad])
1159
1160_grad_broadcast_unary_normal = dict(
1161    normal=[np.asarray(rand_ranged(-5, 5, (2, 3)), dtype=floatX)],
1162    corner_case=[corner_case_grad],
1163    # empty = [np.asarray([])] # XXX: should this be included?
1164    )
1165
1166# Avoid epsilon around integer values
1167_grad_broadcast_unary_normal_noint = dict(
1168    normal=[(rand_ranged(_eps, 1 - _eps, (2, 3)) + randint(2, 3))
1169            .astype(floatX)])
1170
1171_grad_broadcast_unary_normal_small_neg_range = dict(
1172    normal=[np.asarray(rand_ranged(-2, 5, (2, 3)), dtype=floatX)],
1173    corner_case=[corner_case_grad])
1174
1175_grad_broadcast_unary_normal_no_complex_no_corner_case = copymod(
1176    _grad_broadcast_unary_normal_no_complex,
1177    without=['corner_case'])
1178
1179_grad_broadcast_unary_abs1_no_complex = dict(
1180    normal=[np.asarray(rand_ranged(-1 + _eps, 1 - _eps, (2, 3)), dtype=floatX)],
1181    )
1182
1183_grad_broadcast_unary_0_2_no_complex = dict(
1184    # Don't go too close to 0 or 2 for tests in float32
1185    normal=[np.asarray(rand_ranged(_eps, 1 - _eps, (2, 3)), dtype=floatX)],
1186    )
1187
1188# inplace ops when the input is integer and the output is float*
1189# don't have a well defined behavior. We don't test that case.
1190
1191AbsTester = makeBroadcastTester(
1192    op=tensor.abs_,
1193    expected=lambda x: abs(x),
1194    good=_good_broadcast_unary_normal,
1195    grad=_grad_broadcast_unary_normal)
1196_good_broadcast_unary_normal_abs = copy(_good_broadcast_unary_normal)
1197# Can't do inplace on Abs as the input/output are not of the same type!
1198del _good_broadcast_unary_normal_abs['complex']
1199AbsInplaceTester = makeBroadcastTester(
1200    op=inplace.abs__inplace,
1201    expected=lambda x: np.abs(x),
1202    good=_good_broadcast_unary_normal_abs,
1203    inplace=True)
1204
1205NegTester = makeBroadcastTester(
1206    op=tensor.neg,
1207    expected=lambda x: -x,
1208    good=_good_broadcast_unary_normal,
1209    grad=_grad_broadcast_unary_normal)
1210NegInplaceTester = makeBroadcastTester(
1211    op=inplace.neg_inplace,
1212    expected=lambda x: -x,
1213    good=_good_broadcast_unary_normal,
1214    inplace=True)
1215
1216SgnTester = makeBroadcastTester(
1217    op=tensor.sgn,
1218    expected=np.sign,
1219    good=_good_broadcast_unary_normal_no_complex,
1220    grad=_grad_broadcast_unary_normal,)
1221SgnInplaceTester = makeBroadcastTester(
1222    op=inplace.sgn_inplace,
1223    expected=np.sign,
1224    good=_good_broadcast_unary_normal_no_complex,
1225    inplace=True)
1226
1227IntDivTester = makeBroadcastTester(
1228    op=tensor.int_div,
1229    expected=lambda x, y: check_floatX((x, y), x // y),
1230    good=_good_broadcast_div_mod_normal_float,
1231    # I don't test the grad as the output is always an integer
1232    # (this is not a continuous output).
1233    # grad=_grad_broadcast_div_mod_normal,
1234    )
1235
1236IntDivInplaceTester = makeBroadcastTester(
1237    op=inplace.int_div_inplace,
1238    expected=lambda x, y: check_floatX((x, y), x // y),
1239    good=_good_broadcast_div_mod_normal_float_inplace,
1240    # I don't test the grad as the output is always an integer
1241    # (this is not a continuous output).
1242    # grad=_grad_broadcast_div_mod_normal,
1243    inplace=True
1244    )
1245
1246
1247CeilTester = makeBroadcastTester(
1248    op=tensor.ceil,
1249    expected=upcast_float16_ufunc(np.ceil),
1250    good=_good_broadcast_unary_normal_no_complex,
1251    grad=copymod(_grad_broadcast_unary_normal_noint,
1252                 extra=[np.asarray([-2.5, -1.5, -1.51, 0.49, .98, 1.02],
1253                                   dtype=floatX)]))
1254
1255CeilInplaceTester = makeBroadcastTester(
1256    op=inplace.ceil_inplace,
1257    expected=upcast_float16_ufunc(np.ceil),
1258    good=copymod(_good_broadcast_unary_normal_no_complex,
1259                 without=['integers', 'int8', 'uint8', 'uint16']),
1260    # corner cases includes a lot of integers: points where Ceil is not
1261    # continuous (not differentiable)
1262    inplace=True)
1263
1264FloorTester = makeBroadcastTester(
1265    op=tensor.floor,
1266    expected=upcast_float16_ufunc(np.floor),
1267    good=_good_broadcast_unary_normal_no_complex,
1268    grad=_grad_broadcast_unary_normal_noint)
1269
1270FloorInplaceTester = makeBroadcastTester(
1271    op=inplace.floor_inplace,
1272    expected=upcast_float16_ufunc(np.floor),
1273    good=copymod(_good_broadcast_unary_normal_no_complex,
1274                 without=["integers", "int8", "uint8", "uint16"]),
1275    inplace=True)
1276
1277TruncInplaceTester = makeBroadcastTester(
1278    op=inplace.trunc_inplace,
1279    expected=upcast_float16_ufunc(np.trunc),
1280    good=_good_broadcast_unary_normal_no_complex,
1281    inplace=True)
1282
1283TruncTester = makeBroadcastTester(
1284    op=tensor.trunc,
1285    expected=upcast_float16_ufunc(np.trunc),
1286    good=_good_broadcast_unary_normal_no_complex)
1287
1288RoundHalfToEvenTester = makeBroadcastTester(
1289    op=tensor.round_half_to_even,
1290    expected=np.round,
1291    good=_good_broadcast_unary_normal_float_no_complex,
1292    grad=_grad_broadcast_unary_normal_no_complex_no_corner_case)
1293
1294RoundHalfToEvenInplaceTester = makeBroadcastTester(
1295    op=inplace.round_half_to_even_inplace,
1296    expected=np.round,
1297    good=_good_broadcast_unary_normal_float_no_complex,
1298    inplace=True)
1299
1300# np.vectorize don't handle correctly empty ndarray.
1301# see in their file numpy/lib/function_base.py in class vectorize.__call__
1302# This happen in float32 mode.
1303RoundHalfAwayFromZeroTester = makeBroadcastTester(
1304    op=tensor.round_half_away_from_zero,
1305    expected=lambda a: theano.scalar.basic.round_half_away_from_zero_vec(a),
1306    good=_good_broadcast_unary_normal_float_no_empty_no_complex,
1307    grad=_grad_broadcast_unary_normal_no_complex_no_corner_case)
1308
1309RoundHalfAwayFromZeroInplaceTester = makeBroadcastTester(
1310    op=inplace.round_half_away_from_zero_inplace,
1311    expected=lambda a: theano.scalar.basic.round_half_away_from_zero_vec(a),
1312    good=_good_broadcast_unary_normal_float_no_empty_no_complex,
1313    inplace=True)
1314
1315SqrTester = makeBroadcastTester(
1316    op=tensor.sqr,
1317    expected=np.square,
1318    good=_good_broadcast_unary_normal,
1319    grad=_grad_broadcast_unary_normal)
1320
1321SqrInplaceTester = makeBroadcastTester(
1322    op=inplace.sqr_inplace,
1323    expected=np.square,
1324    good=_good_broadcast_unary_normal,
1325    inplace=True)
1326
1327ExpTester = makeBroadcastTester(
1328    op=tensor.exp,
1329    expected=upcast_float16_ufunc(np.exp),
1330    good=dict(_good_broadcast_unary_normal,
1331              int8=[np.arange(-127, 89, dtype='int8')],
1332              uint8=[np.arange(0, 89, dtype='uint8')],
1333              uint16=[np.arange(0, 89, dtype='uint16')]),
1334    grad=_grad_broadcast_unary_normal)
1335ExpInplaceTester = makeBroadcastTester(
1336    op=inplace.exp_inplace,
1337    expected=np.exp,
1338    good=_good_broadcast_unary_normal_float,
1339    inplace=True)
1340
1341Exp2Tester = makeBroadcastTester(
1342    op=tensor.exp2,
1343    expected=upcast_float16_ufunc(np.exp2),
1344    good=_good_broadcast_unary_normal,
1345    grad=_grad_broadcast_unary_normal)
1346Exp2InplaceTester = makeBroadcastTester(
1347    op=inplace.exp2_inplace,
1348    expected=np.exp2,
1349    good=_good_broadcast_unary_normal_float,
1350    inplace=True)
1351
1352
1353Expm1Tester = makeBroadcastTester(
1354    op=tensor.expm1,
1355    expected=upcast_float16_ufunc(np.expm1),
1356    good=dict(_good_broadcast_unary_normal,
1357              int8=[np.arange(-127, 89, dtype='int8')],
1358              uint8=[np.arange(0, 89, dtype='uint8')],
1359              uint16=[np.arange(0, 89, dtype='uint16')]),
1360    grad=_grad_broadcast_unary_normal)
1361Expm1InplaceTester = makeBroadcastTester(
1362    op=inplace.expm1_inplace,
1363    expected=np.expm1,
1364    good=_good_broadcast_unary_normal_float,
1365    inplace=True)
1366
1367
1368_good_broadcast_unary_positive = dict(
1369    normal=(rand_ranged(0.001, 5, (2, 3)),),
1370    integers=(randint_ranged(1, 5, (2, 3)),),
1371    uint8=[np.arange(1, 256, dtype='uint8')],
1372    complex=(randc128_ranged(1, 5, (2, 3)),),
1373    empty=(np.asarray([], dtype=config.floatX),),
1374    )
1375
1376_good_broadcast_unary_positive_float = copymod(
1377    _good_broadcast_unary_positive,
1378    without=['integers', 'uint8'])
1379
1380_grad_broadcast_unary_positive = dict(normal=(rand_ranged(_eps, 5, (2, 3)),),)
1381
1382LogTester = makeBroadcastTester(
1383    op=tensor.log,
1384    expected=upcast_float16_ufunc(np.log),
1385    good=_good_broadcast_unary_positive,
1386    grad=_grad_broadcast_unary_positive)
1387LogInplaceTester = makeBroadcastTester(
1388    op=inplace.log_inplace,
1389    expected=np.log,
1390    good=_good_broadcast_unary_positive_float,
1391    inplace=True)
1392
1393Log2Tester = makeBroadcastTester(
1394    op=tensor.log2,
1395    expected=upcast_float16_ufunc(np.log2),
1396    good=_good_broadcast_unary_positive,
1397    grad=_grad_broadcast_unary_positive)
1398Log2InplaceTester = makeBroadcastTester(
1399    op=inplace.log2_inplace,
1400    expected=np.log2,
1401    good=_good_broadcast_unary_positive_float,
1402    inplace=True)
1403
1404Log10Tester = makeBroadcastTester(
1405    op=tensor.log10,
1406    expected=upcast_float16_ufunc(np.log10),
1407    good=_good_broadcast_unary_positive,
1408    grad=_grad_broadcast_unary_positive)
1409Log10InplaceTester = makeBroadcastTester(
1410    op=inplace.log10_inplace,
1411    expected=np.log10,
1412    good=_good_broadcast_unary_positive_float,
1413    inplace=True)
1414
1415Log1pTester = makeBroadcastTester(
1416    op=tensor.log1p,
1417    expected=upcast_float16_ufunc(np.log1p),
1418    good=_good_broadcast_unary_positive,
1419    grad=_grad_broadcast_unary_positive)
1420Log1pInplaceTester = makeBroadcastTester(
1421    op=inplace.log1p_inplace,
1422    expected=np.log1p,
1423    good=_good_broadcast_unary_positive_float,
1424    inplace=True)
1425
1426SqrtTester = makeBroadcastTester(
1427    op=tensor.sqrt,
1428    expected=upcast_float16_ufunc(np.sqrt),
1429    good=_good_broadcast_unary_positive,
1430    grad=_grad_broadcast_unary_positive)
1431SqrtInplaceTester = makeBroadcastTester(
1432    op=inplace.sqrt_inplace,
1433    expected=np.sqrt,
1434    good=_good_broadcast_unary_positive_float,
1435    inplace=True)
1436
1437_good_broadcast_unary_wide = dict(
1438    normal=(rand_ranged(-1000, 1000, (2, 3)),),
1439    integers=(randint_ranged(-1000, 1000, (2, 3)),),
1440    int8=[np.arange(-127, 128, dtype='int8')],
1441    uint8=[np.arange(0, 255, dtype='uint8')],
1442    uint16=[np.arange(0, 65535, dtype='uint16')],
1443    complex=(randc128_ranged(-1000, 1000, (2, 3)),),
1444    empty=(np.asarray([], dtype=config.floatX),),)
1445_good_broadcast_unary_wide_float = copymod(
1446    _good_broadcast_unary_wide,
1447    without=['integers', 'int8', 'uint8', 'uint16'])
1448_grad_broadcast_unary_wide = dict(normal=(rand_ranged(-1000, 1000, (2, 3)),),)
1449
1450if theano.config.floatX == 'float32':
1451    angle_eps = 1e-4
1452else:
1453    angle_eps = 1e-10
1454
1455Deg2radTester = makeBroadcastTester(
1456    op=tensor.deg2rad,
1457    expected=upcast_float16_ufunc(np.deg2rad),
1458    good=_good_broadcast_unary_normal_no_complex,
1459    grad=_grad_broadcast_unary_normal_no_complex,
1460    eps=angle_eps)
1461Deg2radInplaceTester = makeBroadcastTester(
1462    op=inplace.deg2rad_inplace,
1463    expected=np.deg2rad,
1464    good=_good_broadcast_unary_normal_float_no_complex,
1465    inplace=True,
1466    eps=angle_eps)
1467
1468Rad2degTester = makeBroadcastTester(
1469    op=tensor.rad2deg,
1470    expected=upcast_float16_ufunc(np.rad2deg),
1471    good=_good_broadcast_unary_normal_no_complex,
1472    grad=_grad_broadcast_unary_normal_no_complex,
1473    eps=angle_eps)
1474Rad2degInplaceTester = makeBroadcastTester(
1475    op=inplace.rad2deg_inplace,
1476    expected=np.rad2deg,
1477    good=_good_broadcast_unary_normal_float_no_complex,
1478    inplace=True,
1479    eps=angle_eps)
1480
1481SinTester = makeBroadcastTester(
1482    op=tensor.sin,
1483    expected=upcast_float16_ufunc(np.sin),
1484    good=_good_broadcast_unary_wide,
1485    grad=_grad_broadcast_unary_wide)
1486SinInplaceTester = makeBroadcastTester(
1487    op=inplace.sin_inplace,
1488    expected=np.sin,
1489    good=_good_broadcast_unary_wide_float,
1490    inplace=True)
1491
1492_good_broadcast_unary_arcsin = dict(
1493    normal=(rand_ranged(-1, 1, (2, 3)),),
1494    integers=(randint_ranged(-1, 1, (2, 3)),),
1495    int8=[np.arange(-1, 2, dtype='int8')],
1496    uint8=[np.arange(0, 2, dtype='uint8')],
1497    uint16=[np.arange(0, 2, dtype='uint16')],
1498    complex=(randc128_ranged(-1, 1, (2, 3)),),
1499    empty=(np.asarray([], dtype=config.floatX),),)
1500
1501_good_broadcast_unary_arcsin_float = copymod(
1502    _good_broadcast_unary_arcsin,
1503    without=['integers', 'int8', 'uint8', 'uint16'])
1504
1505# The actual range is [-1, 1] but the numerical gradient is too
1506# unstable near those values
1507_grad_broadcast_unary_arcsin = dict(normal=(rand_ranged(-0.9, 0.9, (2, 3)),),)
1508
1509ArcsinTester = makeBroadcastTester(
1510    op=tensor.arcsin,
1511    expected=upcast_float16_ufunc(np.arcsin),
1512    good=_good_broadcast_unary_arcsin,
1513    grad=_grad_broadcast_unary_arcsin)
1514ArcsinInplaceTester = makeBroadcastTester(
1515    op=inplace.arcsin_inplace,
1516    expected=np.arcsin,
1517    good=_good_broadcast_unary_arcsin_float,
1518    inplace=True)
1519
1520CosTester = makeBroadcastTester(
1521    op=tensor.cos,
1522    expected=upcast_float16_ufunc(np.cos),
1523    good=_good_broadcast_unary_wide,
1524    grad=_grad_broadcast_unary_wide)
1525CosInplaceTester = makeBroadcastTester(
1526    op=inplace.cos_inplace,
1527    expected=np.cos,
1528    good=_good_broadcast_unary_wide_float,
1529    inplace=True)
1530
1531
1532def test_py_c_match():
1533    a = tensor.TensorType(dtype='int8', broadcastable=(False,))()
1534    f = theano.function([a], tensor.arccos(a), mode='DebugMode')
1535    # This can fail in DebugMode
1536    f(np.asarray([1, 0, -1], dtype='int8'))
1537
1538ArccosTester = makeBroadcastTester(
1539    op=tensor.arccos,
1540    expected=upcast_float16_ufunc(np.arccos),
1541    good=_good_broadcast_unary_arcsin,
1542    grad=_grad_broadcast_unary_arcsin)
1543ArccosInplaceTester = makeBroadcastTester(
1544    op=inplace.arccos_inplace,
1545    expected=np.arccos,
1546    good=_good_broadcast_unary_arcsin_float,
1547    inplace=True)
1548
1549_good_broadcast_unary_tan = dict(
1550    normal=(rand_ranged(-3.14, 3.14, (2, 3)),),
1551    shifted=(rand_ranged(3.15, 6.28, (2, 3)),),
1552    integers=(randint_ranged(-3, 3, (2, 3)),),
1553    int8=[np.arange(-3, 4, dtype='int8')],
1554    uint8=[np.arange(0, 4, dtype='uint8')],
1555    uint16=[np.arange(0, 4, dtype='uint16')],
1556    complex=(randc128_ranged(-3.14, 3.14, (2, 3)),),
1557    empty=(np.asarray([], dtype=config.floatX),),)
1558# We do not want to test around the discontinuity.
1559_grad_broadcast_unary_tan = dict(normal=(rand_ranged(-1.5, 1.5, (2, 3)),),
1560                                 shifted=(rand_ranged(1.6, 4.6, (2, 3)),))
1561
1562TanTester = makeBroadcastTester(
1563    op=tensor.tan,
1564    expected=upcast_float16_ufunc(np.tan),
1565    good=_good_broadcast_unary_tan,
1566    grad=_grad_broadcast_unary_tan)
1567
1568TanInplaceTester = makeBroadcastTester(
1569    op=inplace.tan_inplace,
1570    expected=np.tan,
1571    good=copymod(_good_broadcast_unary_tan, without=['integers', 'int8', 'uint8', 'uint16']),
1572    inplace=True)
1573
1574ArctanTester = makeBroadcastTester(
1575    op=tensor.arctan,
1576    expected=upcast_float16_ufunc(np.arctan),
1577    good=_good_broadcast_unary_wide,
1578    grad=_grad_broadcast_unary_wide)
1579ArctanInplaceTester = makeBroadcastTester(
1580    op=inplace.arctan_inplace,
1581    expected=np.arctan,
1582    good=_good_broadcast_unary_wide_float,
1583    inplace=True)
1584
1585_good_broadcast_binary_arctan2 = dict(
1586    same_shapes=(rand(2, 3), rand(2, 3)),
1587    not_same_dimensions=(rand(2, 2), rand(2)),
1588    scalar=(rand(2, 3), rand(1, 1)),
1589    row=(rand(2, 3), rand(1, 3)),
1590    column=(rand(2, 3), rand(2, 1)),
1591    integers=(randint(2, 3), randint(2, 3)),
1592    int8=[np.arange(-127, 128, dtype='int8'),
1593          np.arange(-127, 128, dtype='int8')[:, np.newaxis]],
1594    uint8=[np.arange(0, 128, dtype='uint8'),
1595           np.arange(0, 128, dtype='uint8')[:, np.newaxis]],
1596    uint16=[np.arange(0, 128, dtype='uint16'),
1597            np.arange(0, 128, dtype='uint16')[:, np.newaxis]],
1598    dtype_mixup_1=(rand(2, 3), randint(2, 3)),
1599    dtype_mixup_2=(randint(2, 3), rand(2, 3)),
1600    empty=(np.asarray([], dtype=config.floatX),
1601           np.asarray([1], dtype=config.floatX)),
1602    )
1603
1604_grad_broadcast_binary_arctan2 = dict(
1605    same_shapes=(rand(2, 3), rand(2, 3)),
1606    scalar=(rand(2, 3), rand(1, 1)),
1607    row=(rand(2, 3), rand(1, 3)),
1608    column=(rand(2, 3), rand(2, 1)),
1609    )
1610
1611Arctan2Tester = makeBroadcastTester(
1612    op=tensor.arctan2,
1613    expected=upcast_float16_ufunc(np.arctan2),
1614    good=_good_broadcast_binary_arctan2,
1615    grad=_grad_broadcast_binary_arctan2)
1616
1617Arctan2InplaceTester = makeBroadcastTester(
1618    op=inplace.arctan2_inplace,
1619    expected=np.arctan2,
1620    good=copymod(_good_broadcast_binary_arctan2,
1621                 without=['integers', 'int8', 'uint8',
1622                          'uint16', 'dtype_mixup_2']),
1623    inplace=True)
1624
1625CoshTester = makeBroadcastTester(
1626    op=tensor.cosh,
1627    expected=upcast_float16_ufunc(np.cosh),
1628    good=dict(_good_broadcast_unary_normal,
1629              int8=[np.arange(-89, 90, dtype='int8')],
1630              uint8=[np.arange(0, 90, dtype='uint8')],
1631              uint16=[np.arange(0, 90, dtype='uint16')]),
1632    grad=_grad_broadcast_unary_normal)
1633CoshInplaceTester = makeBroadcastTester(
1634    op=inplace.cosh_inplace,
1635    expected=np.cosh,
1636    good=_good_broadcast_unary_normal_float,
1637    inplace=True)
1638
1639_good_broadcast_unary_arccosh = dict(
1640    normal=(rand_ranged(1, 1000, (2, 3)),),
1641    integers=(randint_ranged(1, 1000, (2, 3)),),
1642    uint8=[np.arange(1, 256, dtype='uint8')],
1643    complex=(randc128_ranged(1, 1000, (2, 3)),),
1644    empty=(np.asarray([], dtype=config.floatX),),)
1645_grad_broadcast_unary_arccosh = dict(normal=(rand_ranged(1 + _eps, 1000, (2, 3)),),)
1646
1647ArccoshTester = makeBroadcastTester(
1648    op=tensor.arccosh,
1649    expected=upcast_float16_ufunc(np.arccosh),
1650    good=_good_broadcast_unary_arccosh,
1651    grad=_grad_broadcast_unary_arccosh)
1652ArccoshInplaceTester = makeBroadcastTester(
1653    op=inplace.arccosh_inplace,
1654    expected=np.arccosh,
1655    good=copymod(_good_broadcast_unary_arccosh, without=['integers', 'uint8']),
1656    inplace=True)
1657
1658SinhTester = makeBroadcastTester(
1659    op=tensor.sinh,
1660    expected=upcast_float16_ufunc(np.sinh),
1661    good=dict(_good_broadcast_unary_normal,
1662              int8=[np.arange(-89, 90, dtype='int8')],
1663              uint8=[np.arange(0, 90, dtype='uint8')],
1664              uint16=[np.arange(0, 90, dtype='uint16')]),
1665    grad=_grad_broadcast_unary_normal)
1666SinhInplaceTester = makeBroadcastTester(
1667    op=inplace.sinh_inplace,
1668    expected=np.sinh,
1669    good=_good_broadcast_unary_normal_float,
1670    inplace=True)
1671
1672ArcsinhTester = makeBroadcastTester(
1673    op=tensor.arcsinh,
1674    expected=upcast_float16_ufunc(np.arcsinh),
1675    good=_good_broadcast_unary_normal,
1676    grad=_grad_broadcast_unary_normal)
1677ArcsinhInplaceTester = makeBroadcastTester(
1678    op=inplace.arcsinh_inplace,
1679    expected=np.arcsinh,
1680    good=_good_broadcast_unary_normal_float,
1681    inplace=True)
1682
1683TanhTester = makeBroadcastTester(
1684    op=tensor.tanh,
1685    expected=upcast_float16_ufunc(np.tanh),
1686    good=_good_broadcast_unary_normal,
1687    grad=_grad_broadcast_unary_normal)
1688TanhInplaceTester = makeBroadcastTester(
1689    op=inplace.tanh_inplace,
1690    expected=np.tanh,
1691    good=_good_broadcast_unary_normal_float,
1692    inplace=True)
1693
1694_good_broadcast_unary_arctanh = dict(
1695    normal=(rand_ranged(-1 + _eps, 1 - _eps, (2, 3)),),
1696    integers=(randint_ranged(-1 + _eps, 1 - _eps, (2, 3)),),
1697    int8=[np.arange(0, 1, dtype='int8')],
1698    uint8=[np.arange(0, 1, dtype='uint8')],
1699    uint16=[np.arange(0, 1, dtype='uint16')],
1700    complex=(randc128_ranged(-1 + _eps, 1 - _eps, (2, 3)),),
1701    empty=(np.asarray([], dtype=config.floatX),),)
1702_grad_broadcast_unary_arctanh = dict(
1703    normal=(rand_ranged(-1 + _eps, 1 - _eps, (2, 3)),),)
1704
1705ArctanhTester = makeBroadcastTester(
1706    op=tensor.arctanh,
1707    expected=upcast_float16_ufunc(np.arctanh),
1708    good=_good_broadcast_unary_arctanh,
1709    grad=_grad_broadcast_unary_arctanh)
1710ArctanhInplaceTester = makeBroadcastTester(
1711    op=inplace.arctanh_inplace,
1712    expected=np.arctanh,
1713    good=copymod(_good_broadcast_unary_arctanh, without=['integers', 'int8', 'uint8', 'uint16']),
1714    inplace=True)
1715
1716
1717# We can't test it if scipy is not installed!
1718# Precomputing the result is brittle(it have been broken!)
1719# As if we do any modification to random number here,
1720# The input random number will change and the output!
1721if imported_scipy_special:
1722    expected_erf = scipy.special.erf
1723    expected_erfc = scipy.special.erfc
1724    expected_erfinv = scipy.special.erfinv
1725    expected_erfcinv = scipy.special.erfcinv
1726    expected_gamma = scipy.special.gamma
1727    expected_gammaln = scipy.special.gammaln
1728    expected_psi = scipy.special.psi
1729    expected_tri_gamma = partial(scipy.special.polygamma, 1)
1730    expected_chi2sf = scipy.stats.chi2.sf
1731    expected_j0 = scipy.special.j0
1732    expected_j1 = scipy.special.j1
1733    expected_jv = scipy.special.jv
1734    expected_i0 = scipy.special.i0
1735    expected_i1 = scipy.special.i1
1736    expected_iv = scipy.special.iv
1737    skip_scipy = False
1738    expected_erfcx = scipy.special.erfcx
1739else:
1740    expected_erf = []
1741    expected_erfc = []
1742    expected_erfcx = []
1743    expected_erfinv = []
1744    expected_erfcinv = []
1745    expected_gamma = []
1746    expected_gammaln = []
1747    expected_psi = []
1748    expected_tri_gamma = []
1749    expected_chi2sf = []
1750    expected_j0 = []
1751    expected_j1 = []
1752    expected_jv = []
1753    expected_i0 = []
1754    expected_i1 = []
1755    expected_iv = []
1756    skip_scipy = "scipy is not present"
1757
1758ErfTester = makeBroadcastTester(
1759    op=tensor.erf,
1760    expected=expected_erf,
1761    good=_good_broadcast_unary_normal,
1762    grad=_grad_broadcast_unary_normal,
1763    eps=2e-10,
1764    mode=mode_no_scipy,
1765    skip=skip_scipy)
1766ErfInplaceTester = makeBroadcastTester(
1767    op=inplace.erf_inplace,
1768    expected=expected_erf,
1769    good=_good_broadcast_unary_normal_float,
1770    mode=mode_no_scipy,
1771    eps=2e-10,
1772    inplace=True,
1773    skip=skip_scipy)
1774
1775ErfcTester = makeBroadcastTester(
1776    op=tensor.erfc,
1777    expected=expected_erfc,
1778    good=_good_broadcast_unary_normal_float_no_complex,
1779    grad=_grad_broadcast_unary_normal,
1780    eps=2e-10,
1781    mode=mode_no_scipy,
1782    skip=skip_scipy)
1783ErfcInplaceTester = makeBroadcastTester(
1784    op=inplace.erfc_inplace,
1785    expected=expected_erfc,
1786    good=_good_broadcast_unary_normal_float_no_complex,
1787    eps=2e-10,
1788    mode=mode_no_scipy,
1789    inplace=True,
1790    skip=skip_scipy)
1791
1792ErfcxTester = makeBroadcastTester(
1793    op=tensor.erfcx,
1794    expected=expected_erfcx,
1795    good=_good_broadcast_unary_normal_float_no_complex_small_neg_range,
1796    grad=_grad_broadcast_unary_normal_small_neg_range,
1797    eps=2e-10,
1798    mode=mode_no_scipy,
1799    skip=skip_scipy)
1800ErfcxInplaceTester = makeBroadcastTester(
1801    op=inplace.erfcx_inplace,
1802    expected=expected_erfcx,
1803    good=_good_broadcast_unary_normal_float_no_complex_small_neg_range,
1804    eps=2e-10,
1805    mode=mode_no_scipy,
1806    inplace=True,
1807    skip=skip_scipy)
1808
1809ErfinvTester = makeBroadcastTester(
1810    op=tensor.erfinv,
1811    expected=expected_erfinv,
1812    good={'normal': [rand_ranged(-.9, .9, (2, 3))],
1813          'empty': [np.asarray([], dtype=config.floatX)]},
1814    grad=_grad_broadcast_unary_abs1_no_complex,
1815    eps=2e-10,
1816    mode=mode_no_scipy,
1817    skip=skip_scipy)
1818
1819ErfcinvTester = makeBroadcastTester(
1820    op=tensor.erfcinv,
1821    expected=expected_erfcinv,
1822    good={'normal': [rand_ranged(0.001, 1.9, (2, 3))],
1823          'empty': [np.asarray([], dtype=config.floatX)]},
1824    grad=_grad_broadcast_unary_0_2_no_complex,
1825    eps=2e-10,
1826    mode=mode_no_scipy,
1827    skip=skip_scipy)
1828
1829_good_broadcast_unary_gammaln = dict(
1830    normal=(rand_ranged(-1 + 1e-2, 10, (2, 3)),),
1831    empty=(np.asarray([], dtype=config.floatX),),
1832    int=(randint_ranged(1, 10, (2, 3)),),
1833    uint8=(randint_ranged(1, 6, (2, 3)).astype('uint8'),),
1834    uint16=(randint_ranged(1, 10, (2, 3)).astype('uint16'),),
1835    uint64=(randint_ranged(1, 10, (2, 3)).astype('uint64'),))
1836_grad_broadcast_unary_gammaln = dict(
1837    # smaller range as our grad method does not estimate it well enough.
1838    normal=(rand_ranged(1e-1, 8, (2, 3)),),)
1839
1840GammaTester = makeBroadcastTester(
1841    op=tensor.gamma,
1842    expected=expected_gamma,
1843    good=_good_broadcast_unary_gammaln,
1844    grad=_grad_broadcast_unary_gammaln,
1845    mode=mode_no_scipy,
1846    eps=1e-5,
1847    skip=skip_scipy)
1848GammaInplaceTester = makeBroadcastTester(
1849    op=inplace.gamma_inplace,
1850    expected=expected_gamma,
1851    good=_good_broadcast_unary_gammaln,
1852    mode=mode_no_scipy,
1853    eps=1e-5,
1854    inplace=True,
1855    skip=skip_scipy)
1856
1857GammalnTester = makeBroadcastTester(
1858    op=tensor.gammaln,
1859    expected=expected_gammaln,
1860    good=_good_broadcast_unary_gammaln,
1861    grad=_grad_broadcast_unary_gammaln,
1862    eps=2e-10,
1863    mode=mode_no_scipy,
1864    skip=skip_scipy)
1865GammalnInplaceTester = makeBroadcastTester(
1866    op=inplace.gammaln_inplace,
1867    expected=expected_gammaln,
1868    good=_good_broadcast_unary_gammaln,
1869    eps=2e-10,
1870    mode=mode_no_scipy,
1871    inplace=True,
1872    skip=skip_scipy)
1873
1874_good_broadcast_unary_psi = dict(
1875    normal=(rand_ranged(1, 10, (2, 3)),),
1876    empty=(np.asarray([], dtype=config.floatX),),
1877    int=(randint_ranged(1, 10, (2, 3)),),
1878    uint8=(randint_ranged(1, 10, (2, 3)).astype('uint8'),),
1879    uint16=(randint_ranged(1, 10, (2, 3)).astype('uint16'),))
1880
1881PsiTester = makeBroadcastTester(
1882    op=tensor.psi,
1883    expected=expected_psi,
1884    good=_good_broadcast_unary_psi,
1885    eps=2e-10,
1886    mode=mode_no_scipy,
1887    skip=skip_scipy)
1888PsiInplaceTester = makeBroadcastTester(
1889    op=inplace.psi_inplace,
1890    expected=expected_psi,
1891    good=_good_broadcast_unary_psi,
1892    eps=2e-10,
1893    mode=mode_no_scipy,
1894    inplace=True,
1895    skip=skip_scipy)
1896
1897_good_broadcast_unary_tri_gamma = _good_broadcast_unary_psi
1898
1899TriGammaTester = makeBroadcastTester(
1900    op=tensor.tri_gamma,
1901    expected=expected_tri_gamma,
1902    good=_good_broadcast_unary_psi,
1903    eps=2e-8,
1904    mode=mode_no_scipy,
1905    skip=skip_scipy)
1906TriGammaInplaceTester = makeBroadcastTester(
1907    op=inplace.tri_gamma_inplace,
1908    expected=expected_tri_gamma,
1909    good=_good_broadcast_unary_tri_gamma,
1910    eps=2e-8,
1911    mode=mode_no_scipy,
1912    inplace=True,
1913    skip=skip_scipy)
1914
1915# chi2sf takes two inputs, a value (x) and a degrees of freedom (k).
1916# not sure how to deal with that here...
1917
1918_good_broadcast_unary_chi2sf = dict(
1919    normal=(rand_ranged(1, 10, (2, 3)),
1920            np.asarray(1, dtype=config.floatX)),
1921    empty=(np.asarray([], dtype=config.floatX),
1922           np.asarray(1, dtype=config.floatX)),
1923    integers=(randint_ranged(1, 10, (2, 3)),
1924              np.asarray(1, dtype=config.floatX)),
1925    uint8=(randint_ranged(1, 10, (2, 3)).astype('uint8'),
1926           np.asarray(1, dtype=config.floatX)),
1927    uint16=(randint_ranged(1, 10, (2, 3)).astype('uint16'),
1928            np.asarray(1, dtype=config.floatX)))
1929
1930Chi2SFTester = makeBroadcastTester(
1931    op=tensor.chi2sf,
1932    expected=expected_chi2sf,
1933    good=_good_broadcast_unary_chi2sf,
1934    eps=2e-10,
1935    mode=mode_no_scipy,
1936    skip=skip_scipy,
1937    name='Chi2SF')
1938
1939Chi2SFInplaceTester = makeBroadcastTester(
1940    op=inplace.chi2sf_inplace,
1941    expected=expected_chi2sf,
1942    good=_good_broadcast_unary_chi2sf,
1943    eps=2e-10,
1944    mode=mode_no_scipy,
1945    inplace=True,
1946    skip=skip_scipy,
1947    name='Chi2SF')
1948
1949_good_broadcast_unary_bessel = dict(
1950    normal=(rand_ranged(-10, 10, (2, 3)),),
1951    empty=(np.asarray([], dtype=config.floatX),),
1952    int=(randint_ranged(-10, 10, (2, 3)),),
1953    uint8=(randint_ranged(0, 10, (2, 3)).astype('uint8'),),
1954    uint16=(randint_ranged(0, 10, (2, 3)).astype('uint16'),))
1955
1956_grad_broadcast_unary_bessel = dict(
1957    normal=(rand_ranged(-10., 10., (2, 3)),),)
1958
1959_good_broadcast_binary_bessel = dict(
1960    normal=(rand_ranged(-5, 5, (2, 3)),
1961            rand_ranged(0, 10, (2, 3))),
1962    empty=(np.asarray([], dtype=config.floatX),
1963           np.asarray([], dtype=config.floatX)),
1964    integers=(randint_ranged(-5, 5, (2, 3)),
1965              randint_ranged(-10, 10, (2, 3))),
1966    uint8=(randint_ranged(0, 5, (2, 3)).astype('uint8'),
1967           randint_ranged(0, 10, (2, 3)).astype('uint8')),
1968    uint16=(randint_ranged(0, 5, (2, 3)).astype('uint16'),
1969            randint_ranged(0, 10, (2, 3)).astype('uint16')))
1970
1971_grad_broadcast_binary_bessel = dict(
1972    normal=(rand_ranged(1, 5, (2, 3)),
1973            rand_ranged(0, 10, (2, 3))))
1974
1975J0Tester = makeBroadcastTester(
1976    op=tensor.j0,
1977    expected=expected_j0,
1978    good=_good_broadcast_unary_bessel,
1979    grad=_grad_broadcast_unary_bessel,
1980    eps=2e-10,
1981    mode=mode_no_scipy,
1982    skip=skip_scipy)
1983
1984J0InplaceTester = makeBroadcastTester(
1985    op=inplace.j0_inplace,
1986    expected=expected_j0,
1987    good=_good_broadcast_unary_bessel,
1988    eps=2e-10,
1989    mode=mode_no_scipy,
1990    inplace=True,
1991    skip=skip_scipy)
1992
1993J1Tester = makeBroadcastTester(
1994    op=tensor.j1,
1995    expected=expected_j1,
1996    good=_good_broadcast_unary_bessel,
1997    grad=_grad_broadcast_unary_bessel,
1998    eps=2e-10,
1999    mode=mode_no_scipy,
2000    skip=skip_scipy)
2001
2002J1InplaceTester = makeBroadcastTester(
2003    op=inplace.j1_inplace,
2004    expected=expected_j1,
2005    good=_good_broadcast_unary_bessel,
2006    eps=2e-10,
2007    mode=mode_no_scipy,
2008    inplace=True,
2009    skip=skip_scipy)
2010
2011JvTester = makeBroadcastTester(
2012    op=tensor.jv,
2013    expected=expected_jv,
2014    good=_good_broadcast_binary_bessel,
2015    eps=2e-10,
2016    mode=mode_no_scipy,
2017    skip=skip_scipy)
2018
2019JvInplaceTester = makeBroadcastTester(
2020    op=inplace.jv_inplace,
2021    expected=expected_jv,
2022    good=_good_broadcast_binary_bessel,
2023    eps=2e-10,
2024    mode=mode_no_scipy,
2025    inplace=True,
2026    skip=skip_scipy)
2027
2028
2029def test_verify_jv_grad():
2030    # Verify Jv gradient.
2031    # Implemented separately due to need to fix first input for which grad is
2032    # not defined.
2033    if skip_scipy:
2034        raise SkipTest("SciPy needed")
2035    v_val, x_val = _grad_broadcast_binary_bessel['normal']
2036
2037    def fixed_first_input_jv(x):
2038        return tensor.jv(v_val, x)
2039
2040    utt.verify_grad(fixed_first_input_jv, [x_val])
2041
2042
2043I0Tester = makeBroadcastTester(
2044    op=tensor.i0,
2045    expected=expected_i0,
2046    good=_good_broadcast_unary_bessel,
2047    grad=_grad_broadcast_unary_bessel,
2048    eps=2e-10,
2049    mode=mode_no_scipy,
2050    skip=skip_scipy)
2051
2052I0InplaceTester = makeBroadcastTester(
2053    op=inplace.i0_inplace,
2054    expected=expected_i0,
2055    good=_good_broadcast_unary_bessel,
2056    eps=2e-10,
2057    mode=mode_no_scipy,
2058    inplace=True,
2059    skip=skip_scipy)
2060
2061I1Tester = makeBroadcastTester(
2062    op=tensor.i1,
2063    expected=expected_i1,
2064    good=_good_broadcast_unary_bessel,
2065    grad=_grad_broadcast_unary_bessel,
2066    eps=2e-10,
2067    mode=mode_no_scipy,
2068    skip=skip_scipy)
2069
2070I1InplaceTester = makeBroadcastTester(
2071    op=inplace.i1_inplace,
2072    expected=expected_i1,
2073    good=_good_broadcast_unary_bessel,
2074    eps=2e-10,
2075    mode=mode_no_scipy,
2076    inplace=True,
2077    skip=skip_scipy)
2078
2079IvTester = makeBroadcastTester(
2080    op=tensor.iv,
2081    expected=expected_iv,
2082    good=_good_broadcast_binary_bessel,
2083    eps=2e-10,
2084    mode=mode_no_scipy,
2085    skip=skip_scipy)
2086
2087IvInplaceTester = makeBroadcastTester(
2088    op=inplace.iv_inplace,
2089    expected=expected_iv,
2090    good=_good_broadcast_binary_bessel,
2091    eps=2e-10,
2092    mode=mode_no_scipy,
2093    inplace=True,
2094    skip=skip_scipy)
2095
2096
2097def test_verify_iv_grad():
2098    # Verify Iv gradient.
2099    # Implemented separately due to need to fix first input for which grad is
2100    # not defined.
2101    if skip_scipy:
2102        raise SkipTest("SciPy needed")
2103
2104    v_val, x_val = _grad_broadcast_binary_bessel['normal']
2105
2106    def fixed_first_input_iv(x):
2107        return tensor.iv(v_val, x)
2108
2109    utt.verify_grad(fixed_first_input_iv, [x_val])
2110
2111
2112ZerosLikeTester = makeBroadcastTester(
2113    op=tensor.zeros_like,
2114    expected=np.zeros_like,
2115    good=_good_broadcast_unary_normal,
2116    grad=_grad_broadcast_unary_normal,
2117    name='ZerosLike')
2118
2119OnesLikeTester = makeBroadcastTester(
2120    op=tensor.ones_like,
2121    expected=np.ones_like,
2122    good=_good_broadcast_unary_normal,
2123    grad=_grad_broadcast_unary_normal,
2124    name='OnesLike')
2125
2126# Complex operations
2127_good_complex_from_polar = dict(
2128    same_shapes=(abs(rand(2, 3)), rand(2, 3)),
2129    not_same_dimensions=(abs(rand(2, 2)), rand(2)),
2130    scalar=(abs(rand(2, 3)), rand(1, 1)),
2131    row=(abs(rand(2, 3)), rand(1, 3)),
2132    column=(abs(rand(2, 3)), rand(2, 1)),
2133    integers=(abs(randint(2, 3)), randint(2, 3)),
2134    empty=(np.asarray([], dtype=config.floatX),
2135           np.asarray([1], dtype=config.floatX)),)
2136_grad_complex_from_polar = dict(
2137    same_shapes=(abs(rand(2, 3)), rand(2, 3)),
2138    scalar=(abs(rand(2, 3)), rand(1, 1)),
2139    row=(abs(rand(2, 3)), rand(1, 3)),
2140    column=(abs(rand(2, 3)), rand(2, 1)))
2141
2142ComplexFromPolarTester = makeBroadcastTester(
2143    op=tensor.complex_from_polar,
2144    expected=lambda r, theta: r * np.cos(theta) + 1j * r * np.sin(theta),
2145    good=_good_complex_from_polar)
2146
2147ConjTester = makeBroadcastTester(
2148    op=tensor.conj,
2149    expected=np.conj,
2150    good=_good_broadcast_unary_normal)
2151ConjInplaceTester = makeBroadcastTester(
2152    op=inplace.conj_inplace,
2153    expected=np.conj,
2154    good=_good_broadcast_unary_normal,
2155    inplace=True)
2156
2157
2158DotTester = makeTester(
2159    name='DotTester',
2160    op=dot,
2161    expected=lambda x, y: np.dot(x, y),
2162    checks={},
2163    good=dict(correct1=(rand(5, 7), rand(7, 5)),
2164              correct2=(rand(5, 7), rand(7, 9)),
2165              correct3=(rand(5, 7), rand(7)),
2166              correct4=(rand(5), rand(5, 7)),
2167              mixed1=(rand(5).astype('float32'), rand(5, 7)),
2168              mixed2=(rand(5).astype('float64'), rand(5, 7)),
2169              complex1=(randcomplex(5, 7), randcomplex(7)),
2170              complex2=(rand(5, 7), randcomplex(7)),
2171              complex3=(randcomplex(5, 7), rand(7)),
2172              empty1=(np.asarray([], dtype=config.floatX),
2173                      np.asarray([], dtype=config.floatX)),
2174              empty2=(rand(5, 0), rand(0, 2)),
2175              empty3=(rand(0, 5), rand(5, 0)),
2176              ),
2177    bad_build=dict(),
2178    bad_runtime=dict(bad1=(rand(5, 7), rand(5, 7)),
2179                     bad2=(rand(5, 7), rand(8, 3))))
2180
2181BatchedDotTester = makeTester(
2182    name='BatchedDotTester',
2183    op=batched_dot,
2184    expected=(lambda xs, ys:
2185              np.asarray(
2186                  list(x * y if x.ndim == 0 or y.ndim == 0 else np.dot(x, y)
2187                       for x, y in zip(xs, ys)),
2188                  dtype=theano.scalar.upcast(xs.dtype, ys.dtype))),
2189    checks={},
2190    grad=dict(correct1=(rand(3, 5, 7), rand(3, 7, 5)),
2191              correct2=(rand(3, 5, 7), rand(3, 7, 9)),
2192              correct3=(rand(3, 5, 7), rand(3, 7)),
2193              correct4=(rand(3, 5), rand(3, 5, 7)),
2194              correct5=(rand(3), rand(3, 5, 7)),
2195              correct6=(rand(3, 5), rand(3)),
2196              correct7=(rand(3, 5), rand(3, 5)),
2197              correct8=(rand(3), rand(3)),
2198              correct9=(rand(3, 5, 7, 11), rand(3)),
2199              correct10=(rand(3, 2, 6, 5), rand(3, 5)),
2200              correct11=(rand(3, 2, 6, 5), rand(3, 5, 7)),
2201              correct12=(rand(3, 2, 6, 5), rand(3, 7, 5, 8)),
2202              mixed1=(rand(3, 5).astype('float32'),
2203                      rand(3, 5, 7)),
2204              mixed2=(rand(3, 5).astype('float64'),
2205                      rand(3, 5, 7))),
2206    good=dict(correct1=(rand(3, 5, 7), rand(3, 7, 5)),
2207              correct2=(rand(3, 5, 7), rand(3, 7, 9)),
2208              correct3=(rand(3, 5, 7), rand(3, 7)),
2209              correct4=(rand(3, 5), rand(3, 5, 7)),
2210              correct5=(rand(3), rand(3, 5, 7)),
2211              correct6=(rand(3, 5), rand(3)),
2212              correct7=(rand(3, 5), rand(3, 5)),
2213              correct8=(rand(3), rand(3)),
2214              correct9=(rand(3, 5, 7, 11), rand(3)),
2215              correct10=(rand(3, 7, 11, 5), rand(3, 5)),
2216              correct11=(rand(3, 7, 11, 5), rand(3, 5, 13)),
2217              correct12=(rand(3, 7, 11, 5), rand(3, 13, 5, 17)),
2218              mixed1=(rand(3, 5).astype('float32'),
2219                      rand(3, 5, 7)),
2220              mixed2=(rand(3, 5).astype('float64'),
2221                      rand(3, 5, 7))),
2222    bad_build=dict(no_batch_axis2=(rand(), rand(3, 5)),
2223                   no_batch_axis3=(rand(3, 5), rand())),
2224    bad_runtime=dict(batch_dim_mismatch1=(rand(2, 5, 7), rand(3, 7, 9)),
2225                     batch_dim_mismatch2=(rand(3, 5, 7), rand(2, 7, 9)),
2226                     batch_dim_mismatch3=(rand(3), rand(5)),
2227                     bad_dim1=(rand(3, 5, 7), rand(3, 5, 7)),
2228                     bad_dim2=(rand(3, 5, 7), rand(3, 8, 3)),
2229                     bad_dim3=(rand(3, 5), rand(3, 7)),
2230                     bad_dim4=(rand(3, 5, 7, 11), rand(3, 5)),
2231                     bad_dim5=(rand(3, 5, 7, 11), rand(3, 5, 13)),
2232                     bad_dim6=(rand(3, 5, 7, 11), rand(3, 13, 5, 17))))
2233
2234
2235def _numpy_second(x, y):
2236    return np.broadcast_arrays(x, y)[1]
2237
2238# Don't forget to modify the two lines after!
2239ALL_DTYPES = ('int8', 'int16', 'int32', 'int64', 'float32', 'float64',
2240              'uint8', 'uint16',
2241              'complex64', 'complex128')
2242REAL_DTYPES = ALL_DTYPES[:6]
2243COMPLEX_DTYPES = ALL_DTYPES[-2:]
2244
2245
2246def multi_dtype_checks(shape1, shape2, dtypes=ALL_DTYPES, nameprefix=''):
2247    for dtype1, dtype2 in itertools.combinations(dtypes, 2):
2248        name1 = '%s_%s_%s' % (nameprefix, dtype1, dtype2)
2249        name2 = '%s_%s_%s' % (nameprefix, dtype2, dtype1)
2250        obj1 = rand_of_dtype(shape1, dtype1)
2251        obj2 = rand_of_dtype(shape2, dtype2)
2252        yield (name1, (obj1, obj2))
2253        yield (name2, (obj2, obj1))
2254
2255
2256def multi_dtype_cast_checks(shape, dtypes=ALL_DTYPES, nameprefix=''):
2257    for dtype1, dtype2 in itertools.combinations(dtypes, 2):
2258        name1 = '%s_%s_%s' % (nameprefix, dtype1, dtype2)
2259        name2 = '%s_%s_%s' % (nameprefix, dtype2, dtype1)
2260        obj1 = rand_of_dtype(shape, dtype1)
2261        obj2 = rand_of_dtype(shape, dtype2)
2262        yield (name1, (obj1, dtype2))
2263        yield (name2, (obj2, dtype1))
2264
2265SecondBroadcastTester = makeTester(
2266    name='SecondBroadcastTester',
2267    op=second,
2268    expected=_numpy_second,
2269    good=dict(itertools.chain(
2270        multi_dtype_checks((4, 5), (5,)),
2271        multi_dtype_checks((2, 3, 2), (3, 2)),
2272        multi_dtype_checks((2, 3, 2), (2,)),
2273        )),
2274    # I can't think of any way to make this fail at build time
2275    # Just some simple smoke tests
2276    bad_runtime=dict(
2277        fail1=(rand(5, 4), rand(5)),
2278        fail2=(rand(3, 2, 3), rand(6, 9)),
2279        fail3=(randint(6, 2, 9), rand(3, 2)),
2280        )
2281    )
2282
2283# We exclude local_fill_to_alloc because it optimizes the "second" node
2284# away from the graph.
2285SecondSameRankTester = makeTester(
2286    name='SecondSameRankTester',
2287    op=second,
2288    expected=_numpy_second,
2289    good=dict(itertools.chain(
2290        multi_dtype_checks((4, 5), (4, 5)),
2291        multi_dtype_checks((1, 2), (3, 2)),
2292        multi_dtype_checks((3, 2), (1, 2)),
2293        )),
2294    # These sizes are not broadcastable to one another
2295    # and SHOULD raise an error, but currently don't.
2296    bad_runtime=dict(itertools.chain(
2297        multi_dtype_checks((4, 5), (5, 4)),
2298        multi_dtype_checks((1, 5), (5, 4)),
2299        )),
2300    mode=get_default_mode().excluding(
2301        'local_fill_to_alloc',
2302        'local_useless_fill')
2303    )
2304
2305# Alloc
2306AllocTester = makeBroadcastTester(
2307    name='AllocTester',
2308    op=alloc,
2309    expected=(lambda x, *shp: np.zeros(shp, dtype=x.dtype) + x),
2310    good=dict(
2311        correct01=(rand(), np.int32(7)),
2312        correct01_bcast=(rand(1), np.int32(7)),
2313        correct02=(rand(), np.int32(4), np.int32(7)),
2314        correct12=(rand(7), np.int32(4), np.int32(7)),
2315        correct13=(rand(7), np.int32(2), np.int32(4), np.int32(7)),
2316        correct23=(rand(4, 7), np.int32(2), np.int32(4), np.int32(7)),
2317        correctb1=(rand(1, 7), np.int32(4), np.int32(7)),
2318        correctb2=(rand(1, 7), np.int32(2), np.int32(4), np.int32(7)),
2319        correctb3=(rand(7, 1), np.int32(7), np.int32(4)),
2320        correctb4=(rand(7, 1), np.int32(2), np.int32(7), np.int32(4)),
2321        ),
2322    bad_runtime=dict(
2323        bad_shape12=(rand(7), np.int32(7), np.int32(5)),
2324        ),
2325    bad_build=dict(
2326        vec=(rand(1), [np.int32(2)]),
2327        too_big32=(rand(6, 2, 4), np.int32(6), np.int32(2)),
2328        too_big32b=(rand(6, 2, 4), np.int32(6), np.int32(4)),
2329        too_big32c=(rand(6, 2, 4), np.int32(2), np.int32(4)),
2330        too_big32d=(rand(6, 2, 4), np.int32(2), np.int32(6)),
2331        too_big32e=(rand(6, 2, 4), np.int32(4), np.int32(6)),
2332        too_big32f=(rand(6, 2, 4), np.int32(4), np.int32(2)),
2333        ),
2334    )
2335
2336# Since not all inputs of Alloc are differentiable, we need different testers
2337s1, s2, s3 = randint_ranged(1, 13, (3,))
2338# alloc a scalar into a vector
2339Alloc01GradTester = makeBroadcastTester(
2340    name='Alloc01GradTester',
2341    op=(lambda x: alloc(x, s1)),
2342    expected=(lambda x: np.zeros((s1,), dtype=x.dtype) + x),
2343    grad=dict(
2344        x1=(rand(),),
2345        x2=(rand(),),
2346        x3=(rand(),),
2347        ),
2348    )
2349
2350# alloc a vector into a tensor3
2351Alloc13GradTester = makeBroadcastTester(
2352    name='Alloc13GradTester',
2353    op=(lambda x: alloc(x, s1, s2, s3)),
2354    expected=(lambda x: np.zeros((s1, s2, s3), dtype=x.dtype) + x),
2355    grad=dict(
2356        x1=(rand(s3),),
2357        x2=(rand(s3),),
2358        x3=(rand(s3),),
2359        ),
2360    )
2361
2362# unbroadcast a row to a matrix
2363Allocb1GradTester = makeBroadcastTester(
2364    name='Allocb1GradTester',
2365    op=lambda x: alloc(x, s1, s2),
2366    expected=(lambda x: np.zeros((s1, s2), dtype=x.dtype) + x),
2367    grad=dict(
2368        x1=(rand(1, s2),),
2369        x2=(rand(1, s2),),
2370        x3=(rand(1, s2),),
2371    ),
2372)
2373
2374# unbroadcast a row to a tensor3
2375Allocb2GradTester = makeBroadcastTester(
2376    name='Allocb2GradTester',
2377    op=lambda x: alloc(x, s1, s2, s3),
2378    expected=(lambda x: np.zeros((s1, s2, s3), dtype=x.dtype) + x),
2379    grad=dict(
2380        x1=(rand(1, s3),),
2381        x2=(rand(1, s3),),
2382        x3=(rand(1, s3),),
2383    ),
2384)
2385
2386# unbroadcast a col to a matrix
2387Allocb3GradTester = makeBroadcastTester(
2388    name='Allocb3GradTester',
2389    op=lambda x: alloc(x, s1, s2),
2390    expected=(lambda x: np.zeros((s1, s2), dtype=x.dtype) + x),
2391    grad=dict(
2392        x1=(rand(s1, 1),),
2393        x2=(rand(s1, 1),),
2394        x3=(rand(s1, 1),),
2395    ),
2396)
2397
2398# unbroadcast a col to a tensor3
2399Allocb4GradTester = makeBroadcastTester(
2400    name='Allocb4GradTester',
2401    op=lambda x: alloc(x, s1, s2, s3),
2402    expected=(lambda x: np.zeros((s1, s2, s3), dtype=x.dtype) + x),
2403    grad=dict(
2404        x1=(rand(s2, 1),),
2405        x2=(rand(s2, 1),),
2406        x3=(rand(s2, 1),),
2407    ),
2408)
2409
2410
2411# Partial un broadcast of a dimshuffled input
2412AllocDimshuffleGradTester = makeBroadcastTester(
2413    name='Allocb4GradTester',
2414    op=lambda x: alloc(x.dimshuffle('x', 'x', 0), 1, s2, s3),
2415    expected=(lambda x: np.zeros((1, s2, s3), dtype=x.dtype) + x),
2416    grad=dict(
2417        x1=(rand(s3),),
2418        x2=(rand(s3),),
2419        x3=(rand(s3),),
2420    ),
2421)
2422AllocDimshuffleGradTester2 = makeBroadcastTester(
2423    name='Allocb4GradTester',
2424    op=lambda x: alloc(x.dimshuffle('x', 0), 1, s2, s3),
2425    expected=(lambda x: np.zeros((1, s2, s3), dtype=x.dtype) + x),
2426    grad=dict(
2427        x1=(rand(s3),),
2428        x2=(rand(s3),),
2429        x3=(rand(s3),),
2430    ),
2431)
2432
2433
2434class ApplyDefaultTestOp(theano.Op):
2435    def __init__(self, id):
2436        self.default_output = id
2437
2438    def make_node(self, x):
2439        x = theano.tensor.as_tensor_variable(x)
2440        return theano.Apply(self, [x], [x.type()])
2441
2442
2443class TestAsTensorVariable(unittest.TestCase):
2444    # Unit test for ensuring that as_tensor_variable handles Apply objects
2445    # correctly and removes leading broadcastable dimensions when possible.
2446    def setUp(self):
2447        self.x = tensor.scalar('x')
2448
2449    def test_one_output(self):
2450        good_apply_var = ApplyDefaultTestOp(0).make_node(self.x)
2451        as_tensor_variable(good_apply_var)
2452
2453    def test_below_zero_output(self):
2454        bad_apply_var = ApplyDefaultTestOp(-1).make_node(self.x)
2455        self.assertRaises(AttributeError, as_tensor_variable, bad_apply_var)
2456
2457    def test_above_output_len(self):
2458        bad_apply_var = ApplyDefaultTestOp(2).make_node(self.x)
2459        self.assertRaises(AttributeError, as_tensor_variable, bad_apply_var)
2460
2461    def test_list(self):
2462        bad_apply_var = ApplyDefaultTestOp([0, 1]).make_node(self.x)
2463        self.assertRaises(AttributeError, as_tensor_variable, bad_apply_var)
2464
2465    def test_strip_leading_broadcastable(self):
2466        x = tensor.TensorType(config.floatX, (True, False))('x')
2467        x = as_tensor_variable(x, ndim=1)
2468        assert(x.ndim == 1)
2469
2470        x = tensor.matrix('x', dtype=config.floatX)
2471        self.assertRaises(ValueError, as_tensor_variable, x, ndim=1)
2472
2473
2474class TestAlloc(unittest.TestCase):
2475    dtype = config.floatX
2476    mode = mode_opt
2477    shared = staticmethod(theano.shared)
2478    allocs = [tensor.Alloc()] * 3
2479
2480    def setUp(self):
2481        self.rng = np.random.RandomState(seed=utt.fetch_seed())
2482
2483    def test_alloc_constant_folding(self):
2484        test_params = np.asarray(self.rng.randn(50 * 60),
2485                                 self.dtype)
2486
2487        some_vector = vector('some_vector', dtype=self.dtype)
2488        some_matrix = some_vector.reshape((60, 50))
2489        variables = self.shared(np.ones((50,), dtype=self.dtype))
2490        idx = tensor.constant(np.arange(50))
2491
2492        for alloc_, (subtensor, n_alloc) in zip(self.allocs, [
2493                # IncSubtensor1
2494                (some_matrix[:60], 2),
2495                # AdvancedIncSubtensor1
2496                (some_matrix[arange(60)], 2),
2497                # AdvancedIncSubtensor
2498                (some_matrix[idx, idx], 1)
2499        ]):
2500            derp = sum(dot(subtensor, variables))
2501
2502            fobj = theano.function([some_vector], derp, mode=self.mode)
2503            grad_derp = theano.grad(derp, some_vector)
2504            fgrad = theano.function([some_vector], grad_derp,
2505                                    mode=self.mode)
2506
2507            topo_obj = fobj.maker.fgraph.toposort()
2508            assert np.sum([isinstance(node.op, type(alloc_))
2509                           for node in topo_obj]) == 0
2510
2511            topo_grad = fgrad.maker.fgraph.toposort()
2512            assert np.sum([isinstance(node.op, type(alloc_))
2513                           for node in topo_grad]) == n_alloc, (
2514                               alloc_, subtensor, n_alloc, topo_grad)
2515            fobj(test_params)
2516            fgrad(test_params)
2517
2518    def test_alloc_output(self):
2519        val = tensor.constant(self.rng.randn(1, 1), dtype=self.dtype)
2520        for alloc_ in self.allocs:
2521            # The output is the result of the alloc operation,
2522            # we do not want it to be constant-folded
2523            out = alloc_(val, 50, 60)
2524
2525            f = theano.function([], out, mode=self.mode)
2526            topo = f.maker.fgraph.toposort()
2527            assert np.sum([isinstance(node.op, type(alloc_))
2528                           for node in topo]) == 1
2529            assert not isinstance(topo[0].op, DeepCopyOp)
2530
2531    def test_ones(self):
2532        for shp in [[], 1, [1], [1, 2], [1, 2, 3]]:
2533            ones = theano.function([], [tensor.ones(shp)], mode=self.mode)
2534            assert np.allclose(ones(), np.ones(shp))
2535
2536        # scalar doesn't have to be provided as input
2537        x = scalar()
2538        shp = []
2539        ones_scalar = theano.function([], [tensor.ones(x.shape)],
2540                                      mode=self.mode)
2541        assert np.allclose(ones_scalar(), np.ones(shp))
2542
2543        for (typ, shp) in [(vector, [3]), (matrix, [3, 4])]:
2544            x = typ()
2545            ones_tensor = theano.function([x], [tensor.ones(x.shape)],
2546                                          mode=self.mode)
2547            inp = np.zeros(shp, dtype=config.floatX)
2548            assert np.allclose(ones_tensor(inp),
2549                               np.ones(shp))
2550
2551    def test_zeros(self):
2552        for shp in [[], 1, [1], [1, 2], [1, 2, 3]]:
2553            zeros = theano.function([], [tensor.zeros(shp)],
2554                                    mode=self.mode)
2555            assert np.allclose(zeros(), np.zeros(shp))
2556
2557        # scalar doesn't have to be provided as input
2558        x = scalar()
2559        shp = []
2560        zeros_scalar = theano.function([], [tensor.zeros(x.shape)],
2561                                       mode=self.mode)
2562        assert np.allclose(zeros_scalar(), np.zeros(shp))
2563
2564        for (typ, shp) in [(vector, [3]), (matrix, [3, 4])]:
2565            x = typ()
2566            zeros_tensor = theano.function([x], [tensor.zeros(x.shape)],
2567                                           mode=self.mode)
2568            inp = np.zeros(shp, dtype=config.floatX)
2569            assert np.allclose(zeros_tensor(inp),
2570                               np.zeros(shp))
2571
2572
2573# This is slow for the ('int8', 3) version.
2574def test_eye():
2575    def check(dtype, N, M_=None, k=0):
2576        # Theano does not accept None as a tensor.
2577        # So we must use a real value.
2578        M = M_
2579        # Currently DebugMode does not support None as inputs even if this is
2580        # allowed.
2581        if M is None and theano.config.mode in ['DebugMode', 'DEBUG_MODE']:
2582            M = N
2583        N_symb = tensor.iscalar()
2584        M_symb = tensor.iscalar()
2585        k_symb = tensor.iscalar()
2586        f = function([N_symb, M_symb, k_symb],
2587                     eye(N_symb, M_symb, k_symb, dtype=dtype))
2588        result = f(N, M, k)
2589        assert np.allclose(result, np.eye(N, M_, k, dtype=dtype))
2590        assert result.dtype == np.dtype(dtype)
2591    for dtype in ALL_DTYPES:
2592        yield check, dtype, 3
2593        # M != N, k = 0
2594        yield check, dtype, 3, 5
2595        yield check, dtype, 5, 3
2596        # N == M, k != 0
2597        yield check, dtype, 3, 3, 1
2598        yield check, dtype, 3, 3, -1
2599        # N < M, k != 0
2600        yield check, dtype, 3, 5, 1
2601        yield check, dtype, 3, 5, -1
2602        # N > M, k != 0
2603        yield check, dtype, 5, 3, 1
2604        yield check, dtype, 5, 3, -1
2605
2606
2607class test_triangle(unittest.TestCase):
2608    def test_tri(self):
2609        def check(dtype, N, M_=None, k=0):
2610            # Theano does not accept None as a tensor.
2611            # So we must use a real value.
2612            M = M_
2613            # Currently DebugMode does not support None as inputs even if this is
2614            # allowed.
2615            if M is None and theano.config.mode in ['DebugMode', 'DEBUG_MODE']:
2616                M = N
2617            N_symb = tensor.iscalar()
2618            M_symb = tensor.iscalar()
2619            k_symb = tensor.iscalar()
2620            f = function([N_symb, M_symb, k_symb],
2621                         tri(N_symb, M_symb, k_symb, dtype=dtype))
2622            result = f(N, M, k)
2623            self.assertTrue(
2624                np.allclose(result, np.tri(N, M_, k, dtype=dtype)))
2625            self.assertTrue(result.dtype == np.dtype(dtype))
2626        for dtype in ALL_DTYPES:
2627            yield check, dtype, 3
2628            # M != N, k = 0
2629            yield check, dtype, 3, 5
2630            yield check, dtype, 5, 3
2631            # N == M, k != 0
2632            yield check, dtype, 3, 3, 1
2633            yield check, dtype, 3, 3, -1
2634            # N < M, k != 0
2635            yield check, dtype, 3, 5, 1
2636            yield check, dtype, 3, 5, -1
2637            # N > M, k != 0
2638            yield check, dtype, 5, 3, 1
2639            yield check, dtype, 5, 3, -1
2640
2641    def test_tril_triu(self):
2642        def check_l(m, k=0):
2643            m_symb = matrix(dtype=m.dtype)
2644            k_symb = iscalar()
2645            f = function([m_symb, k_symb], tril(m_symb, k_symb))
2646            result = f(m, k)
2647            self.assertTrue(np.allclose(result, np.tril(m, k)))
2648            self.assertTrue(result.dtype == np.dtype(dtype))
2649
2650        def check_u(m, k=0):
2651            m_symb = matrix(dtype=m.dtype)
2652            k_symb = iscalar()
2653            f = function([m_symb, k_symb], triu(m_symb, k_symb))
2654            result = f(m, k)
2655            self.assertTrue(np.allclose(result, np.triu(m, k)))
2656            self.assertTrue(result.dtype == np.dtype(dtype))
2657
2658        for dtype in ALL_DTYPES:
2659            m = rand_of_dtype((10, 10), dtype)
2660            yield check_l, m, 0
2661            yield check_l, m, 1
2662            yield check_l, m, -1
2663
2664            yield check_u, m, 0
2665            yield check_u, m, 1
2666            yield check_u, m, -1
2667
2668            m = rand_of_dtype((10, 5), dtype)
2669            yield check_l, m, 0
2670            yield check_l, m, 1
2671            yield check_l, m, -1
2672
2673            yield check_u, m, 0
2674            yield check_u, m, 1
2675            yield check_u, m, -1
2676
2677
2678class test_nonzero(unittest.TestCase):
2679    def test_nonzero(self):
2680        def check(m):
2681            m_symb = theano.tensor.tensor(dtype=m.dtype,
2682                                          broadcastable=(False,) * m.ndim)
2683
2684            f_tuple = function([m_symb], nonzero(m_symb, return_matrix=False))
2685            f_matrix = function([m_symb], nonzero(m_symb, return_matrix=True))
2686
2687            self.assertTrue(np.allclose(f_matrix(m),
2688                                        np.vstack(np.nonzero(m))))
2689            for i, j in zip(f_tuple(m), np.nonzero(m)):
2690                self.assertTrue(np.allclose(i, j))
2691
2692        rand0d = np.array(rand())
2693        self.assertRaises(ValueError, check, rand0d)
2694
2695        rand1d = rand(8)
2696        rand1d[:4] = 0
2697        check(rand1d)
2698
2699        rand2d = rand(8, 9)
2700        rand2d[:4] = 0
2701        check(rand2d)
2702
2703        rand3d = rand(8, 9, 10)
2704        rand3d[:4] = 0
2705        check(rand3d)
2706
2707        rand4d = rand(8, 9, 10, 11)
2708        rand4d[:4] = 0
2709        check(rand4d)
2710
2711    def test_flatnonzero(self):
2712        def check(m):
2713            m_symb = theano.tensor.tensor(dtype=m.dtype,
2714                                          broadcastable=(False,) * m.ndim)
2715            f = function([m_symb], flatnonzero(m_symb))
2716            result = f(m)
2717            assert np.allclose(result, np.flatnonzero(m))
2718
2719        rand0d = np.array(rand())
2720        self.assertRaises(ValueError, check, rand0d)
2721
2722        rand1d = rand(8)
2723        rand1d[:4] = 0
2724        check(rand1d)
2725
2726        rand2d = rand(8, 9)
2727        rand2d[:4] = 0
2728        check(rand2d)
2729
2730        rand3d = rand(8, 9, 10)
2731        rand3d[:4] = 0
2732        check(rand3d)
2733
2734        rand4d = rand(8, 9, 10, 11)
2735        rand4d[:4] = 0
2736        check(rand4d)
2737
2738    def test_nonzero_values(self):
2739        def check(m):
2740            m_symb = theano.tensor.tensor(dtype=m.dtype,
2741                                          broadcastable=(False,) * m.ndim)
2742            f = function([m_symb], nonzero_values(m_symb))
2743            result = f(m)
2744            assert np.allclose(result, m[np.nonzero(m)])
2745
2746        rand0d = rand()
2747        self.assertRaises(ValueError, check, rand0d)
2748
2749        rand1d = rand(8)
2750        rand1d[:4] = 0
2751        check(rand1d)
2752
2753        rand2d = rand(8, 9)
2754        rand2d[:4] = 0
2755        check(rand2d)
2756
2757        rand3d = rand(8, 9, 10)
2758        rand3d[:4] = 0
2759        check(rand3d)
2760
2761        rand4d = rand(8, 9, 10, 11)
2762        rand4d[:4] = 0
2763        check(rand4d)
2764
2765
2766def test_identity():
2767    def check(dtype):
2768        obj = rand_of_dtype((2,), dtype)
2769        sym = tensor.vector(dtype=dtype)
2770        f = function([sym], tensor_copy(sym))
2771        assert np.all(obj == f(obj))
2772        assert obj.dtype == f(obj).dtype
2773        topo = f.maker.fgraph.toposort()
2774        assert len(topo) == 1
2775        if theano.config.mode != 'FAST_COMPILE':
2776            assert isinstance(topo[0].op, DeepCopyOp)
2777
2778    for dtype in ALL_DTYPES:
2779        yield check, dtype
2780
2781
2782class CastTester(unittest.TestCase):
2783    def test_good_between_real_types(self):
2784        good = itertools.chain(
2785            multi_dtype_cast_checks((2,), dtypes=REAL_DTYPES),
2786            # Casts from foo to foo
2787            [('%s_%s' % (rand_of_dtype((2,), dtype), dtype),
2788              (rand_of_dtype((2,), dtype), dtype))
2789             for dtype in ALL_DTYPES])
2790        for testname, (obj, dtype) in good:
2791            inp = tensor.vector(dtype=obj.dtype)
2792            out = tensor.cast(inp, dtype=dtype)
2793            f = function([inp], out)
2794            assert f(obj).dtype == np.dtype(dtype)
2795
2796            # Test astype too
2797            out2 = inp.astype(dtype=dtype)
2798            assert out2.type == out.type
2799
2800    def test_cast_from_real_to_complex(self):
2801        for real_dtype in REAL_DTYPES:
2802            for complex_dtype in COMPLEX_DTYPES:
2803                inp = tensor.vector(dtype=real_dtype)
2804                out = tensor.cast(inp, dtype=complex_dtype)
2805                f = function([inp], out)
2806                obj = rand_of_dtype((2, ), real_dtype)
2807                assert f(obj).dtype == np.dtype(complex_dtype)
2808
2809    def test_cast_from_complex_to_real_raises_error(self):
2810        for real_dtype in REAL_DTYPES:
2811            for complex_dtype in COMPLEX_DTYPES:
2812                inp = tensor.vector(dtype=real_dtype)
2813                self.assertRaises(TypeError, tensor.cast(
2814                    inp, dtype=complex_dtype))
2815
2816ClipTester = makeTester(
2817    name='ClipTester',
2818    op=clip,
2819    expected=lambda x, y, z: np.clip(x, y, z),
2820    good=dict(correct1=((5 * rand(5, 5)).astype('float32'),
2821                        np.array(-1, dtype='float32'),
2822                        np.array(1, dtype='float32')),
2823              correct2=((5 * rand(5, 5)).astype('float64'),
2824                        np.array(-1, dtype='float64'),
2825                        np.array(1, dtype='float64')),
2826              correct3=(randint(5, 5).astype('int8'),
2827                        np.array(-1, dtype='int8'),
2828                        np.array(1, dtype='int8')),
2829              correct4=(randint(5, 5).astype('int16'),
2830                        np.array(-1, dtype='int16'),
2831                        np.array(1, dtype='int16')),
2832              correct5=(randint(5, 5).astype('int32'),
2833                        np.array(-1, dtype='int32'),
2834                        np.array(1, dtype='int32')),
2835              correct6=(randint(5, 5).astype('int64'),
2836                        np.array(-1, dtype='int64'),
2837                        np.array(1, dtype='int64')),
2838              # min > max case moved below as numpy has changed
2839              correct8=(randint(0, 5).astype('uint8'),
2840                        np.array(2, dtype='uint8'),
2841                        np.array(4, dtype='uint8')),
2842              correct9=(randint(0, 5).astype('uint16'),
2843                        np.array(2, dtype='uint16'),
2844                        np.array(4, dtype='uint16')),)
2845    # I can't think of any way to make this fail at runtime
2846    )
2847
2848
2849# min > max case - numpy.clip has changed but we haven't
2850# https://github.com/Theano/Theano/issues/6715
2851BackwardsClipTester = makeTester(
2852    name='BackwardsClipTester',
2853    op=clip,
2854    expected=lambda x, y, z: np.where(x < y, y, np.minimum(x, z)),
2855    good=dict(correct7=((5 * rand(5, 5)).astype('float64'),
2856                        np.array(1, dtype='float64'),
2857                        np.array(-1, dtype='float64')),)
2858    )
2859
2860
2861class T_Clip(unittest.TestCase):
2862    def test_complex_value(self):
2863        for dtype in ['complex64', 'complex128']:
2864            a = tensor.vector(dtype=dtype)
2865            b = tensor.scalar()
2866            c = tensor.scalar()
2867            self.assertRaises(TypeError, clip, a, b, c)
2868
2869    def test_clip_repeat_grad(self):
2870        # This is testing for the issue #633
2871        x, y = tensor.vectors('xy')
2872        a = clip(x, y, x)
2873        g = theano.gradient.grad(a.sum(), x)
2874        fn = theano.function([x, y], [g])
2875
2876        # Test the other way around as well
2877        a2 = clip(x, x, y)
2878        g2 = theano.gradient.grad(a2.sum(), x)
2879        fn2 = theano.function([x, y], [g2])
2880
2881        # Test for the equal case too
2882        a3 = theano.tensor.clip(x, x, x)
2883        g3 = theano.gradient.grad(a3.sum(), x)
2884        fn3 = theano.function([x], [g3])
2885
2886        rng = np.random.RandomState(utt.fetch_seed())
2887
2888        nvals = 50
2889        xval = rng.rand(nvals).astype(config.floatX)
2890        # To ensure that the min < x
2891        yval_mn = rng.rand(nvals).astype(config.floatX) - 1.0
2892
2893        # To ensure that the max > x
2894        yval_mx = rng.rand(nvals).astype(config.floatX) + 1.0
2895
2896        aval, = fn(xval, yval_mn)
2897        aval2, = fn2(xval, yval_mx)
2898        aval3, = fn3(xval)
2899        self.assertTrue(np.all(aval == 1.))
2900        self.assertTrue(np.all(aval2 == 1.))
2901        self.assertTrue(np.all(aval3 == 1.))
2902
2903    def test_clip_repeat_verify_grad(self):
2904        # Additional tests for issue gh-633
2905        utt.verify_grad(
2906            op=lambda x: clip(x, 0, x),
2907            pt=[rand_nonzero((3, 7))])
2908
2909        utt.verify_grad(
2910            op=lambda x: clip(x, x, 0),
2911            pt=[rand_nonzero((3, 7))])
2912
2913        utt.verify_grad(
2914            op=lambda x: clip(0, x, x),
2915            pt=[rand_nonzero((3, 7))])
2916
2917        utt.verify_grad(
2918            op=lambda x: clip(x, x, x),
2919            pt=[rand_nonzero((3, 7))])
2920
2921
2922# TODO: consider moving this function / functionality to gradient.py
2923#      rationale: it's tricky, and necessary every time you want to verify
2924#      gradient numerically
2925
2926
2927def test_batched_dot():
2928    first = theano.tensor.tensor3("first")
2929    second = theano.tensor.tensor3("second")
2930    output = theano.tensor.basic.batched_dot(first, second)
2931    first_val = np.random.rand(10, 10, 20).astype(config.floatX)
2932    second_val = np.random.rand(10, 20, 5).astype(config.floatX)
2933    result_fn = theano.function([first, second], output)
2934    result = result_fn(first_val, second_val)
2935    assert result.shape[0] == first_val.shape[0]
2936    assert result.shape[1] == first_val.shape[1]
2937    assert result.shape[2] == second_val.shape[2]
2938
2939    first_mat = theano.tensor.dmatrix("first")
2940    second_mat = theano.tensor.dmatrix("second")
2941    output = theano.tensor.basic.batched_dot(first_mat, second_mat)
2942    first_mat_val = np.random.rand(10, 10).astype(config.floatX)
2943    second_mat_val = np.random.rand(10, 10).astype(config.floatX)
2944    result_fn = theano.function([first_mat, second_mat], output)
2945    result = result_fn(first_mat_val, second_mat_val)
2946
2947    assert result.shape[0] == first_mat_val.shape[0]
2948
2949
2950def test_batched_dot_not_contiguous():
2951    def np_genarray(*_shape):
2952        size = 1
2953        for dimsize in _shape:
2954            size *= dimsize
2955        return np.arange(size, dtype=floatX).reshape(_shape)
2956
2957    X = tensor3()
2958    W = tensor3()
2959    Z = batched_dot(X, W)
2960    f = function([X, W], Z)
2961
2962    w = np_genarray(30, 10, 5)
2963    reversed_x_container = np_genarray(20, 40, 30)
2964    x_container = reversed_x_container.T
2965
2966    def check_first_dim(inverted):
2967        direction = -1 if inverted else 1
2968        x = x_container[::direction, ::2, ::2]
2969        assert x.shape == (30, 20, 10)
2970        assert x.strides[0] == direction * np.dtype(floatX).itemsize
2971        assert not (x.flags['C_CONTIGUOUS'] or x.flags['F_CONTIGUOUS'])
2972        result = f(x, w)
2973        ref_result = np.asarray(list(np.dot(u, v) for u, v in zip(x, w)))
2974        utt.assert_allclose(ref_result, result)
2975
2976    for inverted in (0, 1):
2977        yield (check_first_dim, inverted)
2978
2979
2980def test_batched_tensordot():
2981    first = theano.tensor.tensor4("first")
2982    second = theano.tensor.tensor4("second")
2983    axes = [[1, 2], [3, 1]]
2984    output = theano.tensor.basic.batched_tensordot(first, second, axes)
2985    first_val = np.random.rand(8, 10, 20, 3).astype(config.floatX)
2986    second_val = np.random.rand(8, 20, 5, 10).astype(config.floatX)
2987    result_fn = theano.function([first, second], output)
2988    result = result_fn(first_val, second_val)
2989    assert result.shape[0] == first_val.shape[0]
2990    assert result.shape[1] == first_val.shape[3]
2991    assert result.shape[2] == second_val.shape[2]
2992
2993    first_mat = theano.tensor.dmatrix("first")
2994    second_mat = theano.tensor.dmatrix("second")
2995    axes = 1
2996    output = theano.tensor.basic.batched_tensordot(first_mat, second_mat, axes)
2997    first_mat_val = np.random.rand(10, 4).astype(config.floatX)
2998    second_mat_val = np.random.rand(10, 4).astype(config.floatX)
2999    result_fn = theano.function([first_mat, second_mat], output)
3000    result = result_fn(first_mat_val, second_mat_val)
3001    assert result.shape[0] == first_mat_val.shape[0]
3002    assert len(result.shape) == 1
3003
3004
3005def test_tensor_values_eq_approx():
3006    # test, inf, -inf and nan equal themself
3007    a = np.asarray([-np.inf, -1, 0, 1, np.inf, np.nan])
3008    assert TensorType.values_eq_approx(a, a)
3009
3010    # test inf, -inf don't equal themself
3011    b = np.asarray([np.inf, -1, 0, 1, np.inf, np.nan])
3012    assert not TensorType.values_eq_approx(a, b)
3013    b = np.asarray([-np.inf, -1, 0, 1, -np.inf, np.nan])
3014    assert not TensorType.values_eq_approx(a, b)
3015
3016    # test allow_remove_inf
3017    b = np.asarray([np.inf, -1, 0, 1, 5, np.nan])
3018    assert TensorType.values_eq_approx(a, b, allow_remove_inf=True)
3019    b = np.asarray([np.inf, -1, 0, 1, 5, 6])
3020    assert not TensorType.values_eq_approx(a, b, allow_remove_inf=True)
3021
3022    # test allow_remove_nan
3023    b = np.asarray([np.inf, -1, 0, 1, 5, np.nan])
3024    assert not TensorType.values_eq_approx(a, b, allow_remove_nan=False)
3025    b = np.asarray([-np.inf, -1, 0, 1, np.inf, 6])
3026    assert not TensorType.values_eq_approx(a, b, allow_remove_nan=False)
3027
3028
3029def test_nan_inf_constant_signature():
3030    # Test that the signature of a constant tensor containing NaN and Inf
3031    # values is correct.
3032    test_constants = [
3033        [np.nan, np.inf, 0, 1],
3034        [np.nan, np.inf, -np.inf, 1],
3035        [0, np.inf, -np.inf, 1],
3036        [0, 3, -np.inf, 1],
3037        [0, 3, np.inf, 1],
3038        [np.nan, 3, 4, 1],
3039        [0, 3, 4, 1],
3040        np.nan,
3041        np.inf,
3042        -np.inf,
3043        0,
3044        1,
3045        ]
3046    n = len(test_constants)
3047    # We verify that signatures of two rows i, j in the matrix above are
3048    # equal if and only if i == j.
3049    for i in xrange(n):
3050        for j in xrange(n):
3051            x = constant(test_constants[i])
3052            y = constant(test_constants[j])
3053            assert (x.signature() == y.signature()) == (i == j)
3054
3055    # Also test that nan !=0 and nan != nan.
3056    x = tensor.scalar()
3057    mode = get_default_mode()
3058    if isinstance(mode, theano.compile.debugmode.DebugMode):
3059        # Disable the check preventing usage of NaN / Inf values.
3060        # We first do a copy of the mode to avoid side effects on other tests.
3061        mode = copy(mode)
3062        mode.check_isfinite = False
3063    f = theano.function([x], eq(x, np.nan), mode=mode)
3064
3065    assert f(0) == 0
3066    assert f(np.nan) == 0
3067
3068
3069def test_isnan():
3070    for x in [tensor.matrix(), tensor.imatrix(), tensor.matrix(dtype='bool')]:
3071        y = tensor.isnan(x)
3072        assert isinstance(y.owner.op, tensor.Elemwise) == (
3073            x.dtype not in tensor.discrete_dtypes)
3074        assert y.dtype == 'bool'
3075
3076        # Test c code generator even for int type.
3077        y = tensor.isnan_(x)
3078        assert isinstance(y.owner.op, tensor.Elemwise)
3079        assert y.dtype == 'bool'
3080        f = theano.function([x], y, allow_input_downcast=True)
3081        f([[0, 1, 2]])
3082
3083
3084class T_Shape(unittest.TestCase):
3085    def test_basic0(self):
3086        s = shape(np.ones((5, 3)))
3087        self.assertTrue((eval_outputs([s]) == [5, 3]).all())
3088
3089    def test_basic1(self):
3090        s = shape(np.ones((2)))
3091        self.assertTrue((eval_outputs([s]) == [2]).all())
3092
3093    def test_basic2(self):
3094        s = shape(np.ones((5, 3, 10)))
3095        self.assertTrue((eval_outputs([s]) == [5, 3, 10]).all())
3096
3097
3098class T_max_and_argmax(unittest.TestCase):
3099    def setUp(self):
3100        utt.seed_rng()
3101        MaxAndArgmax.debug = 0
3102
3103    def test0(self):
3104        n = as_tensor_variable(5.0)
3105        v, i = eval_outputs(max_and_argmax(n))
3106        self.assertTrue(v == 5.0)
3107        self.assertTrue(i == 0)
3108        assert i.dtype == 'int64'
3109        v = eval_outputs(max_and_argmax(n)[0].shape)
3110        assert len(v) == 0
3111        v = eval_outputs(max_and_argmax(n)[1].shape)
3112        assert len(v) == 0
3113
3114    def test1(self):
3115        n = as_tensor_variable([1, 2, 3, 2, -6])
3116        v, i = eval_outputs(max_and_argmax(n))
3117        self.assertTrue(v == 3)
3118        self.assertTrue(i == 2)
3119        assert i.dtype == 'int64'
3120        v = eval_outputs(max_and_argmax(n)[0].shape)
3121        assert len(v) == 0
3122
3123    def test2(self):
3124        data = rand(2, 3)
3125        n = as_tensor_variable(data)
3126        for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (None, None),
3127                                ([0, 1], None), ([1, 0], None),
3128                                (NoneConst.clone(), None),
3129                                (constant(0), 0)]:
3130            v, i = eval_outputs(max_and_argmax(n, axis))
3131            assert i.dtype == 'int64'
3132            self.assertTrue(np.all(v == np.max(data, np_axis)))
3133            self.assertTrue(np.all(i == np.argmax(data, np_axis)))
3134            v_shape = eval_outputs(max_and_argmax(n, axis)[0].shape)
3135            assert tuple(v_shape) == np.max(data, np_axis).shape
3136
3137    def test2_float16(self):
3138        # Test negative values and bigger range to make sure numpy don't do the argmax as on uint16
3139        data = (rand(20, 30).astype("float16") - 0.5) * 20
3140        n = shared(data)
3141        for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (None, None),
3142                                ([0, 1], None), ([1, 0], None),
3143                                (NoneConst.clone(), None),
3144                                (constant(0), 0)]:
3145            v, i = eval_outputs(max_and_argmax(n, axis), (MaxAndArgmax,))
3146            assert i.dtype == 'int64'
3147            self.assertTrue(np.all(v == np.max(data, np_axis)))
3148            self.assertTrue(np.all(i == np.argmax(data, np_axis)))
3149            v_shape = eval_outputs(max_and_argmax(n, axis)[0].shape)
3150            assert tuple(v_shape) == np.max(data, np_axis).shape
3151
3152    def test2_invalid(self):
3153        n = as_tensor_variable(rand(2, 3))
3154        # Silence expected error messages
3155        _logger = logging.getLogger('theano.gof.opt')
3156        oldlevel = _logger.level
3157        _logger.setLevel(logging.CRITICAL)
3158        try:
3159            try:
3160                eval_outputs(max_and_argmax(n, 3))
3161                assert False
3162            except ValueError:
3163                pass
3164        finally:
3165            _logger.setLevel(oldlevel)
3166
3167    def test2_invalid_neg(self):
3168        n = as_tensor_variable(rand(2, 3))
3169        old_stderr = sys.stderr
3170        sys.stderr = StringIO()
3171        try:
3172            try:
3173                eval_outputs(max_and_argmax(n, -3))
3174                assert False
3175            except ValueError:
3176                pass
3177        finally:
3178            sys.stderr = old_stderr
3179
3180    def test2_valid_neg(self):
3181        n = as_tensor_variable(rand(2, 3))
3182        v, i = eval_outputs(max_and_argmax(n, -1))
3183        assert i.dtype == 'int64'
3184        self.assertTrue(v.shape == (2,))
3185        self.assertTrue(i.shape == (2,))
3186        self.assertTrue(np.all(v == np.max(n.value, -1)))
3187        self.assertTrue(np.all(i == np.argmax(n.value, -1)))
3188        v, i = eval_outputs(max_and_argmax(n, -2))
3189        assert i.dtype == 'int64'
3190        self.assertTrue(v.shape == (3,))
3191        self.assertTrue(i.shape == (3,))
3192        self.assertTrue(np.all(v == np.max(n.value, -2)))
3193        self.assertTrue(np.all(i == np.argmax(n.value, -2)))
3194        v = eval_outputs(max_and_argmax(n, -1)[0].shape)
3195        assert v == (2)
3196        v = eval_outputs(max_and_argmax(n, -2)[0].shape)
3197        assert v == (3)
3198
3199    def test3(self):
3200        data = rand(2, 3, 4)
3201        n = as_tensor_variable(data)
3202        for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (None, None),
3203                                ([0, 1, 2], None), ([1, 2, 0], None)]:
3204            v, i = eval_outputs(max_and_argmax(n, axis))
3205            assert i.dtype == 'int64'
3206            self.assertTrue(np.all(v == np.max(data, np_axis)))
3207            self.assertTrue(np.all(i == np.argmax(data, np_axis)))
3208            v = eval_outputs(max_and_argmax(n, axis)[0].shape)
3209            assert tuple(v) == np.max(data, np_axis).shape
3210
3211    def test_arg_grad(self):
3212        # The test checks that the gradient of argmax(x).sum() is 0
3213
3214        x = matrix()
3215        cost = argmax(x, axis=0).sum()
3216        gx = grad(cost, x)
3217        val = tensor.get_scalar_constant_value(gx)
3218        assert val == 0.0
3219
3220    def test_grad(self):
3221        data = rand(2, 3)
3222        n = as_tensor_variable(data)
3223
3224        def safe_verify_grad(func, data):
3225            # Wrapper around 'verify_grad' that picks a proper value for epsilon.
3226            #
3227            # This is needed because 'verify_grad' may fail when its epsilon is
3228            # too large, due to the fact the argmax is not continuous.
3229            # We make sure epsilon is less than the minimum absolute value found
3230            # in the matrix of pairwise differences between all elements in the
3231            # data. This way, the argmax will not change when adding epsilon.
3232
3233            # 'data' is a one-element list.
3234            data_tensor, = data
3235            # Flatten it into a 1D vector.
3236            data_vector = data_tensor.flatten()
3237            # Compute pairwise absolute differences.
3238            diff = np.abs(data_vector.reshape((-1, 1)) - data_vector)
3239            # Alter the diagonal to avoid a zero minimum.
3240            for i in xrange(len(diff)):
3241                diff[i, i] = 1
3242            # Find an appropriate epsilon.
3243            eps = builtin_min(numeric_grad.type_eps[config.floatX],
3244                              diff.min() / 2)
3245            # Run gradient verification.
3246            utt.verify_grad(func, data, eps=eps)
3247
3248        def check_grad_max(data, max_grad_data, axis=None):
3249            # Why this is needed? verify_grad is not enough?
3250            # This works only for axis in [0, None].
3251            assert axis in [0, None]
3252            z = np.zeros_like(data)
3253            z = z.flatten()
3254            argmax = np.argmax(data, axis=axis)
3255            if argmax.ndim == 0:
3256                z[argmax] += 1
3257            else:
3258                for id, v in enumerate(argmax):
3259                    z[v * np.prod(data.shape[data.ndim - 1:axis:-1]) +
3260                      id] += 1
3261
3262            z = z.reshape(data.shape)
3263            assert np.all(max_grad_data == z)
3264
3265        for axis in (-1, 0, 1, None):
3266            for j in xrange(2):
3267                safe_verify_grad(lambda v: max_and_argmax(v, axis=axis)[j],
3268                                 [data])
3269                if axis != 1:
3270                    safe_verify_grad(lambda v: max_and_argmax(v.flatten(),
3271                                                              axis=axis)[j],
3272                                     [data])
3273            if axis in (0, None):
3274                check_grad_max(data, eval_outputs(grad(
3275                    max_and_argmax(n, axis=axis)[0].sum(), n)), axis=axis)
3276            check_grad_max(data, eval_outputs(grad(
3277                max_and_argmax(n.flatten())[0], n)))
3278
3279        # Test 3d inner dimensions
3280        data = rand(3, 4, 5)
3281
3282        for i in [0, 1, 2]:
3283            safe_verify_grad(lambda v: max_and_argmax(v, axis=[i])[0], [data])
3284            safe_verify_grad(lambda v: max_and_argmax(v, axis=[i])[1], [data])
3285
3286        # Test 4d inner dimensions
3287        data = rand(2, 3, 4, 5)
3288
3289        for i in [0, 1, 2, 3]:
3290            safe_verify_grad(lambda v: max_and_argmax(v, axis=[i])[0], [data])
3291            safe_verify_grad(lambda v: max_and_argmax(v, axis=[i])[1], [data])
3292
3293        # Test grad with multiple axes
3294        for i in [[0, 1], [0, 0]]:
3295            safe_verify_grad(lambda v: max_and_argmax(v, axis=i)[0], [data])
3296            safe_verify_grad(lambda v: max_and_argmax(v, axis=i)[1], [data])
3297
3298    def test_preserve_broadcastable(self):
3299        # Ensure the original broadcastable flags are preserved by Max/Argmax.
3300        x = tensor.matrix().dimshuffle('x', 0, 'x', 1, 'x')
3301        y = x.max(axis=1)
3302        assert y.type.broadcastable == (True, True, False, True)
3303
3304    def test_multiple_axes(self):
3305        data = np.arange(24).reshape(3, 2, 4)
3306        x = as_tensor_variable(data)
3307        v, i = eval_outputs(max_and_argmax(x, [1, -1]))
3308        assert np.all(v == np.array([7, 15, 23]))
3309        assert np.all(i == np.array([7, 7, 7]))
3310
3311        v = eval_outputs(max_and_argmax(x, [1, -1])[0].shape)
3312        assert tuple(v) == np.max(data, (1, -1)).shape
3313
3314    def test_zero_shape(self):
3315        x = tensor.matrix()
3316        m, i = max_and_argmax(x, axis=1)
3317        f = theano.function([x], [m, i])
3318        xv = np.zeros((0, 4), dtype=floatX)
3319        mv, iv = f(xv)
3320        assert mv.shape == (0,)
3321        assert iv.shape == (0,)
3322
3323    def test_numpy_input(self):
3324        ar = np.array([1, 2, 3])
3325        max, argmax = max_and_argmax(ar, axis=None)
3326        self.assertEqual(max.eval(), 3)
3327        self.assertEqual(argmax.eval(), 2)
3328
3329
3330class T_argmin_argmax(unittest.TestCase):
3331    def setUp(self):
3332        utt.seed_rng()
3333        MaxAndArgmax.debug = 0
3334
3335    def test_scalar(self):
3336        for fct in [argmin, argmax]:
3337            n = as_tensor_variable(5.0)
3338            i = eval_outputs(fct(n))
3339            self.assertTrue(i == 0)
3340            v = eval_outputs(fct(n).shape)
3341            assert len(v) == 0
3342
3343    def test_list(self):
3344        n = as_tensor_variable([1, 2, 3, 2, -6])
3345        i = eval_outputs(argmin(n))
3346        self.assertTrue(i == 4)
3347        v = eval_outputs(argmin(n).shape)
3348        assert len(v) == 0
3349
3350        n = as_tensor_variable([1, 2, 3, 2, -6])
3351        i = eval_outputs(argmax(n))
3352        self.assertTrue(i == 2)
3353        v = eval_outputs(argmax(n).shape)
3354        assert len(v) == 0
3355
3356    def test2(self):
3357        data = rand(2, 3)
3358        n = as_tensor_variable(data)
3359        for fct, nfct in [(argmax, np.argmax), (argmin, np.argmin)]:
3360            for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (None, None),
3361                                    ([0, 1], None), ([1, 0], None)]:
3362                v = eval_outputs(fct(n, axis))
3363                self.assertTrue(np.all(v == nfct(data, np_axis)))
3364                v_shape = eval_outputs(fct(n, axis).shape)
3365                assert tuple(v_shape) == nfct(data, np_axis).shape
3366
3367    def test2_float16(self):
3368        # Test negative values and bigger range to make sure numpy don't do the argmax as on uint16
3369        data = (rand(20, 30).astype("float16") - 0.5) * 20
3370        n = shared(data)
3371        mode = get_default_mode().including("local_max_and_argmax", "uncanonicalize")
3372        for fct, nfct in [(argmax, np.argmax), (argmin, np.argmin)]:
3373            for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (None, None),
3374                                    ([0, 1], None), ([1, 0], None)]:
3375                v = eval_outputs(fct(n, axis), (Argmax,), mode=mode)
3376                self.assertTrue(np.all(v == nfct(data, np_axis)))
3377                v_shape = eval_outputs(fct(n, axis).shape, mode=mode)
3378                assert tuple(v_shape) == nfct(data, np_axis).shape
3379
3380    def test2_invalid(self):
3381        for fct, nfct in [(argmax, np.argmax), (argmin, np.argmin)]:
3382            n = as_tensor_variable(rand(2, 3))
3383            # Silence expected error messages
3384            _logger = logging.getLogger('theano.gof.opt')
3385            oldlevel = _logger.level
3386            _logger.setLevel(logging.CRITICAL)
3387            try:
3388                try:
3389                    eval_outputs(fct(n, 3))
3390                    assert False
3391                except ValueError:
3392                    pass
3393            finally:
3394                _logger.setLevel(oldlevel)
3395
3396    def test2_invalid_neg(self):
3397        for fct, nfct in [(argmax, np.argmax), (argmin, np.argmin)]:
3398            n = as_tensor_variable(rand(2, 3))
3399            old_stderr = sys.stderr
3400            sys.stderr = StringIO()
3401            try:
3402                try:
3403                    eval_outputs(fct(n, -3))
3404                    assert False
3405                except ValueError:
3406                    pass
3407            finally:
3408                sys.stderr = old_stderr
3409
3410    def test2_valid_neg(self):
3411        for fct, nfct in [(argmax, np.argmax), (argmin, np.argmin)]:
3412            n = as_tensor_variable(rand(2, 3))
3413            i = eval_outputs(fct(n, -1))
3414            self.assertTrue(i.shape == (2,))
3415            self.assertTrue(np.all(i == nfct(n.value, -1)))
3416            i = eval_outputs(fct(n, -2))
3417            self.assertTrue(i.shape == (3,))
3418            self.assertTrue(np.all(i == nfct(n.value, -2)))
3419
3420            v = eval_outputs(fct(n, -1).shape)
3421            assert v == (2)
3422            v = eval_outputs(fct(n, -2).shape)
3423            assert v == (3)
3424
3425    def test3(self):
3426        data = rand(2, 3, 4)
3427        n = as_tensor_variable(data)
3428        for fct, nfct in [(argmax, np.argmax), (argmin, np.argmin)]:
3429            for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (2, 2),
3430                                    (None, None), ([0, 1, 2], None),
3431                                    ([1, 0, 2], None)]:
3432                v = eval_outputs(fct(n, axis))
3433                self.assertTrue(np.all(v == nfct(data, np_axis)))
3434                v_shape = eval_outputs(fct(n, axis).shape)
3435                assert tuple(v_shape) == nfct(data, np_axis).shape
3436
3437    def test_grad_argmin(self):
3438        data = rand(2, 3)
3439        n = as_tensor_variable(data)
3440        n.name = 'n'
3441
3442        # test grad of argmin
3443        utt.verify_grad(lambda v: argmin(v, axis=-1), [data])
3444
3445        utt.verify_grad(lambda v: argmin(v, axis=[0]), [data])
3446
3447        utt.verify_grad(lambda v: argmin(v, axis=[1]), [data])
3448
3449        utt.verify_grad(lambda v: argmin(v.flatten()), [data])
3450
3451        try:
3452            cost = argmin(n, axis=-1)
3453            cost.name = None
3454            grad(cost, n)
3455            raise Exception('Expected an error')
3456        except TypeError:
3457            pass
3458
3459    def test_grad_argmax(self):
3460        data = rand(2, 3)
3461        n = as_tensor_variable(data)
3462
3463        # test grad of argmax
3464        utt.verify_grad(lambda v: argmax(v, axis=-1), [data])
3465
3466        utt.verify_grad(lambda v: argmax(v, axis=[0]), [data])
3467
3468        utt.verify_grad(lambda v: argmax(v, axis=[1]), [data])
3469
3470        utt.verify_grad(lambda v: argmax(v.flatten()), [data])
3471
3472        try:
3473            grad(argmax(n, axis=-1), n)
3474            raise Exception('Expected an error')
3475        except TypeError:
3476            pass
3477
3478    def test_uint(self):
3479        for dtype in ('uint8', 'uint16', 'uint32', 'uint64'):
3480            itype = np.iinfo(dtype)
3481            data = np.array([itype.min + 3, itype.min, itype.max - 5, itype.max], dtype)
3482            n = as_tensor_variable(data)
3483            i = eval_outputs(argmin(n))
3484            self.assertEqual(i, 1)
3485            i = eval_outputs(argmax(n))
3486            self.assertEqual(i, 3)
3487
3488    def test_bool(self):
3489        data = np.array([True, False], 'bool')
3490        n = as_tensor_variable(data)
3491        i = eval_outputs(argmin(n))
3492        self.assertEqual(i, 1)
3493        i = eval_outputs(argmax(n))
3494        self.assertEqual(i, 0)
3495
3496
3497class T_min_max(unittest.TestCase):
3498    def setUp(self):
3499        utt.seed_rng()
3500        MaxAndArgmax.debug = 0
3501
3502    def test_scalar(self):
3503        for fct in [max, min]:
3504            n = as_tensor_variable(5.0)
3505            v = eval_outputs(fct(n))
3506            self.assertTrue(v == 5.0)
3507
3508            v = eval_outputs(fct(n).shape)
3509            assert len(v) == 0
3510
3511    def test_list(self):
3512        for fct, nfct in [(max, np.max), (min, np.min)]:
3513            n = as_tensor_variable([1, 2, 3, 2, -6])
3514            v = eval_outputs([fct(n)])
3515            self.assertTrue(v == nfct(n.value))
3516
3517            v = eval_outputs(fct(n).shape)
3518            assert len(v) == 0
3519
3520    def test2(self):
3521        data = rand(2, 3)
3522        n = as_tensor_variable(data)
3523        for fct, nfct in [(max, np.max), (min, np.min)]:
3524            for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (None, None),
3525                                    ([0, 1], None), ([1, 0], None)]:
3526                v = eval_outputs(fct(n, axis))
3527                self.assertTrue(np.all(v == nfct(data, np_axis)))
3528                v_shape = eval_outputs(fct(n, axis).shape)
3529                assert tuple(v_shape) == nfct(data, np_axis).shape
3530
3531    def test2_invalid(self):
3532        for fct in [max, min]:
3533            n = as_tensor_variable(rand(2, 3))
3534            # Silence expected error messages
3535            _logger = logging.getLogger('theano.gof.opt')
3536            oldlevel = _logger.level
3537            _logger.setLevel(logging.CRITICAL)
3538            try:
3539                try:
3540                    eval_outputs(fct(n, 3))
3541                    assert False
3542                except ValueError:
3543                    pass
3544            finally:
3545                _logger.setLevel(oldlevel)
3546
3547    def test2_invalid_neg(self):
3548        for fct in [max, min]:
3549            n = as_tensor_variable(rand(2, 3))
3550            old_stderr = sys.stderr
3551            sys.stderr = StringIO()
3552            try:
3553                try:
3554                    eval_outputs(fct(n, -3))
3555                    assert False
3556                except ValueError:
3557                    pass
3558            finally:
3559                sys.stderr = old_stderr
3560
3561    def test2_valid_neg(self):
3562        for fct, nfct in [(max, np.max), (min, np.min)]:
3563            n = as_tensor_variable(rand(2, 3))
3564            v = eval_outputs(fct(n, -1))
3565            self.assertTrue(v.shape == (2,))
3566            self.assertTrue(np.all(v == nfct(n.value, -1)))
3567            v = eval_outputs(fct(n, -2))
3568            self.assertTrue(v.shape == (3,))
3569            self.assertTrue(np.all(v == nfct(n.value, -2)))
3570
3571            v = eval_outputs(fct(n, -1).shape)
3572            assert v == (2)
3573            v = eval_outputs(fct(n, -2).shape)
3574            assert v == (3)
3575
3576    def test3(self):
3577        # Test with 1 axis or all axis out of 3 dims
3578        data = rand(2, 3, 4)
3579        n = as_tensor_variable(data)
3580        for fct, nfct in [(max, np.max), (min, np.min)]:
3581            for (axis, np_axis) in [(-1, -1), (0, 0), (1, 1), (2, 2),
3582                                    (None, None), ([0, 1, 2], None),
3583                                    ([1, 0, 2], None)]:
3584                v = eval_outputs(fct(n, axis))
3585                self.assertTrue(np.all(v == nfct(data, np_axis)))
3586                v_shape = eval_outputs(fct(n, axis).shape)
3587                assert tuple(v_shape) == nfct(data, np_axis).shape
3588
3589    def test3b(self):
3590        # Test with 2 axis out of 3 dims
3591        data = rand(2, 3, 4)
3592        n = as_tensor_variable(data)
3593        for fct, nfct in [(max, np.max), (min, np.min)]:
3594            for axis in [[0, 1], [1, 2], [0, 2]]:
3595                v = eval_outputs(fct(n, axis))
3596                np_v = nfct(nfct(data, axis[1]), axis[0])
3597                self.assertTrue(np.all(v == np_v))
3598                v_shape = eval_outputs(fct(n, axis).shape)
3599                assert tuple(v_shape) == np_v.shape
3600
3601    def test_grad_max(self):
3602        data = rand(2, 3)
3603        n = as_tensor_variable(data)
3604
3605        def check_grad_max(data, max_grad_data, axis=None):
3606            # This work only for axis in [0,None]
3607            assert axis in [0, None]
3608            z = np.zeros_like(data)
3609            z = z.flatten()
3610            argmax = np.argmax(data, axis=axis)
3611            if argmax.ndim == 0:
3612                z[np.argmax(data, axis=axis)] += 1
3613            else:
3614                for id, v in enumerate(argmax):
3615                    z[v * np.prod(data.shape[data.ndim - 1:axis:-1]) +
3616                      id] += 1
3617
3618            z = z.reshape(data.shape)
3619            assert np.all(max_grad_data == z)
3620
3621        # test grad of max
3622        # axis is the last one
3623        utt.verify_grad(lambda v: max(v, axis=-1), [data])
3624
3625        utt.verify_grad(lambda v: max(v, axis=[0]), [data])
3626        check_grad_max(data, eval_outputs(grad(max(n, axis=0).sum(), n)),
3627                       axis=0)
3628
3629        utt.verify_grad(lambda v: max(v, axis=[1]), [data])
3630        # check_grad_max(data,eval_outputs(grad(max(n,axis=1),n)),axis=1)
3631
3632        utt.verify_grad(lambda v: max(v.flatten()), [data])
3633        check_grad_max(data, eval_outputs(grad(max(n.flatten()), n)))
3634
3635    def test_grad_min(self):
3636        data = rand(2, 3)
3637        n = as_tensor_variable(data)
3638
3639        def check_grad_min(data, min_grad_data, axis=None):
3640            # This work only for axis in [0, None]
3641            assert axis in [0, None]
3642            z = np.zeros_like(data)
3643            z = z.flatten()
3644            argmin = np.argmin(data, axis=axis)
3645            if argmin.ndim == 0:
3646                z[np.argmin(data, axis=axis)] += 1
3647            else:
3648                for id, v in enumerate(argmin):
3649                    z[v * np.prod(data.shape[data.ndim - 1:axis:-1]) +
3650                      id] += 1
3651
3652            z = z.reshape(data.shape)
3653            assert np.all(min_grad_data == z)
3654
3655        # test grad of min
3656        # axis is the last one
3657        utt.verify_grad(lambda v: min(v, axis=-1), [data])
3658
3659        utt.verify_grad(lambda v: min(v, axis=[0]), [data])
3660        check_grad_min(data, eval_outputs(grad(min(n, axis=0).sum(), n)),
3661                       axis=0)
3662
3663        utt.verify_grad(lambda v: min(v, axis=[1]), [data])
3664        # check_grad_min(data,eval_outputs(grad(min(n,axis=1),n)),axis=1)
3665
3666        utt.verify_grad(lambda v: min(v.flatten()), [data])
3667        check_grad_min(data, eval_outputs(grad(min(n.flatten()), n)))
3668
3669    def _grad_list(self):
3670        # Test the gradient when we have multiple axis at the same time.
3671        #
3672        # This not implemented, so we disable the test. See ticket:
3673        # http://www.assembla.com/spaces/theano/tickets/511
3674        data = rand(2, 3)
3675        for fct in [max_and_argmax, max, min]:
3676            utt.verify_grad(lambda v: fct(v, axis=[0, 1]), [data])
3677        # n = as_tensor_variable(data)
3678        # check_grad_max(data, eval_outputs(grad(max_and_argmax(n,
3679        # axis=1)[0], n)),axis=1)
3680
3681    def test_uint(self):
3682        for dtype in ('uint8', 'uint16', 'uint32', 'uint64'):
3683            itype = np.iinfo(dtype)
3684            data = np.array([itype.min + 3, itype.min, itype.max - 5, itype.max], dtype)
3685            n = as_tensor_variable(data)
3686            self.assertEqual(min(n).dtype, dtype)
3687            i = eval_outputs(min(n))
3688            self.assertEqual(i, itype.min)
3689            self.assertEqual(max(n).dtype, dtype)
3690            i = eval_outputs(max(n))
3691            self.assertEqual(i, itype.max)
3692
3693    def test_bool(self):
3694        data = np.array([True, False], 'bool')
3695        n = as_tensor_variable(data)
3696        self.assertEqual(min(n).dtype, 'bool')
3697        i = eval_outputs(min(n))
3698        self.assertEqual(i, False)
3699        self.assertEqual(max(n).dtype, 'bool')
3700        i = eval_outputs(max(n))
3701        self.assertEqual(i, True)
3702
3703
3704def test_basic_allclose():
3705    # This was raised by a user in https://github.com/Theano/Theano/issues/2975
3706    assert tensor.basic._allclose(-0.311023883434, -0.311022856884)
3707
3708
3709class T_outer(unittest.TestCase):
3710    def test_outer(self):
3711        for m in range(4):
3712            for n in range(4):
3713                x = tensor.tensor(dtype='floatX', broadcastable=(False,) * m)
3714                y = tensor.tensor(dtype='floatX', broadcastable=(False,) * n)
3715                s1 = np.random.randint(1, 10, m)
3716                s2 = np.random.randint(1, 10, n)
3717                v1 = np.asarray(np.random.rand(*s1)).astype(floatX)
3718                v2 = np.asarray(np.random.rand(*s2)).astype(floatX)
3719                o = tensor.outer(x, y).eval({x: v1, y: v2})
3720                assert_allclose(o, np.outer(v1, v2))
3721
3722    def test_grad(self):
3723        # Test the combined graph of the graph of outer
3724        # with broadcastable dimensions, just in case.
3725        for shp0, shp1 in [((1,), (2,)),
3726                           ((3,), (1,)),
3727                           ((1,), (1,)),
3728                           ((3,), (2,)),
3729                           ((3, 2), (1, 1)),
3730                           ((3, 2), (1, 4)),
3731                           ((3, 2), (4, 1)),
3732                           ((3, 2), (4, 5)),
3733                           ((1, 2), (4, 5)),
3734                           ((3, 1), (4, 5)),
3735                           ((1, 1), (4, 5)),
3736                           ((1, 1), (1, 1)),
3737                           ]:
3738            data0 = np.random.rand(*shp0).astype(floatX)
3739            data1 = np.random.rand(*shp1).astype(floatX)
3740            utt.verify_grad(tensor.outer, [data0, data1])
3741
3742
3743class T_GetVectorLength(unittest.TestCase):
3744    def test_get_vector_length(self):
3745        x = theano.shared(np.zeros((2, 3, 4, 5)))
3746        assert len(list(x.shape)) == 4
3747        assert len(list(x.shape[2:4])) == 2
3748        assert len(list(x.shape[2:])) == 2
3749        assert len(list(x.shape[1:4])) == 3
3750        assert len(list(x.shape[2:2])) == 0
3751        assert len(list(x.shape[1:5])) == 3
3752        assert len(list(x.shape[1:10])) == 3
3753        # Test step
3754        assert len(list(x.shape[1:10:2])) == 2
3755        # Test neg start
3756        assert len(list(x.shape[-1:4])) == 1
3757        assert len(list(x.shape[-6:4])) == 4
3758        # test neg stop
3759        assert len(list(x.shape[1:-2])) == 1
3760        assert len(list(x.shape[1:-1])) == 2
3761
3762
3763class T_Join_and_Split(unittest.TestCase):
3764    # Split is tested by each verify_grad method.
3765    def setUp(self):
3766        Join.debug = False
3767        utt.seed_rng()
3768        self.mode = theano.compile.get_default_mode().excluding(
3769            'constant_folding')
3770        self.join_op = Join()
3771        self.split_op_class = Split
3772        self.make_vector_op = opt.MakeVector()
3773        self.floatX = config.floatX
3774        self.hide_error = theano.config.mode not in [
3775            'DebugMode', 'DEBUG_MODE', 'FAST_COMPILE']
3776        self.shared = shared
3777
3778    def eval_outputs_and_check_join(self, outputs):
3779        f = theano.function([], outputs, self.mode)
3780        topo = f.maker.fgraph.toposort()
3781        assert [True for node in topo
3782                if isinstance(node.op, type(self.join_op))]
3783        variables = f()
3784        if isinstance(variables, (tuple, list)) and len(variables) == 1:
3785            return variables[0]
3786        return variables
3787
3788    def eval_outputs_and_check_vector(self, outputs,
3789                                      make_vector_op=None):
3790        if make_vector_op is None:
3791            make_vector_op = self.make_vector_op
3792        f = theano.function([], outputs, self.mode)
3793        topo = f.maker.fgraph.toposort()
3794        assert [True for node in topo
3795                if isinstance(node.op, type(make_vector_op))]
3796        variables = f()
3797        if isinstance(variables, (tuple, list)) and len(variables) == 1:
3798            return variables[0]
3799        return variables
3800
3801    def test_join_scalar(self):
3802        a = as_tensor_variable(1)
3803        b = as_tensor_variable(2)
3804        self.assertRaises(TypeError, join, 0, a, b)
3805
3806    def test_stack_mixed_type_constants(self):
3807        # tested only on cpu as gpu support only float32
3808        a = as_tensor_variable(1)
3809        b = as_tensor_variable(2.0)
3810        c = tensor._shared(np.asarray(3.0, dtype=self.floatX))
3811        s = stack([a, b, c])
3812        want = np.array([1, 2, 3])
3813        out = self.eval_outputs_and_check_vector([s], opt.MakeVector())
3814        self.assertTrue((out == want).all())
3815
3816    def test_stack_scalar(self):
3817        a = self.shared(np.asarray(1., dtype=self.floatX))
3818        b = as_tensor_variable(2.)
3819        c = as_tensor_variable(3.)
3820        s = stack([a, b, c])
3821
3822        want = np.array([1, 2, 3])
3823        out = self.eval_outputs_and_check_vector([s])
3824        self.assertTrue((out == want).all())
3825
3826    def test_stack_scalar_make_vector(self):
3827        # Test that calling stack() on scalars instantiates MakeVector,
3828        # not Join. Test that the floatX dtype stay floatX, not downcasted
3829        # to int64
3830        a = tensor.scalar('a', dtype=self.floatX)
3831        b = tensor.scalar('b', dtype=self.floatX)
3832        s = stack([a, b, a, b])
3833        f = function([a, b], s, mode=self.mode)
3834        val = f(1, 2)
3835        # print val
3836        self.assertTrue(np.all(val == [1, 2, 1, 2]))
3837        topo = f.maker.fgraph.toposort()
3838        assert len([n for n in topo if isinstance(n.op, opt.MakeVector)]) > 0
3839        assert len([n for n in topo if isinstance(n, type(self.join_op))]) == 0
3840        assert f.maker.fgraph.outputs[0].dtype == self.floatX
3841
3842    def test_stack_scalar_make_vector_dtype(self):
3843        # Test that calling stack() on scalars instantiates MakeVector,
3844        # event when the scalar don't have the same dtype.
3845        a = tensor.iscalar('a')
3846        b = tensor.lscalar('b')
3847        s = stack([a, b, a, b])
3848        f = function([a, b], s, mode=self.mode)
3849        val = f(1, 2)
3850        self.assertTrue(np.all(val == [1, 2, 1, 2]))
3851        topo = f.maker.fgraph.toposort()
3852        assert len([n for n in topo if isinstance(n.op, opt.MakeVector)]) > 0
3853        assert len([n for n in topo if isinstance(n, type(self.join_op))]) == 0
3854        assert f.maker.fgraph.outputs[0].dtype == 'int64'
3855
3856    def test_stack_scalar_make_vector_constant(self):
3857        # Test that calling stack() on scalars instantiates MakeVector,
3858        # event when the scalar are simple int type.
3859        a = tensor.iscalar('a')
3860        b = tensor.lscalar('b')
3861        # test when the constant is the first element.
3862        # The first element is used in a special way
3863        s = stack([10, a, b, np.int8(3)])
3864        f = function([a, b], s, mode=self.mode)
3865        val = f(1, 2)
3866        self.assertTrue(np.all(val == [10, 1, 2, 3]))
3867        topo = f.maker.fgraph.toposort()
3868        assert len([n for n in topo if isinstance(n.op, opt.MakeVector)]) > 0
3869        assert len([n for n in topo if isinstance(n, type(self.join_op))]) == 0
3870        assert f.maker.fgraph.outputs[0].dtype == 'int64'
3871
3872    def test_stack_new_interface(self):
3873        # Test the new numpy-like interface: stack(tensors, axis=0).
3874
3875        # Testing against old interface
3876        warnings.simplefilter('always', DeprecationWarning)
3877        a = tensor.imatrix('a')
3878        b = tensor.imatrix('b')
3879        s1 = stack(a, b)
3880        s2 = stack([a, b])
3881        f = function([a, b], [s1, s2], mode=self.mode)
3882        v1, v2 = f([[1, 2]], [[3, 4]])
3883        self.assertTrue(v1.shape == v2.shape)
3884        self.assertTrue(np.all(v1 == v2))
3885        # Testing axis parameter
3886        s3 = stack([a, b], 1)
3887        f = function([a, b], s3, mode=self.mode)
3888        v3 = f([[1, 2]], [[3, 4]])
3889        v4 = np.array([[[1, 2], [3, 4]]])
3890        self.assertTrue(v3.shape == v4.shape)
3891        self.assertTrue(np.all(v3 == v4))
3892        # Testing negative axis
3893        v1 = [[1, 2, 3], [4, 5, 6]]
3894        v2 = [[7, 8, 9], [10, 11, 12]]
3895        s = stack([a, b], axis=-1)
3896        f = function([a, b], s, mode=self.mode)
3897        v = np.zeros((2, 3, 2))
3898        v[:, :, 0] = v1
3899        v[:, :, 1] = v2
3900        out = f(v1, v2)
3901        self.assertTrue(v.shape == out.shape)
3902        self.assertTrue(np.all(v == out))
3903        s = stack([a, b], axis=-2)
3904        f = function([a, b], s, mode=self.mode)
3905        v = np.zeros((2, 2, 3))
3906        v[:, 0, :] = v1
3907        v[:, 1, :] = v2
3908        out = f(v1, v2)
3909        self.assertTrue(v.shape == out.shape)
3910        self.assertTrue(np.all(v == out))
3911        # Testing out-of-bounds axis
3912        self.assertRaises(IndexError, stack, [a, b], 4)
3913        self.assertRaises(IndexError, stack, [a, b], -4)
3914        # Testing depreciation warning
3915        with warnings.catch_warnings(record=True) as w:
3916            s = stack(a, b)
3917            assert len(w) == 1
3918            assert issubclass(w[-1].category, DeprecationWarning)
3919        with warnings.catch_warnings(record=True) as w:
3920            s = stack([a, b])
3921            s = stack([a, b], 1)
3922            s = stack([a, b], axis=1)
3923            s = stack(tensors=[a, b])
3924            s = stack(tensors=[a, b], axis=1)
3925            assert not w
3926
3927    def test_stack_hessian(self):
3928        # Test the gradient of stack when used in hessian, see gh-1589
3929        a = tensor.dvector('a')
3930        b = tensor.dvector('b')
3931        A = stack([a, b])
3932        B = A.T.dot(A)
3933        Ha, Hb = hessian(B.sum(), [a, b])
3934
3935        # Try some values
3936        a_v = np.random.rand(4)
3937        b_v = np.random.rand(4)
3938        f = theano.function([a, b], [Ha, Hb])
3939        Ha_v, Hb_v = f(a_v, b_v)
3940        # The Hessian is always a matrix full of 2
3941        assert Ha_v.shape == (4, 4)
3942        assert Hb_v.shape == (4, 4)
3943        assert np.allclose(Ha_v, 2.)
3944        assert np.allclose(Hb_v, 2.)
3945
3946    def test_stack_hessian2(self):
3947        # Test the hessian macro when the gradient itself does not depend
3948        # on the input (but the cost does)
3949        a = tensor.dvector('a')
3950        b = tensor.dvector('b')
3951        A = stack([a, b])
3952        Ha, Hb = hessian(A.sum(), [a, b])
3953
3954        # Try some values
3955        a_v = np.random.rand(4)
3956        b_v = np.random.rand(4)
3957        f = theano.function([a, b], [Ha, Hb])
3958        Ha_v, Hb_v = f(a_v, b_v)
3959        # The Hessian is always a matrix full of 0
3960        assert Ha_v.shape == (4, 4)
3961        assert Hb_v.shape == (4, 4)
3962        assert np.allclose(Ha_v, 0.)
3963        assert np.allclose(Hb_v, 0.)
3964
3965    def test_join_concatenate_one_element(self):
3966        # Fast test of concatenate as this is an alias for join.
3967        # also test that we remove the Join op if there is only 1 input
3968        m = tensor.fmatrix()
3969        c = tensor.concatenate([m])
3970        f = theano.function(inputs=[m], outputs=[c],
3971                            mode=self.mode.including('local_join_1'))
3972        topo = f.maker.fgraph.toposort()
3973        assert len(topo) == 1
3974        assert isinstance(topo[0].op, DeepCopyOp)
3975
3976    def test_join_vector(self):
3977        a = self.shared(np.array([1, 2, 3], dtype=self.floatX))
3978        b = as_tensor_variable(np.array([7, 8, 9], dtype=self.floatX))
3979
3980        s = join(0, a, b)
3981        want = np.array([1, 2, 3, 7, 8, 9])
3982        out = self.eval_outputs_and_check_join([s])
3983        self.assertTrue((out == want).all())
3984
3985    def test_roll(self):
3986
3987        for get_shift in [lambda a:a, lambda x:theano.shared(x)]:
3988            # Test simple 1D example
3989            a = self.shared(np.array([1, 2, 3, 4, 5, 6], dtype=self.floatX))
3990            b = roll(a, get_shift(2))
3991            want = np.array([5, 6, 1, 2, 3, 4])
3992            out = theano.function([], b)()
3993
3994            assert (out == want).all()
3995
3996            # Test simple 1D example with explicit 0 axis
3997            b = roll(a, get_shift(-1), 0)
3998            want = np.array([2, 3, 4, 5, 6, 1])
3999            out = theano.function([], b)()
4000
4001            assert (out == want).all()
4002
4003            # Test 2D example - ensure that behavior matches np.roll behavior
4004            a = self.shared(np.arange(21).reshape((3, 7)).astype(self.floatX))
4005            b = roll(a, get_shift(-2), 1)
4006
4007            want = np.roll(a.get_value(borrow=True), -2, 1)
4008            out = theano.function([], b)()
4009
4010            assert (out == want).all()
4011
4012            # Test example when axis < 0 - ensure that behavior matches np.roll behavior
4013            a = self.shared(np.arange(24).reshape((3, 2, 4)).astype(self.floatX))
4014            b = roll(a, get_shift(-2), -2)
4015
4016            want = np.roll(a.get_value(borrow=True), -2, -2)
4017            out = theano.function([], b)()
4018
4019            assert (out == want).all()
4020
4021            # Test rolling on axis 0
4022            want = np.roll(a.get_value(borrow=True), -2, 0)
4023            b = roll(a, get_shift(-2), 0)
4024            out = theano.function([], b)()
4025
4026            assert (out == want).all()
4027
4028            # Test rolling on default axis with ndim > 1
4029            want = np.roll(a.get_value(borrow=True), 2)
4030            b = roll(a, get_shift(2))
4031            out = theano.function([], b)()
4032
4033            assert (out == want).all()
4034
4035            # Test rolling on axis 0 with a positive shift that is
4036            # larger than axis size
4037            want = np.roll(a.get_value(borrow=True), 4, 0)
4038            b = roll(a, get_shift(4), 0)
4039            out = theano.function([], b)()
4040
4041            assert (out == want).all()
4042
4043            # Test rolling on axis 0 with a negative shift that is
4044            # larger than axis size
4045            want = np.roll(a.get_value(borrow=True), -4, 0)
4046            b = roll(a, get_shift(-4), 0)
4047            out = theano.function([], b)()
4048
4049            assert (out == want).all()
4050
4051    def test_stack_vector(self):
4052        a = self.shared(np.array([1, 2, 3], dtype=self.floatX))
4053        b = as_tensor_variable(np.array([7, 8, 9], dtype=self.floatX))
4054
4055        s = stack([a, b])
4056        want = np.array([[1, 2, 3], [7, 8, 9]])
4057        out = self.eval_outputs_and_check_join([s])
4058        self.assertTrue((out == want).all())
4059
4060    def test_join_matrix0(self):
4061        a = self.shared(np.array([[1, 2, 3], [4, 5, 6]],
4062                                 dtype=self.floatX))
4063        b = as_tensor_variable(np.array([[7, 8, 9]], dtype=self.floatX))
4064        s = join(0, a, b)
4065
4066        want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
4067        out = self.eval_outputs_and_check_join([s])
4068        self.assertTrue((out == want).all())
4069
4070    def test_join_matrix1(self):
4071        av = np.array([[.1, .2, .3], [.4, .5, .6]], dtype='float32')
4072        bv = np.array([[.7], [.8]], dtype='float32')
4073        a = self.shared(av)
4074        b = as_tensor_variable(bv)
4075        s = join(1, a, b)
4076        want = np.array([[.1, .2, .3, .7], [.4, .5, .6, .8]],
4077                        dtype='float32')
4078        out = self.eval_outputs_and_check_join([s])
4079        self.assertTrue((out == want).all())
4080
4081        utt.verify_grad(lambda a, b: join(1, a, b), [av, bv],
4082                        mode=self.mode)
4083
4084    def test_join_matrix_dtypes(self):
4085        if "float32" in self.shared.__name__:
4086            raise SkipTest(
4087                "The shared variable constructor"
4088                " need to support other dtype then float32")
4089        # Test mixed dtype. There was a bug that caused crash in the past.
4090        av = np.array([[1, 2, 3], [4, 5, 6]], dtype='int8')
4091        bv = np.array([[7], [8]], dtype='float32')
4092        a = self.shared(av)
4093        b = as_tensor_variable(bv)
4094        s = join(1, a, b)
4095        want = np.array([[1, 2, 3, 7], [4, 5, 6, 8]], dtype='float32')
4096        out = self.eval_outputs_and_check_join([s])
4097        self.assertTrue((out == want).all())
4098
4099        grad(s.sum(), b)
4100        grad(s.sum(), a)
4101        utt.verify_grad(lambda b: join(1, a, b), [bv],
4102                        eps=1.0e-2, mode=self.mode)
4103
4104    def test_join_matrix_ints(self):
4105        if "float32" in self.shared.__name__:
4106            raise SkipTest(
4107                "The shared variable constructor"
4108                " need to support other dtype then float32")
4109        # Test mixed dtype. There was a bug that caused crash in the past.
4110        av = np.array([[1, 2, 3], [4, 5, 6]], dtype='int8')
4111        bv = np.array([[7], [8]], dtype='int32')
4112        a = self.shared(av)
4113        b = as_tensor_variable(bv)
4114        s = join(1, a, b)
4115        want = np.array([[1, 2, 3, 7], [4, 5, 6, 8]], dtype='float32')
4116        out = self.eval_outputs_and_check_join([s])
4117        self.assertTrue((out == want).all())
4118
4119        assert (np.asarray(grad(s.sum(), b).eval()) == 0).all()
4120        assert (np.asarray(grad(s.sum(), a).eval()) == 0).all()
4121
4122    def test_join_matrix1_using_vertical_stack(self):
4123        a = self.shared(np.array([[1, 2, 3], [4, 5, 6]], dtype=self.floatX))
4124        b = as_tensor_variable(np.array([[7, 8, 9]], dtype=self.floatX))
4125        c = as_tensor_variable(np.array([[9, 8, 7]], dtype=self.floatX))
4126        s = vertical_stack(a, b, c)
4127
4128        want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 8, 7]])
4129        out = self.eval_outputs_and_check_join([s])
4130        self.assertTrue((out == want).all())
4131
4132    def test_join_matrix1_using_horizontal_stack(self):
4133        av = np.array([[.1, .2, .3], [.4, .5, .6]], dtype='float32')
4134        bv = np.array([[.7], [.8]], dtype='float32')
4135        cv = np.array([[.3, .2, .1], [.6, .5, .4]], dtype='float32')
4136        a = self.shared(av)
4137        b = as_tensor_variable(bv)
4138        c = as_tensor_variable(cv)
4139        s = horizontal_stack(a, b, c)
4140        want = np.array([[.1, .2, .3, .7, .3, .2, .1],
4141                         [.4, .5, .6, .8, .6, .5, .4]],
4142                        dtype='float32')
4143        out = self.eval_outputs_and_check_join([s])
4144        self.assertTrue((out == want).all())
4145
4146        utt.verify_grad(lambda a, b: join(1, a, b), [av, bv],
4147                        mode=self.mode)
4148
4149    def test_join_matrixV(self):
4150        # variable join axis
4151        v = np.array([[.1, .2, .3], [.4, .5, .6]], dtype=self.floatX)
4152        a = self.shared(v)
4153        b = as_tensor_variable(v)
4154        ax = lscalar()
4155        s = join(ax, a, b)
4156
4157        f = inplace_func([ax], [s], mode=self.mode)
4158        topo = f.maker.fgraph.toposort()
4159        assert [True for node in topo
4160                if isinstance(node.op, type(self.join_op))]
4161
4162        want = np.array([[.1, .2, .3], [.4, .5, .6],
4163                         [.1, .2, .3], [.4, .5, .6]])
4164        got = f(0)
4165        assert np.allclose(got, want)
4166
4167        want = np.array([[.1, .2, .3, .1, .2, .3],
4168                         [.4, .5, .6, .4, .5, .6]])
4169        got = f(1)
4170        assert np.allclose(got, want)
4171
4172        utt.verify_grad(lambda a, b: join(0, a, b), [v, 2 * v], mode=self.mode)
4173        utt.verify_grad(lambda a, b: join(1, a, b), [v, 2 * v], mode=self.mode)
4174
4175    def test_join_matrixV_negative_axis(self):
4176        # variable join negative axis
4177        v = np.array([[.1, .2, .3], [.4, .5, .6]], dtype=self.floatX)
4178        a = self.shared(v)
4179        b = as_tensor_variable(v)
4180        ax = lscalar()
4181        s = join(ax, a, b)
4182
4183        f = inplace_func([ax], [s], mode=self.mode)
4184        topo = f.maker.fgraph.toposort()
4185        assert [True for node in topo
4186                if isinstance(node.op, type(self.join_op))]
4187
4188        want = np.array([[.1, .2, .3, .1, .2, .3],
4189                         [.4, .5, .6, .4, .5, .6]])
4190
4191        got = f(-1)
4192        assert np.allclose(got, want)
4193
4194        want = np.array([[.1, .2, .3], [.4, .5, .6],
4195                         [.1, .2, .3], [.4, .5, .6]])
4196        got = f(-2)
4197        assert np.allclose(got, want)
4198
4199        self.assertRaises(IndexError, f, -3)
4200
4201    def test_join_matrixC_negative_axis(self):
4202        # constant join negative axis
4203        v = np.array([[.1, .2, .3], [.4, .5, .6]], dtype=self.floatX)
4204        a = self.shared(v)
4205        b = as_tensor_variable(v)
4206
4207        s = join(-1, a, b)
4208        f = theano.function([], [s], mode=self.mode)
4209        topo = f.maker.fgraph.toposort()
4210        assert [True for node in topo
4211                if isinstance(node.op, type(self.join_op))]
4212
4213        want = np.array([[.1, .2, .3, .1, .2, .3],
4214                         [.4, .5, .6, .4, .5, .6]])
4215
4216        got = f()
4217        assert np.allclose(got, want)
4218
4219        s = join(-2, a, b)
4220        f = theano.function([], [s], mode=self.mode)
4221        topo = f.maker.fgraph.toposort()
4222        assert [True for node in topo
4223                if isinstance(node.op, type(self.join_op))]
4224
4225        want = np.array([[.1, .2, .3], [.4, .5, .6],
4226                         [.1, .2, .3], [.4, .5, .6]])
4227
4228        got = f()
4229        assert np.allclose(got, want)
4230
4231        self.assertRaises(IndexError, join, -3, a, b)
4232
4233        utt.verify_grad(lambda a, b: join(-1, a, b), [v, 2 * v],
4234                        mode=self.mode)
4235
4236    def test_vector_len(self):
4237        x = lscalar('x')
4238        y = dscalar('y')
4239
4240        triple = as_tensor_variable((x, y, 9.0))
4241        assert 3 == get_vector_length(triple)
4242
4243        a, b, c = triple
4244        f = function([x, y], [b, c, a], mode=self.mode)
4245        topo = f.maker.fgraph.toposort()
4246        assert [True for node in topo if isinstance(node.op, opt.MakeVector)]
4247
4248        assert np.allclose(f(4, 5), [5, 9, 4])
4249
4250    def test_broadcastable_flag_assignment_mixed_otheraxes(self):
4251        # Test that the broadcastable flags for the output of
4252        # a join operation on non-join axes are True if one or
4253        # more inputs is broadcastable on that dimension.
4254        rng = np.random.RandomState(seed=utt.fetch_seed())
4255        a_val = rng.rand(1, 4, 1).astype(self.floatX)
4256        b_val = rng.rand(1, 3, 1).astype(self.floatX)
4257
4258        a = self.shared(a_val, broadcastable=(False, False, True))
4259        b = self.shared(b_val, broadcastable=(True, False, True))
4260        c = self.join_op(1, a, b)
4261        assert c.type.broadcastable[0] and c.type.broadcastable[2]
4262        assert not c.type.broadcastable[1]
4263
4264        # Opt can remplace the int by a Theano constant
4265        c = self.join_op(theano.tensor.constant(1), a, b)
4266        assert c.type.broadcastable[0] and c.type.broadcastable[2]
4267        assert not c.type.broadcastable[1]
4268
4269        # In case futur opt insert other useless stuff
4270        c = self.join_op(theano.tensor.cast(theano.tensor.constant(1),
4271                                            dtype="int32"),
4272                         a, b)
4273        assert c.type.broadcastable[0] and c.type.broadcastable[2]
4274        assert not c.type.broadcastable[1]
4275
4276        f = function([], c, mode=self.mode)
4277        topo = f.maker.fgraph.toposort()
4278        assert [True for node in topo
4279                if isinstance(node.op, type(self.join_op))]
4280
4281        f()
4282        utt.verify_grad((lambda a, b: join(1, a, b)), [a_val, b_val], rng=rng,
4283                        mode=self.mode)
4284
4285        # Should raise an error if dimension 0 does not match
4286        a.set_value(rng.rand(2, 4, 1).astype(self.floatX))
4287        self.assertRaises(ValueError, f)
4288
4289    def test_broadcastable_flag_assignment_mixed_thisaxes(self):
4290        # Test that the broadcastable flag of the join axis
4291        # is False when some inputs are broadcastable on that
4292        # dimension.
4293        rng = np.random.RandomState(seed=utt.fetch_seed())
4294        a_val = rng.rand(2, 4, 1).astype(self.floatX)
4295        b_val = rng.rand(1, 4, 1).astype(self.floatX)
4296
4297        a = self.shared(a_val, broadcastable=(False, False, True))
4298        b = self.shared(b_val, broadcastable=(True, False, True))
4299        c = self.join_op(0, a, b)
4300        assert not c.type.broadcastable[0]
4301
4302        f = function([], c, mode=self.mode)
4303        topo = f.maker.fgraph.toposort()
4304        assert [True for node in topo
4305                if isinstance(node.op, type(self.join_op))]
4306
4307        f()
4308        utt.verify_grad((lambda a, b: join(0, a, b)), [a_val, b_val], rng=rng,
4309                        mode=self.mode)
4310        # Should raise an error if b_val.shape[0] is not 1
4311        # We can't set the value|
4312        self.assertRaises(TypeError, b.set_value,
4313                          rng.rand(3, 4, 1).astype(self.floatX))
4314        a = TensorType(dtype=self.floatX, broadcastable=[0, 0, 1])()
4315        b = TensorType(dtype=self.floatX, broadcastable=[1, 0, 1])()
4316        c = self.join_op(0, a, b)
4317        f = function([a, b], c, mode=self.mode)
4318        bad_b_val = rng.rand(3, 4, 1).astype(self.floatX)
4319        self.assertRaises(TypeError, f, a_val, bad_b_val)
4320
4321    def test_broadcastable_flags_all_broadcastable_on_joinaxis(self):
4322        # Test that joining together several inputs which are all
4323        # broadcastable on the join dimension results in the output
4324        # being non-broadcastable on the join dimension.
4325        rng = np.random.RandomState(seed=utt.fetch_seed())
4326        a_val = rng.rand(1, 4, 1).astype(self.floatX)
4327        b_val = rng.rand(1, 4, 1).astype(self.floatX)
4328
4329        a = self.shared(a_val, broadcastable=(True, False, True))
4330        b = self.shared(b_val, broadcastable=(True, False, True))
4331        c = self.join_op(0, a, b)
4332        assert not c.type.broadcastable[0]
4333
4334        f = function([], c, mode=self.mode)
4335        topo = f.maker.fgraph.toposort()
4336        assert [True for node in topo
4337                if isinstance(node.op, type(self.join_op))]
4338
4339        f()
4340        utt.verify_grad((lambda a, b: join(0, a, b)), [a_val, b_val], rng=rng,
4341                        mode=self.mode)
4342
4343    def test_broadcastable_single_input_broadcastable_dimension(self):
4344        # Test that all broadcastable flags are preserved by a
4345        # single-input join.
4346        rng = np.random.RandomState(seed=utt.fetch_seed())
4347        a_val = rng.rand(1, 4, 1).astype(self.floatX)
4348        a = self.shared(a_val, broadcastable=(True, False, True))
4349        b = self.join_op(0, a)
4350        assert b.type.broadcastable[0]
4351        assert b.type.broadcastable[2]
4352        assert not b.type.broadcastable[1]
4353
4354        f = function([], b, mode=self.mode)
4355        topo = f.maker.fgraph.toposort()
4356        if theano.config.mode != 'FAST_COMPILE':
4357            assert not [True for node in topo
4358                        if isinstance(node.op, type(self.join_op))]
4359
4360        f()
4361        utt.verify_grad((lambda a: join(0, a)), [a_val], rng=rng,
4362                        mode=self.mode)
4363        # Should raise an error if length of dimension 0 is not 1
4364        self.assertRaises(TypeError, a.set_value,
4365                          rng.rand(2, 4, 1).astype(self.floatX))
4366        # self.assertRaises(TypeError, f, bad_a_val)
4367
4368    def test_broadcastable_flags_many_dims_and_inputs(self):
4369        # Test that the right broadcastable flags get set for a join
4370        # with many inputs and many input dimensions.
4371        a = TensorType(dtype=self.floatX, broadcastable=[1, 0, 1, 0, 0, 0])()
4372        b = TensorType(dtype=self.floatX, broadcastable=[1, 1, 1, 0, 0, 0])()
4373        c = TensorType(dtype=self.floatX, broadcastable=[1, 0, 0, 0, 0, 0])()
4374        d = TensorType(dtype=self.floatX, broadcastable=[1, 0, 1, 1, 0, 1])()
4375        e = TensorType(dtype=self.floatX, broadcastable=[1, 0, 1, 0, 0, 1])()
4376        f = self.join_op(0, a, b, c, d, e)
4377        fb = f.type.broadcastable
4378        assert not fb[0] and fb[1] and fb[2] and fb[3] and not fb[4] and fb[5]
4379        g = self.join_op(1, a, b, c, d, e)
4380        gb = g.type.broadcastable
4381        assert gb[0] and not gb[1] and gb[2] and gb[3] and not gb[4] and gb[5]
4382        h = self.join_op(4, a, b, c, d, e)
4383        hb = h.type.broadcastable
4384        assert hb[0] and hb[1] and hb[2] and hb[3] and not hb[4] and hb[5]
4385
4386        f = function([a, b, c, d, e], f, mode=self.mode)
4387        topo = f.maker.fgraph.toposort()
4388        assert [True for node in topo
4389                if isinstance(node.op, type(self.join_op))]
4390
4391        rng = np.random.RandomState(seed=utt.fetch_seed())
4392        a_val = rng.rand(1, 1, 1, 1, 2, 1).astype(self.floatX)
4393        b_val = rng.rand(1, 1, 1, 1, 2, 1).astype(self.floatX)
4394        c_val = rng.rand(1, 1, 1, 1, 2, 1).astype(self.floatX)
4395        d_val = rng.rand(1, 1, 1, 1, 2, 1).astype(self.floatX)
4396        e_val = rng.rand(1, 1, 1, 1, 2, 1).astype(self.floatX)
4397        f(a_val, b_val, c_val, d_val, e_val)
4398        utt.verify_grad((lambda a, b, c, d, e: join(0, a, b, c, d, e)),
4399                        [a_val, b_val, c_val, d_val, e_val], rng=rng,
4400                        mode=self.mode)
4401        # Should raise an error if length of dimension 0 is not 1
4402        bad_val = rng.rand(2, 1, 1, 1, 2, 1).astype(self.floatX)
4403        self.assertRaises(TypeError, f, bad_val, b_val, c_val, d_val, e_val)
4404        self.assertRaises(TypeError, f, a_val, bad_val, c_val, d_val, e_val)
4405        self.assertRaises(TypeError, f, a_val, b_val, bad_val, d_val, e_val)
4406        self.assertRaises(TypeError, f, a_val, b_val, c_val, bad_val, e_val)
4407        self.assertRaises(TypeError, f, a_val, b_val, c_val, d_val, bad_val)
4408        # Should raise an error if any dimension other than 4 has length != 1
4409        bad_a_val = rng.rand(1, 2, 1, 1, 2, 1).astype(self.floatX)
4410        bad_b_val = rng.rand(1, 1, 1, 1, 2, 2).astype(self.floatX)
4411        bad_c_val = rng.rand(1, 1, 2, 1, 2, 1).astype(self.floatX)
4412        bad_d_val = rng.rand(1, 2, 1, 1, 2, 1).astype(self.floatX)
4413        bad_e_val = rng.rand(1, 1, 1, 2, 2, 1).astype(self.floatX)
4414        self.assertRaises(ValueError, f, bad_a_val, b_val, c_val, d_val, e_val)
4415        self.assertRaises(ValueError, f, a_val, bad_b_val, c_val, d_val, e_val)
4416        self.assertRaises(ValueError, f, a_val, b_val, bad_c_val, d_val, e_val)
4417        self.assertRaises(ValueError, f, a_val, b_val, c_val, bad_d_val, e_val)
4418        self.assertRaises(ValueError, f, a_val, b_val, c_val, d_val, bad_e_val)
4419
4420    def test_infer_shape_join(self):
4421        def get_mat(s1, s2):
4422            return np.asarray(np.random.uniform(size=(s1, s2)),
4423                              dtype=self.floatX)
4424
4425        x1 = self.shared(get_mat(3, 4))
4426        x2 = self.shared(get_mat(2, 4))
4427        x3 = self.shared(get_mat(1, 4))
4428
4429        # Test dim 0
4430        z = self.join_op(0, x1, x2, x3)
4431        f = theano.function([], z.shape, mode=self.mode)
4432        topo = f.maker.fgraph.toposort()
4433
4434        out = f()
4435        assert (out == [6, 4]).all()
4436
4437        if theano.config.mode != 'FAST_COMPILE':
4438            for node in f.maker.fgraph.toposort():
4439                assert not isinstance(node.op, type(self.join_op))
4440
4441        # Test dim 1
4442        x1.set_value(get_mat(3, 4))
4443        x2.set_value(get_mat(3, 4))
4444        x3.set_value(get_mat(3, 5))
4445        z = self.join_op(1, x1, x2, x3)
4446        f = theano.function([], z.shape, mode=self.mode)
4447        topo = f.maker.fgraph.toposort()
4448        out = f()
4449        assert (out == [3, 13]).all()
4450
4451        if theano.config.mode != 'FAST_COMPILE':
4452            for node in topo:
4453                assert not isinstance(node.op, type(self.join_op))
4454
4455        with change_flags(compute_test_value='off'):
4456            # Test hide error
4457            x1.set_value(get_mat(3, 4))
4458            x2.set_value(get_mat(3, 4))
4459            x3.set_value(get_mat(2, 5))
4460            if not self.hide_error:
4461                self.assertRaises(ValueError, f)
4462            else:
4463                f()
4464
4465    def test_rebroadcast(self):
4466        # Regression test for a crash that used to happen when rebroadcasting.
4467        x = tensor.TensorType(self.floatX, [False, False, True])()
4468        u = tensor.TensorType(self.floatX, [False, False, True])()
4469        # This line used to crash.
4470        tensor.concatenate([x, -u], axis=2)
4471
4472    def test_concatenate_same(self):
4473        # Test that we can concatenate the same tensor multiple time.
4474
4475        # In the past it was broken on the GPU.
4476        rng = np.random.RandomState(seed=utt.fetch_seed())
4477        T_shared = self.shared(rng.rand(3, 4).astype(self.floatX))
4478        Tout = tensor.concatenate([T_shared, T_shared])
4479        f = function([], Tout, mode=self.mode)
4480        out = f()
4481        if theano.config.mode != 'FAST_COMPILE':
4482            assert [True for node in f.maker.fgraph.toposort()
4483                    if isinstance(node.op, type(self.join_op))]
4484        assert np.allclose(out,
4485                           np.concatenate([T_shared.get_value(),
4486                                           T_shared.get_value()]))
4487
4488    def test_mixed_ndim_error(self):
4489        rng = np.random.RandomState(seed=utt.fetch_seed())
4490        v = self.shared(rng.rand(4).astype(self.floatX))
4491        m = self.shared(rng.rand(4, 4).astype(self.floatX))
4492        self.assertRaises(TypeError, self.join_op, 0, v, m)
4493
4494    def test_split_0elem(self):
4495        rng = np.random.RandomState(seed=utt.fetch_seed())
4496        m = self.shared(rng.rand(4, 6).astype(self.floatX))
4497        o = self.split_op_class(2)(m, 0, [4, 0])
4498        f = function([], o, mode=self.mode)
4499        assert any([isinstance(node.op, self.split_op_class)
4500                    for node in f.maker.fgraph.toposort()])
4501        o1, o2 = f()
4502        assert np.allclose(o1, m.get_value(borrow=True))
4503        assert np.allclose(o2, m.get_value(borrow=True)[4:])
4504
4505    @change_flags(compute_test_value='off')
4506    def test_split_neg(self):
4507        rng = np.random.RandomState(seed=utt.fetch_seed())
4508        m = self.shared(rng.rand(4, 6).astype(self.floatX))
4509        o = self.split_op_class(2)(m, 0, [5, -1])
4510        f = function([], o, mode=self.mode)
4511        assert any([isinstance(node.op, self.split_op_class)
4512                    for node in f.maker.fgraph.toposort()])
4513        self.assertRaises(ValueError, f)
4514
4515
4516def test_join_inplace():
4517    # Test join to work inplace.
4518    #
4519    # This function tests the case when several elements are passed to the
4520    # join function but all except one of them are empty. In this case join
4521    # should work inplace and the output should be the view of the non-empty
4522    # element.
4523    s = tensor.lscalar()
4524    x = tensor.vector('x')
4525    z = tensor.zeros((s,))
4526
4527    join = Join(view=0)
4528    c = join(0, x, z, z)
4529
4530    f = theano.function([theano.In(x, borrow=True), s], theano.Out(c, borrow=True))
4531
4532    data = np.array([3, 4, 5], dtype=theano.config.floatX)
4533    print(f(data, 0))
4534
4535    if theano.config.mode not in ["DebugMode", "DEBUG_MODE"]:
4536        assert f(data, 0) is data
4537    assert np.allclose(f(data, 0), [3, 4, 5])
4538
4539
4540def test_join_oneInput():
4541    # Test join when only 1 input is given.
4542    #
4543    # This functions tests the case when concatenate is called
4544    # on an array of tensors but the array has only one element.
4545    # In this case, we would like to avoid the computational
4546    # overhead of concatenation of one element.
4547    x_0 = theano.tensor.fmatrix()
4548    x_1 = theano.tensor.fmatrix()
4549    x_2 = theano.tensor.fvector()
4550    join_0 = theano.tensor.concatenate([x_0], axis=1)
4551    join_1 = theano.tensor.concatenate([x_0, x_1, theano.tensor.shape_padright(x_2)],
4552                                       axis=1)
4553
4554    assert join_0 is x_0
4555    assert join_1 is not x_0
4556
4557
4558class test_comparison(unittest.TestCase):
4559    # Test <, >, <=, >=, == and !=
4560    #
4561    # Test that we can do the comparison with different
4562    # combination of tensor(shared and constant variable) with
4563    # ndarray. ndarray cmp tensor was crashing.  In a NumPy PR (should
4564    # be in the release 1.8 of NumPy), it will work.  So we assert it
4565    # work(futur behavior) or raise an error(current NumPy release).
4566    def setUp(self):
4567        utt.seed_rng()
4568        self.mode = None
4569        self.shared = shared
4570        self.dtypes = ['float64', 'float32', 'complex64', 'complex128']
4571
4572    def inplace_func(self, inputs, outputs, check_isfinite=None):
4573        mode = self.mode
4574        if check_isfinite is False:
4575            if mode is None:
4576                mode = get_default_mode()
4577            mode.check_isfinite = False
4578        f = inplace_func(inputs, outputs, mode=mode)
4579        return f
4580
4581    def test_gt(self):
4582        for dtype in self.dtypes:
4583            l = np.asarray([0., -1., 1.], dtype=dtype)
4584            r = np.asarray([0., 1., -1.], dtype=dtype)
4585            for x, y, err in [
4586                (self.shared(l.astype(dtype)),
4587                 self.shared(r.astype(dtype)), False),
4588                (l, self.shared(r.astype(dtype)), True),
4589                (tensor.constant(l), self.shared(r.astype(dtype)), False),
4590                (self.shared(l.astype(dtype)), r, False),
4591                (self.shared(l.astype(dtype)), tensor.constant(r), False),
4592            ]:
4593                try:
4594                    fn = self.inplace_func([], x > y)
4595                    v = fn()
4596                    self.assertTrue(np.all(v == (l > r)), (v, (l > r)))
4597                except TypeError:
4598                    assert err
4599
4600    def test_lt(self):
4601        for dtype in self.dtypes:
4602            l = np.asarray([0., -1., 1.], dtype=dtype)
4603            r = np.asarray([0., 1., -1.], dtype=dtype)
4604            for x, y, err in [
4605                (self.shared(l.astype(dtype)), self.shared(r.astype(dtype)), False),
4606                (l, self.shared(r.astype(dtype)), True),
4607                (tensor.constant(l), self.shared(r.astype(dtype)), False),
4608                (self.shared(l.astype(dtype)), r, False),
4609                (self.shared(l.astype(dtype)), tensor.constant(r), False),
4610            ]:
4611                try:
4612                    fn = self.inplace_func([], x < y)
4613                    v = fn()
4614                    self.assertTrue(np.all(v == (l < r)), (v, (l < r)))
4615                except TypeError:
4616                    assert err
4617
4618    def test_le(self):
4619        for dtype in self.dtypes:
4620            l = np.asarray([0., -1., 1.], dtype=dtype)
4621            r = np.asarray([0., 1., -1.], dtype=dtype)
4622            for x, y, err in [
4623                (self.shared(l.astype(dtype)),
4624                 self.shared(r.astype(dtype)), False),
4625                (l, self.shared(r.astype(dtype)), True),
4626                (tensor.constant(l), self.shared(r.astype(dtype)), False),
4627                (self.shared(l.astype(dtype)), r, False),
4628                (self.shared(l.astype(dtype)), tensor.constant(r), False),
4629            ]:
4630                try:
4631                    fn = self.inplace_func([], x <= y)
4632                    v = fn()
4633                    self.assertTrue(np.all(v == (l <= r)), (v, (l <= r)))
4634                except TypeError:
4635                    assert err
4636
4637    def test_ge(self):
4638        for dtype in self.dtypes:
4639            l = np.asarray([0., -1., 1.], dtype=dtype)
4640            r = np.asarray([0., 1., -1.], dtype=dtype)
4641            for x, y, err in [
4642                (self.shared(l.astype(dtype)),
4643                 self.shared(r.astype(dtype)), False),
4644                (l, self.shared(r.astype(dtype)), True),
4645                (tensor.constant(l), self.shared(r.astype(dtype)), False),
4646                (self.shared(l.astype(dtype)), r, False),
4647                (self.shared(l.astype(dtype)), tensor.constant(r), False),
4648            ]:
4649                try:
4650                    fn = self.inplace_func([], x >= y)
4651                    v = fn()
4652                    self.assertTrue(np.all(v == (l >= r)), (v, (l >= r)))
4653                except TypeError:
4654                    assert err
4655
4656    def test_eq(self):
4657        for dtype in self.dtypes:
4658            l = np.asarray([0., -1., 1.], dtype=dtype)
4659            r = np.asarray([0., 1., -1.], dtype=dtype)
4660            for x, y, err in [
4661                (self.shared(l.astype(dtype)),
4662                 self.shared(r.astype(dtype)), False),
4663                (l, self.shared(r.astype(dtype)), True),
4664                (tensor.constant(l), self.shared(r.astype(dtype)), False),
4665                (self.shared(l.astype(dtype)), r, False),
4666                (self.shared(l.astype(dtype)), tensor.constant(r), False),
4667            ]:
4668                try:
4669                    fn = self.inplace_func([], eq(x, y))
4670                    v = fn()
4671                    self.assertTrue(np.all(v == (l == r)), (v, (l == r)))
4672                except TypeError:
4673                    assert err
4674
4675    def test_neq(self):
4676        for dtype in self.dtypes:
4677            l = np.asarray([0., -1., 1.], dtype=dtype)
4678            r = np.asarray([0., 1., -1.], dtype=dtype)
4679            for x, y, err in [
4680                (self.shared(l.astype(dtype)),
4681                 self.shared(r.astype(dtype)), False),
4682                (l, self.shared(r.astype(dtype)), True),
4683                (tensor.constant(l), self.shared(r.astype(dtype)), False),
4684                (self.shared(l.astype(dtype)), r, False),
4685                (self.shared(l.astype(dtype)), tensor.constant(r), False),
4686            ]:
4687                try:
4688                    fn = self.inplace_func([], neq(x, y))
4689                    v = fn()
4690                    self.assertTrue(np.all(v == (l != r)), (v, (l != r)))
4691                except TypeError:
4692                    assert err
4693
4694    def test_isclose(self):
4695        for dtype in self.dtypes:
4696            l = np.asarray(
4697                [0., 1., -1., 0.,
4698                 np.nan, np.inf, -np.inf, np.inf],
4699                dtype=dtype)
4700            r = np.asarray(
4701                [0., 1.0001, -1.000000000001, np.nan,
4702                 np.nan, np.inf, np.inf, 0.],
4703                dtype=dtype)
4704            for x, y, err in [
4705                (self.shared(l.astype(dtype)),
4706                 self.shared(r.astype(dtype)), False),
4707                (l, self.shared(r.astype(dtype)), True),
4708                (constant(l), self.shared(r.astype(dtype)), False),
4709                (self.shared(l.astype(dtype)), r, False),
4710                (self.shared(l.astype(dtype)), constant(r), False),
4711            ]:
4712                try:
4713                    o1 = isclose(x, y, equal_nan=False)
4714                    fn1 = self.inplace_func([], o1, check_isfinite=False)
4715
4716                    o2 = isclose(x, y, equal_nan=True)
4717                    fn2 = self.inplace_func([], o2, check_isfinite=False)
4718
4719                    v1 = fn1()
4720                    v2 = fn2()
4721                    self.assertTrue(
4722                        np.all(
4723                            v1 == np.asarray(
4724                                [True, False, True, False,
4725                                 False, True, False, False],
4726                                dtype="bool"
4727                            )
4728                        ),
4729                        np.all(
4730                            v2 == np.asarray(
4731                                [True, False, True, False,
4732                                 True, True, False, False],
4733                                dtype="bool"
4734                            )
4735                        )
4736                    )
4737                except TypeError:
4738                    if not dtype.startswith('complex'):
4739                        raise
4740                        assert err
4741
4742    def test_allclose(self):
4743        # equal_nan argument not in current version of numpy allclose,
4744        # force it to False.
4745        for dtype in self.dtypes:
4746            l = np.asarray(
4747                [0., 1., -1., 0.,
4748                 np.nan, np.inf, -np.inf, np.inf],
4749                dtype=dtype)
4750            r = np.asarray(
4751                [0., 1.0001, -1.000000000001, np.nan,
4752                 np.nan, np.inf, np.inf, 0.],
4753                dtype=dtype)
4754            for x, y, err in [
4755                (self.shared(l.astype(dtype)),
4756                 self.shared(r.astype(dtype)), False),
4757                (l, self.shared(r.astype(dtype)), True),
4758                (constant(l), self.shared(r.astype(dtype)), False),
4759                (self.shared(l.astype(dtype)), r, False),
4760                (self.shared(l.astype(dtype)), constant(r), False),
4761            ]:
4762                try:
4763                    fn = self.inplace_func([], allclose(x, y, equal_nan=False),
4764                                           check_isfinite=False)
4765                    v = fn()
4766                    self.assertTrue(np.all(v == np.allclose(l, r)))
4767                except TypeError:
4768                    if not dtype.startswith('complex'):
4769                        assert err
4770
4771
4772class test_bitwise(unittest.TestCase):
4773    dtype = ['int8', 'int16', 'int32', 'int64', ]
4774
4775    def test_or(self):
4776        for dtype in self.dtype:
4777            x, y = vector(dtype=dtype), vector(dtype=dtype)
4778            fn = inplace_func([x, y], x | y)
4779            l = theano._asarray([0, 0, 1, 1], dtype=dtype)
4780            r = theano._asarray([0, 1, 0, 1], dtype=dtype)
4781            v = fn(l, r)
4782            self.assertTrue(np.all(v == (operator.or_(l, r))), (l, r, v))
4783
4784    def test_xor(self):
4785        for dtype in self.dtype:
4786            x, y = vector(dtype=dtype), vector(dtype=dtype)
4787            fn = inplace_func([x, y], x ^ y)
4788            ix = x
4789            ix = inplace.xor_inplace(ix, y)
4790            gn = inplace_func([x, y], ix)
4791            l = theano._asarray([0, 0, 1, 1], dtype=dtype)
4792            r = theano._asarray([0, 1, 0, 1], dtype=dtype)
4793            v = fn(l, r)
4794            self.assertTrue(np.all(v == (operator.xor(l, r))), (l, r, v))
4795            v = gn(l, r)
4796            # test the in-place stuff
4797            self.assertTrue(np.all(l == np.asarray([0, 1, 1, 0])), l)
4798
4799    def test_and(self):
4800        for dtype in self.dtype:
4801            x, y = vector(dtype=dtype), vector(dtype=dtype)
4802            fn = inplace_func([x, y], x & y)
4803            l = theano._asarray([0, 0, 1, 1], dtype=dtype)
4804            r = theano._asarray([0, 1, 0, 1], dtype=dtype)
4805            v = fn(l, r)
4806            self.assertTrue(np.all(v == (operator.and_(l, r))), (l, r, v))
4807
4808    def test_inv(self):
4809        for dtype in self.dtype:
4810            x = vector(dtype=dtype)
4811            fn = inplace_func([x], ~x)
4812            for l in [[0, 0, 1, 1], [0, 1, 0, 1],
4813                      [0, 0, 1, 1], [0, 1, 0, 1],
4814                      [-1, 2 ** 16, 2 ** 16 - 1]
4815                      ]:
4816                l = theano._asarray([0, 0, 1, 1], dtype=dtype)
4817                v = fn(l)
4818                self.assertTrue(np.all(v == (~l)), (l, v))
4819
4820    def test_eye(self):
4821        n = iscalar()
4822        m = iscalar()
4823        k = iscalar()
4824        fn = theano.function([m, n, k], eye(m, n, k))
4825        self.assertTrue(np.all(fn(5, 6, 1) == np.eye(5, 6, 1)))
4826
4827
4828class T_add(unittest.TestCase):
4829    def setUp(self):
4830        utt.seed_rng()
4831
4832    def test_complex_all_ops(self):
4833        for nbits in (64, 128):
4834            a = shared(np.ones(3, dtype='complex%i' % nbits) + 0.5j)
4835            b = shared(np.ones(3, dtype='complex%i' % nbits) + 1.5j)
4836            tests = (("+", lambda x, y: x + y),
4837                     ("-", lambda x, y: x - y),
4838                     ("*", lambda x, y: x * y),
4839                     ("/", lambda x, y: x / y))
4840            for s, fn in tests:
4841                f = inplace_func([], fn(a, b))
4842                # print 'valid output:', fn(a.data, b.data)
4843                # print 'theano output:', f(a.data, b.data)
4844                self.assertTrue(a.type.values_eq_approx(fn(
4845                    a.get_value(), b.get_value()), f()))
4846
4847    def test_grad_scalar_l(self):
4848        utt.verify_grad(add, [np.asarray([3.0]), rand(3)])
4849
4850    def test_grad_scalar_r(self):
4851        utt.verify_grad(add, [rand(3), np.asarray([3.0])])
4852
4853    def test_grad_row(self):
4854        utt.verify_grad(add, [rand(3, 5), rand(1, 5)])
4855
4856    def test_grad_col(self):
4857        utt.verify_grad(add, [rand(3, 5), rand(3, 1)])
4858
4859
4860class T_ceil(unittest.TestCase):
4861    def test_complex(self):
4862        self.assertRaises(TypeError, tensor.ceil, tensor.zvector())
4863
4864
4865class T_exp(unittest.TestCase):
4866    def test_grad_0(self):
4867        utt.verify_grad(exp, [
4868            np.asarray([[1.5089518, 1.48439076, -4.7820262],
4869                        [2.04832468, 0.50791564, -1.58892269]])])
4870
4871    def test_grad_1(self):
4872        utt.verify_grad(inplace.exp_inplace, [
4873            np.asarray([[1.5089518, 1.48439076, -4.7820262],
4874                        [2.04832468, 0.50791564, -1.58892269]])])
4875
4876    if theano.config.cycle_detection == 'fast' and theano.config.mode != 'FAST_COMPILE':
4877        test_grad_1 = unittest.expectedFailure(test_grad_1)
4878
4879    def test_int(self):
4880        x = ivector()
4881        f = function([x], exp(x))
4882        exp_3 = f([3])
4883        assert exp_3.dtype == 'float64'
4884
4885    def test_complex(self):
4886        x = zvector()
4887        assert exp(x).dtype == 'complex128'
4888        f = function([x], exp(x))
4889        exp_3 = f([3 + 2j])
4890        assert np.allclose(exp_3, np.exp(3 + 2j))
4891
4892
4893class T_divimpl(unittest.TestCase):
4894    def test_impls(self):
4895        i = iscalar()
4896        ii = lscalar()
4897        d = dscalar()
4898        f = fscalar()
4899        c = cscalar()
4900
4901        assert np.allclose(function([i, d], i / d)(5, 7.0), (5.0 / 7.0))
4902        assert np.allclose(function([i, d], d / i)(5, 7.0), (7.0 / 5.0))
4903        assert np.allclose(function([i, f], i / f)(5, 11.0), (5.0 / 11.0))
4904        assert np.allclose(function([i, f], f / i)(5, 11.0), (11.0 / 5.0))
4905        assert np.allclose(function([i, ii], i // ii)(5, 3), (5 // 3))
4906        assert np.allclose(function([i, ii], ii // i)(5, 3), (3 // 5))
4907        assert np.allclose(function([i, ii], true_div(i, ii))(5, 3),
4908                           (5. / 3.))
4909        assert np.allclose(function([i, ii], true_div(ii, i))(5, 3),
4910                           (3. / 5.))
4911        assert np.allclose(function([i, c], i / c)(5, np.complex(5, 3)),
4912                           (5. / (5 + 3j)))
4913        assert np.allclose(function([i, c], c / i)(5, np.complex(5, 3)),
4914                           ((5 + 3j) / 5.))
4915
4916
4917class T_mean(unittest.TestCase):
4918    def test_regression_mean_of_ndarray_failure(self):
4919        try:
4920            tensor.mean(np.zeros(1))
4921        except AttributeError:
4922            self.fail()
4923
4924    def test_mean_f16(self):
4925        x = tensor.vector(dtype='float16')
4926        y = x.mean()
4927        f = theano.function([x], y)
4928        utt.assert_allclose(f(np.ones((100000,), dtype='float16')), 1.0)
4929
4930    def test0(self):
4931        # Simple test...
4932        x = tensor.vector()
4933        f = theano.function([x], tensor.mean(x))
4934        data = rand(50)
4935        assert np.allclose(f(data), np.mean(data))
4936
4937    def test_list(self):
4938        ll = [theano.shared(0.), theano.shared(2.)]
4939        tensor.mean(ll).eval() == 1
4940
4941
4942class test_matinv(unittest.TestCase):
4943
4944    def mat_reciprocal(self, dim):
4945        # symbolic program
4946        # broadcastable=[False,False] means that the shape of matrix is two dimensional,
4947        # and none of the dimensions are constrained to have length 1.
4948        # Note that TensorType's constructor does not actually allocate any memory.
4949        # TODO: Make TensorType syntax more explicit, and maybe give shape or number of dimensions.
4950
4951        rng = np.random.RandomState(seed=utt.fetch_seed())
4952
4953        a, b = matrices('ab')
4954        ab = a * b
4955        # Here, as_tensor_variable actually uses the data allocated by np.
4956        diff = ab - as_tensor_variable(np.ones((dim, dim),
4957                                               dtype=config.floatX))
4958        # Sum of squared errors
4959        ssdiff = sum((diff ** 2.0))
4960
4961        g_b = grad(ssdiff, b)
4962
4963        # compilation to function
4964        # [a,b] are the inputs, [ssdiff,g_b] are the outputs
4965        fn = inplace_func([a, b], [ssdiff, g_b])
4966
4967        # use the function
4968        x = rng.rand(dim, dim) + 0.1      # Initialized s.t. x is not too tiny
4969        w = rng.rand(dim, dim)
4970        x = np.asarray(x, dtype=config.floatX)
4971        w = np.asarray(w, dtype=config.floatX)
4972
4973        for i in xrange(100):
4974            ssd, gw = fn(x, w)
4975            # print ssd, x*w, x, w
4976            if i == 0:
4977                ssd0 = ssd
4978            w -= 0.4 * gw
4979
4980        return ssd0, ssd
4981
4982    def test_reciprocal(self):
4983        # Matrix reciprocal by gradient descent
4984        ssd0, ssd = self.mat_reciprocal(3)
4985
4986        rng = np.random.RandomState(seed=utt.fetch_seed())
4987        # hand-coded numpy implementation for verification
4988        x = rng.rand(3, 3) + 0.1
4989        w = rng.rand(3, 3)
4990        x = np.asarray(x, dtype=config.floatX)
4991        w = np.asarray(w, dtype=config.floatX)
4992        ones = np.ones((3, 3), dtype=config.floatX)
4993
4994        myssd0 = np.sum((x * w - ones) ** 2.0)
4995        # we want at least a test that is not too fast. So we make one here.
4996        for i in xrange(100):
4997            gw = 2 * (x * w - ones) * x  # derivative of dMSE/dw
4998            myssd = np.sum((x * w - ones) ** 2)
4999            w -= 0.4 * gw
5000        self.assertAlmostEqual(ssd0, myssd0)
5001        self.assertAlmostEqual(ssd, myssd)
5002
5003
5004class t_dot(unittest.TestCase):
5005    def setUp(self):
5006        utt.seed_rng()
5007
5008    def cmp_dot(self, x, y):
5009        # x, y are matrices or numbers
5010        def spec(x):
5011            x = np.asarray(x)
5012            return type(x), x.dtype, x.shape
5013        nz = np.dot(x, y)
5014        tz = eval_outputs([dot(as_tensor_variable(x), as_tensor_variable(y))])
5015        self.assertTrue(tz.dtype == nz.dtype,
5016                        (tz.dtype, tz.dtype.num, nz.dtype, nz.dtype.num))
5017        self.assertTrue(tz.shape == nz.shape, (tz.shape, nz.shape))
5018        utt.assert_allclose(nz, tz, rtol=1e-4, atol=1e-4)
5019
5020    def test_Op_dims(self):
5021        # _dot is a Dot op instance
5022        _dot = theano.tensor.basic._dot
5023        d0 = scalar()
5024        d1 = vector()
5025        d2 = matrix()
5026        d3 = tensor3()
5027
5028        self.assertRaises(TypeError, _dot, d0, d0)
5029        self.assertRaises(TypeError, _dot, d0, d1)
5030        self.assertRaises(TypeError, _dot, d0, d2)
5031        self.assertRaises(TypeError, _dot, d0, d3)
5032        self.assertRaises(TypeError, _dot, d1, d0)
5033        _dot(d1, d1)
5034        _dot(d1, d2)
5035        self.assertRaises(TypeError, _dot, d1, d3)
5036        self.assertRaises(TypeError, _dot, d2, d0)
5037        _dot(d2, d1)
5038        _dot(d2, d2)
5039        self.assertRaises(TypeError, _dot, d2, d3)
5040        self.assertRaises(TypeError, _dot, d3, d0)
5041        self.assertRaises(TypeError, _dot, d3, d1)
5042        self.assertRaises(TypeError, _dot, d3, d2)
5043        self.assertRaises(TypeError, _dot, d3, d3)
5044
5045    def test_dot_0d_0d(self):
5046        self.cmp_dot(rand(), rand())
5047
5048    def test_dot_0d_1d(self):
5049        self.cmp_dot(rand(), rand(5))
5050
5051    def test_dot_0d_2d(self):
5052        self.cmp_dot(rand(), rand(6, 7))
5053
5054    def test_dot_0d_3d(self):
5055        self.cmp_dot(rand(), rand(8, 6, 7))
5056
5057    def test_dot_1d_0d(self):
5058        self.cmp_dot(rand(5), rand())
5059
5060    def test_dot_1d_1d(self):
5061        self.cmp_dot(rand(5), rand(5))
5062
5063    def test_dot_1d0_1d0(self):
5064        self.cmp_dot(rand(0), rand(0))
5065
5066    # numpy return matrix not aligned...
5067    def test_dot_1d_1d0(self):
5068        self.assertRaises(ValueError, self.cmp_dot, rand(5), rand(0))
5069
5070    # numpy return matrix not aligned...
5071    def test_dot_1d0_1d(self):
5072        self.assertRaises(ValueError, self.cmp_dot, rand(0), rand(5))
5073
5074    def test_dot_1d_2d(self):
5075        self.cmp_dot(rand(6), rand(6, 7))
5076
5077    def test_dot_1d0_2d(self):
5078        self.cmp_dot(rand(0), rand(0, 7))
5079
5080    def test_dot_1d_2d0(self):
5081        self.cmp_dot(rand(6), rand(6, 0))
5082
5083    def test_dot_1d0_2d0(self):
5084        self.cmp_dot(rand(0), rand(0, 0))
5085
5086    def test_dot_1d_3d(self):
5087        self.cmp_dot(rand(6), rand(8, 6, 7))
5088
5089    def test_dot_2d_0d(self):
5090        self.cmp_dot(rand(5, 6), rand())
5091
5092    def test_dot_2d_1d(self):
5093        self.cmp_dot(rand(5, 6), rand(6))
5094
5095    def test_dot_2d0_1d(self):
5096        self.cmp_dot(rand(0, 6), rand(6))
5097
5098    def test_dot_2d_1d0(self):
5099        self.cmp_dot(rand(5, 0), rand(0))
5100
5101    def test_dot_2d0_1d0(self):
5102        self.cmp_dot(rand(0, 0), rand(0))
5103
5104    def test_dot_2d_2d(self):
5105        self.cmp_dot(rand(5, 6), rand(6, 7))
5106
5107    def test_dot_2d0_2d(self):
5108        self.cmp_dot(rand(0, 6), rand(6, 7))
5109
5110    def test_dot_2d_2d0(self):
5111        self.cmp_dot(rand(5, 6), rand(6, 0))
5112
5113    def test_dot_2d0_2d0(self):
5114        self.cmp_dot(rand(0, 6), rand(6, 0))
5115
5116    def test_dot_2d_0_2d(self):
5117        self.cmp_dot(rand(5, 0), rand(0, 7))
5118
5119    def test_dot_2d0_0_2d0(self):
5120        self.cmp_dot(rand(0, 6), rand(6, 0))
5121
5122    def test_dot_2d_3d(self):
5123        self.cmp_dot(rand(5, 6), rand(8, 6, 7))
5124
5125    def test_dot_3d_0d(self):
5126        self.cmp_dot(rand(4, 5, 6), rand())
5127
5128    def test_dot_3d_1d(self):
5129        self.cmp_dot(rand(4, 5, 6), rand(6))
5130
5131    def test_dot_3d_2d(self):
5132        self.cmp_dot(rand(4, 5, 6), rand(6, 7))
5133
5134    def test_dot_3d_3d(self):
5135        self.cmp_dot(rand(4, 5, 6), rand(8, 6, 7))
5136
5137    def not_aligned(self, x, y):
5138        ctv_backup = config.compute_test_value
5139        config.compute_test_value = 'off'
5140        try:
5141            z = dot(x, y)
5142        finally:
5143            config.compute_test_value = ctv_backup
5144        # constant folding will complain to _logger that things are not aligned
5145        # this is normal, testers are not interested in seeing that output.
5146        _logger = logging.getLogger('theano.gof.opt')
5147        oldlevel = _logger.level
5148        _logger.setLevel(logging.CRITICAL)
5149        try:
5150            try:
5151                eval_outputs([z])
5152                assert False    # should have raised exception
5153            except ValueError as e:
5154                e0 = exc_message(e)
5155                self.assertTrue(
5156                    # Reported by numpy.
5157                    e0.split()[1:4] == ['are', 'not', 'aligned'] or
5158                    # Reported by blas or Theano.
5159                    e0.split()[0:2] == ['Shape', 'mismatch:'] or
5160                    # Reported by Theano perform
5161                    (e0.split()[0:4] ==
5162                        ['Incompatible', 'shapes', 'for', 'gemv']) or
5163                    e)
5164        finally:
5165            _logger.setLevel(oldlevel)
5166
5167    def test_align_1_1(self):
5168        self.not_aligned(rand(5), rand(6))
5169
5170    def test_align_1_2(self):
5171        self.not_aligned(rand(5), rand(6, 4))
5172
5173    def test_align_1_3(self):
5174        self.not_aligned(rand(5), rand(6, 4, 7))
5175
5176    def test_align_2_1(self):
5177        self.not_aligned(rand(5, 4), rand(6))
5178
5179    def test_align_2_2(self):
5180        self.not_aligned(rand(5, 4), rand(6, 7))
5181
5182    def test_align_2_3(self):
5183        self.not_aligned(rand(5, 4), rand(6, 7, 8))
5184
5185    def test_align_3_1(self):
5186        self.not_aligned(rand(5, 4, 3), rand(6))
5187
5188    def test_align_3_2(self):
5189        self.not_aligned(rand(5, 4, 3), rand(6, 7))
5190
5191    def test_align_3_3(self):
5192        self.not_aligned(rand(5, 4, 3), rand(6, 7, 8))
5193
5194    def test_grad(self):
5195        utt.verify_grad(dot, [rand(2, 3), rand(3, 2)])
5196        utt.verify_grad(dot, [rand(2), rand(2, 3)])
5197        utt.verify_grad(dot, [rand(3, 2), rand(2)])
5198        utt.verify_grad(dot, [rand(2), rand(2)])
5199        utt.verify_grad(dot, [rand(), rand(2)])
5200        utt.verify_grad(dot, [rand(), rand(2, 5)])
5201        utt.verify_grad(dot, [rand(2), rand()])
5202        utt.verify_grad(dot, [rand(2, 5), rand()])
5203        utt.verify_grad(dot, [rand(2, 3, 4), rand(4)])
5204        utt.verify_grad(dot, [rand(3), rand(2, 3, 4)])
5205        utt.verify_grad(dot, [rand(4, 3), rand(2, 3, 4)])
5206        utt.verify_grad(dot, [rand(2, 3, 4), rand(4, 5)])
5207        utt.verify_grad(dot, [rand(2, 3, 4), rand(3, 4, 5)])
5208
5209    @attr('slow')
5210    def test_broadcastable_patterns(self):
5211
5212        #
5213        # These examples should all work because we broadcastable or
5214        # no, all dimensions of all results have size 1.
5215        #
5216        def val_for(r):
5217            if r.dtype.startswith('complex'):
5218                # We want to test complex at the same time, so we give a value
5219                # To the imaginary component.
5220                # This strange way of doing things is the only way that worked
5221                # on numpy 1.4.1
5222                if r.ndim == 0:
5223                    return np.asarray(np.complex(1.1, 2.1),
5224                                      dtype=r.dtype)
5225                if r.ndim == 1:
5226                    if r.dtype == 'complex64':
5227                        return np.complex64([np.complex(1.2, 2.2)])
5228                    elif r.dtype == 'complex128':
5229                        return np.complex128([np.complex(1.2, 2.2)])
5230                elif r.ndim == 2:
5231                    if r.dtype == 'complex64':
5232                        return np.complex64([[np.complex(1.3, 2.3)]])
5233                    elif r.dtype == 'complex128':
5234                        return np.complex128([[np.complex(1.3, 2.3)]])
5235
5236            if r.ndim == 0:
5237                return np.asarray(1.1, dtype=r.dtype)
5238            if r.ndim == 1:
5239                return np.asarray([1.2], dtype=r.dtype)
5240            elif r.ndim == 2:
5241                return np.asarray([[1.3]], dtype=r.dtype)
5242            raise ValueError()
5243
5244        for dtype0 in ('float32', 'float64', 'complex64'):
5245            for dtype1 in ('float32', 'complex64', 'complex128'):
5246                for bc0 in ((True,), (False,), (True, True),
5247                            (True, False), (False, True),
5248                            (False, False)):
5249                    x = TensorType(dtype=dtype0, broadcastable=bc0)()
5250                    for bc1 in ((True,), (False,), (True, True),
5251                                (True, False), (False, True),
5252                                (False, False)):
5253
5254                        y = TensorType(dtype=dtype1, broadcastable=bc1)()
5255                        z = dot(x, y)
5256                        t = TensorType(dtype=dtype0,
5257                                       broadcastable=z.broadcastable)()
5258
5259                        rval = z * 3 + 2 * t
5260                        f = function([x, y, t], rval)
5261                        xval = val_for(x)
5262                        yval = val_for(y)
5263                        tval = val_for(t)
5264
5265                        f(xval, yval, tval)  # debugmode checks result
5266                        if (dtype0.startswith('float') and
5267                                dtype1.startswith('float')):
5268                            g = grad(z.sum(), x)
5269                            assert g.broadcastable == x.broadcastable
5270                            g = grad(z.sum(), y)
5271                            assert g.broadcastable == y.broadcastable
5272
5273
5274class T_tensorfromscalar(unittest.TestCase):
5275    def test0(self):
5276        s = scal.constant(56)
5277        t = tensor_from_scalar(s)
5278        self.assertTrue(t.owner.op is tensor_from_scalar)
5279        self.assertTrue(t.type.broadcastable == (), t.type.broadcastable)
5280        self.assertTrue(t.type.ndim == 0, t.type.ndim)
5281        self.assertTrue(t.type.dtype == s.type.dtype)
5282
5283        v = eval_outputs([t])
5284
5285        self.assertTrue(v == 56, v)
5286        self.assertTrue(isinstance(v, np.ndarray))
5287        self.assertTrue(v.shape == (), v.shape)
5288
5289    def test1(self):
5290        s = scal.constant(56)
5291        t = as_tensor_variable(s)
5292        self.assertTrue(t.owner.op is tensor_from_scalar)
5293        self.assertTrue(t.type.broadcastable == (), t.type.broadcastable)
5294        self.assertTrue(t.type.ndim == 0, t.type.ndim)
5295        self.assertTrue(t.type.dtype == s.type.dtype)
5296
5297        v = eval_outputs([t])
5298
5299        self.assertTrue(v == 56, v)
5300        self.assertTrue(isinstance(v, np.ndarray))
5301        self.assertTrue(v.shape == (), v.shape)
5302
5303        g = grad(t, s)
5304        self.assertTrue(eval_outputs([g]) == 0.)
5305
5306    def test2(self):
5307        s = scal.constant(56.)
5308        t = as_tensor_variable(s)
5309        self.assertTrue(t.owner.op is tensor_from_scalar)
5310        self.assertTrue(t.type.broadcastable == (), t.type.broadcastable)
5311        self.assertTrue(t.type.ndim == 0, t.type.ndim)
5312        self.assertTrue(t.type.dtype == s.type.dtype)
5313
5314        v = eval_outputs([t])
5315
5316        self.assertTrue(v == 56., v)
5317        self.assertTrue(isinstance(v, np.ndarray))
5318        self.assertTrue(v.shape == (), v.shape)
5319
5320        g = grad(t, s)
5321        self.assertTrue(eval_outputs([g]) == 1.)
5322
5323
5324class T_scalarfromtensor(unittest.TestCase):
5325    def test0(self):
5326        tt = constant(56)  # scal.constant(56)
5327        ss = scalar_from_tensor(tt)
5328        self.assertTrue(ss.owner.op is scalar_from_tensor)
5329        self.assertTrue(ss.type.dtype == tt.type.dtype)
5330
5331        v = eval_outputs([ss])
5332
5333        self.assertTrue(v == 56, v)
5334        if config.cast_policy == 'custom':
5335            self.assertTrue(isinstance(v, np.int8))
5336        elif config.cast_policy in ('numpy', 'numpy+floatX'):
5337            self.assertTrue(isinstance(
5338                v, getattr(np, str(np.asarray(56).dtype))))
5339        else:
5340            raise NotImplementedError(config.cast_policy)
5341        self.assertTrue(v.shape == (), v.shape)
5342        tt = lscalar()
5343        ss = scalar_from_tensor(tt)
5344        ss.owner.op.grad([tt], [ss])
5345        fff = function([tt], ss)
5346        v = fff(np.asarray(5))
5347        self.assertTrue(v == 5, v)
5348        self.assertTrue(isinstance(v, np.int64))
5349        self.assertTrue(v.shape == (), v.shape)
5350
5351
5352class test_grad(unittest.TestCase):
5353    class Obj1(gof.op.Op):
5354        def __init__(self):
5355            self.gval0 = scalar('e')
5356            self.gval1 = scalar('f')
5357
5358        def make_node(self):
5359            inputs = [scalar('a'), scalar('c')]
5360            outputs = [scalar('b'), scalar('d')]
5361            return gof.Apply(self, inputs, outputs)
5362
5363        def grad(self, inp, grads):
5364            x0, x1 = inp
5365            gz0, gz1 = grads
5366            return self.gval0, self.gval1
5367
5368    def test_1param(self):
5369        # grad: Test passing a single variable param
5370        o = test_grad.Obj1()
5371        a1 = o.make_node()
5372        self.assertTrue(o.gval0 is tensor.grad(a1.outputs[0], a1.inputs[0]))
5373
5374    def test_Nparam(self):
5375        # grad: Test passing multiple variable params
5376        o = test_grad.Obj1()
5377        a1 = o.make_node()
5378        g0, g1 = grad(a1.outputs[0], a1.inputs)
5379        g0.name = None
5380        self.assertTrue(o.gval0 is g0)
5381        self.assertTrue(o.gval1 is g1)
5382
5383    def test_grad_keep_type(self):
5384        # Tests that the theano grad method returns a list if it is passed a list
5385        # and a single variable if it is passed a single variable.
5386        # pylearn2 depends on theano behaving this way. This functionality has been
5387        # added three times and erroneously removed twice. If you do anything that
5388        # requires changing this test or making it fail you are almost certainly
5389        # making a common mistake, NOT fixing something.
5390
5391        X = tensor.matrix()
5392        y = X.sum()
5393
5394        G = tensor.grad(y, [X])
5395
5396        assert isinstance(G, list)
5397
5398        G = tensor.grad(y, X)
5399
5400        assert not isinstance(G, list)
5401
5402    def test_1None_rval(self):
5403        # grad: Test returning a single zero value from grad
5404        o = test_grad.Obj1()
5405        a1 = o.make_node()
5406        g = grad(a1.outputs[0], a1.outputs[1],
5407                 disconnected_inputs='ignore')
5408        self.assertTrue(g.owner.op == fill)
5409        self.assertTrue(g.owner.inputs[1].data == 0)
5410        self.assertRaises(TypeError, grad, a1.outputs[0], 'wtf')
5411
5412    def test_NNone_rval(self):
5413        # grad: Test returning some zero value from grad
5414        o = test_grad.Obj1()
5415        a1 = o.make_node()
5416        g0, g1, g2 = grad(a1.outputs[0], a1.inputs + [scalar('z')],
5417                          disconnected_inputs='ignore')
5418        self.assertTrue(o.gval0 is g0)
5419        self.assertTrue(o.gval1 is g1)
5420        self.assertTrue(g2.owner.op == fill)
5421        self.assertTrue(g2.owner.inputs[1].data == 0)
5422
5423    def test_zero_gradient_shape(self):
5424        # Ensure that a zero gradient has the proper shape.
5425        x = dmatrix()
5426        f = theano.function([x], grad(dscalar(), x,
5427                                      disconnected_inputs='ignore'))
5428        a = np.ones((3, 7))
5429        self.assertTrue((f(a) == 0).all())  # Zero gradient.
5430        self.assertTrue(a.shape == f(a).shape)  # With proper shape.
5431
5432    def test_cost_is_scalar(self):
5433        # grad: Test that a non-scalar cost raises a TypeError
5434        v = vector()
5435        m = matrix()
5436        # grad(v,...) and grad(m,...) should fail
5437        self.assertRaises(TypeError, grad, v, v)
5438        self.assertRaises(TypeError, grad, m, m)
5439
5440
5441class T_op_cache(unittest.TestCase):
5442    def setUp(self):
5443        utt.seed_rng()
5444
5445    def test0(self):
5446        # trigger bug in ticket #162
5447        v = matrix()
5448        v.name = 'v'
5449        gv = fill(v / v, 1.0) / v - (fill(v / v, 1.0) * v) / (v * v)
5450        fn_py = inplace_func([v], gv)
5451        fn_c_or_py = inplace_func([v], gv)
5452
5453        a = rand(5, 2).astype(config.floatX)
5454        self.assertTrue(np.all(fn_py(a) == fn_c_or_py(a)))
5455
5456
5457class T_reshape(utt.InferShapeTester, utt.TestOptimizationMixin):
5458    def __init__(self, name, shared=tensor._shared, op=Reshape, mode=None,
5459                 ignore_topo=(DeepCopyOp, opt.MakeVector,
5460                              opt.Shape_i, DimShuffle, theano.tensor.Elemwise)):
5461        self.shared = shared
5462        self.op = op
5463        # The tag canonicalize is needed for the shape test in FAST_COMPILE
5464        self.mode = mode
5465        self.ignore_topo = ignore_topo
5466        super(T_reshape, self).__init__(name)
5467
5468    def function(self, inputs, outputs, ignore_empty=False):
5469        f = function(inputs, outputs, mode=self.mode)
5470        if self.mode is not None or theano.config.mode != "FAST_COMPILE":
5471            topo = f.maker.fgraph.toposort()
5472            topo_ = [node for node in topo if not isinstance(node.op,
5473                                                             self.ignore_topo)]
5474            if ignore_empty:
5475                assert len(topo_) <= 1, topo_
5476            else:
5477                assert len(topo_) == 1, topo_
5478            if len(topo_) > 0:
5479                assert type(topo_[0].op) is self.op
5480        return f
5481
5482    def test_reshape(self):
5483        a = dvector()
5484        b = dmatrix()
5485        d = dmatrix()
5486
5487        # basic to 1 dim(without list)
5488        c = reshape(b, as_tensor_variable(6), ndim=1)
5489        f = self.function([b], c)
5490
5491        b_val1 = np.asarray([[0, 1, 2], [3, 4, 5]])
5492        c_val1 = np.asarray([0, 1, 2, 3, 4, 5])
5493        b_val2 = b_val1.T
5494        c_val2 = np.asarray([0, 3, 1, 4, 2, 5])
5495
5496        f_out1 = f(b_val1)
5497        f_out2 = f(b_val2)
5498        assert np.all(f_out1 == c_val1), (f_out1, c_val1)
5499        assert np.all(f_out2 == c_val2), (f_out2, c_val2)
5500        # print f.maker.fgraph.toposort()
5501        # check that we remove the useless reshape
5502
5503        # basic to 1 dim(with list)
5504        c = reshape(b, (as_tensor_variable(6),), ndim=1)
5505        f = self.function([b], c)
5506        assert np.all(f(np.asarray([[0, 1, 2], [3, 4, 5]])) ==
5507                      np.asarray([0, 1, 2, 3, 4, 5]))
5508        # print f.maker.fgraph.toposort()
5509        # check that we remove the useless reshape
5510
5511        # basic to shape object of same ndim
5512        c = reshape(b, d.shape)
5513        f = self.function([b, d], c)
5514        assert np.all(f(np.asarray([[0, 1, 2], [3, 4, 5]]),
5515                        [[0, 1], [2, 3], [4, 5]]) ==
5516                      np.asarray([[0, 1], [2, 3], [4, 5]]))
5517
5518        # basic to 2 dims
5519        c = reshape(a, [2, 3])
5520        f = self.function([a], c)
5521        assert np.all(f(np.asarray([0, 1, 2, 3, 4, 5])) ==
5522                      np.asarray([[0, 1, 2], [3, 4, 5]]))
5523
5524        # test that it works without inplace operations
5525        a_val = np.asarray([0, 1, 2, 3, 4, 5])
5526        a_val_copy = np.asarray([0, 1, 2, 3, 4, 5])
5527        b_val = np.asarray([[0, 1, 2], [3, 4, 5]])
5528
5529        f_sub = self.function([a, b], c - b)
5530        assert np.all(f_sub(a_val, b_val) == 0.0)
5531        assert np.all(a_val == a_val_copy)
5532
5533        # test that it works with inplace operations
5534        a_val = theano._asarray([0, 1, 2, 3, 4, 5], dtype='float64')
5535        a_val_copy = theano._asarray([0, 1, 2, 3, 4, 5], dtype='float64')
5536        b_val = theano._asarray([[0, 1, 2], [3, 4, 5]], dtype='float64')
5537
5538        f_sub = self.function([a, b], c - b)
5539        assert np.all(f_sub(a_val, b_val) == 0.0)
5540        assert np.all(a_val == a_val_copy)
5541
5542        # verify gradient
5543        def just_vals(v):
5544            return Reshape(2)(v, theano._asarray([2, 3], dtype='int32'))
5545        utt.verify_grad(just_vals, [a_val], mode=self.mode)
5546
5547        # test infer_shape
5548        self._compile_and_check([a], [c], (a_val,), self.op)
5549
5550        # test broadcast flag for constant value of 1
5551        c = reshape(b, (b.shape[0], b.shape[1], 1))
5552        # That reshape may get replaced with a dimshuffle, with is ignored,
5553        # so we pass "ignore_empty=True"
5554        f = self.function([b], c, ignore_empty=True)
5555        assert np.all(f(np.asarray([[0, 1, 2], [3, 4, 5]])) ==
5556                      np.asarray([[[0], [1], [2]], [[3], [4], [5]]]))
5557        assert (f.maker.fgraph.toposort()[-1].outputs[0].type.broadcastable ==
5558                (False, False, True))
5559
5560        # test broadcast flag for constant value of 1 if it cannot be
5561        # replaced with dimshuffle
5562        c = reshape(b, (b.shape[1], b.shape[0], 1))
5563        f = self.function([b], c, ignore_empty=True)
5564        assert np.all(f(np.asarray([[0, 1, 2], [3, 4, 5]])) ==
5565                      np.asarray([[[0], [1]], [[2], [3]], [[4], [5]]]))
5566        assert (f.maker.fgraph.toposort()[-1].outputs[0].type.broadcastable ==
5567                (False, False, True))
5568
5569    def test_m1(self):
5570        t = tensor3()
5571        rng = np.random.RandomState(seed=utt.fetch_seed())
5572        val = rng.uniform(size=(3, 4, 5)).astype(config.floatX)
5573        for out in [t.reshape([-1]), t.reshape([-1, 5]),
5574                    t.reshape([5, -1]), t.reshape([5, -1, 3])]:
5575            self._compile_and_check([t], [out], [val], self.op)
5576
5577    def test_reshape_long_in_shape(self):
5578        v = dvector('v')
5579        r = v.reshape((v.shape[0], L(1)))
5580        print(r.eval({v: np.arange(5.)}))
5581        assert np.allclose(r.eval({v: np.arange(5.)}).T,
5582                           np.arange(5.))
5583
5584    def test_bad_shape(self):
5585        a = matrix('a')
5586        shapes = ivector('shapes')
5587        rng = np.random.RandomState(seed=utt.fetch_seed())
5588        a_val = rng.uniform(size=(3, 4)).astype(config.floatX)
5589
5590        # Test reshape to 1 dim
5591        r = a.reshape(shapes, ndim=1)
5592
5593        f = self.function([a, shapes], r)
5594        self.assertRaises(ValueError, f, a_val, [13])
5595
5596        # Test reshape to 2 dim
5597        r = a.reshape(shapes, ndim=2)
5598
5599        f = self.function([a, shapes], r)
5600
5601        self.assertRaises(ValueError, f, a_val, [-1, 5])
5602        self.assertRaises(ValueError, f, a_val, [7, -1])
5603        self.assertRaises(ValueError, f, a_val, [7, 5])
5604        self.assertRaises(ValueError, f, a_val, [-1, -1])
5605
5606    def test_0(self):
5607        x = fvector('x')
5608        f = self.function([x], x.reshape((0, 100)))
5609        assert f(np.ndarray((0,), dtype='float32')).shape == (0, 100)
5610
5611    def test_empty_shp(self):
5612        const = theano.tensor.constant([1]).reshape(())
5613        f = function([], const)
5614        assert f().shape == ()
5615
5616
5617def test_make_column_matrix_broadcastable():
5618    # The goal of the operation made by `b` is to ensure the second dimension
5619    # of the column matrix is broadcastable.
5620    a = tensor.dmatrix()
5621    b = a.reshape((a.shape[0], )).dimshuffle(0, 'x')
5622    f = function([a], b)
5623    assert (f(np.zeros((3, 1))) + np.ones(2) == np.ones((3, 2))).all()
5624
5625
5626def test_flatten_outdimNone():
5627    a = dmatrix()
5628    c = flatten(a)
5629    f = inplace_func([a], c)
5630    a_val = theano._asarray([[0, 1, 2], [3, 4, 5]], dtype='float64')
5631    c_val = theano._asarray([0, 1, 2, 3, 4, 5], dtype='float64')
5632    assert np.all(f(a_val) == c_val)
5633    f = inplace_func([a], c)
5634    assert np.all(f(a_val) == c_val)
5635
5636    utt.verify_grad(flatten, [a_val])
5637
5638
5639def test_flatten_scalar():
5640    a = dscalar()
5641    c = flatten(a)
5642    f = inplace_func([a], c)
5643    a_val = theano._asarray(3.0, dtype='float64')
5644    c_val = theano._asarray([3.0], dtype='float64')
5645    assert np.all(f(a_val) == c_val)
5646    f = inplace_func([a], c)
5647    assert np.all(f(a_val) == c_val)
5648
5649    # utt.verify_grad(flatten, [a_val]) #TODO: fix verify_grd to work on scalars
5650
5651
5652def test_flatten_ndim1():
5653    a = dmatrix()
5654    c = flatten(a, 1)
5655    f = inplace_func([a], c)
5656    a_val = theano._asarray([[0, 1, 2], [3, 4, 5]], dtype='float64')
5657    c_val = theano._asarray([0, 1, 2, 3, 4, 5], dtype='float64')
5658    assert np.all(f(a_val) == c_val)
5659    f = inplace_func([a], c)
5660    assert np.all(f(a_val) == c_val)
5661
5662    utt.verify_grad(flatten, [a_val])
5663
5664
5665def test_flatten_ndim2():
5666    a = dmatrix()
5667    c = flatten(a, 2)
5668    f = inplace_func([a], c)
5669    a_val = theano._asarray([[0, 1, 2], [3, 4, 5]], dtype='float64')
5670    assert np.all(f(a_val) == a_val)
5671    f = inplace_func([a], c)
5672    assert np.all(f(a_val) == a_val)
5673
5674    flatten_2 = partial(flatten, ndim=2)
5675    utt.verify_grad(flatten_2, [a_val])
5676
5677
5678def test_flatten_ndim2_of_3():
5679    a = TensorType('float64', (False, False, False))()
5680    c = flatten(a, 2)
5681    f = inplace_func([a], c)
5682    a_val = theano._asarray([[[0, 1], [2, 3]], [[4, 5], [6, 7]]],
5683                            dtype='float64')
5684    c_val = theano._asarray([[0, 1, 2, 3], [4, 5, 6, 7]], dtype='float64')
5685    assert np.all(f(a_val) == c_val)
5686    f = inplace_func([a], c)
5687    assert np.all(f(a_val) == c_val)
5688
5689    flatten_2 = partial(flatten, ndim=2)
5690    utt.verify_grad(flatten_2, [a_val])
5691    # test outdim parameter name
5692    flatten_2 = partial(flatten, outdim=2)
5693    utt.verify_grad(flatten_2, [a_val])
5694
5695
5696def test_flatten_broadcastable():
5697    # Ensure that the broadcastable pattern of the output is coherent with
5698    # that of the input
5699
5700    inp = TensorType('float64', (False, False, False, False))()
5701    out = flatten(inp, ndim=2)
5702    assert out.broadcastable == (False, False)
5703
5704    inp = TensorType('float64', (False, False, False, True))()
5705    out = flatten(inp, ndim=2)
5706    assert out.broadcastable == (False, False)
5707
5708    inp = TensorType('float64', (False, True, False, True))()
5709    out = flatten(inp, ndim=2)
5710    assert out.broadcastable == (False, False)
5711
5712    inp = TensorType('float64', (False, True, True, True))()
5713    out = flatten(inp, ndim=2)
5714    assert out.broadcastable == (False, True)
5715
5716    inp = TensorType('float64', (True, False, True, True))()
5717    out = flatten(inp, ndim=3)
5718    assert out.broadcastable == (True, False, True)
5719
5720
5721def test_flatten_ndim_invalid():
5722    a = dmatrix()
5723    assert_raises(ValueError, flatten, a, 3)
5724    assert_raises(ValueError, flatten, a, 0)
5725
5726
5727def test_is_flat():
5728    # tests is_flat method for constant and symbolic variables,
5729    # as well as reshaped constant and symbolic variables on the
5730    # given outdim
5731
5732    # Constant variable
5733    assert tensor.is_flat(tensor.as_tensor_variable(np.zeros((10))))
5734    assert tensor.is_flat(tensor.as_tensor_variable(np.zeros((10, 10, 10))),
5735                          ndim=3)
5736    assert not tensor.is_flat(
5737        tensor.as_tensor_variable(np.zeros((10, 10, 10))))
5738
5739    # Symbolic variable
5740    assert tensor.is_flat(tensor.vector())
5741    assert tensor.is_flat(tensor.tensor3(), ndim=3)
5742    assert not tensor.is_flat(tensor.tensor3())
5743
5744    # Reshape with constant shape
5745    X = tensor.tensor4()
5746    assert tensor.is_flat(X.reshape((-1, )))
5747    assert tensor.is_flat(X.reshape((10, 10, -1)), ndim=3)
5748    assert not tensor.is_flat(X.reshape((10, 10, -1)))
5749
5750    # Reshape with symbolic shape
5751    X = tensor.tensor4()
5752    assert tensor.is_flat(X.reshape((tensor.iscalar(), )))
5753    assert tensor.is_flat(X.reshape((tensor.iscalar(), ) * 3), ndim=3)
5754    assert not tensor.is_flat(X.reshape((tensor.iscalar(), ) * 3))
5755
5756
5757def test_tile():
5758    def run_tile(x, x_, reps, use_symbolic_reps):
5759        if use_symbolic_reps:
5760            rep_symbols = [iscalar() for _ in range(len(reps))]
5761            f = function([x] + rep_symbols, tile(x, rep_symbols))
5762            return f(*([x_] + list(reps)))
5763        else:
5764            f = function([x], tile(x, reps))
5765            return f(x_)
5766
5767    rng = np.random.RandomState(utt.fetch_seed())
5768
5769    for use_symbolic_reps in [False, True]:
5770        # Test the one-dimensional case.
5771        x = vector()
5772        x_ = rng.randn(5).astype(config.floatX)
5773        assert np.all(run_tile(x, x_, (2,), use_symbolic_reps) ==
5774                      np.tile(x_, (2,)))
5775
5776        # Test the two-dimensional case.
5777        x = matrix()
5778        x_ = rng.randn(2, 4).astype(config.floatX)
5779        assert np.all(run_tile(x, x_, (2, 3), use_symbolic_reps) ==
5780                      np.tile(x_, (2, 3)))
5781
5782        # Test the three-dimensional case.
5783        x = tensor3()
5784        x_ = rng.randn(2, 4, 3).astype(config.floatX)
5785        assert np.all(run_tile(x, x_, (2, 3, 4), use_symbolic_reps) ==
5786                      np.tile(x_, (2, 3, 4)))
5787
5788        # Test the four-dimensional case.
5789        x = tensor4()
5790        x_ = rng.randn(2, 4, 3, 5).astype(config.floatX)
5791        assert np.all(run_tile(x, x_, (2, 3, 4, 6), use_symbolic_reps) ==
5792                      np.tile(x_, (2, 3, 4, 6)))
5793
5794    # Test when reps is integer, tensor.scalar or tensor.vector.
5795    # Test 1,2,3,4-dimensional cases.
5796    # Test input x has the shape [2], [2, 4], [2, 4, 3], [2, 4, 3, 5].
5797    test_shape = [2, 4, 3, 5]
5798    k = 0
5799    for xtype in [vector(), matrix(), tensor3(), tensor4()]:
5800        x = xtype
5801        k = k + 1
5802        x_ = rng.randn(*test_shape[0:k]).astype(config.floatX)
5803
5804        # integer:
5805        reps_ = 2
5806        f = function([x], tile(x, reps_))
5807        assert np.all(f(x_) == np.tile(x_, reps_))
5808
5809        # tensor.scalar:
5810        reps = iscalar()
5811        reps_ = 2
5812        f = function([x, reps], tile(x, reps))
5813        assert np.all(f(x_, reps_) == np.tile(x_, reps_))
5814
5815        # tensor.vector:
5816        reps = ivector()
5817        reps_ = [2] if k == 1 or k == 2 else [2, 3]
5818        ndim_ = k
5819        f = function([x, reps], tile(x, reps, ndim_))
5820        assert np.all(f(x_, reps_) == np.tile(x_, reps_))
5821
5822        # list of integers:
5823        reps_ = [2, 3, 4]
5824        f = function([x], tile(x, reps_))
5825        assert np.all(f(x_) == np.tile(x_, reps_))
5826
5827        # list of integers and tensor.scalars:
5828        d = iscalar()
5829        reps = [2, d, 4]
5830        f = function([x, d], tile(x, reps))
5831        reps_ = [2, 3, 4]
5832        assert np.all(f(x_, 3) == np.tile(x_, reps_))
5833
5834        # reps is list, len(reps) > x.ndim, 3 cases below:
5835        r = [2, 3, 4, 5, 6]
5836        reps_ = r[:k + 1]  # len(reps_) = x.ndim+1
5837        # (1) ndim = None.
5838        f = function([x], tile(x, reps_))
5839        assert np.all(f(x_) == np.tile(x_, reps_))
5840        # (2) ndim = len(reps).
5841        ndim_ = len(reps_)
5842        f = function([x], tile(x, reps_, ndim_))
5843        assert np.all(f(x_) == np.tile(x_, reps_))
5844        # (3) ndim > len(reps)
5845        ndim_ = len(reps_) + 1
5846        f = function([x], tile(x, reps_, ndim_))
5847        assert np.all(f(x_) == np.tile(x_, [1] + reps_))
5848
5849        # reps is list, ndim > x.ndim > len(reps):
5850        r = [2, 3, 4, 5]
5851        if k > 1:
5852            ndim_ = k + 1
5853            reps_ = r[:k - 1]
5854            f = function([x], tile(x, reps_, ndim_))
5855            assert np.all(f(x_) == np.tile(x_, [1, 1] + reps_))
5856
5857        # error raising test: ndim not specified when reps is vector
5858        reps = ivector()
5859        np.testing.assert_raises(ValueError, tile, x, reps)
5860
5861        # error raising test: not a integer
5862        for reps in [2.5, fscalar(), fvector()]:
5863            np.testing.assert_raises(ValueError, tile, x, reps)
5864
5865        # error raising test: the dimension of reps exceeds 1
5866        reps = imatrix()
5867        np.testing.assert_raises(ValueError, tile, x, reps)
5868
5869        # error raising test: ndim is not None, ndim < x.ndim
5870        # 3 cases below (reps is list/tensor.scalar/tensor.vector):
5871        for reps in [[2, 3, 4], iscalar(), ivector()]:
5872            if k > 1:
5873                ndim = k - 1
5874                np.testing.assert_raises(ValueError, tile, x, reps, ndim)
5875
5876        # error raising test: reps is list, len(reps) > ndim
5877        r = [2, 3, 4, 5, 6]
5878        reps = r[:k + 1]
5879        ndim = k
5880        np.testing.assert_raises(ValueError, tile, x, reps, ndim)
5881
5882        # error raising test:
5883        # reps is tensor.vector and len(reps_value) > ndim,
5884        # reps_value is the real value when excuting the function.
5885        reps = ivector()
5886        r = [2, 3, 4, 5, 6, 7]
5887        reps_ = r[:k + 2]
5888        ndim_ = k + 1
5889        f = function([x, reps], tile(x, reps, ndim_))
5890        np.testing.assert_raises(AssertionError, f, x_, reps_)
5891
5892
5893def test_tile_grad():
5894
5895    def grad_tile(x, reps, np_x):
5896        y = tile(x, reps)
5897        z = y.sum()
5898        g = theano.function([x], grad(z, x))
5899        grad_res = g(np_x)
5900        # The gradient should be the product of the tiling dimensions
5901        # (since the gradients are additive through the tiling operation)
5902        assert np.all(grad_res == np.prod(reps))
5903
5904    rng = np.random.RandomState(utt.fetch_seed())
5905
5906    # test vector
5907    grad_tile(vector('x'), [3], rng.randn(5).astype(config.floatX))
5908    # test matrix
5909    grad_tile(matrix('x'), [3, 4], rng.randn(2, 3).astype(config.floatX))
5910    # test tensor3
5911    grad_tile(tensor3('x'), [3, 4, 5],
5912              rng.randn(2, 4, 3).astype(config.floatX))
5913    # test tensor4
5914    grad_tile(tensor4('x'), [3, 4, 5, 6],
5915              rng.randn(2, 4, 3, 5).astype(config.floatX))
5916
5917
5918class TestARange(unittest.TestCase):
5919    def setUp(self):
5920        utt.seed_rng()
5921
5922    def test_Op_integers(self):
5923        # Test behaviour of ARange Op on integer inputs
5924        start, stop, step = iscalars('start', 'stop', 'step')
5925        out = ARange(start.type.dtype)(start, stop, step)
5926        f = function([start, stop, step], out)
5927
5928        assert np.all(f(0, 5, 1) == np.arange(0, 5, 1))
5929        assert np.all(f(2, 11, 4) == np.arange(2, 11, 4))
5930        assert np.all(f(-5, 1, 1) == np.arange(-5, 1, 1))
5931        assert np.all(f(10, 2, -2) == np.arange(10, 2, -2))
5932        assert np.all(f(10, 2, 2) == np.arange(10, 2, 2))
5933        assert np.all(f(0, 0, 1) == np.arange(0, 0, 1))
5934
5935    def test_grads(self):
5936        def f(start, stop, step):
5937            return ARange(start.type.dtype)(start, stop, step)
5938
5939        rng = np.random.RandomState(utt.fetch_seed())
5940        # Due to the random projection, we should not use the exact
5941        # point that change the shape of the output.
5942        for start, stop, step in [(0, 4.9, 1),
5943                                  (5.1, 0, -0.5),
5944                                  (1, 5.1, 0.5)]:
5945            utt.verify_grad(f, [np.asarray(start).astype(config.floatX),
5946                                np.asarray(stop).astype(config.floatX),
5947                                np.asarray(step).astype(config.floatX)],
5948                            rng=rng)
5949
5950    def test_integers(self):
5951        # Test arange constructor, on integer outputs
5952        start, stop, step = iscalars('start', 'stop', 'step')
5953        out = arange(start, stop, step)
5954        f = function([start, stop, step], out)
5955
5956        if config.cast_policy == 'custom':
5957            assert out.dtype == 'int64'
5958        elif config.cast_policy in ('numpy', 'numpy+floatX'):
5959            numpy_dtype = np.arange(np.array(1, dtype='int32')).dtype
5960            assert out.dtype == numpy_dtype
5961        else:
5962            raise NotImplementedError(config.cast_policy)
5963        assert np.all(f(0, 5, 1) == np.arange(0, 5, 1))
5964        assert np.all(f(2, 11, 4) == np.arange(2, 11, 4))
5965        assert np.all(f(-5, 1, 1) == np.arange(-5, 1, 1))
5966        assert np.all(f(10, 2, -2) == np.arange(10, 2, -2))
5967        assert np.all(f(10, 2, 2) == np.arange(10, 2, 2))
5968        assert np.all(f(0, 0, 1) == np.arange(0, 0, 1))
5969
5970    def test_float32(self):
5971        # Test arange constructor, on float32 outputs
5972        start, stop, step = fscalars('start', 'stop', 'step')
5973        out = arange(start, stop, step)
5974        f = function([start, stop, step], out)
5975
5976        if config.cast_policy == 'custom':
5977            assert out.dtype == start.type.dtype
5978        elif config.cast_policy == 'numpy':
5979            numpy_dtype = np.arange(np.array(0, dtype=start.dtype),
5980                                    np.array(1, dtype=stop.dtype),
5981                                    np.array(1, dtype=step.dtype)).dtype
5982            assert out.dtype == numpy_dtype
5983        elif config.cast_policy == 'numpy+floatX':
5984            assert out.dtype == config.floatX
5985        else:
5986            raise NotImplementedError(config.cast_policy)
5987        arg_vals = [(0, 5, 1), (2, 11, 4), (-5, 1.1, 1.2), (1.3, 2, -2.1),
5988                    (10, 2, 2)]
5989        for arg_v in arg_vals:
5990            start_v, stop_v, step_v = arg_v
5991            start_v_, stop_v_, step_v_ = np.asarray(arg_v,
5992                                                    dtype=start.type.dtype)
5993            f_val = f(start_v_, stop_v_, step_v_)
5994            if config.cast_policy == 'custom':
5995                expected_val = np.arange(start_v, stop_v, step_v,
5996                                         dtype=start.type.dtype)
5997            elif config.cast_policy in ('numpy', 'numpy+floatX'):
5998                expected_val = np.arange(start_v_, stop_v_, step_v_,
5999                                         dtype=out.dtype)
6000            else:
6001                raise NotImplementedError(config.cast_policy)
6002            assert np.all(f_val == expected_val)
6003
6004    def test_float64(self):
6005        # Test arange constructor, on float64 outputs
6006        start, stop, step = dscalars('start', 'stop', 'step')
6007        out = arange(start, stop, step)
6008        f = function([start, stop, step], out)
6009
6010        assert out.dtype == start.type.dtype
6011        arg_vals = [(0, 5, 1), (2, 11, 4), (-5, 1.1, 1.2),
6012                    (1.3, 2, -2.1), (10, 2, 2)]
6013        for arg_v in arg_vals:
6014            start_v, stop_v, step_v = arg_v
6015            start_v_, stop_v_, step_v_ = np.asarray(arg_v,
6016                                                    dtype=start.type.dtype)
6017            f_val = f(start_v_, stop_v_, step_v_)
6018            if config.cast_policy == 'custom':
6019                expected_val = np.arange(start_v, stop_v, step_v,
6020                                         dtype=start.type.dtype)
6021            elif config.cast_policy in ('numpy', 'numpy+floatX'):
6022                expected_val = np.arange(start_v_, stop_v_, step_v_)
6023            else:
6024                raise NotImplementedError(config.cast_policy)
6025            assert np.all(f_val == expected_val)
6026
6027    def test_default_step(self):
6028        # Test that arange constructor uses the correct default step
6029        start, stop = iscalars('start', 'stop')
6030        out = arange(start, stop)
6031        f = function([start, stop], out)
6032
6033        if config.cast_policy == 'custom':
6034            assert out.dtype == 'int64'
6035        elif config.cast_policy in ('numpy', 'numpy+floatX'):
6036            assert out.dtype == np.arange(np.int32(0),
6037                                          np.int32(1)).dtype
6038        else:
6039            raise NotImplementedError(config.cast_policy)
6040        assert np.all(f(0, 5) == np.arange(0, 5))
6041        assert np.all(f(-5, 1) == np.arange(-5, 1))
6042        assert np.all(f(0, 0) == np.arange(0, 0))
6043
6044        dstart, dstop = dscalars('start', 'stop')
6045        dout = arange(dstart, dstop)
6046        df = function([dstart, dstop], dout)
6047
6048        assert dout.dtype == dstart.type.dtype
6049        # print df(0.2, 5.3)
6050        # print np.arange(0.2, 5.3)
6051        assert np.all(df(0.2, 5.3) == np.arange(0.2, 5.3))
6052        assert np.all(df(0.8, 5.3) == np.arange(0.8, 5.3))
6053        assert np.all(df(-0.7, 5.3) == np.arange(-0.7, 5.3))
6054
6055    def test_default_start(self):
6056        # Test that arange constructor uses the correct default start
6057        stop = iscalar('stop')
6058        out = arange(stop)
6059        f = function([stop], out)
6060
6061        if config.cast_policy == 'custom':
6062            assert out.dtype == 'int64'
6063        elif config.cast_policy in ('numpy', 'numpy+floatX'):
6064            assert out.dtype == np.arange(np.int32(1)).dtype
6065        else:
6066            raise NotImplementedError(config.cast_policy)
6067        assert np.all(f(8) == np.arange(8))
6068        assert np.all(f(-2) == np.arange(-2))
6069
6070        fstop = fscalar('stop')
6071        fout = arange(fstop)
6072        ff = function([fstop], fout)
6073
6074        if config.cast_policy == 'custom':
6075            assert fout.dtype == fstop.type.dtype
6076        elif config.cast_policy == 'numpy':
6077            assert fout.dtype == np.arange(np.float32(1)).dtype
6078        elif config.cast_policy == 'numpy+floatX':
6079            if config.floatX == 'float32':
6080                assert fout.dtype == 'float32'
6081            else:
6082                assert fout.dtype == np.arange(np.float32(1)).dtype
6083        else:
6084            raise NotImplementedError(config.cast_policy)
6085
6086        fstop_values = [0.2, -0.7, 8.5]
6087        for fstop_v in fstop_values:
6088            fstop_v32 = np.float32(fstop_v)
6089            assert np.all(ff(fstop_v32) == np.arange(fstop_v))
6090
6091    def test_upcast(self):
6092        # Test that arange computes output type adequately
6093        if config.cast_policy == 'custom':
6094            assert arange(iscalar()).dtype == 'int64'
6095            assert arange(fscalar()).dtype == fscalar().dtype
6096            assert arange(dscalar()).dtype == dscalar().dtype
6097
6098            # int32 + float32 -> float64
6099            assert arange(iscalar(), fscalar()).dtype == dscalar().dtype
6100            assert arange(iscalar(), dscalar()).dtype == dscalar().dtype
6101            assert arange(fscalar(), dscalar()).dtype == dscalar().dtype
6102
6103            assert arange(iscalar(), fscalar(), dscalar()).dtype == \
6104                dscalar().dtype
6105        elif config.cast_policy in ('numpy', 'numpy+floatX'):
6106            for dtype in get_numeric_types():
6107                # Test with a single argument.
6108                arange_dtype = arange(scalar(dtype=str(dtype))).dtype
6109                numpy_dtype = np.arange(np.array(1, dtype=dtype)).dtype
6110                if (dtype != 'float64' and
6111                        numpy_dtype == 'float64' and
6112                        config.cast_policy == 'numpy+floatX' and
6113                        config.floatX == 'float32'):
6114                    # We want a float32 arange.
6115                    assert arange_dtype == 'float32'
6116                else:
6117                    # Follow numpy.
6118                    assert arange_dtype == numpy_dtype
6119
6120                # Test with two arguments.
6121                for stop_dtype in get_numeric_types():
6122                    arange_dtype = arange(
6123                        start=scalar(dtype=str(dtype)),
6124                        stop=scalar(dtype=str(stop_dtype))).dtype
6125                    numpy_dtype = np.arange(
6126                        start=np.array(0, dtype=dtype),
6127                        stop=np.array(1, dtype=stop_dtype)).dtype
6128                    if (dtype != 'float64' and
6129                            stop_dtype != 'float64' and
6130                            numpy_dtype == 'float64' and
6131                            config.cast_policy == 'numpy+floatX' and
6132                            config.floatX == 'float32'):
6133                        # We want a float32 arange.
6134                        assert arange_dtype == 'float32'
6135                    else:
6136                        # Follow numpy.
6137                        assert arange_dtype == numpy_dtype
6138
6139                    # Test with three arguments.
6140                    for step_dtype in get_numeric_types():
6141                        arange_dtype = arange(
6142                            start=scalar(dtype=str(dtype)),
6143                            stop=scalar(dtype=str(stop_dtype)),
6144                            step=scalar(dtype=str(step_dtype))).dtype
6145                        numpy_dtype = np.arange(
6146                            start=np.array(0, dtype=dtype),
6147                            stop=np.array(1, dtype=stop_dtype),
6148                            step=np.array(1, dtype=step_dtype)).dtype
6149                        if (dtype != 'float64' and
6150                                stop_dtype != 'float64' and
6151                                step_dtype != 'float64' and
6152                                numpy_dtype == 'float64' and
6153                                config.cast_policy == 'numpy+floatX' and
6154                                config.floatX == 'float32'):
6155                            # We want a float32 arange.
6156                            assert arange_dtype == 'float32'
6157                        else:
6158                            # Follow numpy.
6159                            assert arange_dtype == numpy_dtype
6160        else:
6161            raise NotImplementedError(config.cast_policy)
6162
6163    def test_dtype_cache(self):
6164        # Checks that the same Op is returned on repeated calls to arange
6165        # using the same dtype, but not for different dtypes.
6166
6167        start, stop, step = iscalars('start', 'stop', 'step')
6168        out1 = arange(start, stop, step)
6169        out2 = arange(start, stop, step, dtype=out1.dtype)
6170        out3 = arange(start, stop, 2., dtype=out1.dtype)
6171        out4 = arange(start, stop, 2.)
6172
6173        assert out1.owner.op is out2.owner.op
6174        assert out2.owner.op is out3.owner.op
6175        assert out3.owner.op is not out4.owner.op
6176
6177    def test_infer_shape(self):
6178        start, stop, step = iscalars('start', 'stop', 'step')
6179        out = arange(start, stop, step)
6180        mode = theano.config.mode
6181        if mode == 'FAST_COMPILE':
6182            mode = 'FAST_RUN'
6183        mode = compile.mode.get_mode(mode).excluding('fusion')
6184        f = function([start, stop, step], out.shape, mode=mode)
6185        assert len(f.maker.fgraph.toposort()) == 9
6186
6187        if config.cast_policy == 'custom':
6188            assert out.dtype == 'int64'
6189        elif config.cast_policy in ('numpy', 'numpy+floatX'):
6190            numpy_dtype = np.arange(np.array(0, dtype=start.dtype),
6191                                    np.array(1, dtype=stop.dtype),
6192                                    np.array(1, dtype=step.dtype)).dtype
6193            assert out.dtype == numpy_dtype
6194        else:
6195            raise NotImplementedError(config.cast_policy)
6196
6197        assert np.all(f(0, 5, 1) == len(np.arange(0, 5, 1)))
6198        assert np.all(f(2, 11, 4) == len(np.arange(2, 11, 4)))
6199        assert np.all(f(-5, 1, 1) == len(np.arange(-5, 1, 1)))
6200        assert np.all(f(10, 2, -2) == len(np.arange(10, 2, -2)))
6201        assert np.all(f(10, 2, 2) == len(np.arange(10, 2, 2)))
6202        assert np.all(f(0, 0, 1) == len(np.arange(0, 0, 1)))
6203
6204        out = arange(start, stop, 1)
6205        f = function([start, stop], out.shape, mode=mode)
6206        assert len(f.maker.fgraph.toposort()) == 5
6207# 4 [Elemwise{sub,no_inplace}(stop, start), Elemwise{Cast{int64}}(Elemwise{sub,no_inplace}.0), Elemwise{Maximum{output_types_preference=transfer_type{0}}}[(0, 0)](Elemwise{Cast{int64}}.0, 0), MakeVector(Elemwise{Maximum{output_types_preference=transfer_type{0}}}[(0, 0)].0)]
6208        if config.cast_policy == 'custom':
6209            assert out.dtype == 'int64'
6210        elif config.cast_policy in ('numpy', 'numpy+floatX'):
6211            assert out.dtype == np.arange(
6212                np.int32(0), np.int32(1), np.int32(1)).dtype
6213        else:
6214            raise NotImplementedError(config.cast_policy)
6215        assert np.all(f(0, 5) == len(np.arange(0, 5)))
6216        assert np.all(f(2, 11) == len(np.arange(2, 11)))
6217        assert np.all(f(-5, 1) == len(np.arange(-5, 1)))
6218        assert np.all(f(10, 2) == len(np.arange(10, 2)))
6219        assert np.all(f(10, 2) == len(np.arange(10, 2)))
6220        assert np.all(f(0, 0) == len(np.arange(0, 0)))
6221        assert np.all(f(-64, 64) == len(np.arange(-64, 64)))
6222        assert arange(-64, 64).shape.eval() == [128]
6223        assert arange(-64, 64, 2).shape.eval() == [64]
6224
6225        out = arange(0, stop, 1)
6226        f = function([stop], out.shape, mode=mode)
6227        assert len(f.maker.fgraph.toposort()) == 2
6228        # [Elemwise{Cast{int64}}(stop), MakeVector(Elemwise{Cast{int64}}.0)]
6229
6230        if config.cast_policy == 'custom':
6231            assert out.dtype == 'int64'
6232        elif config.cast_policy in ('numpy', 'numpy+floatX'):
6233            numpy_dtype = np.arange(0,
6234                                    np.array(1, dtype=stop.dtype),
6235                                    1).dtype
6236            assert out.dtype == numpy_dtype
6237        else:
6238            raise NotImplementedError(config.cast_policy)
6239
6240        assert np.all(f(5) == len(np.arange(0, 5)))
6241        assert np.all(f(11) == len(np.arange(0, 11)))
6242        assert np.all(f(1) == len(np.arange(0, 1)))
6243        assert np.all(f(2) == len(np.arange(0, 2)))
6244        assert np.all(f(2) == len(np.arange(0, 2)))
6245        assert np.all(f(0) == len(np.arange(0, 0)))
6246
6247
6248class TestNdGrid(unittest.TestCase):
6249
6250    def setUp(self):
6251        pass
6252
6253    def test_mgrid_numpy_equiv(self):
6254        nmgrid = (np.mgrid[0:1:.1, 1:10:1., 10:100:10.],
6255                  np.mgrid[0:2:1, 1:10:1, 10:100:10])
6256        tmgrid = (mgrid[0:1:.1, 1:10:1., 10:100:10.],
6257                  mgrid[0:2:1, 1:10:1, 10:100:10])
6258        for n, t in zip(nmgrid, tmgrid):
6259            for ng, tg in zip(n, t):
6260                utt.assert_allclose(ng, tg.eval())
6261
6262    def test_ogrid_numpy_equiv(self):
6263        nogrid = (np.ogrid[0:1:.1, 1:10:1., 10:100:10.],
6264                  np.ogrid[0:2:1, 1:10:1, 10:100:10])
6265        togrid = (ogrid[0:1:.1, 1:10:1., 10:100:10.],
6266                  ogrid[0:2:1, 1:10:1, 10:100:10])
6267        for n, t in zip(nogrid, togrid):
6268            for ng, tg in zip(n, t):
6269                utt.assert_allclose(ng, tg.eval())
6270
6271    def test_mgrid_theano_variable_numpy_equiv(self):
6272        nfmgrid = np.mgrid[0:1:.1, 1:10:1., 10:100:10.]
6273        nimgrid = np.mgrid[0:2:1, 1:10:1, 10:100:10]
6274        i, j, k = dscalars('i', 'j', 'k')
6275        l, m, n = iscalars('l', 'm', 'n')
6276        tfmgrid = mgrid[i:1:.1, 1:j:1., 10:100:k]
6277        timgrid = mgrid[l:2:1, 1:m:1, 10:100:n]
6278        ff = theano.function([i, j, k], tfmgrid)
6279        fi = theano.function([l, m, n], timgrid)
6280        for n, t in zip((nfmgrid, nimgrid), (ff(0, 10, 10.), fi(0, 10, 10))):
6281            for ng, tg in zip(n, t):
6282                utt.assert_allclose(ng, tg)
6283
6284    def test_ogrid_theano_variable_numpy_equiv(self):
6285        nfogrid = np.ogrid[0:1:.1, 1:10:1., 10:100:10.]
6286        niogrid = np.ogrid[0:2:1, 1:10:1, 10:100:10]
6287        i, j, k = dscalars('i', 'j', 'k')
6288        l, m, n = iscalars('l', 'm', 'n')
6289        tfogrid = ogrid[i:1:.1, 1:j:1., 10:100:k]
6290        tiogrid = ogrid[l:2:1, 1:m:1, 10:100:n]
6291        ff = theano.function([i, j, k], tfogrid)
6292        fi = theano.function([l, m, n], tiogrid)
6293        for n, t in zip((nfogrid, niogrid), (ff(0, 10, 10.), fi(0, 10, 10))):
6294            for ng, tg in zip(n, t):
6295                utt.assert_allclose(ng, tg)
6296
6297
6298class TestInversePermutation(unittest.TestCase):
6299    def setUp(self):
6300        utt.seed_rng()
6301
6302    def test_dim1(self):
6303        # Test the inversion of one permutation (int vector)
6304        p = ivector()
6305        inv = inverse_permutation(p)
6306        assert inv.dtype == p.dtype
6307        f_inverse = function([p], inv)
6308
6309        # Generate a random permutation
6310        rng = np.random.RandomState(utt.fetch_seed())
6311        p_val = rng.permutation(10).astype('int32')
6312        inv_val = f_inverse(p_val)
6313
6314        # Check that the inverse of the inverse is the original permutation
6315        assert np.all(f_inverse(inv_val) == p_val)
6316        # Check that permutation(inverse) == inverse(permutation) = identity
6317        assert np.all(p_val[inv_val] == np.arange(10))
6318        assert np.all(inv_val[p_val] == np.arange(10))
6319
6320    def test_dim2(self):
6321        # Test the inversion of several permutations at a time
6322        # Each row of p is a different permutation to inverse
6323        p = imatrix()
6324        inv = inverse_permutation(p)
6325        f_inverse = function([p], inv)
6326
6327        rng = np.random.RandomState(utt.fetch_seed())
6328        # Generate 10 random permutations
6329        p_val = np.asarray([rng.permutation(10) for i in range(7)],
6330                           dtype='int32')
6331        inv_val = f_inverse(p_val)
6332
6333        # Check that the inverse of the inverse is the original permutation list
6334        assert np.all(f_inverse(inv_val) == p_val)
6335        # Check that, for each permutation,
6336        # permutation(inverse) == inverse(permutation) = identity
6337        for p_row, i_row in zip(p_val, inv_val):
6338            assert np.all(p_row[i_row] == np.arange(10))
6339            assert np.all(i_row[p_row] == np.arange(10))
6340
6341
6342class TestPermuteRowElements(unittest.TestCase):
6343    def setUp(self):
6344        utt.seed_rng()
6345
6346    def test_1_1(self):
6347        # Test PermuteRowElements(vector, vector)
6348        input = dvector()
6349        p = ivector()
6350        out = permute_row_elements(input, p)
6351        permute = function([input, p], out)
6352
6353        rng = np.random.RandomState(utt.fetch_seed())
6354        input_val = rng.uniform(size=(5,))
6355        p_val = rng.permutation(5).astype('int32')
6356        out_val = permute(input_val, p_val)
6357
6358        # Should be equivalent to advanced indexing
6359        out_bis = input_val[p_val]
6360        assert np.all(out_val == out_bis)
6361
6362        # Verify gradient
6363        def permute_fixed(s_input):
6364            # Auxiliary op defined to get rid of gradient wrt p_val
6365            return permute_row_elements(s_input, p_val)
6366        utt.verify_grad(permute_fixed, [input_val])
6367
6368    def test_2_1(self):
6369        # Test broadcasting in PermuteRowElements(matrix, vector)
6370        input = matrix()
6371        p = ivector()
6372        out = permute_row_elements(input, p)
6373        permute = function([input, p], out)
6374
6375        rng = np.random.RandomState(utt.fetch_seed())
6376        input_val = rng.uniform(size=(3, 5)).astype(config.floatX)
6377        p_val = rng.permutation(5).astype('int32')
6378        out_val = permute(input_val, p_val)
6379
6380        # The same permutation should be applied to every row of the input matrix.
6381        out_bis = np.asarray([r[p_val] for r in input_val])
6382        assert np.all(out_val == out_bis)
6383
6384        # Verify gradient
6385        def permute_fixed(s_input):
6386            # Auxiliary op defined to get rid of gradient wrt p_val
6387            return permute_row_elements(s_input, p_val)
6388        utt.verify_grad(permute_fixed, [input_val])
6389
6390    def test_2_2(self):
6391        # Test PermuteRowElements(matrix, matrix)
6392        input = matrix()
6393        p = imatrix()
6394        out = permute_row_elements(input, p)
6395        permute = function([input, p], out)
6396
6397        rng = np.random.RandomState(utt.fetch_seed())
6398        input_val = rng.uniform(size=(3, 5)).astype(config.floatX)
6399        p_val = np.asarray([rng.permutation(5) for i in range(3)],
6400                           dtype='int32')
6401        out_val = permute(input_val, p_val)
6402
6403        # Each row of p contains a permutation to apply to the corresponding
6404        # row of input
6405        out_bis = np.asarray([i_row[p_row]
6406                              for i_row, p_row in zip(input_val, p_val)])
6407        assert np.all(out_val == out_bis)
6408
6409        # Verify gradient
6410        def permute_fixed(s_input):
6411            # Auxiliary op defined to get rid of gradient wrt p_val
6412            return permute_row_elements(s_input, p_val)
6413        utt.verify_grad(permute_fixed, [input_val])
6414
6415    def test_1_2(self):
6416        # Test PermuteRowElements(vector, matrix)
6417        # Different permutations will be applied to the same input vector
6418        input = vector()
6419        p = imatrix()
6420        out = permute_row_elements(input, p)
6421        permute = function([input, p], out)
6422
6423        rng = np.random.RandomState(utt.fetch_seed())
6424        input_val = rng.uniform(size=(5,)).astype(config.floatX)
6425        p_val = np.asarray([rng.permutation(5)
6426                            for i in range(3)], dtype='int32')
6427        out_val = permute(input_val, p_val)
6428
6429        # Each row of p contains a permutation to apply to the input vector
6430        out_bis = np.asarray([input_val[p_row] for p_row in p_val])
6431        assert np.all(out_val == out_bis)
6432
6433        # Verify gradient
6434        def permute_fixed(s_input):
6435            # Auxiliary op defined to get rid of gradient wrt p_val
6436            return permute_row_elements(s_input, p_val)
6437        utt.verify_grad(permute_fixed, [input_val])
6438
6439    def test_3b_2(self):
6440        # Test permute_row_elements on a more complex broadcasting pattern:
6441        # input.type.broadcastable = (False, True, False),
6442        # p.type.broadcastable = (False, False).
6443
6444        input = TensorType('floatX', (False, True, False))()
6445        p = imatrix()
6446        out = permute_row_elements(input, p)
6447        permute = function([input, p], out)
6448
6449        rng = np.random.RandomState(utt.fetch_seed())
6450        input_val = rng.uniform(size=(4, 1, 5)).astype(config.floatX)
6451        p_val = np.asarray([rng.permutation(5) for i in range(3)],
6452                           dtype='int32')
6453        out_val = permute(input_val, p_val)
6454
6455        # Each row of p contains a permutation to apply to each row
6456        # of the input tensor
6457        out_bis = np.asarray([[in_mat[0, p_row] for p_row in p_val]
6458                              for in_mat in input_val])
6459        assert np.all(out_val == out_bis)
6460
6461        # Verify gradient
6462        def permute_fixed(s_input):
6463            # Auxiliary op defined to get rid of gradient wrt p_val
6464            return permute_row_elements(s_input, p_val)
6465        utt.verify_grad(permute_fixed, [input_val])
6466
6467
6468class test_tensordot(unittest.TestCase):
6469    def TensorDot(self, axes):
6470        # Since tensordot is no longer an op, mimic the old op signature
6471        # to allow easy use of verify_grad.
6472        return lambda a, b: tensordot(a, b, axes)
6473
6474    def setUp(self):
6475        utt.seed_rng()
6476
6477    def test0(self):
6478
6479        # Test vector-vector
6480        avec = vector()
6481        bvec = vector()
6482        axes = ((0, ), (0, ))
6483        c = tensordot(avec, bvec, axes)
6484        f1 = inplace_func([avec, bvec], c)
6485        aval = rand(5)
6486        bval = rand(5)
6487        out0 = np.tensordot(aval, bval, axes)
6488        out1 = f1(aval, bval)
6489        utt.assert_allclose(out0, out1)
6490        utt.verify_grad(self.TensorDot(axes), [aval, bval])
6491
6492        # Test matrix-vector
6493        bmat = matrix()
6494        axes = ((0, ), (1, ))
6495        c = tensordot(avec, bmat, axes)
6496        f2 = inplace_func([avec, bmat], c)
6497        aval = rand(5)
6498        bval = rand(8, 5)
6499        utt.assert_allclose(np.tensordot(aval, bval, axes),
6500                            f2(aval, bval))
6501        utt.verify_grad(self.TensorDot(axes), [aval, bval])
6502
6503        # Test matrix-matrix
6504        amat = matrix()
6505        for axes, shps in [[((0,), (0,)), [(4, 7), (4, 9)]],
6506                           [((0,), (1,)), [(4, 7), (9, 4)]],
6507                           [((1,), (0,)), [(4, 7), (7, 9)]],
6508                           [((1,), (1,)), [(4, 7), (9, 7)]],
6509                           [((0, 1), (0, 1)), [(4, 7), (4, 7)]],
6510                           # [((0, 1), (1, 0)), [(4, 7), (7, 4)]],
6511                           # [((1, 0), (1, 0)), [(4, 7), (4, 7)]],
6512                           # [((1, 0), (0, 1)), [(4, 7), (7, 4)]],
6513                           ]:
6514            c = tensordot(amat, bmat, axes)
6515            f3 = inplace_func([amat, bmat], c)
6516            aval = rand(*shps[0])
6517            bval = rand(*shps[1])
6518            utt.assert_allclose(np.tensordot(aval, bval, axes),
6519                                f3(aval, bval))
6520            utt.verify_grad(self.TensorDot(axes), [aval, bval])
6521
6522        # Test ndarray-matrix, sum over one dim of matrix
6523        for axes, shps in [[((2,), (1,)), [(1, 2, 3, 4), (2, 3)]],
6524                           [((0,), (1,)), [(1, 2, 3, 4), (3, 1)]],
6525                           [((0,), (0,)), [(1, 2, 3, 4), (1, 3)]],
6526                           [((3,), (0,)), [(1, 2, 3, 4), (4, 1)]],
6527                           # [((3, 1), (0, 1)), [(1, 2, 3, 4), (4, 2)]],
6528                           # [((0, 1), (1, 0)), [(1, 2, 3, 4), (2, 1)]],
6529                           # [((3, 1), (1, 0)), [(1, 2, 3, 4), (2, 4)]],
6530                           ]:
6531            atens = tensor4()
6532            c = tensordot(atens, bmat, axes)
6533            f4 = inplace_func([atens, bmat], c)
6534            aval = rand(*shps[0])
6535            bval = rand(*shps[1])
6536            utt.assert_allclose(np.tensordot(aval, bval, axes),
6537                                f4(aval, bval))
6538            utt.verify_grad(self.TensorDot(axes), [aval, bval])
6539
6540        # Test ndarray-ndarray
6541        atens = tensor4()
6542        btens = tensor3()
6543        axes = ((1, 3), (0, 2))
6544        c = tensordot(atens, btens, axes)
6545        f5 = inplace_func([atens, btens], c)
6546        aval = rand(4, 3, 5, 2)
6547        bval = rand(3, 4, 2)
6548        utt.assert_allclose(np.tensordot(aval, bval, axes),
6549                            f5(aval, bval))
6550        utt.verify_grad(self.TensorDot(axes), [aval, bval])
6551
6552        axes = (axes[1], axes[0])
6553        c = tensordot(btens, atens, axes)
6554        f6 = inplace_func([btens, atens], c)
6555        utt.assert_allclose(np.tensordot(bval, aval, axes),
6556                            f6(bval, aval))
6557        utt.verify_grad(self.TensorDot(axes), [bval, aval])
6558
6559    def test_raise_error(self):
6560        amat = matrix()
6561        bmat = matrix()
6562        bvec = vector()
6563
6564        # Test invalid length for axes
6565        self.assertRaises(ValueError, tensordot, amat, bmat, (0, 1, 2))
6566
6567        # Test axes of uneven length
6568        self.assertRaises(ValueError, tensordot, amat, bmat, ((0, 1), (0)))
6569
6570        # Test invalid len(axes) given inputs are matrices
6571        self.assertRaises(ValueError, tensordot, amat, bmat, ((0, 1, 2), (0, 1, 2)))
6572
6573        # Test invalid axes[1] given that y is a vector
6574        self.assertRaises(ValueError, tensordot, amat, bvec, (0, 1))
6575
6576        # Test invalid scalar axes given inputs are matrices
6577        self.assertRaises(ValueError, tensordot, amat, bvec, 2)
6578
6579    def test_weird_valid_axes(self):
6580        # Test matrix-matrix
6581        amat = matrix()
6582        bmat = matrix()
6583        for axes in [0,
6584                     (1, 0),
6585                     [1, 0],
6586                     (1, (0, )),
6587                     ((1, ), 0),
6588                     ([1], [0]),
6589                     ([], [])]:
6590            c = tensordot(amat, bmat, axes)
6591            f3 = inplace_func([amat, bmat], c)
6592            aval = rand(4, 7)
6593            bval = rand(7, 9)
6594            utt.assert_allclose(np.tensordot(aval, bval, axes),
6595                                f3(aval, bval))
6596            utt.verify_grad(self.TensorDot(axes), [aval, bval])
6597
6598    def test_scalar_axes(self):
6599        # Test matrix-matrix
6600        amat = fmatrix()
6601        bmat = dmatrix()
6602        # We let at float64 to test mix of float32 and float64.
6603        axes = 1
6604        aval = rand(4, 5).astype('float32')
6605        bval = rand(5, 3)
6606        c = tensordot(amat, bmat, axes)
6607        f3 = inplace_func([amat, bmat], c)
6608        self.assertTrue(np.allclose(np.tensordot(aval, bval, axes),
6609                                    f3(aval, bval)))
6610        utt.verify_grad(self.TensorDot(axes), [aval, bval])
6611
6612        # Test tensor-tensor
6613        amat = tensor3()
6614        bmat = tensor3()
6615        axes = 2
6616        aval = rand(3, 4, 5)
6617        bval = rand(4, 5, 3)
6618        c = tensordot(amat, bmat, axes)
6619        f3 = inplace_func([amat, bmat], c)
6620        self.assertTrue(np.allclose(np.tensordot(aval, bval, axes),
6621                                    f3(aval, bval)))
6622        utt.verify_grad(self.TensorDot(axes), [aval, bval])
6623
6624    def test_scalar0(self):
6625        # Test tensor-tensor
6626        amat = matrix()
6627        bmat = matrix()
6628        axes = 0
6629        aval = rand(4, 5)
6630        bval = rand(5, 4)
6631        c = tensordot(amat, bmat, axes)
6632        f3 = inplace_func([amat, bmat], c)
6633        self.assertTrue(np.allclose(np.tensordot(aval, bval, axes),
6634                                    f3(aval, bval)))
6635        utt.verify_grad(self.TensorDot(axes), [aval, bval])
6636
6637    def test_broadcastable1(self):
6638        x = TensorType(dtype=floatX, broadcastable=(True, False, False))('x')
6639        y = tensor3('y')
6640        z = tensordot(x, y)
6641        assert z.broadcastable == (True, False)
6642        f = inplace_func([x, y], z)
6643        xv = rand(1, 3, 4)
6644        yv = rand(3, 4, 5)
6645        zv = f(xv, yv)
6646        self.assertTrue(np.allclose(np.tensordot(xv, yv), zv))
6647
6648    def test_broadcastable2(self):
6649        x = TensorType(dtype=floatX, broadcastable=(True, False, False))('x')
6650        y = tensor3('y')
6651        axes = [[2, 1], [0, 1]]
6652        z = tensordot(x, y, axes=axes)
6653        assert z.broadcastable == (True, False)
6654        f = inplace_func([x, y], z)
6655        xv = rand(1, 3, 4)
6656        yv = rand(4, 3, 5)
6657        zv = f(xv, yv)
6658        self.assertTrue(np.allclose(np.tensordot(xv, yv, axes=axes), zv))
6659
6660
6661def test_smallest_stack():
6662    sx, sy = dscalar(), dscalar()
6663
6664    rval = inplace_func([sx, sy], stack([sx, sy]))(-4.0, -2.0)
6665    assert type(rval) == np.ndarray
6666    assert [-4, -2] == list(rval)
6667
6668
6669def test_smallest():
6670    x = dvector()
6671    y = dvector()
6672    z = dvector()
6673    f1 = inplace_func([x], smallest(x))
6674    assert np.all([1, 2, 3] == f1([1, 2, 3]))
6675    f3 = inplace_func([x, y, z], smallest(x, y, z))
6676    assert np.all([1, 2, 3] == f3([1, 3, 9], [7, 7, 7], [8, 2, 3]))
6677
6678    sx, sy = dscalar(), dscalar()
6679
6680    assert -4 == inplace_func([sx, sy], smallest(sx, sy))(-4.0, -2.0)
6681
6682
6683def test_reshape_member_fn():
6684    x = dmatrix()
6685    y = x.reshape((4, 5, 6))
6686    assert y.owner.op == Reshape(3)
6687
6688
6689def test_var():
6690    a = Tensor(dtype='float64', broadcastable=[False, False, False])()
6691    f = function([a], var(a))
6692
6693    a_val = np.arange(60).reshape(3, 4, 5)
6694    assert np.allclose(np.var(a_val), f(a_val))
6695
6696    f = function([a], var(a, axis=0))
6697    assert np.allclose(np.var(a_val, axis=0), f(a_val))
6698
6699    f = function([a], var(a, axis=1))
6700    assert np.allclose(np.var(a_val, axis=1), f(a_val))
6701
6702    f = function([a], var(a, axis=2))
6703    assert np.allclose(np.var(a_val, axis=2), f(a_val))
6704
6705    f = function([a], var(a, axis=0, ddof=0))
6706    assert np.allclose(np.var(a_val, axis=0, ddof=0), f(a_val))
6707
6708    f = function([a], var(a, axis=1, ddof=1))
6709    assert np.allclose(np.var(a_val, axis=1, ddof=1), f(a_val))
6710
6711    f = function([a], var(a, axis=2, ddof=1))
6712    assert np.allclose(np.var(a_val, axis=2, ddof=1), f(a_val))
6713
6714    f = function([a], var(a, ddof=0, corrected=True))
6715    mean_a = np.mean(a_val)
6716    centered_a = a_val - mean_a
6717    v = np.mean(centered_a ** 2)
6718    error = (np.mean(centered_a)) ** 2
6719    v = v - error
6720    assert np.allclose(v, f(a_val))
6721
6722    f = function([a], var(a, axis=2, ddof=1, corrected=True))
6723    mean_a = np.mean(a_val, axis=2, keepdims=True)
6724    centered_a = a_val - mean_a
6725    v = np.var(a_val, axis=2, ddof=1)
6726    shp_inp = np.shape(a_val)
6727    shp = shp_inp - np.array(1)
6728    error = (np.sum(centered_a, axis=2)) ** 2
6729    error = np.true_divide(error, shp[1] * shp_inp[1])
6730    v = v - error
6731    assert np.allclose(v, f(a_val))
6732
6733    # Test that we don't upcast float16 computation
6734    assert theano.tensor.vector(dtype='float16').var().dtype == 'float16'
6735
6736
6737class T_sum(unittest.TestCase):
6738    def test_sum_overflow(self):
6739        # Ensure that overflow errors are a little bit harder to get
6740        a = Tensor(dtype='int8', broadcastable=[False])()
6741        f = function([a], sum(a))
6742        assert f([1] * 300) == 300
6743
6744    def test_list(self):
6745        ll = [theano.shared(0.), theano.shared(2.)]
6746        tensor.sum(ll).eval() == 2
6747
6748
6749@dec.skipif(
6750    isinstance(get_default_mode(), theano.compile.debugmode.DebugMode),
6751    ("This test fails in DEBUG_MODE, but the generated code is OK. "
6752     "It is actually a problem of DEBUG_MODE, see #626."))
6753def test_default():
6754    x, y = scalars('xy')
6755    z = default(x, y)
6756    f = function([x, y], z)
6757    assert f(1, 2) == 1
6758    assert f(None, 2) == 2
6759    assert f(1, None) == 1
6760
6761
6762@dec.skipif(
6763    isinstance(get_default_mode(), theano.compile.debugmode.DebugMode),
6764    ("This test fails in DEBUG_MODE, but the generated code is OK. "
6765     "It is actually a problem of DEBUG_MODE, see #626."))
6766def test_default_state():
6767    x, y = scalars('xy')
6768    # print config.floatX
6769    # print x.type
6770    # print y.type
6771    z = default(x, 3.8)
6772    new_x = y + z
6773    f = function([y, compile.In(x, update=new_x, value=12.0)], new_x)
6774    assert f(3) == 15
6775    f['x'] = None
6776    assert np.allclose(f(1), 4.8)
6777    assert np.allclose(f(np.asarray(2.2, dtype=config.floatX)), 7)
6778
6779
6780def test_autocast():
6781    backup_config = config.cast_policy
6782    # Call test functions for all possible values of `config.cast_policy`.
6783    for autocast_cfg in (
6784            'custom',
6785            # 'numpy', # Commented out until it is implemented properly.
6786            'numpy+floatX',
6787            ):
6788        config.cast_policy = autocast_cfg
6789        try:
6790            eval('_test_autocast_' + autocast_cfg.replace('+', '_'))()
6791        finally:
6792            config.cast_policy = backup_config
6793
6794
6795def _test_autocast_custom():
6796    # Called from `test_autocast`.
6797    assert config.cast_policy == 'custom'
6798    orig_autocast = autocast_float.dtypes
6799
6800    # Test that autocast_float_as sets the autocast dtype correctly
6801    with autocast_float_as('float32'):
6802        assert autocast_float.dtypes == ('float32',)
6803    assert autocast_float.dtypes == orig_autocast
6804
6805    with autocast_float_as('float64'):
6806        assert autocast_float.dtypes == ('float64',)
6807    assert autocast_float.dtypes == orig_autocast
6808
6809    # Test that we can set it back to something, and nest it
6810    with autocast_float_as('float32'):
6811        assert autocast_float.dtypes == ('float32',)
6812        with autocast_float_as('float64'):
6813            assert autocast_float.dtypes == ('float64',)
6814        assert autocast_float.dtypes == ('float32',)
6815    assert autocast_float.dtypes == orig_autocast
6816
6817    # Test that the autocasting dtype is used correctly in expression-building
6818    with autocast_float_as('float32'):
6819        assert (dvector() + 1.1).dtype == 'float64'
6820        assert (fvector() + 1.1).dtype == 'float32'
6821        assert ((fvector() + theano._asarray(1.1, dtype='float64')).dtype ==
6822                'float64')
6823        assert ((fvector() + theano._asarray(1.1, dtype='float32')).dtype ==
6824                'float32')
6825
6826        assert (dvector() + 1).dtype == 'float64'
6827        assert (fvector() + 1).dtype == 'float32'
6828
6829    # Test that the autocasting dtype is used correctly in expression-building
6830    with autocast_float_as('float64'):
6831        assert (dvector() + 1.1).dtype == 'float64'
6832        assert (fvector() + 1.1).dtype == 'float64'
6833        assert (fvector() + 1.0).dtype == 'float64'
6834        assert ((fvector() + theano._asarray(1.1, dtype='float64')).dtype ==
6835                'float64')
6836        assert ((fvector() + theano._asarray(1.1, dtype='float32')).dtype ==
6837                'float32')
6838
6839        assert (dvector() + 1).dtype == 'float64'
6840        assert (fvector() + 1).dtype == 'float32'
6841
6842    # Test that the autocasting dtype is used correctly in expression-building
6843    with autocast_float_as('float32', 'float64'):
6844        assert (dvector() + 1.1).dtype == 'float64'
6845        assert (fvector() + 1.1).dtype == theano.config.floatX
6846        assert (fvector() + 1.0).dtype == 'float32'
6847        assert (dvector() + np.float32(1.1)).dtype == 'float64'
6848        assert (dvector() + np.float64(1.1)).dtype == 'float64'
6849        assert (dvector() + np.float(1.1)).dtype == 'float64'
6850        assert (fvector() + np.float32(1.1)).dtype == 'float32'
6851        assert (fvector() + np.float64(1.1)).dtype == 'float64'
6852        assert (fvector() + np.float(1.1)).dtype == theano.config.floatX
6853        assert (lvector() + np.int64(1)).dtype == 'int64'
6854        assert (lvector() + np.int32(1)).dtype == 'int64'
6855        assert (lvector() + np.int16(1)).dtype == 'int64'
6856        assert (lvector() + np.int8(1)).dtype == 'int64'
6857        assert (ivector() + np.int8(1)).dtype == 'int32'
6858        assert (wvector() + np.int8(1)).dtype == 'int16'
6859        assert (bvector() + np.int8(1)).dtype == 'int8'
6860        with autocast_float_as('float64'):
6861            assert (fvector() + 1.0).dtype == 'float64'
6862
6863
6864def _test_autocast_numpy():
6865    # Called from `test_autocast`.
6866    assert config.cast_policy == 'numpy'
6867    # Go through some typical scalar values.
6868
6869    def ok(z):
6870        assert tensor.constant(z).dtype == np.asarray(z).dtype
6871    for x in ([2 ** i for i in xrange(63)] +
6872              [0, L(0), L(1), L(2 ** 63 - 1)] +
6873              [0., 1., 1.1, 1.5]):
6874        n_x = np.asarray(x)
6875        # Make sure the data type is the same as the one found by numpy.
6876        ok(x)
6877        ok(-x)
6878        ok(x - 1)
6879        ok(-x + 1)
6880        ok(n_x)
6881
6882
6883def _test_autocast_numpy_floatX():
6884    # Called from `test_autocast`.
6885    assert config.cast_policy == 'numpy+floatX'
6886    backup_floatX = config.floatX
6887
6888    def ok(z, floatX):
6889        if (isinstance(z, float) and
6890                floatX == 'float32' and
6891                not hasattr(z, 'dtype')):
6892            # Special case where we use 'float32' instead of 'float64'.
6893            assert tensor.constant(z).dtype == 'float32'
6894        else:
6895            assert tensor.constant(z).dtype == np.asarray(z).dtype
6896    try:
6897        # Test with various values of `config.floatX`.
6898        for floatX in ('float32', 'float64'):
6899            config.floatX = floatX
6900            # Go through some typical scalar values.
6901            # We only consider 'int' and 'long' Python values that can fit
6902            # into int64, as that is the maximal integer type that Theano
6903            # supports, and that is the maximal type in Python indexing.
6904            for x in ([2 ** i - 1 for i in xrange(64)] +
6905                      [0, L(0), L(1), L(2 ** 63 - 1)] +
6906                      [0., 1., 1.1, 1.5]):
6907                ok(x, floatX)
6908                ok(-x, floatX)
6909                ok(x - 1, floatX)
6910                ok(-x + 1, floatX)
6911                ok(np.asarray(x), floatX)
6912                ok(np.float64(x), floatX)
6913    finally:
6914        config.floatX = backup_floatX
6915
6916
6917class test_arithmetic_cast(unittest.TestCase):
6918    # Test output types of basic arithmeric operations (* / + - //).
6919    #
6920    # We only test the behavior for `config.cast_policy` set to either 'numpy' or
6921    # 'numpy+floatX': the 'custom' behavior is (at least partially) tested in
6922    # `_test_autocast_custom`.
6923    def test_arithmetic_cast(self):
6924        backup_config = config.cast_policy
6925        dtypes = get_numeric_types(with_complex=True)
6926
6927        # Here:
6928        # scalar == scalar stored as a 0d array
6929        # array == 1d array
6930        # i_scalar == scalar type used internally by Theano
6931        def theano_scalar(dtype):
6932            return tensor.scalar(dtype=str(dtype))
6933
6934        def numpy_scalar(dtype):
6935            return np.array(1, dtype=dtype)
6936
6937        def theano_array(dtype):
6938            return tensor.vector(dtype=str(dtype))
6939
6940        def numpy_array(dtype):
6941            return np.array([1], dtype=dtype)
6942
6943        def theano_i_scalar(dtype):
6944            return theano.scalar.Scalar(str(dtype))()
6945
6946        def numpy_i_scalar(dtype):
6947            return numpy_scalar(dtype)
6948
6949        if config.int_division == 'int':
6950            # Avoid deprecation warning during tests.
6951            warnings.filterwarnings('ignore', message='Division of two integer',
6952                                    category=DeprecationWarning)
6953        try:
6954            for cfg in ('numpy+floatX', ):  # Used to test 'numpy' as well.
6955                config.cast_policy = cfg
6956                for op in (operator.add, operator.sub, operator.mul,
6957                           operator_div, operator.floordiv):
6958                    for a_type in dtypes:
6959                        for b_type in dtypes:
6960                            # Note that we do not test division between
6961                            # integers if it is forbidden.
6962                            # Theano deals with integer division in its own
6963                            # special way (depending on `config.int_division`).
6964                            is_int_division = (
6965                                op is operator_div and
6966                                a_type in tensor.discrete_dtypes and
6967                                b_type in tensor.discrete_dtypes)
6968                            # We will test all meaningful combinations of
6969                            # scalar and array operations.
6970                            for combo in (
6971                                    ('scalar', 'scalar'),
6972                                    ('array', 'array'),
6973                                    ('scalar', 'array'),
6974                                    ('array', 'scalar'),
6975                                    ('i_scalar', 'i_scalar'),
6976                                    ):
6977
6978                                theano_args = list(
6979                                    map(eval, ['theano_%s' % c for c in combo]))
6980                                numpy_args = list(
6981                                    map(eval, ['numpy_%s' % c for c in combo]))
6982                                try:
6983                                    theano_dtype = op(
6984                                        theano_args[0](a_type),
6985                                        theano_args[1](b_type)).type.dtype
6986                                    # Should have crashed if it is an integer
6987                                    # division and `config.int_division` does
6988                                    # not allow it.
6989                                    assert not (is_int_division and
6990                                                config.int_division == 'raise')
6991                                except theano.scalar.IntegerDivisionError:
6992                                    assert (is_int_division and
6993                                            config.int_division == 'raise')
6994                                    # This is the expected behavior.
6995                                    continue
6996                                # For numpy we have a problem:
6997                                #   http://projects.scipy.org/numpy/ticket/1827
6998                                # As a result we only consider the highest data
6999                                # type that numpy may return.
7000                                numpy_dtypes = [
7001                                    op(numpy_args[0](a_type),
7002                                       numpy_args[1](b_type)).dtype,
7003                                    op(numpy_args[1](b_type),
7004                                       numpy_args[0](a_type)).dtype]
7005                                numpy_dtype = theano.scalar.upcast(
7006                                    *list(map(str, numpy_dtypes)))
7007                                if numpy_dtype == theano_dtype:
7008                                    # Same data type found, all is good!
7009                                    continue
7010                                if (cfg == 'numpy+floatX' and
7011                                        config.floatX == 'float32' and
7012                                        a_type != 'float64' and
7013                                        b_type != 'float64' and
7014                                        numpy_dtype == 'float64'):
7015                                    # We should keep float32.
7016                                    assert theano_dtype == 'float32'
7017                                    continue
7018                                if 'array' in combo and 'scalar' in combo:
7019                                    # For mixed scalar / array operations,
7020                                    # Theano may differ from numpy as it does
7021                                    # not try to prevent the scalar from
7022                                    # upcasting the array.
7023                                    array_type, scalar_type = (
7024                                        (a_type, b_type)[list(combo).index(arg)]
7025                                        for arg in ('array', 'scalar'))
7026                                    up_type = theano.scalar.upcast(array_type,
7027                                                                   scalar_type)
7028                                    if (
7029                                            # The two data types are different.
7030                                            scalar_type != array_type and
7031                                            # The array type is not enough to hold
7032                                            # the scalar type as well.
7033                                            array_type != up_type and
7034                                            # Theano upcasted the result array.
7035                                            theano_dtype == up_type and
7036                                            # But Numpy kept its original type.
7037                                            array_type == numpy_dtype):
7038                                        # Then we accept this difference in
7039                                        # behavior.
7040                                        continue
7041                                if (is_int_division and
7042                                        config.int_division == 'floatX'):
7043                                    assert theano_dtype == config.floatX
7044                                    continue
7045                                if (cfg == 'numpy+floatX' and
7046                                        a_type == 'complex128' and
7047                                        (b_type == 'float32' or
7048                                         b_type == 'float16') and
7049                                        combo == ('scalar', 'array') and
7050                                        theano_dtype == 'complex128' and
7051                                        numpy_dtype == 'complex64'):
7052                                    # In numpy 1.6.x adding a complex128 with
7053                                    # a float32 may result in a complex64. As
7054                                    # of 1.9.2. this is still the case so it is
7055                                    # probably by design
7056                                    raise SkipTest("Known issue with"
7057                                                   "numpy see #761")
7058                                # In any other situation: something wrong is
7059                                # going on!
7060                                assert False
7061        finally:
7062            config.cast_policy = backup_config
7063            if config.int_division == 'int':
7064                # Restore default deprecation warning behavior.
7065                warnings.filterwarnings(
7066                    'default',
7067                    message='Division of two integer',
7068                    category=DeprecationWarning)
7069
7070
7071class T_long_tensor(unittest.TestCase):
7072    def test_fit_int64(self):
7073        bitwidth = theano.configdefaults.python_int_bitwidth()
7074        for exponent in xrange(bitwidth):
7075            val = L(2 ** exponent - 1)
7076            scalar_ct = constant(val)
7077
7078            assert scalar_ct.dtype in tensor.int_dtypes, (exponent, val, scalar_ct.dtype)
7079            assert scalar_ct.value == val
7080
7081            vector_ct = constant([val, val])
7082            # On Python 2, np.array() on a "long" returns int64,
7083            # but on Python 3, all integers are long, and np.asarray
7084            # will not force the upcasting, and return the native int width.
7085            if PY3 and bitwidth == 32:
7086                assert vector_ct.dtype == 'int32'
7087            else:
7088                assert vector_ct.dtype == 'int64'
7089            assert np.all(vector_ct.value == val)
7090
7091            matrix_ct = constant([[val, val]])
7092            # On Python 2, np.array() on a "long" returns int64,
7093            # but on Python 3, all integers are long, and np.asarray
7094            # will not force the upcasting, and return the native int width.
7095            if PY3 and bitwidth == 32:
7096                assert matrix_ct.dtype == 'int32'
7097            else:
7098                assert matrix_ct.dtype == 'int64'
7099            assert np.all(matrix_ct.value == val)
7100
7101    def test_too_big(self):
7102        val = L(2 ** 64)
7103        # This fail for all NumPy version.
7104        self.assertRaises(Exception, constant, val)
7105        self.assertRaises(Exception, constant, [val, val])
7106        self.assertRaises(Exception, constant, [[val, val]])
7107
7108
7109class test_broadcast(unittest.TestCase):
7110    def test_broadcast_bigdim(self):
7111        def f():
7112            x = matrix()
7113            addbroadcast(x, 2)
7114        self.assertRaises(ValueError, f)
7115
7116    def test_unbroadcast_addbroadcast(self):
7117        # test that the unbroadcast fct don't insert not needed broadcast
7118        # and fuse consecutive Rebroadcast op
7119
7120        x = matrix()
7121        assert unbroadcast(x, 0) is x
7122        assert unbroadcast(x, 1) is x
7123        assert unbroadcast(x, 1, 0) is x
7124        assert unbroadcast(x, 0, 1) is x
7125
7126        assert addbroadcast(x, 0) is not x
7127        assert addbroadcast(x, 1) is not x
7128        assert addbroadcast(x, 1, 0).owner.inputs[0] is x
7129
7130        assert unbroadcast(addbroadcast(x, 0), 0) is x
7131        assert addbroadcast(unbroadcast(x, 0), 0) is not x
7132        x = row()
7133        assert unbroadcast(x, 0) is not x
7134        assert unbroadcast(x, 1) is x
7135        assert unbroadcast(x, 1, 0) is not x
7136        assert unbroadcast(x, 0, 1) is not x
7137
7138        assert addbroadcast(x, 0) is x
7139        assert addbroadcast(x, 1).owner.inputs[0] is x
7140        assert addbroadcast(x, 1, 0).owner.inputs[0] is x
7141        assert addbroadcast(x, 0, 1).owner.inputs[0] is x
7142
7143        assert unbroadcast(addbroadcast(x, 1), 1) is x
7144        assert addbroadcast(unbroadcast(x, 1), 1) is not x
7145
7146        # The first broadcast is remove the broadcast, so the second
7147        # should not make one
7148        assert unbroadcast(unbroadcast(x, 0), 0).owner.inputs[0] is x
7149
7150        # Test that consecutive Rebroadcast op are fused
7151        x = TensorType(dtype='float64', broadcastable=(True, True))()
7152        assert unbroadcast(unbroadcast(x, 1), 0).owner.inputs[0] is x
7153        assert addbroadcast(unbroadcast(x, 1), 0).owner.inputs[0] is x
7154        assert addbroadcast(unbroadcast(x, 0), 0) is x
7155
7156    def test_patternbroadcast(self):
7157        # Test that patternbroadcast with an empty broadcasting pattern works
7158        x = scalar('x')
7159        m = tensor.matrix('m')
7160        s = patternbroadcast(m, x.broadcastable)
7161        assert s is m
7162        x2 = patternbroadcast(x, x.broadcastable)
7163        assert x2 is x
7164
7165    def test_infer_shape(self):
7166        x = matrix()
7167        y = addbroadcast(x, 0)
7168        f = theano.function([x], y.shape)
7169        assert (f(np.zeros((1, 5), dtype=config.floatX)) == [1, 5]).all()
7170        topo = f.maker.fgraph.toposort()
7171        if theano.config.mode != 'FAST_COMPILE':
7172            assert len(topo) == 2
7173            assert isinstance(topo[0].op, opt.Shape_i)
7174            assert isinstance(topo[1].op, opt.MakeVector)
7175
7176        x = matrix()
7177        y = unbroadcast(x, 0)
7178        f = theano.function([x], y.shape)
7179        assert (f(np.zeros((2, 5), dtype=config.floatX)) == [2, 5]).all()
7180        topo = f.maker.fgraph.toposort()
7181        if theano.config.mode != 'FAST_COMPILE':
7182            assert len(topo) == 3
7183            assert isinstance(topo[0].op, opt.Shape_i)
7184            assert isinstance(topo[1].op, opt.Shape_i)
7185            assert isinstance(topo[2].op, opt.MakeVector)
7186
7187        x = row()
7188        y = unbroadcast(x, 0)
7189        f = theano.function([x], y.shape)
7190        assert (f(np.zeros((1, 5), dtype=config.floatX)) == [1, 5]).all()
7191        topo = f.maker.fgraph.toposort()
7192        if theano.config.mode != 'FAST_COMPILE':
7193            assert len(topo) == 2
7194            assert isinstance(topo[0].op, opt.Shape_i)
7195            assert isinstance(topo[1].op, opt.MakeVector)
7196
7197
7198def test_len():
7199    for shape_ in [(5,), (3, 4), (7, 4, 6)]:
7200        x = tensor.tensor(dtype='floatX', broadcastable=(False,) * len(shape_))
7201        assert_raises(TypeError, len, x)
7202
7203
7204def test_mod():
7205    # We add this test as not all language and C implementation give the same
7206    # sign to the result. This check that the c_code of `Mod` is implemented
7207    # as Python. That is what we want.
7208    x, y = fscalars('xy')
7209    fn = gof.DualLinker().accept(
7210        gof.FunctionGraph([x, y], [x % y])).make_function()
7211    for a, b in ((0, 1), (1, 1), (0, -1), (1, -1), (-1, -1),
7212                 (1, 2), (-1, 2), (1, -2), (-1, -2),
7213                 (5, 3), (-5, 3), (5, -3), (-5, -3)
7214                 ):
7215        assert fn(a, b) == a % b, (a,)
7216
7217
7218def test_divmod():
7219    # Confirm that divmod is equivalent to the python version.
7220    x, y = fscalars('xy')
7221    d, r = divmod(x, y)
7222    fn = gof.DualLinker().accept(
7223        gof.FunctionGraph([x, y], [d, r])).make_function()
7224    for a, b in ((0, 1), (1, 1), (0, -1), (1, -1), (-1, -1),
7225                 (1, 2), (-1, 2), (1, -2), (-1, -2),
7226                 (5, 3), (-5, 3), (5, -3), (-5, -3)
7227                 ):
7228        d_v, r_v = fn(a, b)
7229        d_vp, r_vp = divmod(a, b)
7230        assert d_v == d_vp and r_v == r_vp, (a,)
7231
7232
7233def test_mod_compile():
7234    # This test generate an Elemwise of Composite as:
7235    #     Elemwise{
7236    #         Composite{
7237    #             Composite{
7238    #                 Composite{
7239    #                     Composite{mod,EQ},
7240    #                     Switch},
7241    #                 mul},
7242    #             add}}
7243    #
7244    # The c_code generated is not compiling as of 30 June 2010. I fix the
7245    # compilation in the same commit.
7246    x = tensor.vector()
7247    y = tensor.vector()
7248    out = tensor.switch(tensor.eq(3 % x.shape[0], 0), y, y[:-1])
7249
7250    theano.function([x, y], out)
7251
7252
7253def test_unalign():
7254    if config.floatX == 'float64':
7255        dtype = "b1,f8"
7256    else:
7257        dtype = "b1,f4"
7258
7259    a = np.empty(10000, dtype=dtype)['f1']
7260    b = np.empty(10000, dtype=dtype)['f1']
7261    assert not a.flags.aligned
7262    assert not b.flags.aligned
7263    a[:] = rand(len(a))
7264    b[:] = rand(len(b))
7265    out_numpy = 2 * a + 3 * b
7266
7267    av, bv = tensor.vectors('ab')
7268    f = theano.function([av, bv], 2 * av + 3 * bv)
7269    f.maker.fgraph.toposort()
7270
7271    try:
7272        out_theano = f(a, b)
7273        assert not a.flags.aligned
7274        assert not b.flags.aligned
7275        assert np.allclose(out_numpy, out_theano)
7276        assert False
7277    except TypeError:
7278        pass
7279
7280    a = np.empty((), dtype=dtype)['f1']
7281    b = np.empty((), dtype=dtype)['f1']
7282    assert not a.flags.aligned
7283    assert not b.flags.aligned
7284    out_numpy = 2 * a + 3 * b
7285
7286    av, bv = tensor.scalars('ab')
7287    f = theano.function([av, bv], 2 * av + 3 * bv)
7288    f.maker.fgraph.toposort()
7289    try:
7290        out_theano = f(a, b)
7291        assert not a.flags.aligned
7292        assert not b.flags.aligned
7293        assert np.allclose(out_numpy, out_theano)
7294        assert False
7295    except TypeError:
7296        pass
7297
7298
7299def test_dimshuffle_duplicate():
7300    x = tensor.vector()
7301
7302    success = False
7303
7304    try:
7305        tensor.DimShuffle((False, ), (0, 0))(x)
7306    except ValueError as e:
7307        assert str(e).find("may not appear twice") != -1
7308        success = True
7309
7310    assert success
7311
7312
7313class T_get_scalar_constant_value(unittest.TestCase):
7314    def test_get_scalar_constant_value(self):
7315        a = tensor.stack([1, 2, 3])
7316        assert get_scalar_constant_value(a[0]) == 1
7317        assert get_scalar_constant_value(a[1]) == 2
7318        assert get_scalar_constant_value(a[2]) == 3
7319
7320        b = tensor.iscalar()
7321        a = tensor.stack([b, 2, 3])
7322        self.assertRaises(tensor.basic.NotScalarConstantError, get_scalar_constant_value, a[0])
7323        assert get_scalar_constant_value(a[1]) == 2
7324        assert get_scalar_constant_value(a[2]) == 3
7325
7326        # For now get_scalar_constant_value goes through only MakeVector and Join of
7327        # scalars.
7328        v = tensor.ivector()
7329        a = tensor.stack([v, [2], [3]])
7330        self.assertRaises(tensor.NotScalarConstantError, get_scalar_constant_value, a[0])
7331        self.assertRaises(tensor.NotScalarConstantError, get_scalar_constant_value, a[1])
7332        self.assertRaises(tensor.NotScalarConstantError, get_scalar_constant_value, a[2])
7333
7334        # Test the case SubTensor(Shape(v)) when the dimensions
7335        # is broadcastable.
7336        v = tensor.row()
7337        assert get_scalar_constant_value(v.shape[0]) == 1
7338
7339    def test_subtensor_of_constant(self):
7340        c = constant(rand(5))
7341        for i in range(c.value.shape[0]):
7342            assert get_scalar_constant_value(c[i]) == c.value[i]
7343        c = constant(rand(5, 5))
7344        for i in range(c.value.shape[0]):
7345            for j in range(c.value.shape[1]):
7346                assert get_scalar_constant_value(c[i, j]) == c.value[i, j]
7347
7348    def test_numpy_array(self):
7349        # Regression test for crash when called on a numpy array.
7350        assert get_scalar_constant_value(np.array(3)) == 3
7351        self.assertRaises(
7352            tensor.NotScalarConstantError,
7353            get_scalar_constant_value,
7354            np.array([0, 1]))
7355        self.assertRaises(
7356            tensor.EmptyConstantError,
7357            get_scalar_constant_value,
7358            np.array([]))
7359
7360    def test_make_vector(self):
7361        mv = opt.make_vector(1, 2, 3)
7362        self.assertRaises(
7363            tensor.NotScalarConstantError,
7364            get_scalar_constant_value,
7365            mv)
7366        assert get_scalar_constant_value(mv[0]) == 1
7367        assert get_scalar_constant_value(mv[1]) == 2
7368        assert get_scalar_constant_value(mv[2]) == 3
7369        assert get_scalar_constant_value(mv[np.int32(0)]) == 1
7370        assert get_scalar_constant_value(mv[np.int64(1)]) == 2
7371        assert get_scalar_constant_value(mv[np.uint(2)]) == 3
7372        t = theano.scalar.Scalar('int64')
7373        self.assertRaises(
7374            tensor.NotScalarConstantError,
7375            get_scalar_constant_value,
7376            mv[t()])
7377
7378    def test_shape_i(self):
7379        c = theano.tensor.constant(np.random.rand(3, 4))
7380        s = opt.Shape_i(0)(c)
7381        assert get_scalar_constant_value(s) == 3
7382        s = opt.Shape_i(1)(c)
7383        assert get_scalar_constant_value(s) == 4
7384        d = theano.shared(np.random.randn(1, 1), broadcastable=(True, True))
7385        f = theano.tensor.basic.ScalarFromTensor()(opt.Shape_i(0)(d))
7386        assert get_scalar_constant_value(f) == 1
7387
7388    def test_elemwise(self):
7389        # We test only for a few elemwise, the list of all supported
7390        # elemwise are in the fct.
7391        c = theano.tensor.constant(np.random.rand())
7392        s = c + 1
7393        assert np.allclose(get_scalar_constant_value(s), c.data + 1)
7394        s = c - 1
7395        assert np.allclose(get_scalar_constant_value(s), c.data - 1)
7396        s = c * 1.2
7397        assert np.allclose(get_scalar_constant_value(s), c.data * 1.2)
7398        s = c < 0.5
7399        assert np.allclose(get_scalar_constant_value(s), int(c.data < 0.5))
7400        s = tensor.second(c, .4)
7401        assert np.allclose(get_scalar_constant_value(s), .4)
7402
7403    def test_assert(self):
7404        # Make sure we still get the constant value if it is wrapped in
7405        # an Assert.
7406        c = theano.tensor.constant(2)
7407        x = theano.tensor.scalar()
7408
7409        # condition is always True
7410        a = opt.Assert()(c, c > 1)
7411        assert get_scalar_constant_value(a) == 2
7412
7413        with change_flags(compute_test_value='off'):
7414            # condition is always False
7415            a = opt.Assert()(c, c > 2)
7416            self.assertRaises(
7417                tensor.NotScalarConstantError,
7418                get_scalar_constant_value, a)
7419
7420        # condition is not constant
7421        a = opt.Assert()(c, c > x)
7422        self.assertRaises(
7423            tensor.NotScalarConstantError,
7424            get_scalar_constant_value, a)
7425
7426    def test_second(self):
7427        # Second should apply when the value is constant but not the shape
7428        c = theano.tensor.constant(np.random.rand())
7429        shp = theano.tensor.vector()
7430        s = theano.tensor.second(shp, c)
7431        assert get_scalar_constant_value(s) == c.data
7432
7433    def test_copy(self):
7434        # Make sure we do not return the internal storage of a constant,
7435        # so we cannot change the value of a constant by mistake.
7436        c = theano.tensor.constant(3)
7437        d = extract_constant(c)
7438        d += 1
7439        e = extract_constant(c)
7440        self.assertTrue(e == 3, (c, d, e))
7441
7442
7443class T_as_tensor_variable(unittest.TestCase):
7444    # We test that ticket #649 stay fixed.
7445    # We should not allow as_tensor_variable to accept True or False
7446    # But it should upcast an ndarray of bool to uint8
7447    def test_bool(self):
7448        self.assertRaises(TypeError, as_tensor_variable, True)
7449        self.assertRaises(TypeError, as_tensor_variable, False)
7450
7451    def test_ndarray_bool(self):
7452        ten = as_tensor_variable(np.array([True, False, False, True, True]))
7453        assert ten.type.dtype == 'bool'
7454
7455    def test_memmap(self):
7456        inp = np.random.rand(4, 3)
7457        f, fname = mkstemp()
7458        new_inp = np.memmap(fname, dtype=inp.dtype,
7459                            mode='w+', shape=inp.shape)
7460        new_inp[...] = inp
7461        as_tensor_variable(new_inp)
7462
7463    def test_empty_dtype(self):
7464        old = theano.config.floatX
7465        for dtype in ['float16', 'float32', 'float64']:
7466            try:
7467                theano.config.floatX = dtype
7468                assert theano.tensor.as_tensor_variable(()).dtype == dtype
7469                assert theano.tensor.as_tensor_variable([]).dtype == dtype
7470            finally:
7471                theano.config.floatX = old
7472
7473
7474class test_complex_mod(unittest.TestCase):
7475    # Make sure % fails on complex numbers.
7476    def test_fail(self):
7477        x = vector(dtype='complex64')
7478        try:
7479            x % 5
7480            assert False
7481        except theano.scalar.ComplexError:
7482            pass
7483
7484
7485class test_size(unittest.TestCase):
7486    # Ensure the `size` attribute of tensors behaves as in numpy.
7487    def test_matrix(self):
7488        x = tensor.matrix()
7489        y = np.zeros((5, 7), dtype=config.floatX)
7490        assert y.size == function([x], x.size)(y)
7491
7492    def test_vector(self):
7493        x = tensor.vector()
7494        y = np.zeros(7, dtype=config.floatX)
7495        assert y.size == function([x], x.size)(y)
7496
7497    def test_scalar(self):
7498        x = tensor.scalar()
7499        y = np.array(7, dtype=config.floatX)
7500        assert y.size == function([x], x.size)(y)
7501
7502    def test_shared(self):
7503        # NB: we also test higher order tensors at the same time.
7504        y = np.zeros((1, 2, 3, 4), dtype=config.floatX)
7505        x = theano.shared(y)
7506        assert y.size == function([], x.size)()
7507
7508
7509class test_diag(unittest.TestCase):
7510    # Test that tensor.diag has the same behavior as np.diag.
7511    # np.diag has two behaviors:
7512    #
7513    # (1) when given a vector, it returns a matrix with that vector as the
7514    # diagonal.
7515    # (2) when given a matrix, returns a vector which is the diagonal of the
7516    # matrix.
7517    #
7518    # (1) and (2) are tested by test_alloc_diag and test_extract_diag
7519    # respectively.
7520    #
7521    # test_diag test makes sure that linalg.diag instantiates
7522    # the right op based on the dimension of the input.
7523    def __init__(self, name, mode=None, shared=tensor._shared,
7524                 floatX=None, type=tensor.TensorType):
7525        self.mode = mode
7526        self.shared = shared
7527        if floatX is None:
7528            floatX = config.floatX
7529        self.floatX = floatX
7530        self.type = type
7531        super(test_diag, self).__init__(name)
7532
7533    def test_diag(self):
7534        rng = np.random.RandomState(utt.fetch_seed())
7535
7536        # test vector input
7537        x = theano.tensor.vector()
7538        g = diag(x)
7539        assert isinstance(g.owner.op, AllocDiag)
7540        f = theano.function([x], g)
7541        for shp in [5, 0, 1]:
7542            m = rng.rand(shp).astype(self.floatX)
7543            v = np.diag(m)
7544            r = f(m)
7545            # The right matrix is created
7546            assert (r == v).all()
7547
7548        # Test matrix input
7549        xx = self.shared(rng.rand(3, 5))
7550        g = diag(xx)
7551        assert isinstance(g.owner.op, ExtractDiag)
7552        f = theano.function([], g)
7553        for shp in [(5, 3), (3, 5), (5, 1), (1, 5), (5, 0), (0, 5),
7554                    (1, 0), (0, 1)]:
7555            m = rng.rand(*shp).astype(self.floatX)
7556            xx.set_value(m)
7557            v = np.diag(m)
7558            r = f()
7559            # The right matrix is created
7560            assert (r == v).all()
7561
7562        # Test scalar input
7563        xx = theano.tensor.scalar()
7564        np.testing.assert_raises(ValueError, diag, xx)
7565
7566    def test_infer_shape(self):
7567        rng = np.random.RandomState(utt.fetch_seed())
7568
7569        x = theano.tensor.vector()
7570        g = diag(x)
7571        f = theano.function([x], g.shape)
7572        topo = f.maker.fgraph.toposort()
7573        if config.mode != 'FAST_COMPILE':
7574            assert np.sum(
7575                [isinstance(node.op, AllocDiag) for node in topo]) == 0
7576        for shp in [5, 0, 1]:
7577            m = rng.rand(shp).astype(self.floatX)
7578            assert (f(m) == np.diag(m).shape).all()
7579
7580        x = theano.tensor.matrix()
7581        g = diag(x)
7582        f = theano.function([x], g.shape)
7583        topo = f.maker.fgraph.toposort()
7584        if config.mode != 'FAST_COMPILE':
7585            assert np.sum(
7586                [isinstance(node.op, ExtractDiag) for node in topo]) == 0
7587        for shp in [(5, 3), (3, 5), (5, 1), (1, 5), (5, 0), (0, 5),
7588                    (1, 0), (0, 1)]:
7589            m = rng.rand(*shp).astype(self.floatX)
7590            assert (f(m) == np.diag(m).shape).all()
7591
7592    def test_diag_grad(self):
7593        rng = np.random.RandomState(utt.fetch_seed())
7594        x = rng.rand(5)
7595        tensor.verify_grad(diag, [x], rng=rng)
7596        x = rng.rand(5, 3)
7597        tensor.verify_grad(diag, [x], rng=rng)
7598
7599
7600class TestAllocDiag(unittest.TestCase):
7601    def __init__(self, name, alloc_diag=AllocDiag, mode=None):
7602        self.alloc_diag = alloc_diag
7603
7604        if mode is None:
7605            mode = theano.compile.mode.get_default_mode()
7606        self.mode = mode
7607
7608        super(TestAllocDiag, self).__init__(name)
7609
7610    def _generator(self):
7611        dims = 4
7612        shape = (5,) * dims
7613        xv = np.random.randn(*shape).astype(config.floatX)
7614        for d in xrange(1, dims + 1):
7615            # Create a TensorType of the same dimensions as
7616            # as the data we want to test.
7617            x = TensorType(dtype=config.floatX, broadcastable=(False,) * d)('x')
7618
7619            # Make a slice of the test data that has the
7620            # dimensions we need by doing xv[0,...,0]
7621            # For example, for an array of shape (5,), we
7622            # need to do xv[0, 0, 0, 0].
7623            test_val = xv[((0,) * (dims - d))]
7624            yield x, test_val
7625
7626    def test_alloc_diag_values(self):
7627        for x, test_val in self._generator():
7628            for offset, axis1, axis2 in [(0, 0, 1), (0, 1, 2), (1, 0, 1),
7629                                         (0, 1, 3), (0, 2, 3), (1, 2, 3),
7630                                         (-1, 0, 1), (-2, 0, 1), (-1, 1, 2)]:
7631                # Test AllocDiag values
7632                if np.maximum(axis1, axis2) > len(test_val.shape):
7633                    continue
7634                adiag_op = self.alloc_diag(offset=offset,
7635                                           axis1=axis1,
7636                                           axis2=axis2)
7637                f = theano.function([x], adiag_op(x))
7638                # AllocDiag and extract the diagonal again
7639                # to check
7640                diag_arr = f(test_val)
7641                rediag = np.diagonal(
7642                    diag_arr,
7643                    offset=offset,
7644                    axis1=axis1,
7645                    axis2=axis2
7646                )
7647                assert np.all(rediag == test_val)
7648
7649                # Test infer_shape
7650                f_shape = theano.function([x], adiag_op(x).shape, mode='FAST_RUN')
7651
7652                theano.printing.debugprint(f_shape.maker.fgraph.outputs[0])
7653                output_shape = f_shape(test_val)
7654                assert not any(isinstance(node.op, self.alloc_diag)
7655                               for node in f_shape.maker.fgraph.toposort())
7656                rediag_shape = np.diagonal(
7657                    np.ones(output_shape),
7658                    offset=offset,
7659                    axis1=axis1,
7660                    axis2=axis2
7661                ).shape
7662                assert np.all(rediag_shape == test_val.shape)
7663
7664                diag_x = adiag_op(x)
7665                sum_diag_x = tensor.sum(diag_x)
7666                grad_x = tensor.grad(sum_diag_x, x)
7667                grad_diag_x = tensor.grad(sum_diag_x, diag_x)
7668                f_grad_x = theano.function([x], grad_x, mode=self.mode)
7669                f_grad_diag_x = theano.function([x], grad_diag_x, mode=self.mode)
7670                grad_input = f_grad_x(test_val)
7671                grad_diag_input = f_grad_diag_x(test_val)
7672                true_grad_input = np.diagonal(
7673                    grad_diag_input,
7674                    offset=offset,
7675                    axis1=axis1,
7676                    axis2=axis2
7677                )
7678
7679                assert np.all(true_grad_input == grad_input)
7680
7681
7682class test_numpy_assumptions(unittest.TestCase):
7683    # Verify that some assumptions Theano makes on Numpy's behavior still hold.
7684    def test_ndarray_copy(self):
7685        # A copy or deepcopy of the ndarray type should not create a new object.
7686        #
7687        # This is because Theano makes some comparisons of the form:
7688        #     if type(x) is np.ndarray
7689        assert copy(np.ndarray) is np.ndarray
7690        assert deepcopy(np.ndarray) is np.ndarray
7691
7692    def test_dtype_equality(self):
7693        # Ensure dtype string comparisons are consistent.
7694        #
7695        # Theano often uses string representations of dtypes (e.g. 'float32'). We
7696        # need to make sure that comparing the string representations is the same
7697        # as comparing the dtype objects themselves.
7698        dtypes = get_numeric_types(with_complex=True)
7699        # Perform all pairwise comparisons of dtypes, making sure comparing
7700        # their string representation yields the same result.
7701        for dtype1_idx, dtype1 in enumerate(dtypes):
7702            for dtype2 in dtypes[dtype1_idx + 1:]:
7703                assert (dtype1 == dtype2) == (str(dtype1) == str(dtype2))
7704
7705
7706def test_transpose():
7707    x1 = tensor.dvector('x1')
7708    x2 = tensor.dmatrix('x2')
7709    x3 = tensor.dtensor3('x3')
7710
7711    x1v = np.arange(24)
7712    x2v = np.arange(24).reshape(2, 12)
7713    x3v = np.arange(24).reshape(2, 3, 4)
7714
7715    f = theano.function([x1, x2, x3], [
7716        tensor.transpose(x1),
7717        tensor.transpose(x2),
7718        tensor.transpose(x3),
7719        x1.transpose(),
7720        x2.transpose(),
7721        x3.transpose(),
7722        x2.transpose(0, 1),
7723        x3.transpose((0, 2, 1)),
7724        tensor.transpose(x2, [0, 1]),
7725        tensor.transpose(x3, [0, 2, 1]),
7726        ])
7727
7728    t1, t2, t3, t1b, t2b, t3b, t2c, t3c, t2d, t3d = f(x1v, x2v, x3v)
7729    assert t1.shape == np.transpose(x1v).shape
7730    assert t2.shape == np.transpose(x2v).shape
7731    assert t3.shape == np.transpose(x3v).shape
7732    assert np.all(t1 == np.transpose(x1v))
7733    assert np.all(t2 == np.transpose(x2v))
7734    assert np.all(t3 == np.transpose(x3v))
7735    assert np.all(t1b == x1v.transpose())
7736    assert np.all(t2b == x2v.transpose())
7737    assert np.all(t3b == x3v.transpose())
7738    assert t2c.shape == (2, 12)
7739    assert t3c.shape == (2, 4, 3)
7740    assert np.all(t2c == x2v.transpose([0, 1]))
7741    assert np.all(t3c == x3v.transpose([0, 2, 1]))
7742    assert t2d.shape == (2, 12)
7743    assert t3d.shape == (2, 4, 3)
7744    assert np.all(t2d == np.transpose(x2v, [0, 1]))
7745    assert np.all(t3d == np.transpose(x3v, [0, 2, 1]))
7746
7747    # Check that we create a name.
7748    assert tensor.transpose(x1).name == 'x1.T'
7749    assert tensor.transpose(x2).name == 'x2.T'
7750    assert tensor.transpose(x3).name == 'x3.T'
7751    assert tensor.transpose(tensor.dmatrix()).name is None
7752
7753
7754def test_stacklists():
7755    a, b, c, d = map(scalar, 'abcd')
7756    X = stacklists([[a, b],
7757                    [c, d]])
7758    f = function([a, b, c, d], X)
7759    result = f(1, 2, 3, 4)
7760    assert result.shape == (2, 2)
7761    assert np.allclose(f(1, 2, 3, 4), np.asarray([[1, 2], [3, 4]]))
7762
7763    X = stacklists([a, b, c, d])
7764    f = function([a, b, c, d], X)
7765    result = f(1, 2, 3, 4)
7766    assert result.shape == (4,)
7767    assert np.allclose(f(1, 2, 3, 4), np.asarray([[1, 2, 3, 4]]))
7768
7769    X = stacklists([[[a], [b]], [[c], [d]]])
7770    f = function([a, b, c, d], X)
7771    result = f(1, 2, 3, 4)
7772    assert result.shape == (2, 2, 1)
7773
7774    a, b, c, d = [matrix(x) for x in 'abcd']
7775    X = stacklists([[a, b],
7776                    [c, d]])
7777    f = function([a, b, c, d], X)
7778    x = np.ones((4, 4), 'float32')
7779    assert f(x, x, x, x).shape == (2, 2, 4, 4)
7780
7781
7782class TestSpecifyShape(unittest.TestCase):
7783    mode = None
7784    input_type = TensorType
7785
7786    def shortDescription(self):
7787        return None
7788
7789    def test_bad_shape(self):
7790        # Test that at run time we raise an exception when the shape
7791        # is not the one specified
7792        specify_shape = SpecifyShape()
7793
7794        x = vector()
7795        xval = np.random.rand(2).astype(floatX)
7796        f = theano.function([x], specify_shape(x, [2]), mode=self.mode)
7797        f(xval)
7798        xval = np.random.rand(3).astype(floatX)
7799        self.assertRaises(AssertionError, f, xval)
7800
7801        assert isinstance([n for n in f.maker.fgraph.toposort()
7802                           if isinstance(n.op, SpecifyShape)][0].inputs[0].type,
7803                          self.input_type)
7804
7805        x = matrix()
7806        xval = np.random.rand(2, 3).astype(floatX)
7807        f = theano.function([x], specify_shape(x, [2, 3]), mode=self.mode)
7808        assert isinstance([n for n in f.maker.fgraph.toposort()
7809                           if isinstance(n.op, SpecifyShape)][0].inputs[0].type,
7810                          self.input_type)
7811        f(xval)
7812        for shape_ in [(1, 3), (2, 2), (5, 5)]:
7813            xval = np.random.rand(*shape_).astype(floatX)
7814            self.assertRaises(AssertionError, f, xval)
7815
7816    def test_bad_number_of_shape(self):
7817        # Test that the number of dimensions provided is good
7818        specify_shape = SpecifyShape()
7819
7820        x = vector()
7821        shape_vec = ivector()
7822        xval = np.random.rand(2).astype(floatX)
7823        self.assertRaises(AssertionError, specify_shape, x, [])
7824        self.assertRaises(AssertionError, specify_shape, x, [2, 2])
7825
7826        f = theano.function([x, shape_vec], specify_shape(x, shape_vec),
7827                            mode=self.mode)
7828        assert isinstance([n for n in f.maker.fgraph.toposort()
7829                           if isinstance(n.op, SpecifyShape)][0].inputs[0].type,
7830                          self.input_type)
7831        self.assertRaises(AssertionError, f, xval, [])
7832        self.assertRaises(AssertionError, f, xval, [2, 2])
7833
7834        x = matrix()
7835        xval = np.random.rand(2, 3).astype(floatX)
7836        for shape_ in [(),
7837                       (1,),
7838                       (2, 3, 4)]:
7839            self.assertRaises(AssertionError, specify_shape, x, shape_)
7840            f = theano.function([x, shape_vec], specify_shape(x, shape_vec),
7841                                mode=self.mode)
7842            assert isinstance([n for n in f.maker.fgraph.toposort()
7843                               if isinstance(n.op, SpecifyShape)][0].inputs[0].type,
7844                              self.input_type)
7845            self.assertRaises(AssertionError, f, xval, shape_)
7846
7847
7848class TestInferShape(utt.InferShapeTester):
7849
7850    def test_infer_shape(self):
7851
7852        # Flatten
7853        atens3 = tensor3()
7854        atens3_val = rand(4, 5, 3)
7855        for outdim in (3, 2, 1):
7856            self._compile_and_check([atens3],
7857                                    [flatten(atens3, outdim)],
7858                                    [atens3_val], Reshape,
7859                                    excluding=['local_useless_reshape'])
7860
7861        amat = matrix()
7862        amat_val = rand(4, 5)
7863        for outdim in (2, 1):
7864            self._compile_and_check([amat],
7865                                    [flatten(amat, outdim)],
7866                                    [amat_val], Reshape,
7867                                    excluding=['local_useless_reshape'])
7868
7869        avec = vector()
7870        avec_val = rand(4)
7871        outdim = 1
7872        self._compile_and_check([avec],
7873                                [flatten(avec, outdim)],
7874                                [avec_val], Reshape,
7875                                excluding=['local_useless_reshape'])
7876
7877        # Eye
7878        aiscal = iscalar()
7879        biscal = iscalar()
7880        ciscal = iscalar()
7881        self._compile_and_check([aiscal, biscal, ciscal],
7882                                [Eye()(aiscal, biscal, ciscal)],
7883                                [4, 4, 0], Eye)
7884
7885        self._compile_and_check([aiscal, biscal, ciscal],
7886                                [Eye()(aiscal, biscal, ciscal)],
7887                                [4, 5, 0], Eye)
7888
7889        self._compile_and_check([aiscal, biscal, ciscal],
7890                                [Eye()(aiscal, biscal, ciscal)],
7891                                [3, 5, 0], Eye)
7892
7893        # Tri
7894        aiscal = iscalar()
7895        biscal = iscalar()
7896        ciscal = iscalar()
7897        self._compile_and_check([aiscal, biscal, ciscal],
7898                                [Tri()(aiscal, biscal, ciscal)],
7899                                [4, 4, 0], Tri)
7900
7901        self._compile_and_check([aiscal, biscal, ciscal],
7902                                [Tri()(aiscal, biscal, ciscal)],
7903                                [4, 5, 0], Tri)
7904
7905        self._compile_and_check([aiscal, biscal, ciscal],
7906                                [Tri()(aiscal, biscal, ciscal)],
7907                                [3, 5, 0], Tri)
7908
7909        # ExtractDiag
7910        atens3 = tensor3()
7911        atens3_val = rand(4, 5, 3)
7912        atens3_diag = ExtractDiag()(atens3)
7913        self._compile_and_check([atens3], [atens3_diag],
7914                                [atens3_val], ExtractDiag)
7915        atens3_diag = ExtractDiag(1)(atens3)
7916        self._compile_and_check([atens3], [atens3_diag],
7917                                [atens3_val], ExtractDiag)
7918        atens3_diag = ExtractDiag(-1)(atens3)
7919        self._compile_and_check([atens3], [atens3_diag],
7920                                [atens3_val], ExtractDiag)
7921        atens3_diag = ExtractDiag(1, 0, 2)(atens3)
7922        self._compile_and_check([atens3], [atens3_diag],
7923                                [atens3_val], ExtractDiag)
7924        atens3_diag = ExtractDiag(1, 1, 2)(atens3)
7925        self._compile_and_check([atens3], [atens3_diag],
7926                                [atens3_val], ExtractDiag)
7927        atens3_diag = ExtractDiag(1, 2, 0)(atens3)
7928        self._compile_and_check([atens3], [atens3_diag],
7929                                [atens3_val], ExtractDiag)
7930
7931        # AllocDiag
7932        advec = dvector()
7933        advec_val = rand(4)
7934        self._compile_and_check([advec], [AllocDiag()(advec)],
7935                                [advec_val], AllocDiag)
7936
7937        # Shape
7938        # 'opt.Makevector' precludes optimizer from disentangling
7939        # elements of shape
7940        adtens = tensor3()
7941        adtens_val = rand(4, 5, 3)
7942        self._compile_and_check([adtens],
7943                                [Shape()(adtens)],
7944                                [adtens_val], (opt.MakeVector, Shape))
7945
7946        # Dot
7947
7948        # vec/vec
7949        advec = dvector()
7950        bdvec = dvector()
7951        advec_val = rand(4)
7952        bdvec_val = rand(4)
7953        self._compile_and_check([advec, bdvec],
7954                                [Dot()(advec, bdvec)],
7955                                [advec_val, bdvec_val],
7956                                (Dot, tensor.blas.Dot22,
7957                                 tensor.blas.Gemv, tensor.blas_c.CGemv))
7958
7959        # mat/mat
7960        admat = dmatrix()
7961        bdmat = dmatrix()
7962        admat_val = rand(4, 5)
7963        bdmat_val = rand(5, 3)
7964        self._compile_and_check([admat, bdmat],
7965                                [Dot()(admat, bdmat)],
7966                                [admat_val, bdmat_val],
7967                                (Dot, tensor.blas.Dot22))
7968
7969        # vec/mat
7970        bdmat_val = rand(4, 5)
7971        self._compile_and_check([advec, bdmat],
7972                                [Dot()(advec, bdmat)],
7973                                [advec_val, bdmat_val],
7974                                (Dot, tensor.blas.Dot22,
7975                                 tensor.blas.Gemv, tensor.blas_c.CGemv))
7976
7977        # mat/vec
7978        admat_val = rand(5, 4)
7979        self._compile_and_check([admat, bdvec],
7980                                [Dot()(admat, bdvec)],
7981                                [admat_val, bdvec_val],
7982                                (Dot, tensor.blas.Dot22,
7983                                 tensor.blas.Gemv, tensor.blas_c.CGemv))
7984
7985        # Split
7986        aivec = ivector()
7987        adtens_val = rand(4, 10, 3)
7988        aivec_val = [2, 5, 3]
7989        for aiscal_val in [1, -2]:
7990            self._compile_and_check(
7991                [adtens, aiscal, aivec],
7992                [Split(3)(adtens, aiscal, aivec)[0]],
7993                [adtens_val, aiscal_val, aivec_val], (Split))
7994
7995        # Join
7996        cdmat = dmatrix()
7997        admat_val = rand(1, 3)
7998        bdmat_val = rand(2, 3)
7999        cdmat_val = rand(4, 3)
8000        for aiscal_val in [0, -2]:
8001            self._compile_and_check(
8002                [aiscal, admat, bdmat, cdmat],
8003                [Join()(aiscal, admat, bdmat, cdmat)],
8004                [aiscal_val, admat_val, bdmat_val, cdmat_val], Join)
8005
8006        admat_val = rand(4, 1)
8007        bdmat_val = rand(4, 3)
8008        cdmat_val = rand(4, 2)
8009        for aiscal_val in [-1, 1]:
8010            self._compile_and_check(
8011                [aiscal, admat, bdmat, cdmat],
8012                [Join()(aiscal, admat, bdmat, cdmat)],
8013                [aiscal_val, admat_val, bdmat_val, cdmat_val], Join)
8014
8015        # PermuteRowElements
8016        abool = True
8017        rng = np.random.RandomState(utt.fetch_seed())
8018        advec_val = rand(5)
8019        aivec_val = rng.permutation(5).astype('int32')
8020        self._compile_and_check([advec, aivec],
8021                                [PermuteRowElements()(advec, aivec, abool)],
8022                                [advec_val, aivec_val], PermuteRowElements)
8023
8024        admat_val = rand(3, 5)
8025        self._compile_and_check([admat, aivec],
8026                                [PermuteRowElements()(admat, aivec, abool)],
8027                                [admat_val, aivec_val], PermuteRowElements)
8028
8029        adtens3 = dtensor3()
8030        adtens3_val = rand(3, 2, 5)
8031        self._compile_and_check([adtens3, aivec],
8032                                [PermuteRowElements()(adtens3, aivec, abool)],
8033                                [adtens3_val, aivec_val], PermuteRowElements)
8034
8035        aimat = imatrix()
8036        perma = rng.permutation(5).astype('int32')
8037        permb = rng.permutation(5).astype('int32')
8038        permc = rng.permutation(5).astype('int32')
8039        aimat_val = np.vstack((perma, permb, permc))
8040        admat_val = rand(3, 5)
8041        self._compile_and_check([admat, aimat],
8042                                [PermuteRowElements()(admat, aimat, abool)],
8043                                [admat_val, aimat_val], PermuteRowElements)
8044
8045        aitens3 = itensor3()
8046        perma = rng.permutation(5).astype('int32')
8047        permb = rng.permutation(5).astype('int32')
8048        permc = rng.permutation(5).astype('int32')
8049        bimat_val = np.vstack((perma, permb, permc))
8050        aitens3_val = np.empty((2, 3, 5), 'int32')
8051        aitens3_val[0, ::, ::] = aimat_val
8052        aitens3_val[1, ::, ::] = bimat_val
8053        self._compile_and_check([admat, aitens3],
8054                                [PermuteRowElements()(admat, aitens3, abool)],
8055                                [admat_val, aitens3_val], PermuteRowElements)
8056
8057        # ScalarFromTensor
8058        aiscal = iscalar()
8059        self._compile_and_check([aiscal],
8060                                [TensorFromScalar()(ScalarFromTensor()(aiscal))],
8061                                [45], ScalarFromTensor,
8062                                excluding=["local_tensor_scalar_tensor"])
8063
8064        # TensorFromScalar
8065        aiscal = scal.float64()
8066
8067        self._compile_and_check([aiscal],
8068                                [TensorFromScalar()(aiscal)],
8069                                [4.], TensorFromScalar)
8070
8071        # Rebroadcast
8072        adtens4 = dtensor4()
8073        adict = [(0, False), (1, True), (2, False), (3, True)]
8074        adtens4_val = rand(2, 1, 3, 1)
8075        self._compile_and_check([adtens4],
8076                                [Rebroadcast(*adict)(adtens4)],
8077                                [adtens4_val], Rebroadcast,
8078                                warn=False)
8079
8080        adtens4_bro = TensorType('float64', (True, True, True, False))()
8081        bdict = [(0, True), (1, False), (2, False), (3, False)]
8082        adtens4_bro_val = rand(1, 1, 1, 3)
8083        self._compile_and_check([adtens4_bro],
8084                                [Rebroadcast(*bdict)(adtens4_bro)],
8085                                [adtens4_bro_val], Rebroadcast)
8086
8087        # Alloc
8088        randint = np.random.randint
8089        adscal = dscalar()
8090        aiscal = lscalar()
8091        biscal = lscalar()
8092        ciscal = lscalar()
8093        discal = lscalar()
8094        adscal_val = rand()
8095        aiscal_val = randint(3, 6, size=())
8096        biscal_val = randint(3, 6, size=())
8097        ciscal_val = randint(3, 6, size=())
8098        discal_val = randint(3, 6, size=())
8099        self._compile_and_check(
8100            [adscal, aiscal, biscal, ciscal, discal],
8101            [Alloc()(adscal, aiscal, biscal, ciscal, discal)],
8102            [adscal_val, aiscal_val, biscal_val, ciscal_val, discal_val],
8103            Alloc)
8104
8105        # MaxAndArgmax,
8106        adtens3_val = rand(4, 5, 3)
8107        self._compile_and_check([adtens3],
8108                                max_and_argmax(adtens3, None),
8109                                [adtens3_val], MaxAndArgmax)
8110
8111        self._compile_and_check([adtens3],
8112                                max_and_argmax(adtens3, 0),
8113                                [adtens3_val], MaxAndArgmax)
8114
8115        self._compile_and_check([adtens3],
8116                                max_and_argmax(adtens3, 1),
8117                                [adtens3_val], MaxAndArgmax)
8118
8119        self._compile_and_check([adtens3],
8120                                max_and_argmax(adtens3, 2),
8121                                [adtens3_val], MaxAndArgmax)
8122
8123        self._compile_and_check([adtens3],
8124                                max_and_argmax(adtens3, [0, 1, 2]),
8125                                [adtens3_val], MaxAndArgmax)
8126
8127        # ARange
8128        self._compile_and_check([aiscal, biscal, ciscal],
8129                                [ARange('int64')(aiscal, biscal, ciscal)],
8130                                [0, 5, 1], ARange)
8131        self._compile_and_check([aiscal, biscal, ciscal],
8132                                [ARange('int64')(aiscal, biscal, ciscal)],
8133                                [2, 11, 4], ARange)
8134        self._compile_and_check([aiscal, biscal, ciscal],
8135                                [ARange('int64')(aiscal, biscal, ciscal)],
8136                                [-5, 1, 1], ARange)
8137        self._compile_and_check([aiscal, biscal, ciscal],
8138                                [ARange('int64')(aiscal, biscal, ciscal)],
8139                                [10, 2, -2], ARange)
8140        self._compile_and_check([aiscal, biscal, ciscal],
8141                                [ARange('int64')(aiscal, biscal, ciscal)],
8142                                [10, 2, 2], ARange)
8143        self._compile_and_check([aiscal, biscal, ciscal],
8144                                [ARange('int64')(aiscal, biscal, ciscal)],
8145                                [0, 0, 1], ARange)
8146
8147        # SpecifyShape
8148        aivec_val = [3, 4, 2, 5]
8149        adtens4_val = rand(*aivec_val)
8150        self._compile_and_check([adtens4, aivec],
8151                                [SpecifyShape()(adtens4, aivec)],
8152                                [adtens4_val, aivec_val], SpecifyShape)
8153
8154        # Mean
8155        adtens3_val = rand(3, 4, 5)
8156        aiscal_val = 2
8157        self._compile_and_check([adtens3],
8158                                [Mean(None)(adtens3)],
8159                                [adtens3_val], Mean)
8160        self._compile_and_check([adtens3],
8161                                [Mean(aiscal_val)(adtens3)],
8162                                [adtens3_val], Mean)
8163
8164        # Reshape
8165        # TODO: generalize infer_shape to account for tensor variable
8166        # (non-constant) input shape
8167        admat = dmatrix()
8168        aivec = ivector()
8169        ndim = 1
8170        admat_val = rand(3, 4)
8171        self._compile_and_check([admat],
8172                                [Reshape(ndim)(admat, [12])],
8173                                [admat_val], Reshape)
8174
8175        self._compile_and_check([admat],
8176                                [Reshape(ndim)(admat, [-1])],
8177                                [admat_val], Reshape)
8178
8179        ndim = 2
8180        self._compile_and_check([admat],
8181                                [Reshape(ndim)(admat, [4, 3])],
8182                                [admat_val], Reshape)
8183
8184        self._compile_and_check([admat],
8185                                [Reshape(ndim)(admat, [4, -1])],
8186                                [admat_val], Reshape)
8187
8188        self._compile_and_check([admat],
8189                                [Reshape(ndim)(admat, [3, -1])],
8190                                [admat_val], Reshape)
8191
8192        self._compile_and_check([admat],
8193                                [Reshape(ndim)(admat, [-1, 3])],
8194                                [admat_val], Reshape)
8195        self._compile_and_check([admat],
8196                                [Reshape(ndim)(admat, [-1, 4])],
8197                                [admat_val], Reshape)
8198
8199        # enable when infer_shape is generalized:
8200        # self._compile_and_check([admat, aivec],
8201        #                        [Reshape(ndim)(admat, aivec)],
8202        #                        [admat_val, [4, 3]], Reshape)
8203        #
8204        # self._compile_and_check([admat, aivec],
8205        #                        [Reshape(ndim)(admat, aivec)],
8206        #                        [admat_val, [4, -1]], Reshape)
8207
8208        adtens4 = dtensor4()
8209        ndim = 4
8210        adtens4_val = rand(2, 4, 3, 5)
8211        self._compile_and_check([adtens4],
8212                                [Reshape(ndim)(adtens4, [1, -1, 10, 4])],
8213                                [adtens4_val], Reshape)
8214
8215        self._compile_and_check([adtens4],
8216                                [Reshape(ndim)(adtens4, [1, 3, 10, 4])],
8217                                [adtens4_val], Reshape)
8218
8219        # enable when infer_shape is generalized:
8220        # self._compile_and_check([adtens4, aivec],
8221        #                        [Reshape(ndim)(adtens4, aivec)],
8222        #                        [adtens4_val, [1, -1, 10, 4]], Reshape)
8223        #
8224        # self._compile_and_check([adtens4, aivec],
8225        #                        [Reshape(ndim)(adtens4, aivec)],
8226        #                        [adtens4_val, [1, 3, 10, 4]], Reshape)
8227
8228        # Tile op is deprecated so the tile function doesn't use it
8229        # anymore, we'll test here the op directly
8230        advec = dvector()
8231        advec_val = rand(5)
8232        aivec_val = [3]
8233        ndim = 1
8234        self._compile_and_check([advec],
8235                                [Tile(ndim)(advec, aivec_val)],
8236                                [advec_val], Tile)
8237
8238        admat = dmatrix()
8239        admat_val = rand(2, 4)
8240        aivec_val = [2, 3]
8241        ndim = 2
8242        self._compile_and_check([admat],
8243                                [Tile(ndim)(admat, aivec_val)],
8244                                [admat_val], Tile)
8245
8246        adtens4 = dtensor4()
8247        adtens4_val = rand(2, 4, 3, 5)
8248        aivec_val = [2, 3, 1, 4]
8249        ndim = 4
8250        self._compile_and_check([adtens4],
8251                                [Tile(ndim)(adtens4, aivec_val)],
8252                                [adtens4_val], Tile)
8253
8254
8255class TestTensorInstanceMethods(unittest.TestCase):
8256    def setUp(self):
8257        self.vars = matrices('X', 'Y')
8258        self.vals = [m.astype(floatX) for m in [rand(2, 2), rand(2, 2)]]
8259
8260    def test_argmin(self):
8261        X, _ = self.vars
8262        x, _ = self.vals
8263        assert_array_equal(X.argmin().eval({X: x}), x.argmin())
8264
8265    def test_argmax(self):
8266        X, _ = self.vars
8267        x, _ = self.vals
8268        assert_array_equal(X.argmax().eval({X: x}), x.argmax())
8269
8270    def test_argsort(self):
8271        X, _ = self.vars
8272        x, _ = self.vals
8273        assert_array_equal(X.argsort().eval({X: x}), x.argsort())
8274        assert_array_equal(X.argsort(1).eval({X: x}), x.argsort(1))
8275
8276    def test_clip(self):
8277        X, Y = self.vars
8278        x, y = self.vals
8279        # np.clip gives unexpected values when min > max,
8280        # so we have to make sure that min <= max in that test,
8281        # otherwise it randomly fails.
8282        Z = X.clip(Y - 0.5, Y + 0.5)
8283        z = x.clip(y - 0.5, y + 0.5)
8284        assert_array_equal(Z.eval({X: x, Y: y}), z)
8285
8286    def test_dot(self):
8287        X, Y = self.vars
8288        x, y = self.vals
8289        # Use allclose comparison as a user reported on the mailing
8290        # list failure otherwise with array that print exactly the same.
8291        assert_allclose(x.dot(y), X.dot(Y).eval({X: x, Y: y}))
8292        Z = X.dot(Y)
8293        z = x.dot(y)
8294        assert_allclose(x.dot(z), X.dot(Z).eval({X: x, Z: z}))
8295
8296    def test_real_imag(self):
8297        X, Y = self.vars
8298        x, y = self.vals
8299        Z = X + Y * 1j
8300        z = x + y * 1j
8301        assert_array_equal(Z.real.eval({Z: z}), x)
8302        assert_array_equal(Z.imag.eval({Z: z}), y)
8303
8304    def test_conj(self):
8305        X, Y = self.vars
8306        x, y = self.vals
8307        Z = X + Y * 1j
8308        z = x + y * 1j
8309        assert_array_equal(Z.conj().eval({Z: z}), z.conj())
8310        assert_array_equal(Z.conjugate().eval({Z: z}), z.conj())
8311
8312    def test_round(self):
8313        X, _ = self.vars
8314        x, _ = self.vals
8315        assert_array_equal(X.round().eval({X: x}), x.round())
8316
8317    def test_std(self):
8318        X, _ = self.vars
8319        x, _ = self.vals
8320        # std() is implemented as theano tree and does not pass its
8321        # args directly to numpy. This sometimes results in small
8322        # difference, so we use allclose test.
8323        assert_allclose(X.std().eval({X: x}), x.std())
8324
8325    def test_repeat(self):
8326        X, _ = self.vars
8327        x, _ = self.vals
8328        assert_array_equal(X.repeat(2).eval({X: x}), x.repeat(2))
8329
8330    def test_trace(self):
8331        X, _ = self.vars
8332        x, _ = self.vals
8333        assert_array_equal(X.trace().eval({X: x}), x.trace())
8334
8335    def test_ravel(self):
8336        X, _ = self.vars
8337        x, _ = self.vals
8338        assert_array_equal(X.ravel().eval({X: x}), x.ravel())
8339
8340    def test_diagonal(self):
8341        X, _ = self.vars
8342        x, _ = self.vals
8343        assert_array_equal(X.diagonal().eval({X: x}), x.diagonal())
8344        assert_array_equal(X.diagonal(1).eval({X: x}), x.diagonal(1))
8345        assert_array_equal(X.diagonal(-1).eval({X: x}), x.diagonal(-1))
8346        for offset, axis1, axis2 in [(1, 0, 1), (-1, 0, 1), (0, 1, 0), (-2, 1, 0)]:
8347            assert_array_equal(X.diagonal(offset, axis1, axis2).eval({X: x}),
8348                               x.diagonal(offset, axis1, axis2))
8349
8350    def test_take(self):
8351        X, _ = self.vars
8352        x, _ = self.vals
8353        indices = [1, 0, 3]
8354        assert_array_equal(X.take(indices).eval({X: x}), x.take(indices))
8355        indices = [1, 0, 1]
8356        assert_array_equal(X.take(indices, 1).eval({X: x}), x.take(indices, 1))
8357        indices = np.array([-10, 5, 12], dtype='int32')
8358        assert_array_equal(X.take(indices, 1, mode='wrap').eval({X: x}),
8359                           x.take(indices, 1, mode='wrap'))
8360        assert_array_equal(X.take(indices, -1, mode='wrap').eval({X: x}),
8361                           x.take(indices, -1, mode='wrap'))
8362        assert_array_equal(X.take(indices, 1, mode='clip').eval({X: x}),
8363                           x.take(indices, 1, mode='clip'))
8364        assert_array_equal(X.take(indices, -1, mode='clip').eval({X: x}),
8365                           x.take(indices, -1, mode='clip'))
8366        # Test error handling
8367        self.assertRaises(IndexError, X.take(indices).eval, {X: x})
8368        self.assertRaises(IndexError, (2 * X.take(indices)).eval, {X: x})
8369        self.assertRaises(TypeError, X.take, [0.0])
8370        indices = [[1, 0, 1], [0, 1, 1]]
8371        assert_array_equal(X.take(indices, 1).eval({X: x}), x.take(indices, 1))
8372        # Test equivalent advanced indexing
8373        assert_array_equal(X[:, indices].eval({X: x}), x[:, indices])
8374
8375    def test_cumsum(self):
8376        X, _ = self.vars
8377        x, _ = self.vals
8378        assert_array_equal(X.cumsum().eval({X: x}), x.cumsum())
8379
8380    def test_cumprod(self):
8381        X, _ = self.vars
8382        x, _ = self.vals
8383        assert_array_equal(X.cumprod().eval({X: x}), x.cumprod())
8384
8385
8386def test_norm():
8387    x = theano.tensor.vector('x')
8388    n = x.norm(2)
8389    f = theano.function([x], n)
8390    assert np.allclose(f([1, 1]), np.sqrt(2))
8391
8392
8393class test_cov(unittest.TestCase):
8394
8395    def test_core(self):
8396        x = theano.tensor.matrix('x')
8397        c = theano.tensor.cov(x)
8398        f = theano.function([x], c)
8399
8400        # basic cov function
8401        data = np.asarray(np.random.rand(3, 5), dtype=config.floatX)
8402        assert np.allclose(f(data), np.cov(data))
8403
8404        data = np.asarray(np.random.rand(5, 3), dtype=config.floatX)
8405        assert np.allclose(f(data), np.cov(data))
8406
8407        data = np.asarray(np.random.rand(10, 10), dtype=config.floatX)
8408        assert np.allclose(f(data), np.cov(data))
8409
8410        data = np.asarray(np.random.rand(2, 2), dtype=config.floatX)
8411        assert np.allclose(f(data), np.cov(data))
8412
8413        data = np.asarray(np.random.rand(1, 2), dtype=config.floatX)
8414        assert np.allclose(f(data), np.cov(data))
8415
8416    def test_rowvar(self):
8417        for rowvar in [True, False]:
8418            x = theano.tensor.matrix('x')
8419            c = theano.tensor.cov(x, rowvar=rowvar)
8420            f = theano.function([x], c)
8421
8422            data = np.asarray(np.random.rand(3, 5), dtype=config.floatX)
8423            assert np.allclose(f(data), np.cov(data, rowvar=rowvar))
8424
8425            data = np.asarray(np.random.rand(5, 3), dtype=config.floatX)
8426            assert np.allclose(f(data), np.cov(data, rowvar=rowvar))
8427
8428            data = np.asarray(np.random.rand(10, 10), dtype=config.floatX)
8429            assert np.allclose(f(data), np.cov(data, rowvar=rowvar))
8430
8431            data = np.asarray(np.random.rand(2, 2), dtype=config.floatX)
8432            assert np.allclose(f(data), np.cov(data, rowvar=rowvar))
8433
8434        # check when variables are along the first axis
8435        x = theano.tensor.matrix('x')
8436        c = theano.tensor.cov(x, rowvar=False)
8437        f = theano.function([x], c)
8438        data = np.asarray(np.random.rand(2, 1), dtype=config.floatX)
8439        assert np.allclose(f(data), np.cov(data, rowvar=False))
8440
8441    def test_y(self):
8442        # test y
8443        x = theano.tensor.matrix('x')
8444        y = theano.tensor.matrix('y')
8445        c = theano.tensor.cov(x, y=y)
8446        f = theano.function([x, y], c)
8447
8448        data = np.asarray(np.random.rand(3, 5), dtype=config.floatX)
8449        y = np.asarray(np.random.rand(3, 5), dtype=config.floatX)
8450        assert np.allclose(f(data, y), np.cov(data, y=y))
8451
8452        data = np.asarray(np.random.rand(5, 3), dtype=config.floatX)
8453        y = np.asarray(np.random.rand(5, 3), dtype=config.floatX)
8454        assert np.allclose(f(data, y), np.cov(data, y=y))
8455
8456        data = np.asarray(np.random.rand(10, 10), dtype=config.floatX)
8457        y = np.asarray(np.random.rand(10, 10), dtype=config.floatX)
8458        assert np.allclose(f(data, y), np.cov(data, y=y))
8459
8460        data = np.asarray(np.random.rand(2, 2), dtype=config.floatX)
8461        y = np.asarray(np.random.rand(2, 2), dtype=config.floatX)
8462        assert np.allclose(f(data, y), np.cov(data, y=y))
8463
8464    def test_ddof(self):
8465
8466        for ddof in range(0, 5):
8467            x = theano.tensor.matrix('x')
8468            c = theano.tensor.cov(x, ddof=ddof)
8469            f = theano.function([x], c)
8470
8471            data = np.asarray(np.random.rand(3, 5), dtype=config.floatX)
8472            assert np.allclose(f(data), np.cov(data, ddof=ddof))
8473
8474    def test_bias(self):
8475
8476        for bias in [True, False]:
8477            x = theano.tensor.matrix('x')
8478            c = theano.tensor.cov(x, bias=bias)
8479            f = theano.function([x], c)
8480
8481            data = np.asarray(np.random.rand(3, 5), dtype=config.floatX)
8482            assert np.allclose(f(data), np.cov(data, bias=bias))
8483
8484        for ddof in range(0, 5):
8485            for bias in [True, False]:
8486                x = theano.tensor.matrix('x')
8487                c = theano.tensor.cov(x, ddof=ddof, bias=bias)
8488                f = theano.function([x], c)
8489
8490                data = np.asarray(np.random.rand(3, 5), dtype=config.floatX)
8491                assert np.allclose(f(data), np.cov(data, ddof=ddof, bias=bias))
8492
8493
8494class test_ptp(unittest.TestCase):
8495    def test_scalar(self):
8496        # Should return 0 for all scalar
8497        x = scalar('x')
8498        p = ptp(x)
8499        f = theano.function([x], p)
8500
8501        y = np.asarray(rand() * 2000 - 1000, dtype=config.floatX)
8502        result = f(y)
8503        numpyResult = np.ptp(y)
8504
8505        self.assertTrue(np.array_equal(result, numpyResult))
8506
8507    def test_vector(self):
8508
8509        x = vector('x')
8510        p = ptp(x, 0)
8511        f = theano.function([x], p)
8512
8513        y = rand_ranged(-1000, 1000, [100])
8514        result = f(y)
8515        numpyResult = np.ptp(y, 0)
8516
8517        self.assertTrue(np.array_equal(result, numpyResult))
8518
8519    def test_matrix_first_axis(self):
8520
8521        x = matrix('x')
8522        p = ptp(x, 1)
8523        f = theano.function([x], p)
8524
8525        y = rand_ranged(-1000, 1000, [100, 100])
8526        result = f(y)
8527        numpyResult = np.ptp(y, 1)
8528
8529        self.assertTrue(np.array_equal(result, numpyResult))
8530
8531    def test_matrix_second_axis(self):
8532        x = matrix('x')
8533        p = ptp(x, 0)
8534        f = theano.function([x], p)
8535
8536        y = rand_ranged(-1000, 1000, [100, 100])
8537        result = f(y)
8538        numpyResult = np.ptp(y, 0)
8539
8540        self.assertTrue(np.array_equal(result, numpyResult))
8541
8542    def test_matrix_neg_axis(self):
8543        x = matrix('x')
8544        p = ptp(x, -1)
8545        f = theano.function([x], p)
8546
8547        y = rand_ranged(-1000, 1000, [100, 100])
8548        result = f(y)
8549        numpyResult = np.ptp(y, -1)
8550
8551        self.assertTrue(np.array_equal(result, numpyResult))
8552
8553    def test_matrix_no_axis(self):
8554        x = matrix('x')
8555        p = ptp(x)
8556        f = theano.function([x], p)
8557
8558        y = rand_ranged(-1000, 1000, [100, 100])
8559        result = f(y)
8560        numpyResult = np.ptp(y)
8561
8562        self.assertTrue(np.array_equal(result, numpyResult))
8563
8564    def test_interface(self):
8565        x = matrix('x')
8566        p = x.ptp(1)
8567        f = theano.function([x], p)
8568
8569        y = rand_ranged(-1000, 1000, [100, 100])
8570        result = f(y)
8571        numpyResult = np.ptp(y, 1)
8572
8573        self.assertTrue(np.array_equal(result, numpyResult))
8574
8575if __name__ == '__main__':
8576
8577    t = TestInferShape('setUp')
8578    t.setUp()
8579    t.test_infer_shape()
8580
8581
8582class T_swapaxes(unittest.TestCase):
8583
8584    def test_no_dimensional_input(self):
8585        self.assertRaises(IndexError, swapaxes, 2, 0, 1)
8586
8587    def test_unidimensional_input(self):
8588        self.assertRaises(IndexError, swapaxes, [2, 1], 0, 1)
8589
8590    def test_not_enough_dimension(self):
8591        self.assertRaises(IndexError, swapaxes, [[2, 1], [3, 4]], 3, 4)
8592
8593    def test_doubleswap(self):
8594        y = matrix()
8595        n = swapaxes(y, 0, 1)
8596        f = function([y], n)
8597        testMatrix = [[2, 1], [3, 4]]
8598        self.assertTrue(np.array_equal(testMatrix, f(f(testMatrix))))
8599
8600    def test_interface(self):
8601        x = theano.tensor.matrix()
8602        x.swapaxes(0, 1)
8603
8604    def test_numpy_compare(self):
8605        rng = np.random.RandomState(utt.fetch_seed())
8606        A = tensor.matrix("A", dtype=theano.config.floatX)
8607        Q = swapaxes(A, 0, 1)
8608        fn = function([A], [Q])
8609        a = rng.rand(4, 4).astype(theano.config.floatX)
8610
8611        n_s = np.swapaxes(a, 0, 1)
8612        t_s = fn(a)
8613        assert np.allclose(n_s, t_s)
8614
8615
8616class T_Power(unittest.TestCase):
8617    def test_numpy_compare(self):
8618        rng = np.random.RandomState(utt.fetch_seed())
8619        A = tensor.matrix("A", dtype=theano.config.floatX)
8620        Q = power(A, 3)
8621        fn = function([A], [Q])
8622        a = rng.rand(4, 4).astype(theano.config.floatX)
8623
8624        n_p = np.power(a, 3)
8625        t_p = fn(a)
8626        assert np.allclose(n_p, t_p)
8627
8628    def test_multiple_power(self):
8629        x = tensor.vector()
8630        y = [1, 2, 3]
8631        z = power(x, y)
8632        f = function([x], z)
8633        assert np.allclose(f([1, 2, 3]), [1, 4, 27])
8634
8635    def test_wrong_shape(self):
8636        x = tensor.vector()
8637        y = [1, 2, 3]
8638        z = power(x, y)
8639        f = function([x], z)
8640        self.assertRaises(ValueError, f, [1, 2, 3, 4])
8641
8642
8643class T_Choose(utt.InferShapeTester):
8644    op = staticmethod(choose)
8645    op_class = Choose
8646    modes = ['raise', 'wrap', 'clip']
8647
8648    def test_numpy_compare(self):
8649
8650        a = tensor.vector(dtype='int32')
8651        b = tensor.matrix(dtype='float32')
8652
8653        A = np.random.randint(0, 4, 4).astype('int32')
8654        B = np.asarray(np.random.rand(4, 4), dtype='float32')
8655
8656        for m in self.modes:
8657            f = function([a, b], choose(a, b, mode=m))
8658            t_c = f(A, B)
8659            n_c = np.choose(A, B, mode=m)
8660            assert np.allclose(t_c, n_c)
8661
8662    def test_method(self):
8663        a = tensor.vector(dtype='int32')
8664        b = tensor.matrix(dtype='float32')
8665
8666        A = np.random.randint(0, 4, 4).astype('int32')
8667        B = np.asarray(np.random.rand(4, 4), dtype='float32')
8668
8669        for m in self.modes:
8670            f = function([a, b], a.choose(b, mode=m))
8671            t_c = f(A, B)
8672            n_c = A.choose(B, mode=m)
8673            assert np.allclose(t_c, n_c)
8674
8675    def test_broadcasted(self):
8676        a = tensor.scalar(dtype='int32')
8677        b = tensor.matrix(dtype='float32')
8678
8679        # Test when a is broadcastable
8680        A = 3
8681        B = np.asarray(np.random.rand(4, 4), dtype='float32')
8682
8683        for m in self.modes:
8684            f = function([a, b], choose(a, b, mode=m))
8685            t_c = f(A, B)
8686            n_c = np.choose(A, B, mode=m)
8687            assert np.allclose(t_c, n_c)
8688
8689        # Test when the result should be broadcastable
8690        b = theano.tensor.col(dtype='float32')
8691        B = np.asarray(np.random.rand(4, 1), dtype='float32')
8692        for m in self.modes:
8693            f = function([a, b], choose(a, b, mode=m))
8694            assert choose(a, b, mode=m).broadcastable[0]
8695            t_c = f(A, B)
8696            n_c = np.choose(A, B, mode=m)
8697            assert np.allclose(t_c, n_c)
8698
8699    def test_dtype_error(self):
8700        a = tensor.scalar(dtype='float32')
8701        b = tensor.matrix(dtype='float32')
8702
8703        self.assertRaises(TypeError, choose, a, b)
8704
8705    def test_numpy_compare_tuple(self):
8706
8707        a = tensor.tensor3(dtype='int32')
8708        b = tensor.tensor3(dtype='float32')
8709        c = tensor.tensor3(dtype='float32')
8710
8711        A = np.random.randint(0, 2, (2, 1, 1)).astype('int32')
8712        B = np.asarray(np.random.rand(1, 6, 1), dtype='float32')
8713        C = np.asarray(np.random.rand(1, 1, 5), dtype='float32')
8714
8715        for m in self.modes:
8716            f = function([a, b, c], choose(a, (b, c), mode=m))
8717            t_c = f(A, B, C)
8718            n_c = np.choose(A, (B, C), mode=m)
8719            assert np.allclose(t_c, n_c)
8720
8721    def test_infer_shape(self):
8722        for shp1, shp2 in [
8723            ((5, 4), (7, 4)),
8724            ((1, 4), (7, 4)),
8725            ((5, 1), (7, 4)),
8726            ((5, 4), (1, 4)),
8727            ((5, 4), (7, 1)),
8728
8729            ((5, 4), (4,)),
8730            ((1, 4), (4,)),
8731            ((5, 1), (4,)),
8732            ((5, 4), (1,)),
8733
8734            ((4,), (5, 4)),
8735            ((1,), (5, 4)),
8736            ((4,), (1, 4)),
8737            ((4,), (3, 1)),
8738
8739            ((4,), (4,)),
8740            ((1,), (4,)),
8741            ((4,), (1,)),
8742            ((1,), (1,)),
8743        ]:
8744            a = tensor.tensor(dtype='int32',
8745                              broadcastable=[n == 1 for n in shp1])
8746            c = tensor.tensor(dtype='float32',
8747                              broadcastable=[n == 1 for n in shp2])
8748            A = np.asarray(np.random.rand(*shp1) * shp2[0], dtype='int32')
8749            C = np.asarray(np.random.rand(*shp2) * shp2[0], dtype='float32')
8750            self._compile_and_check([a, c],  # theano.function inputs
8751                                    [self.op(a, c)],  # theano.function outputs
8752                                    # Always use not square matrix!
8753                                    # inputs data
8754                                    [A, C],
8755                                    # Op that should be removed from the graph.
8756                                    self.op_class)
8757
8758# Disabled as it isn't implemented.
8759    def ___test_infer_shape_tuple(self):
8760
8761        a = tensor.tensor3(dtype='int32')
8762        b = tensor.tensor3(dtype='int32')
8763        c = tensor.tensor3(dtype='int32')
8764
8765        A = np.asarray([1, 0], dtype='int32').reshape((2, 1, 1))
8766        B = np.asarray(np.random.rand(1, 4, 1), dtype='int32')
8767        C = np.asarray(np.random.rand(1, 1, 7), dtype='int32')
8768
8769        f = function([a, b, c], choose(a, (b, c)))
8770        shape = (2, 4, 7)
8771        assert np.allclose(f(A, B, C).shape, shape)
8772
8773        self._compile_and_check([a, b, c],  # theano.function inputs
8774                                [self.op(a, (b, c))],  # theano.function outputs
8775                                # Always use not square matrix!
8776                                # inputs data
8777                                [A, B, C],
8778                                # Op that should be removed from the graph.
8779                                self.op_class)
8780
8781
8782def test_allocempty():
8783    # Test that we allocated correctly
8784    f = theano.function([], AllocEmpty("float32")(2, 3))
8785    assert len(f.maker.fgraph.apply_nodes) == 1
8786    out = f()
8787
8788    assert out.shape == (2, 3)
8789    assert out.dtype == 'float32'
8790
8791
8792def test_symbolic_slice():
8793    x = theano.tensor.tensor4('x')
8794    a, b = x.shape[:2]
8795    output = a.eval({x: np.zeros((5, 4, 3, 2), dtype=theano.config.floatX)})
8796    assert output == np.array(5)
8797