[theano] 03/03: Fix test failures on big-endian systems. (Closes: #878596)
Rebecca Palmer
rnpalmer-guest at moszumanska.debian.org
Sun Oct 15 21:30:27 UTC 2017
This is an automated email from the git hooks/post-receive script.
rnpalmer-guest pushed a commit to branch master
in repository theano.
commit 786f9652ae39b527cfbef10d575abb170bc426c3
Author: Rebecca N. Palmer <rebecca_palmer at zoho.com>
Date: Sun Oct 15 22:30:06 2017 +0100
Fix test failures on big-endian systems. (Closes: #878596)
---
debian/changelog | 1 +
debian/patches/878596.patch | 450 ++++++++++++++++++++++++++++++++++++++++++++
debian/patches/series | 1 +
3 files changed, 452 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 9049817..da913b6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,7 @@
theano (0.9.0+dfsg2-1) UNRELEASED; urgency=medium
* Really remove the pre-minified Javascript.
+ * Fix test failures on big-endian systems. (Closes: #878596)
-- Rebecca N. Palmer <rebecca_palmer at zoho.com> Sun, 15 Oct 2017 21:56:05 +0100
diff --git a/debian/patches/878596.patch b/debian/patches/878596.patch
new file mode 100644
index 0000000..b185517
--- /dev/null
+++ b/debian/patches/878596.patch
@@ -0,0 +1,450 @@
+Description: Fix invalid pointer casts and potential index overflows
+
+ws/stride/pad may be int32 or int64 arrays
+int32 = *(int64*)(int32*) is broken on big-endian systems, and also
+a strict aliasing violation (i.e. technically undefined everywhere)
+int32 = *(int64*)(int64*) may overflow
+
+Author: Rebecca N. Palmer <rebecca_palmer at zoho.com>
+Bug-Debian: https://bugs.debian.org/878596
+Forwarded: no
+
+--- theano-0.9.0+dfsg.orig/theano/tensor/signal/pool.py
++++ theano-0.9.0+dfsg/theano/tensor/signal/pool.py
+@@ -642,18 +642,18 @@ class Pool(OpenMPOp):
+ PyErr_SetString(PyExc_ValueError, "pad must be a vector of size %(nd)s");
+ %(fail)s;
+ }
+- int z[%(nd)s]; // shape of the output
+- int r[%(nd)s]; // shape of the padded_input
+- int ws[%(nd)s];
+- int st[%(nd)s];
+- int pd[%(nd)s];
++ npy_intp z[%(nd)s]; // shape of the output
++ npy_intp r[%(nd)s]; // shape of the padded_input
++ npy_intp ws[%(nd)s];
++ npy_intp st[%(nd)s];
++ npy_intp pd[%(nd)s];
+ int nonzero_padding;
+ nonzero_padding = 0;
+ for (int i=0; i<%(nd)s; i++)
+ {
+- ws[i] = *((npy_intp*)PyArray_GETPTR1(%(ws)s, i));
+- st[i] = *((npy_intp*)PyArray_GETPTR1(%(stride)s, i));
+- pd[i] = *((npy_intp*)PyArray_GETPTR1(%(pad)s, i));
++ ws[i] = *((dtype_%(ws)s*)PyArray_GETPTR1(%(ws)s, i));
++ st[i] = *((dtype_%(stride)s*)PyArray_GETPTR1(%(stride)s, i));
++ pd[i] = *((dtype_%(pad)s*)PyArray_GETPTR1(%(pad)s, i));
+ r[i] = PyArray_DIMS(%(x)s)[%(non_pool_ndim)s + i] + 2 * pd[i];
+ if (pd[i]>0)
+ nonzero_padding = 1;
+@@ -690,7 +690,7 @@ class Pool(OpenMPOp):
+ }
+ else
+ {
+- z[i] = std::max(0, (r[i] - 1 - ws[i] + st[i]) / st[i]) + 1;
++ z[i] = std::max((npy_intp)0, (r[i] - 1 - ws[i] + st[i]) / st[i]) + 1;
+ }
+ assert(z[i] > 0);
+ }
+@@ -741,7 +741,7 @@ class Pool(OpenMPOp):
+ }
+ // initialize temp var for the value in a region
+ dtype_%(x)s collector;
+- int z_prod;
++ npy_intp z_prod;
+ // do not run if any z[i] is zero
+ z_prod = 1;
+ for (int i=0; i<%(nd)s; i++)
+@@ -751,23 +751,23 @@ class Pool(OpenMPOp):
+ if (z_prod)
+ {
+ // will be used to hold start and end index of a region
+- int r_st[%(nd)s];
+- int r_end[%(nd)s];
++ npy_intp r_st[%(nd)s];
++ npy_intp r_end[%(nd)s];
+ // index for iterating over the pooling regions
+- int r_idx[%(nd)s];
++ npy_intp r_idx[%(nd)s];
+ // placeholder for PyArray indexing (output)
+ npy_intp o_idx[%(total_ndim)s];
+ // placeholder for PyArray indexing (input)
+ npy_intp i_idx[%(total_ndim)s];
+ // loop over non-pooling dimensions
+- int non_pooling_prod = 1;
++ npy_intp non_pooling_prod = 1;
+ for (int i=0; i<%(non_pool_ndim)s; i++)
+ {
+ non_pooling_prod *= PyArray_DIMS(%(x)s)[i];
+ }
+ %(omp_parallel)s
+ // first loop over non-pooling dimensions
+- for (int t=0; t<non_pooling_prod; t++)
++ for (npy_intp t=0; t<non_pooling_prod; t++)
+ {
+ // compute the non-pooling index in each dimension
+ if (%(non_pool_ndim)s!=0)
+@@ -831,7 +831,7 @@ class Pool(OpenMPOp):
+ for i in xrange(nd):
+ ccode += """
+ // go through the pooled region in the unpadded input
+- for(int m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
++ for(npy_intp m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
+ {
+ i_idx[%(non_pool_ndim)s + %(i)s] = m%(i)s;
+ """ % dict(i=i, non_pool_ndim=non_pool_ndim)
+@@ -859,7 +859,7 @@ class Pool(OpenMPOp):
+ for i in xrange(nd):
+ ccode += """
+ // go through the pooled region in the unpadded input
+- for(int m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
++ for(npy_intp m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
+ {
+ i_idx[%(non_pool_ndim)s + %(i)s] = m%(i)s;
+ """ % dict(i=i, non_pool_ndim=non_pool_ndim)
+@@ -904,7 +904,7 @@ class Pool(OpenMPOp):
+ return ccode % locals()
+
+ def c_code_cache_version(self):
+- return (0, 6, 8, 7, self.openmp)
++ return (0, 6, 8, 7, self.openmp, 0xdeb1a)
+
+
+ class PoolGrad(OpenMPOp):
+@@ -1232,18 +1232,18 @@ class MaxPoolGrad(PoolGrad):
+ PyErr_SetString(PyExc_ValueError, "pad must be a vector of size %(nd)s");
+ %(fail)s;
+ }
+- int z[%(nd)s]; // shape of the output
+- int r[%(nd)s]; // shape of the padded_input
+- int ws[%(nd)s];
+- int st[%(nd)s];
+- int pd[%(nd)s];
++ npy_intp z[%(nd)s]; // shape of the output
++ npy_intp r[%(nd)s]; // shape of the padded_input
++ npy_intp ws[%(nd)s];
++ npy_intp st[%(nd)s];
++ npy_intp pd[%(nd)s];
+ int nonzero_padding;
+ nonzero_padding = 0;
+ for (int i=0; i<%(nd)s; i++)
+ {
+- ws[i] = *((npy_intp*)PyArray_GETPTR1(%(ws)s, i));
+- st[i] = *((npy_intp*)PyArray_GETPTR1(%(stride)s, i));
+- pd[i] = *((npy_intp*)PyArray_GETPTR1(%(pad)s, i));
++ ws[i] = *((dtype_%(ws)s*)PyArray_GETPTR1(%(ws)s, i));
++ st[i] = *((dtype_%(stride)s*)PyArray_GETPTR1(%(stride)s, i));
++ pd[i] = *((dtype_%(pad)s*)PyArray_GETPTR1(%(pad)s, i));
+ z[i] = PyArray_DIMS(%(z)s)[%(non_pool_ndim)s + i];
+ r[i] = PyArray_DIMS(%(x)s)[%(non_pool_ndim)s + i] + 2 * pd[i];
+ if (pd[i]>0)
+@@ -1277,7 +1277,7 @@ class MaxPoolGrad(PoolGrad):
+ PyArray_FILLWBYTE(%(gx)s, 0);
+ }
+ dtype_%(z)s maximum; // temp var for maximum value in a region
+- int z_prod;
++ npy_intp z_prod;
+ // do not run if any z[i] is zero
+ z_prod = 1;
+ for (int i=0; i<%(nd)s; i++)
+@@ -1287,23 +1287,23 @@ class MaxPoolGrad(PoolGrad):
+ if (z_prod)
+ {
+ // will be used to hold start and end index of a region
+- int r_st[%(nd)s];
+- int r_end[%(nd)s];
++ npy_intp r_st[%(nd)s];
++ npy_intp r_end[%(nd)s];
+ // index for iterating over the pooling regions
+- int r_idx[%(nd)s];
++ npy_intp r_idx[%(nd)s];
+ // placeholder for PyArray indexing (output)
+ npy_intp o_idx[%(total_ndim)s];
+ // placeholder for PyArray indexing (input)
+ npy_intp i_idx[%(total_ndim)s];
+ // loop over non-pooling dimensions
+- int non_pooling_prod = 1;
++ npy_intp non_pooling_prod = 1;
+ for (int i=0; i<%(non_pool_ndim)s; i++)
+ {
+ non_pooling_prod *= PyArray_DIMS(%(x)s)[i];
+ }
+ %(omp_parallel)s
+ // first loop over non-pooling dimensions
+- for (int t=0; t<non_pooling_prod; t++)
++ for (npy_intp t=0; t<non_pooling_prod; t++)
+ {
+ // compute the non-pooling index in each dimension
+ if (%(non_pool_ndim)s!=0)
+@@ -1357,7 +1357,7 @@ class MaxPoolGrad(PoolGrad):
+ for i in xrange(nd):
+ ccode += """
+ // go through the pooled region in the unpadded input
+- for(int m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
++ for(npy_intp m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
+ {
+ i_idx[%(non_pool_ndim)s + %(i)s] = m%(i)s;
+ """ % dict(i=i, non_pool_ndim=non_pool_ndim)
+@@ -1394,7 +1394,7 @@ class MaxPoolGrad(PoolGrad):
+ return ccode % locals()
+
+ def c_code_cache_version(self):
+- return (0, 10, self.openmp)
++ return (0, 10, self.openmp, 0xdeb1a)
+
+
+ class AveragePoolGrad(PoolGrad):
+@@ -1552,18 +1552,18 @@ class AveragePoolGrad(PoolGrad):
+ PyErr_SetString(PyExc_ValueError, "pad must be a vector of size %(nd)s");
+ %(fail)s;
+ }
+- int z[%(nd)s]; // shape of the output
+- int r[%(nd)s]; // shape of the padded_input
+- int ws[%(nd)s];
+- int st[%(nd)s];
+- int pd[%(nd)s];
++ npy_intp z[%(nd)s]; // shape of the output
++ npy_intp r[%(nd)s]; // shape of the padded_input
++ npy_intp ws[%(nd)s];
++ npy_intp st[%(nd)s];
++ npy_intp pd[%(nd)s];
+ int nonzero_padding;
+ nonzero_padding = 0;
+ for (int i=0; i<%(nd)s; i++)
+ {
+- ws[i] = *((npy_intp*)PyArray_GETPTR1(%(ws)s, i));
+- st[i] = *((npy_intp*)PyArray_GETPTR1(%(stride)s, i));
+- pd[i] = *((npy_intp*)PyArray_GETPTR1(%(pad)s, i));
++ ws[i] = *((dtype_%(ws)s*)PyArray_GETPTR1(%(ws)s, i));
++ st[i] = *((dtype_%(stride)s*)PyArray_GETPTR1(%(stride)s, i));
++ pd[i] = *((dtype_%(pad)s*)PyArray_GETPTR1(%(pad)s, i));
+ z[i] = PyArray_DIMS(%(gz)s)[%(non_pool_ndim)s + i];
+ r[i] = PyArray_DIMS(%(x)s)[%(non_pool_ndim)s + i] + 2 * pd[i];
+ if (pd[i]>0)
+@@ -1602,7 +1602,7 @@ class AveragePoolGrad(PoolGrad):
+ else {
+ PyArray_FILLWBYTE(%(gx)s, 0);
+ }
+- int z_prod;
++ npy_intp z_prod;
+ // do not run if any z[i] is zero
+ z_prod = 1;
+ for (int i=0; i<%(nd)s; i++)
+@@ -1612,25 +1612,25 @@ class AveragePoolGrad(PoolGrad):
+ if (z_prod)
+ {
+ // will be used to hold start and end index of a region
+- int r_st[%(nd)s];
+- int r_end[%(nd)s];
++ npy_intp r_st[%(nd)s];
++ npy_intp r_end[%(nd)s];
+ // padded region size
+- int r_pad_width[%(nd)s];
++ npy_intp r_pad_width[%(nd)s];
+ // index for iterating over the pooling regions
+- int r_idx[%(nd)s];
++ npy_intp r_idx[%(nd)s];
+ // placeholder for PyArray indexing (output)
+ npy_intp o_idx[%(total_ndim)s];
+ // placeholder for PyArray indexing (input)
+ npy_intp i_idx[%(total_ndim)s];
+ // loop over non-pooling dimensions
+- int non_pooling_prod = 1;
++ npy_intp non_pooling_prod = 1;
+ for (int i=0; i<%(non_pool_ndim)s; i++)
+ {
+ non_pooling_prod *= PyArray_DIMS(%(x)s)[i];
+ }
+ %(omp_parallel)s
+ // first loop over non-pooling dimensions
+- for (int t=0; t<non_pooling_prod; t++)
++ for (npy_intp t=0; t<non_pooling_prod; t++)
+ {
+ // compute the non-pooling index in each dimension
+ if (%(non_pool_ndim)s!=0)
+@@ -1695,7 +1695,7 @@ class AveragePoolGrad(PoolGrad):
+ for i in xrange(nd):
+ ccode += """
+ // go through the pooled region in the unpadded input
+- for(int m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
++ for(npy_intp m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
+ {
+ i_idx[%(non_pool_ndim)s + %(i)s] = m%(i)s;
+ """ % dict(i=i, non_pool_ndim=non_pool_ndim)
+@@ -1727,7 +1727,7 @@ class AveragePoolGrad(PoolGrad):
+ return ccode % locals()
+
+ def c_code_cache_version(self):
+- return (0, 3, self.openmp)
++ return (0, 3, self.openmp, 0xdeb1a)
+
+
+ class DownsampleFactorMaxGradGrad(OpenMPOp):
+@@ -1861,11 +1861,11 @@ class DownsampleFactorMaxGradGrad(OpenMP
+ omp_parallel = ''
+ ccode = """
+ int z_typenum = PyArray_ObjectType((PyObject*)%(maxout)s, 0);
+- int z[%(nd)s]; // shape of the output
+- int r[%(nd)s]; // shape of the padded_input
+- int ws[%(nd)s];
+- int st[%(nd)s];
+- int pd[%(nd)s];
++ npy_intp z[%(nd)s]; // shape of the output
++ npy_intp r[%(nd)s]; // shape of the padded_input
++ npy_intp ws[%(nd)s];
++ npy_intp st[%(nd)s];
++ npy_intp pd[%(nd)s];
+ if(PyArray_DIM(%(ws)s, 0)!=%(nd)s)
+ {
+ PyErr_SetString(PyExc_ValueError, "ws must be a vector of size %(nd)s");
+@@ -1883,9 +1883,9 @@ class DownsampleFactorMaxGradGrad(OpenMP
+ }
+ for (int i=0; i<%(nd)s; i++)
+ {
+- ws[i] = *((npy_intp*)PyArray_GETPTR1(%(ws)s, i));
+- st[i] = *((npy_intp*)PyArray_GETPTR1(%(stride)s, i));
+- pd[i] = *((npy_intp*)PyArray_GETPTR1(%(pad)s, i));
++ ws[i] = *((dtype_%(ws)s*)PyArray_GETPTR1(%(ws)s, i));
++ st[i] = *((dtype_%(stride)s*)PyArray_GETPTR1(%(stride)s, i));
++ pd[i] = *((dtype_%(pad)s*)PyArray_GETPTR1(%(pad)s, i));
+ z[i] = PyArray_DIMS(%(maxout)s)[%(non_pool_ndim)s + i];
+ r[i] = PyArray_DIMS(%(x)s)[%(non_pool_ndim)s + i] + 2 * pd[i];
+ }
+@@ -1918,16 +1918,16 @@ class DownsampleFactorMaxGradGrad(OpenMP
+ }
+ dtype_%(maxout)s maximum; // temp var for maximum value in a region
+ // will be used to hold start and end index of a region
+- int r_st[%(nd)s];
+- int r_end[%(nd)s];
++ npy_intp r_st[%(nd)s];
++ npy_intp r_end[%(nd)s];
+ // index for iterating over the pooling regions
+- int r_idx[%(nd)s];
++ npy_intp r_idx[%(nd)s];
+ // placeholder for PyArray indexing (output)
+ npy_intp o_idx[%(total_ndim)s];
+ // placeholder for PyArray indexing (input)
+ npy_intp i_idx[%(total_ndim)s];
+ // loop over non-pooling dimensions
+- int non_pooling_prod;
++ npy_intp non_pooling_prod;
+ non_pooling_prod = 1;
+ for (int i=0; i<%(non_pool_ndim)s; i++)
+ {
+@@ -1935,7 +1935,7 @@ class DownsampleFactorMaxGradGrad(OpenMP
+ }
+ %(omp_parallel)s
+ // first loop over non-pooling dimensions
+- for (int t=0; t<non_pooling_prod; t++)
++ for (npy_intp t=0; t<non_pooling_prod; t++)
+ {
+ // compute the non-pooling index in each dimension
+ if (%(non_pool_ndim)s!=0)
+@@ -1989,7 +1989,7 @@ class DownsampleFactorMaxGradGrad(OpenMP
+ for i in xrange(nd):
+ ccode += """
+ // go through the pooled region in the unpadded input
+- for(int m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
++ for(npy_intp m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
+ {
+ i_idx[%(non_pool_ndim)s + %(i)s] = m%(i)s;
+ """ % dict(i=i, non_pool_ndim=non_pool_ndim)
+@@ -2025,7 +2025,7 @@ class DownsampleFactorMaxGradGrad(OpenMP
+ return ccode % locals()
+
+ def c_code_cache_version(self):
+- return (0, 4, self.openmp)
++ return (0, 4, self.openmp, 0xdeb1a)
+
+
+ class MaxPoolRop(OpenMPOp):
+@@ -2206,18 +2206,18 @@ class MaxPoolRop(OpenMPOp):
+ PyErr_SetString(PyExc_ValueError, "pad must be a vector of size %(nd)s");
+ %(fail)s;
+ }
+- int z[%(nd)s]; // shape of the output
+- int r[%(nd)s]; // shape of the padded_input
+- int ws[%(nd)s];
+- int st[%(nd)s];
+- int pd[%(nd)s];
++ npy_intp z[%(nd)s]; // shape of the output
++ npy_intp r[%(nd)s]; // shape of the padded_input
++ npy_intp ws[%(nd)s];
++ npy_intp st[%(nd)s];
++ npy_intp pd[%(nd)s];
+ int nonzero_padding;
+ nonzero_padding = 0;
+ for (int i=0; i<%(nd)s; i++)
+ {
+- ws[i] = *((npy_intp*)PyArray_GETPTR1(%(ws)s, i));
+- st[i] = *((npy_intp*)PyArray_GETPTR1(%(stride)s, i));
+- pd[i] = *((npy_intp*)PyArray_GETPTR1(%(pad)s, i));
++ ws[i] = *((dtype_%(ws)s*)PyArray_GETPTR1(%(ws)s, i));
++ st[i] = *((dtype_%(stride)s*)PyArray_GETPTR1(%(stride)s, i));
++ pd[i] = *((dtype_%(pad)s*)PyArray_GETPTR1(%(pad)s, i));
+ r[i] = PyArray_DIMS(%(x)s)[%(non_pool_ndim)s + i] + 2 * pd[i];
+ if (pd[i]>0)
+ nonzero_padding = 1;
+@@ -2254,7 +2254,7 @@ class MaxPoolRop(OpenMPOp):
+ }
+ else
+ {
+- z[i] = std::max(0, (r[i] - 1 - ws[i] + st[i]) / st[i]) + 1;
++ z[i] = std::max((npy_intp)0, (r[i] - 1 - ws[i] + st[i]) / st[i]) + 1;
+ }
+ assert(z[i] > 0);
+ }
+@@ -2306,7 +2306,7 @@ class MaxPoolRop(OpenMPOp):
+ // initialize temp var for the value in a region
+ dtype_%(x)s collector;
+ dtype_%(ex)s eval_collector;
+- int z_prod;
++ npy_intp z_prod;
+ // do not run if any z[i] is zero
+ z_prod = 1;
+ for (int i=0; i<%(nd)s; i++)
+@@ -2316,23 +2316,23 @@ class MaxPoolRop(OpenMPOp):
+ if (z_prod)
+ {
+ // will be used to hold start and end index of a region
+- int r_st[%(nd)s];
+- int r_end[%(nd)s];
++ npy_intp r_st[%(nd)s];
++ npy_intp r_end[%(nd)s];
+ // index for iterating over the pooling regions
+- int r_idx[%(nd)s];
++ npy_intp r_idx[%(nd)s];
+ // placeholder for PyArray indexing (output)
+ npy_intp o_idx[%(total_ndim)s];
+ // placeholder for PyArray indexing (input)
+ npy_intp i_idx[%(total_ndim)s];
+ // loop over non-pooling dimensions
+- int non_pooling_prod = 1;
++ npy_intp non_pooling_prod = 1;
+ for (int i=0; i<%(non_pool_ndim)s; i++)
+ {
+ non_pooling_prod *= PyArray_DIMS(%(x)s)[i];
+ }
+ %(omp_parallel)s
+ // first loop over non-pooling dimensions
+- for (int t=0; t<non_pooling_prod; t++)
++ for (npy_intp t=0; t<non_pooling_prod; t++)
+ {
+ // compute the non-pooling index in each dimension
+ if (%(non_pool_ndim)s!=0)
+@@ -2398,7 +2398,7 @@ class MaxPoolRop(OpenMPOp):
+ for i in xrange(nd):
+ ccode += """
+ // go through the pooled region in the unpadded input
+- for(int m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
++ for(npy_intp m%(i)s=r_st[%(i)s]; m%(i)s<r_end[%(i)s]; m%(i)s++)
+ {
+ i_idx[%(non_pool_ndim)s + %(i)s] = m%(i)s;
+ """ % dict(i=i, non_pool_ndim=non_pool_ndim)
+@@ -2438,4 +2438,4 @@ class MaxPoolRop(OpenMPOp):
+ return ccode % locals()
+
+ def c_code_cache_version(self):
+- return (0, self.openmp)
++ return (0, self.openmp, 0xdeb1a)
diff --git a/debian/patches/series b/debian/patches/series
index 8a452d5..c696111 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -2,3 +2,4 @@ disable-overly-environment-dependent-test.patch
strip-docs.patch
linkcode.patch
old-nose-parameterized.patch
+878596.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/theano.git
More information about the debian-science-commits
mailing list