diff --git a/python-theano-blas.patch b/python-theano-blas.patch index 034d519..e298ee1 100644 --- a/python-theano-blas.patch +++ b/python-theano-blas.patch @@ -1,5 +1,5 @@ ---- theano/configdefaults.py.orig 2018-05-23 08:05:50.000000000 -0600 -+++ theano/configdefaults.py 2018-05-23 20:20:54.280886303 -0600 +--- theano/configdefaults.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/configdefaults.py 2019-08-23 08:49:26.259908947 -0600 @@ -1274,221 +1274,8 @@ sure you have the right version you *wil diff --git a/python-theano-doc.patch b/python-theano-doc.patch new file mode 100644 index 0000000..2899ccc --- /dev/null +++ b/python-theano-doc.patch @@ -0,0 +1,321 @@ +--- theano/compile/builders.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/compile/builders.py 2019-08-22 13:25:53.896813593 -0600 +@@ -15,7 +15,7 @@ from theano.gradient import Disconnected + + + class OpFromGraph(gof.Op): +- """ ++ r""" + This creates an ``Op`` from inputs and outputs lists of variables. + The signature is similar to :func:`theano.function ` + and the resulting ``Op``'s perform will do the same operation as:: +--- theano/compile/function.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/compile/function.py 2019-08-22 13:33:40.346557969 -0600 +@@ -243,7 +243,7 @@ def function(inputs, outputs=None, mode= + + if name is None: + # Determine possible file names +- source_file = re.sub('\.pyc?', '.py', __file__) ++ source_file = re.sub(r'\.pyc?', '.py', __file__) + compiled_file = source_file + 'c' + + stack = tb.extract_stack() +--- theano/configdefaults.py.orig 2019-08-23 08:49:26.259908947 -0600 ++++ theano/configdefaults.py 2019-08-23 08:50:57.173227993 -0600 +@@ -1614,7 +1614,7 @@ AddConfigVar("compiledir_format", + + def default_compiledirname(): + formatted = theano.config.compiledir_format % compiledir_format_dict +- safe = re.sub("[\(\)\s,]+", "_", formatted) ++ safe = re.sub(r"[\(\)\s,]+", "_", formatted) + return safe + + +--- theano/gof/op.py.orig 2019-08-22 16:26:01.760679539 -0600 ++++ theano/gof/op.py 2019-08-23 10:23:51.024394207 -0600 +@@ -280,13 +280,13 @@ class CLinkerOp(CLinkerObject): + string is the name of a C variable pointing to that input. + The type of the variable depends on the declared type of + the input. There is a corresponding python variable that +- can be accessed by prepending "py_" to the name in the ++ can be accessed by prepending ```"py_"``` to the name in the + list. + outputs : list of strings + Each string is the name of a C variable where the Op should + store its output. The type depends on the declared type of + the output. There is a corresponding python variable that +- can be accessed by prepending "py_" to the name in the ++ can be accessed by prepending ```"py_"``` to the name in the + list. In some cases the outputs will be preallocated and + the value of the variable may be pre-filled. The value for + an unallocated output is type-dependent. +@@ -343,13 +343,13 @@ class CLinkerOp(CLinkerObject): + string is the name of a C variable pointing to that input. + The type of the variable depends on the declared type of + the input. There is a corresponding python variable that +- can be accessed by prepending "py_" to the name in the ++ can be accessed by prepending ```"py_"``` to the name in the + list. + outputs : list of strings + Each string is the name of a C variable correspoinding to + one of the outputs of the Op. The type depends on the + declared type of the output. There is a corresponding +- python variable that can be accessed by prepending "py_" to ++ python variable that can be accessed by prepending ```"py_"``` to + the name in the list. + sub : dict of strings + extra symbols defined in `CLinker` sub symbols (such as 'fail'). +@@ -784,7 +784,7 @@ class PureOp(object): + folded when all its inputs are constant. This allows it to + choose where it puts its memory/speed trade-off. Also, it + could make things faster as constants can't be used for inplace +- operations (see *IncSubtensor). ++ operations (see *IncSubtensor*). + + """ + return True +--- theano/gof/opt.py.orig 2019-08-22 14:06:43.820896086 -0600 ++++ theano/gof/opt.py 2019-08-23 08:50:57.175227956 -0600 +@@ -112,9 +112,9 @@ class Optimizer(object): + + Add features to the fgraph that are required to apply the optimization. + For example: +- fgraph.attach_feature(History()) +- fgraph.attach_feature(MyFeature()) +- etc. ++ fgraph.attach_feature(History()) ++ fgraph.attach_feature(MyFeature()) ++ etc. + + """ + pass +--- theano/gof/unify.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/gof/unify.py 2019-08-22 13:24:58.420815328 -0600 +@@ -322,7 +322,7 @@ def unify_walk(a, b, U): + + @comm_guard(OrVariable, NotVariable) # noqa + def unify_walk(o, n, U): +- """ ++ r""" + OrV(list1) == NV(list2) == OrV(list1 \ list2) + + """ +--- theano/gof/utils.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/gof/utils.py 2019-08-22 13:22:15.449758115 -0600 +@@ -307,7 +307,7 @@ def uniq(seq): + + + def difference(seq1, seq2): +- """ ++ r""" + Returns all elements in seq1 which are not in seq2: i.e ``seq1\seq2``. + + """ +--- theano/gpuarray/fft.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/gpuarray/fft.py 2019-08-22 13:36:08.241971287 -0600 +@@ -283,7 +283,7 @@ cuirfft_op = CuIRFFTOp() + + + def curfft(inp, norm=None): +- """ ++ r""" + Performs the fast Fourier transform of a real-valued input on the GPU. + + The input must be a real-valued float32 variable of dimensions (m, ..., n). +@@ -317,7 +317,7 @@ def curfft(inp, norm=None): + + + def cuirfft(inp, norm=None, is_odd=False): +- """ ++ r""" + Performs the inverse fast Fourier Transform with real-valued output on the GPU. + + The input is a variable of dimensions (m, ..., n//2+1, 2) with +--- theano/sandbox/linalg/ops.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/sandbox/linalg/ops.py 2019-08-22 13:37:11.588863356 -0600 +@@ -199,7 +199,7 @@ theano.compile.mode.optdb.register('Hint + + + def psd(v): +- """ ++ r""" + Apply a hint that the variable `v` is positive semi-definite, i.e. + it is a symmetric matrix and :math:`x^T A x \ge 0` for any vector x. + +--- theano/sparse/basic.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/sparse/basic.py 2019-08-22 16:27:29.828134864 -0600 +@@ -4219,9 +4219,9 @@ class ConstructSparseFromList(gof.Op): + This create a sparse matrix with the same shape as `x`. Its + values are the rows of `values` moved. Pseudo-code:: + +- output = csc_matrix.zeros_like(x, dtype=values.dtype) +- for in_idx, out_idx in enumerate(ilist): +- output[out_idx] = values[in_idx] ++ output = csc_matrix.zeros_like(x, dtype=values.dtype) ++ for in_idx, out_idx in enumerate(ilist): ++ output[out_idx] = values[in_idx] + + """ + x_ = theano.tensor.as_tensor_variable(x) +--- theano/tensor/fft.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/fft.py 2019-08-22 13:36:23.986695912 -0600 +@@ -117,7 +117,7 @@ irfft_op = IRFFTOp() + + + def rfft(inp, norm=None): +- """ ++ r""" + Performs the fast Fourier transform of a real-valued input. + + The input must be a real-valued variable of dimensions (m, ..., n). +@@ -151,7 +151,7 @@ def rfft(inp, norm=None): + + + def irfft(inp, norm=None, is_odd=False): +- """ ++ r""" + Performs the inverse fast Fourier Transform with real-valued output. + + The input is a variable of dimensions (m, ..., n//2+1, 2) +--- theano/tensor/nlinalg.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/nlinalg.py 2019-08-22 13:34:43.660450608 -0600 +@@ -75,7 +75,7 @@ pinv = MatrixPinv() + + + class MatrixInverse(Op): +- """Computes the inverse of a matrix :math:`A`. ++ r"""Computes the inverse of a matrix :math:`A`. + + Given a square matrix :math:`A`, ``matrix_inverse`` returns a square + matrix :math:`A_{inv}` such that the dot product :math:`A \cdot A_{inv}` +@@ -149,7 +149,7 @@ matrix_inverse = MatrixInverse() + + + def matrix_dot(*args): +- """ Shorthand for product between several dots. ++ r""" Shorthand for product between several dots. + + Given :math:`N` matrices :math:`A_0, A_1, .., A_N`, ``matrix_dot`` will + generate the matrix product between all in the given order, namely +--- theano/tensor/nnet/conv.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/nnet/conv.py 2019-08-22 13:35:27.978675488 -0600 +@@ -157,7 +157,7 @@ def conv2d(input, filters, image_shape=N + + + class ConvOp(OpenMPOp): +- """ ++ r""" + This Op serves a dual purpose: it can implement a vanilla 2D convolution + (as taught in any signal processing class) or implement the + convolutional layers found in Convolutional Neural Networks. +--- theano/tensor/nnet/neighbours.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/nnet/neighbours.py 2019-08-22 13:36:36.213482065 -0600 +@@ -618,7 +618,7 @@ class Images2Neibs(Op): + + + def images2neibs(ten4, neib_shape, neib_step=None, mode='valid'): +- """ ++ r""" + Function :func:`images2neibs ` + allows to apply a sliding window operation to a tensor containing + images or other two-dimensional objects. +--- theano/tensor/nnet/nnet.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/nnet/nnet.py 2019-08-22 13:35:17.270862767 -0600 +@@ -409,7 +409,7 @@ softmax_grad = SoftmaxGrad() + + + class Softmax(gof.Op): +- """ ++ r""" + Softmax activation function + :math:`\\varphi(\\mathbf{x})_j = + \\frac{e^{\mathbf{x}_j}}{\sum_{k=1}^K e^{\mathbf{x}_k}}` +@@ -600,7 +600,7 @@ softmax_op = Softmax() + + + class LogSoftmax(gof.Op): +- """ ++ r""" + LogSoftmax activation function + :math:`\\varphi(\\mathbf{x})_j = + \\e^{(\mathbf{x}_j - log{\sum_{k=1}^K e^{\mathbf{x}_k})}} +@@ -1412,7 +1412,7 @@ crossentropy_categorical_1hot_grad = Cro + + + class CrossentropyCategorical1Hot(gof.Op): +- """ ++ r""" + Compute the cross entropy between a coding distribution and + a true distribution of the form [0, 0, ... 0, 1, 0, ..., 0]. + +@@ -2051,7 +2051,7 @@ def sigmoid_binary_crossentropy(output, + + + def categorical_crossentropy(coding_dist, true_dist): +- """ ++ r""" + Return the cross-entropy between an approximating distribution and a true + distribution. + +--- theano/tensor/opt.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/opt.py 2019-08-22 13:34:16.709921972 -0600 +@@ -4582,7 +4582,7 @@ register_canonicalize(gof.OpRemove(T.ten + + + class Canonizer(gof.LocalOptimizer): +- """ ++ r""" + Simplification tool. The variable is a local_optimizer. It is best used + with a TopoOptimizer in in_to_out order. + +@@ -4650,7 +4650,7 @@ class Canonizer(gof.LocalOptimizer): + return [self.main, self.inverse, self.reciprocal] + + def get_num_denum(self, input): +- """ ++ r""" + This extract two lists, num and denum, such that the input is: + self.inverse(self.main(\*num), self.main(\*denum)). It returns + the two lists in a (num, denum) pair. +@@ -4751,7 +4751,7 @@ class Canonizer(gof.LocalOptimizer): + return num, denum + + def merge_num_denum(self, num, denum): +- """ ++ r""" + Utility function which takes two lists, num and denum, and + returns something which is equivalent to inverse(main(\*num), + main(\*denum)), but depends on the length of num and the length +--- theano/tensor/slinalg.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/slinalg.py 2019-08-22 13:36:53.541179005 -0600 +@@ -266,7 +266,7 @@ class Solve(Op): + return [(rows, cols)] + + def L_op(self, inputs, outputs, output_gradients): +- """ ++ r""" + Reverse-mode gradient updates for matrix solve operation c = A \\\ b. + + Symbolic expression for updates taken from [#]_. +--- theano/tensor/tests/mlp_test.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/tests/mlp_test.py 2019-08-22 16:30:23.307092085 -0600 +@@ -93,7 +93,7 @@ class LogisticRegression(object): + self.params = [self.W] + + def negative_log_likelihood(self, y): +- """Return the mean of the negative log-likelihood of the prediction ++ r"""Return the mean of the negative log-likelihood of the prediction + of this model under a given target distribution. + + .. math:: +--- versioneer.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ versioneer.py 2019-08-22 16:19:43.175333211 -0600 +@@ -418,7 +418,7 @@ def run_command(commands, args, cwd=None + return stdout, p.returncode + + +-LONG_VERSION_PY['git'] = ''' ++LONG_VERSION_PY['git'] = r''' + # This file helps to compute a version number in source trees obtained from + # git-archive tarball (such as those provided by githubs download-from-tag + # feature). Distribution tarballs (built by setup.py sdist) and build diff --git a/python-theano-format.patch b/python-theano-format.patch new file mode 100644 index 0000000..a57c543 --- /dev/null +++ b/python-theano-format.patch @@ -0,0 +1,19 @@ +--- theano/gof/op.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/gof/op.py 2019-08-22 16:26:01.760679539 -0600 +@@ -1540,12 +1540,12 @@ class COp(Op): + undef_macros = [] + + for i, inp in enumerate(inputs): +- define_macros.append("#define INPUT_%d %s" (i, inp)) +- undef_macros.append("#undef INPUT_%d", (i,)) ++ define_macros.append("#define INPUT_%d %s" % (i, inp)) ++ undef_macros.append("#undef INPUT_%d" % (i,)) + + for i, out in enumerate(outputs): +- define_macros.append("#define OUTPUT_%d %s" (i, inp)) +- undef_macros.append("#undef OUTPUT_%d", (i,)) ++ define_macros.append("#define OUTPUT_%d %s" % (i, inp)) ++ undef_macros.append("#undef OUTPUT_%d" % (i,)) + + def c_init_code_struct(self, node, name, sub): + """ diff --git a/python-theano-git.patch b/python-theano-git.patch new file mode 100644 index 0000000..412260c --- /dev/null +++ b/python-theano-git.patch @@ -0,0 +1,14 @@ +--- doc/conf.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ doc/conf.py 2019-08-23 09:29:09.742863974 -0600 +@@ -221,10 +221,7 @@ def linkcode_resolve(domain, info): + filename = 'theano/%s#L%d-L%d' % find_source() + except Exception: + filename = info['module'].replace('.', '/') + '.py' +- import subprocess +- tag = subprocess.Popen(['git', 'rev-parse', 'HEAD'], +- stdout=subprocess.PIPE, +- universal_newlines=True).communicate()[0][:-1] ++ tag = '@@tag@@' + return "https://github.com/Theano/theano/blob/%s/%s" % (tag, filename) + + # Options for LaTeX output diff --git a/python-theano-is.patch b/python-theano-is.patch new file mode 100644 index 0000000..45dfb4f --- /dev/null +++ b/python-theano-is.patch @@ -0,0 +1,66 @@ +--- theano/compile/mode.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/compile/mode.py 2019-08-22 13:25:25.024334947 -0600 +@@ -261,7 +261,7 @@ class Mode(object): + def __init__(self, linker=None, optimizer='default'): + if linker is None: + linker = config.linker +- if optimizer is 'default': ++ if optimizer == 'default': + optimizer = config.optimizer + Mode.__setstate__(self, (linker, optimizer)) + +--- theano/gof/opt.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/gof/opt.py 2019-08-22 14:06:43.820896086 -0600 +@@ -1284,7 +1284,7 @@ def local_optimizer(tracks, inplace=Fals + + """ + if tracks is not None: +- if len(tracks) is 0: ++ if len(tracks) == 0: + raise ValueError("Use None instead of an empty list to apply to all nodes.", f.__module__, f.__name__) + for t in tracks: + if not (isinstance(t, op.Op) or issubclass(t, op.PureOp)): +--- theano/gof/tests/test_link.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/gof/tests/test_link.py 2019-08-22 16:29:02.294513027 -0600 +@@ -113,7 +113,7 @@ class TestPerformLinker(unittest.TestCas + def test_input_output_same(self): + x, y, z = inputs() + fn = perform_linker(FunctionGraph([x], [x])).make_function() +- assert 1.0 is fn(1.0) ++ assert 1.0 == fn(1.0) + + def test_input_dependency0(self): + x, y, z = inputs() +--- theano/tensor/nnet/bn.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/nnet/bn.py 2019-08-22 13:35:49.109305914 -0600 +@@ -642,7 +642,7 @@ class AbstractBatchNormTrainGrad(Op): + # some inputs should be disconnected + results = [g_wrt_x, g_wrt_dy, g_wrt_scale, g_wrt_x_mean, g_wrt_x_invstd, + theano.gradient.DisconnectedType()()] +- return [theano.gradient.DisconnectedType()() if r is 0 else r ++ return [theano.gradient.DisconnectedType()() if r == 0 else r + for r in results] + + def connection_pattern(self, node): +--- theano/tensor/nnet/tests/test_conv.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/nnet/tests/test_conv.py 2019-08-22 16:29:51.149656121 -0600 +@@ -95,7 +95,7 @@ class TestConv2D(utt.InferShapeTester): + # REFERENCE IMPLEMENTATION + s = 1. + orig_image_data = image_data +- if border_mode is not 'full': ++ if border_mode != 'full': + s = -1. + out_shape2d = np.array(N_image_shape[-2:]) +\ + s * np.array(N_filter_shape[-2:]) - s +--- theano/tests/test_determinism.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tests/test_determinism.py 2019-08-22 16:31:03.119393791 -0600 +@@ -57,7 +57,7 @@ def test_determinism_1(): + updates.append((s, val)) + + for var in theano.gof.graph.ancestors(update for _, update in updates): +- if var.name is not None and var.name is not 'b': ++ if var.name is not None and var.name != 'b': + if var.name[0] != 's' or len(var.name) != 2: + var.name = None + diff --git a/python-theano-iterable.patch b/python-theano-iterable.patch new file mode 100644 index 0000000..a41f956 --- /dev/null +++ b/python-theano-iterable.patch @@ -0,0 +1,21 @@ +--- theano/tensor/var.py.orig 2019-01-15 14:13:57.000000000 -0700 ++++ theano/tensor/var.py 2019-08-23 09:34:34.902917174 -0600 +@@ -1,5 +1,8 @@ + from __future__ import absolute_import, print_function, division +-import collections ++try: ++ from collections.abc import Iterable ++except (ImportError, AttributeError): ++ from collections import Iterable + import copy + import traceback as tb + import warnings +@@ -465,7 +468,7 @@ class _tensor_py_operators(object): + (hasattr(args_el, 'dtype') and args_el.dtype == 'bool')): + return True + if (not isinstance(args_el, theano.tensor.Variable) and +- isinstance(args_el, collections.Iterable)): ++ isinstance(args_el, Iterable)): + for el in args_el: + if includes_bool(el): + return True diff --git a/python-theano.spec b/python-theano.spec index 355a74f..8c6830d 100644 --- a/python-theano.spec +++ b/python-theano.spec @@ -2,11 +2,12 @@ %global pkgname Theano %global srcname theano +%global commit 29d4caa168eaa213cb0b29fd2cb2bef8cd99b389 #%%global rctag a1 Name: python-theano Version: 1.0.4 -Release: 3%{?rctag:.%{rctag}}%{?dist} +Release: 4%{?rctag:.%{rctag}}%{?dist} Summary: Mathematical expressions involving multidimensional arrays License: BSD @@ -41,6 +42,19 @@ Patch8: %{name}-random.patch # Tests that used to fail with numpy 1.17.0 with TypeError: only integer scalar # arrays can be converted to a scalar index Patch9: %{name}-sort.patch +# More robustly import Iterable. Upstream commits: +# - https://github.com/Theano/Theano/commit/513c676ae3ddcae6d23a7e62db19884eaa8c1008 +# - https://github.com/Theano/Theano/commit/454f4e56c4a859d2f3b48592c731464bf78df342 +# - https://github.com/Theano/Theano/commit/11bd36d580c6ea2a67f9b2fa1483670f63a6a13b +Patch10: %{name}-iterable.patch +# Do not try to invoke git to find the commit +Patch11: %{name}-git.patch +# Fix some malformed format strings +Patch12: %{name}-format.patch +# Fix some incorrect uses of the 'is' keyword +Patch13: %{name}-is.patch +# Fix documentation bugs resulting in sphinx warnings +Patch14: %{name}-doc.patch BuildArch: noarch @@ -74,7 +88,7 @@ efficiently. Theano features: - tight integration with NumPy: Use numpy.ndarray in Theano-compiled functions. - transparent use of a GPU: Perform data-intensive calculations up to - 140x faster than with CPU.(float32 only) + 140x faster than with CPU (float32 only). - efficient symbolic differentiation: Theano does your derivatives for function with one or many inputs. - speed and stability optimizations: Get the right answer for log(1+x) @@ -129,6 +143,9 @@ for fil in $(grep -FRl /bin/env .); do rm $fil.orig done +# We don't have a git checkout, so don't invoke git to find the commit +sed -i 's/@@tag@@/%{commit}/' doc/conf.py + %build # Regenerate the Cython files, and fix the numpy interfaces cython -3 -o theano/scan_module/c_code/scan_perform.c \ @@ -168,6 +185,9 @@ PYTHONPATH=$PWD %{__python3} bin/theano-nose --processes=0 --process-restartwork %doc html %changelog +* Thu Aug 29 2019 Jerry James - 1.0.4-4 +- Add -iterable, -git, -format, -is, and -doc patches to fix warnings + * Fri Aug 23 2019 Robert-André Mauchin - 1.0.4-3 - Fix FTBFS with python-theano-sort patch (#1737011)