提交 f050cdf5 authored 作者: Pascal Lamblin's avatar Pascal Lamblin

PEP 8 fixes

上级 96493027
import copy
import unittest import unittest
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
...@@ -25,7 +24,7 @@ class Test_pfunc(unittest.TestCase): ...@@ -25,7 +24,7 @@ class Test_pfunc(unittest.TestCase):
# Example #1. # Example #1.
a = lscalar() a = lscalar()
b = shared(1) b = shared(1)
f1 = pfunc([a], a+b) f1 = pfunc([a], (a + b))
f2 = pfunc([Param(a, default=44)], a + b, updates={b: b + 1}) f2 = pfunc([Param(a, default=44)], a + b, updates={b: b + 1})
self.assertTrue(b.get_value() == 1) self.assertTrue(b.get_value() == 1)
self.assertTrue(f1(3) == 4) self.assertTrue(f1(3) == 4)
...@@ -48,22 +47,24 @@ class Test_pfunc(unittest.TestCase): ...@@ -48,22 +47,24 @@ class Test_pfunc(unittest.TestCase):
def test_shared(self): def test_shared(self):
# CHECK: two functions (f1 and f2) can share w # CHECK: two functions (f1 and f2) can share w
w = shared(numpy.random.rand(2,2), 'w') w = shared(numpy.random.rand(2, 2), 'w')
wval = w.get_value(borrow=False) wval = w.get_value(borrow=False)
x = dmatrix() x = dmatrix()
out1 = w + x out1 = w + x
out2 = w * x out2 = w * x
f1 = pfunc([x],[out1]) f1 = pfunc([x], [out1])
f2 = pfunc([x],[out2]) f2 = pfunc([x], [out2])
xval = numpy.random.rand(2,2) xval = numpy.random.rand(2, 2)
assert numpy.all(f1(xval) == xval + wval) assert numpy.all(f1(xval) == xval + wval)
assert numpy.all(f2(xval) == xval * wval) assert numpy.all(f2(xval) == xval * wval)
# CHECK: updating a shared value # CHECK: updating a shared value
f3 = pfunc([x], out1, updates=[(w, w-1)]) f3 = pfunc([x], out1, updates=[(w, (w - 1))])
assert numpy.all(f3(xval) == xval + wval) # f3 changes the value of w # f3 changes the value of w
assert numpy.all(f1(xval) == xval + (wval-1)) # this same value is read by f1 assert numpy.all(f3(xval) == xval + wval)
# this same value is read by f1
assert numpy.all(f1(xval) == xval + (wval - 1))
w.set_value(w.get_value(borrow=True) * 10, borrow=True) w.set_value(w.get_value(borrow=True) * 10, borrow=True)
# this same value is read by f1 # this same value is read by f1
...@@ -71,10 +72,10 @@ class Test_pfunc(unittest.TestCase): ...@@ -71,10 +72,10 @@ class Test_pfunc(unittest.TestCase):
def test_no_shared_as_input(self): def test_no_shared_as_input(self):
"""Test that shared variables cannot be used as function inputs.""" """Test that shared variables cannot be used as function inputs."""
w_init = numpy.random.rand(2,2) w_init = numpy.random.rand(2, 2)
w = shared(w_init.copy(), 'w') w = shared(w_init.copy(), 'w')
try: try:
f = pfunc([w], theano.tensor.sum(w * w)) pfunc([w], theano.tensor.sum(w * w))
assert False assert False
except TypeError, e: except TypeError, e:
msg = 'Cannot use a shared variable (w) as explicit input' msg = 'Cannot use a shared variable (w) as explicit input'
...@@ -88,13 +89,13 @@ class Test_pfunc(unittest.TestCase): ...@@ -88,13 +89,13 @@ class Test_pfunc(unittest.TestCase):
rng = numpy.random.RandomState(1827) rng = numpy.random.RandomState(1827)
w_init = rng.rand(5) w_init = rng.rand(5)
w = shared(w_init.copy(), 'w') w = shared(w_init.copy(), 'w')
reg = theano.tensor.sum(w*w) reg = theano.tensor.sum(w * w)
f = pfunc([], reg) f = pfunc([], reg)
assert f() == numpy.sum(w_init * w_init) assert f() == numpy.sum(w_init * w_init)
# Change the value of w and ensure the output changes accordingly. # Change the value of w and ensure the output changes accordingly.
w.set_value(w.get_value(borrow=True) + 1.0, borrow=True) w.set_value(w.get_value(borrow=True) + 1.0, borrow=True)
assert f() == numpy.sum((w_init+1)**2) assert f() == numpy.sum((w_init + 1) ** 2)
def test_default_scalar_container(self): def test_default_scalar_container(self):
# Similar in spirit to test_default_container, but updating a scalar # Similar in spirit to test_default_container, but updating a scalar
...@@ -112,77 +113,79 @@ class Test_pfunc(unittest.TestCase): ...@@ -112,77 +113,79 @@ class Test_pfunc(unittest.TestCase):
out = a + b out = a + b
f = pfunc([Param(a, strict=False)], [out]) f = pfunc([Param(a, strict=False)], [out])
f(numpy.random.rand(8)) # works, rand generates float64 by default # works, rand generates float64 by default
f(numpy.array([1,2,3,4], dtype='int32')) # works, casting is allowed f(numpy.random.rand(8))
# works, casting is allowed
f(numpy.array([1, 2, 3, 4], dtype='int32'))
f = pfunc([Param(a, strict=True)], [out]) f = pfunc([Param(a, strict=True)], [out])
try: try:
f(numpy.array([1,2,3,4], dtype='int32')) # fails, f expects float64 # fails, f expects float64
f(numpy.array([1, 2, 3, 4], dtype='int32'))
except TypeError: except TypeError:
pass pass
def test_param_mutable(self): def test_param_mutable(self):
a = tensor.dvector() a = tensor.dvector()
b = shared(7) a_out = a * 2 # assuming the op which makes this "in place" triggers
out = a + b
a_out = a * 2 # assuming the op which makes this "in place" triggers
# using mutable=True will let fip change the value in aval # using mutable=True will let fip change the value in aval
fip = pfunc([Param(a, mutable=True)], [a_out], mode='FAST_RUN') fip = pfunc([Param(a, mutable=True)], [a_out], mode='FAST_RUN')
aval = numpy.random.rand(10) aval = numpy.random.rand(10)
aval2 = aval.copy() aval2 = aval.copy()
assert numpy.all( fip(aval) == aval2*2 ) assert numpy.all(fip(aval) == (aval2 * 2))
assert not numpy.all( aval == aval2 ) assert not numpy.all(aval == aval2)
# using mutable=False should leave the input untouched # using mutable=False should leave the input untouched
f = pfunc([Param(a, mutable=False)], [a_out], mode='FAST_RUN') f = pfunc([Param(a, mutable=False)], [a_out], mode='FAST_RUN')
aval = numpy.random.rand(10) aval = numpy.random.rand(10)
aval2 = aval.copy() aval2 = aval.copy()
assert numpy.all( f(aval) == aval2*2 ) assert numpy.all(f(aval) == (aval2 * 2))
assert numpy.all( aval == aval2 ) assert numpy.all(aval == aval2)
def test_shared_mutable(self): def test_shared_mutable(self):
bval = numpy.arange(5) bval = numpy.arange(5)
b = shared(bval) b = shared(bval)
b_out = b * 2 b_out = b * 2
assert b.get_value(borrow=True) is not bval # shared vars copy args. # shared vars copy args.
bval = data_of(b) # so we do this to get at the underlying data assert b.get_value(borrow=True) is not bval
# so we do this to get at the underlying data
bval = data_of(b)
# by default, shared are not mutable unless doing an explicit update # by default, shared are not mutable unless doing an explicit update
f = pfunc([], [b_out], mode='FAST_RUN') f = pfunc([], [b_out], mode='FAST_RUN')
assert (f() == numpy.arange(5) * 2).all() assert (f() == numpy.arange(5) * 2).all()
assert numpy.all(b.get_value(borrow=True) == numpy.arange(5)) assert numpy.all(b.get_value(borrow=True) == numpy.arange(5))
# using updates, b is now a mutable parameter # using updates, b is now a mutable parameter
f = pfunc([], [b_out], updates=[(b, b_out)], mode='FAST_RUN') f = pfunc([], [b_out], updates=[(b, b_out)], mode='FAST_RUN')
assert (f() == numpy.arange(5)*2 ).all() assert (f() == (numpy.arange(5) * 2)).all()
# because of the update # because of the update
assert (b.get_value(borrow=True) == numpy.arange(5)*2).all() assert (b.get_value(borrow=True) == (numpy.arange(5) * 2)).all()
assert (bval == numpy.arange(5)*2).all() # because of mutable=True assert (bval == (numpy.arange(5) * 2)).all() # because of mutable=True
# do not depend on updates being in-place though! # do not depend on updates being in-place though!
bval = numpy.arange(5) bval = numpy.arange(5)
b.set_value(bval, borrow=True) b.set_value(bval, borrow=True)
bval = data_of(b) bval = data_of(b)
f = pfunc([], [b_out], updates=[(b, b_out+3)], mode='FAST_RUN') f = pfunc([], [b_out], updates=[(b, (b_out + 3))], mode='FAST_RUN')
assert (f() == numpy.arange(5)*2 ).all() assert (f() == (numpy.arange(5) * 2)).all()
# because of the update # because of the update
assert (b.get_value(borrow=True) == ((numpy.arange(5)*2)+3)).all() assert (b.get_value(borrow=True) == ((numpy.arange(5) * 2) + 3)).all()
# bval got modified to something... # bval got modified to something...
assert not (bval == numpy.arange(5)).all() assert not (bval == numpy.arange(5)).all()
# ... but not to b.value ! # ... but not to b.value !
assert not (bval == b.get_value(borrow=True)).all() assert not (bval == b.get_value(borrow=True)).all()
def test_param_allow_downcast_int(self): def test_param_allow_downcast_int(self):
a = tensor.wvector('a') # int16 a = tensor.wvector('a') # int16
b = tensor.bvector('b') # int8 b = tensor.bvector('b') # int8
c = tensor.bscalar('c') # int8 c = tensor.bscalar('c') # int8
f = pfunc([Param(a, allow_downcast=True), f = pfunc([Param(a, allow_downcast=True),
Param(b, allow_downcast=False), Param(b, allow_downcast=False),
Param(c, allow_downcast=None)], Param(c, allow_downcast=None)],
a+b+c) (a + b + c))
# Both values are in range. Since they're not ndarrays (but lists), # Both values are in range. Since they're not ndarrays (but lists),
# they will be converted, and their value checked. # they will be converted, and their value checked.
...@@ -195,7 +198,7 @@ class Test_pfunc(unittest.TestCase): ...@@ -195,7 +198,7 @@ class Test_pfunc(unittest.TestCase):
[3], numpy.array([6], dtype='int16'), 1) [3], numpy.array([6], dtype='int16'), 1)
# Value too big for a, silently ignored # Value too big for a, silently ignored
assert numpy.all(f([2**20], numpy.ones(1, dtype='int8'), 1) == 2) assert numpy.all(f([2 ** 20], numpy.ones(1, dtype='int8'), 1) == 2)
# Value too big for b, raises TypeError # Value too big for b, raises TypeError
self.assertRaises(TypeError, f, [3], [312], 1) self.assertRaises(TypeError, f, [3], [312], 1)
...@@ -211,7 +214,7 @@ class Test_pfunc(unittest.TestCase): ...@@ -211,7 +214,7 @@ class Test_pfunc(unittest.TestCase):
f = pfunc([Param(a, allow_downcast=True), f = pfunc([Param(a, allow_downcast=True),
Param(b, allow_downcast=False), Param(b, allow_downcast=False),
Param(c, allow_downcast=None)], Param(c, allow_downcast=None)],
a+b+c) (a + b + c))
# If the values can be accurately represented, everything is OK # If the values can be accurately represented, everything is OK
assert numpy.all(f(0, 0, 0) == 0) assert numpy.all(f(0, 0, 0) == 0)
...@@ -236,7 +239,7 @@ class Test_pfunc(unittest.TestCase): ...@@ -236,7 +239,7 @@ class Test_pfunc(unittest.TestCase):
f = pfunc([Param(a, allow_downcast=True), f = pfunc([Param(a, allow_downcast=True),
Param(b, allow_downcast=False), Param(b, allow_downcast=False),
Param(c, allow_downcast=None)], Param(c, allow_downcast=None)],
a+b+c) (a + b + c))
# If the values can be accurately represented, everything is OK # If the values can be accurately represented, everything is OK
z = [0] z = [0]
...@@ -252,17 +255,17 @@ class Test_pfunc(unittest.TestCase): ...@@ -252,17 +255,17 @@ class Test_pfunc(unittest.TestCase):
self.assertRaises(TypeError, f, z, z, [0.1]) self.assertRaises(TypeError, f, z, z, [0.1])
def test_allow_input_downcast_int(self): def test_allow_input_downcast_int(self):
a = tensor.wvector('a') # int16 a = tensor.wvector('a') # int16
b = tensor.bvector('b') # int8 b = tensor.bvector('b') # int8
c = tensor.bscalar('c') # int8 c = tensor.bscalar('c') # int8
f = pfunc([a, b, c], a+b+c, allow_input_downcast=True) f = pfunc([a, b, c], (a + b + c), allow_input_downcast=True)
# Value too big for a, b, or c, silently ignored # Value too big for a, b, or c, silently ignored
assert f([2**20], [1], 0) == 1 assert f([2 ** 20], [1], 0) == 1
assert f([3], [312], 0) == 59 assert f([3], [312], 0) == 59
assert f([3], [1], 806) == 42 assert f([3], [1], 806) == 42
g = pfunc([a, b, c], a+b+c, allow_input_downcast=False) g = pfunc([a, b, c], (a + b + c), allow_input_downcast=False)
# All values are in range. Since they're not ndarrays (but lists # All values are in range. Since they're not ndarrays (but lists
# or scalars), they will be converted, and their value checked. # or scalars), they will be converted, and their value checked.
assert numpy.all(g([3], [6], 0) == 9) assert numpy.all(g([3], [6], 0) == 9)
...@@ -276,7 +279,7 @@ class Test_pfunc(unittest.TestCase): ...@@ -276,7 +279,7 @@ class Test_pfunc(unittest.TestCase):
# Value too big for b, raises TypeError # Value too big for b, raises TypeError
self.assertRaises(TypeError, g, [3], [312], 0) self.assertRaises(TypeError, g, [3], [312], 0)
h = pfunc([a, b, c], a+b+c) # Default: allow_input_downcast=None h = pfunc([a, b, c], (a + b + c)) # Default: allow_input_downcast=None
# Everything here should behave like with False # Everything here should behave like with False
assert numpy.all(h([3], [6], 0) == 9) assert numpy.all(h([3], [6], 0) == 9)
self.assertRaises(TypeError, h, self.assertRaises(TypeError, h,
...@@ -287,9 +290,9 @@ class Test_pfunc(unittest.TestCase): ...@@ -287,9 +290,9 @@ class Test_pfunc(unittest.TestCase):
a = tensor.fscalar('a') a = tensor.fscalar('a')
b = tensor.fvector('b') b = tensor.fvector('b')
f = pfunc([a, b], a+b, allow_input_downcast=True) f = pfunc([a, b], (a + b), allow_input_downcast=True)
g = pfunc([a, b], a+b, allow_input_downcast=False) g = pfunc([a, b], (a + b), allow_input_downcast=False)
h = pfunc([a, b], a+b, allow_input_downcast=None) h = pfunc([a, b], (a + b), allow_input_downcast=None)
# If the values can be accurately represented, OK # If the values can be accurately represented, OK
assert numpy.all(f(0, [0]) == 0) assert numpy.all(f(0, [0]) == 0)
...@@ -315,60 +318,65 @@ class Test_pfunc(unittest.TestCase): ...@@ -315,60 +318,65 @@ class Test_pfunc(unittest.TestCase):
# Simple value assignment. # Simple value assignment.
x = shared(0) x = shared(0)
assign = pfunc([], [], updates = {x: 3}) assign = pfunc([], [], updates={x: 3})
assign() assign()
self.assertTrue(x.get_value() == 3) self.assertTrue(x.get_value() == 3)
# Basic increment function. # Basic increment function.
x.set_value(0) x.set_value(0)
inc = pfunc([], [], updates = {x: x + 1}) inc = pfunc([], [], updates={x: x + 1})
inc() inc()
self.assertTrue(x.get_value() == 1) self.assertTrue(x.get_value() == 1)
# Increment by a constant value. # Increment by a constant value.
x.set_value(-1) x.set_value(-1)
y = shared(2) y = shared(2)
inc_by_y = pfunc([], [], updates = {x: x + y}) inc_by_y = pfunc([], [], updates={x: x + y})
inc_by_y() inc_by_y()
self.assertTrue(x.get_value() == 1) self.assertTrue(x.get_value() == 1)
def test_duplicate_updates(self): def test_duplicate_updates(self):
x, y = dmatrices('x', 'y') x, y = dmatrices('x', 'y')
z = shared(numpy.ones((2,3))) z = shared(numpy.ones((2, 3)))
self.assertRaises(ValueError, theano.function, [x,y], [z], updates=[(z, z+x+y), (z, z-x)]) self.assertRaises(ValueError, theano.function, [x, y], [z],
updates=[(z, (z + x + y)), (z, (z - x))])
def test_givens(self): def test_givens(self):
x = shared(0) x = shared(0)
assign = pfunc([], x, givens = {x: 3}) assign = pfunc([], x, givens={x: 3})
assert assign() == 3 assert assign() == 3
assert x.get_value(borrow=True) == 0 assert x.get_value(borrow=True) == 0
y = tensor.ivector() y = tensor.ivector()
f = pfunc([y], y*x, givens = {x : 6}) f = pfunc([y], (y * x), givens={x: 6})
assert numpy.all(f([1,1,1]) == [6,6,6]) assert numpy.all(f([1, 1, 1]) == [6, 6, 6])
assert x.get_value() == 0 assert x.get_value() == 0
z = tensor.ivector() z = tensor.ivector()
c = z*y c = z * y
f = pfunc([y], c+7, givens = {z : theano._asarray([4,4,4], dtype='int32')}) f = pfunc([y], (c + 7),
assert numpy.all(f([1,1,1]) == [11,11,11]) givens={z: theano._asarray([4, 4, 4], dtype='int32')})
assert numpy.all(f([1, 1, 1]) == [11, 11, 11])
assert x.get_value() == 0 assert x.get_value() == 0
def test_clone0(self): def test_clone0(self):
x = shared(numpy.asarray([4,4,4])) x = shared(numpy.asarray([4, 4, 4]))
y = shared(numpy.asarray([4,4,4])) y = shared(numpy.asarray([4, 4, 4]))
z = shared(numpy.asarray([2,2,2])) z = shared(numpy.asarray([2, 2, 2]))
up = pfunc([], [], updates = {x: (x*5), y:(x*5)+y, z: ((x*5)+y)**z}) up = pfunc([], [], updates={
x: (x * 5),
y: ((x * 5) + y),
z: (((x * 5) + y) ** z)})
up() up()
print x.get_value(borrow=True) print x.get_value(borrow=True)
assert numpy.all(x.get_value()==20) assert numpy.all(x.get_value() == 20)
assert numpy.all(y.get_value()==24) assert numpy.all(y.get_value() == 24)
assert numpy.all(z.get_value()==24**2) assert numpy.all(z.get_value() == (24 ** 2))
def test_default_updates(self): def test_default_updates(self):
x = shared(0) x = shared(0)
x.default_update = x+1 x.default_update = x + 1
f = pfunc([], [x]) f = pfunc([], [x])
f() f()
...@@ -386,7 +394,7 @@ class Test_pfunc(unittest.TestCase): ...@@ -386,7 +394,7 @@ class Test_pfunc(unittest.TestCase):
def test_no_default_updates(self): def test_no_default_updates(self):
x = shared(0) x = shared(0)
y = shared(1) y = shared(1)
x.default_update = x+2 x.default_update = x + 2
# Test that the default update is taken into account in the right cases # Test that the default update is taken into account in the right cases
f1 = pfunc([], [x], no_default_updates=True) f1 = pfunc([], [x], no_default_updates=True)
...@@ -421,35 +429,36 @@ class Test_pfunc(unittest.TestCase): ...@@ -421,35 +429,36 @@ class Test_pfunc(unittest.TestCase):
self.assertRaises(TypeError, pfunc, [], [x], no_default_updates=(x)) self.assertRaises(TypeError, pfunc, [], [x], no_default_updates=(x))
self.assertRaises(TypeError, pfunc, [], [x], no_default_updates=x) self.assertRaises(TypeError, pfunc, [], [x], no_default_updates=x)
self.assertRaises(TypeError, pfunc, [], [x], no_default_updates='canard') self.assertRaises(TypeError, pfunc, [], [x],
no_default_updates='canard')
# Mix explicit updates and no_default_updates # Mix explicit updates and no_default_updates
g1 = pfunc([], [x], updates=[(x,x-1)], no_default_updates=True) g1 = pfunc([], [x], updates=[(x, (x - 1))], no_default_updates=True)
g1() g1()
print x.get_value() print x.get_value()
assert x.get_value() == 5 assert x.get_value() == 5
g2 = pfunc([], [x], updates=[(x,x-1)], no_default_updates=[x]) g2 = pfunc([], [x], updates=[(x, (x - 1))], no_default_updates=[x])
g2() g2()
print x.get_value() print x.get_value()
assert x.get_value() == 4 assert x.get_value() == 4
g3 = pfunc([], [x], updates=[(x,x-1)], no_default_updates=[x, y]) g3 = pfunc([], [x], updates=[(x, (x - 1))], no_default_updates=[x, y])
g3() g3()
print x.get_value() print x.get_value()
assert x.get_value() == 3 assert x.get_value() == 3
g4 = pfunc([], [x], updates=[(x,x-1)], no_default_updates=[y]) g4 = pfunc([], [x], updates=[(x, (x - 1))], no_default_updates=[y])
g4() g4()
print x.get_value() print x.get_value()
assert x.get_value() == 2 assert x.get_value() == 2
g5 = pfunc([], [x], updates=[(x,x-1)], no_default_updates=[]) g5 = pfunc([], [x], updates=[(x, (x - 1))], no_default_updates=[])
g5() g5()
print x.get_value() print x.get_value()
assert x.get_value() == 1 assert x.get_value() == 1
g5 = pfunc([], [x], updates=[(x,x-1)], no_default_updates=False) g5 = pfunc([], [x], updates=[(x, (x - 1))], no_default_updates=False)
g5() g5()
print x.get_value() print x.get_value()
assert x.get_value() == 0 assert x.get_value() == 0
...@@ -459,8 +468,8 @@ class Test_pfunc(unittest.TestCase): ...@@ -459,8 +468,8 @@ class Test_pfunc(unittest.TestCase):
y = shared(1) y = shared(1)
a = lscalar('a') a = lscalar('a')
z = a*x z = a * x
x.default_update = x+y x.default_update = x + y
f1 = pfunc([a], z) f1 = pfunc([a], z)
f1(12) f1(12)
...@@ -481,25 +490,25 @@ class Test_pfunc(unittest.TestCase): ...@@ -481,25 +490,25 @@ class Test_pfunc(unittest.TestCase):
x = shared(0) x = shared(0)
y = shared(1) y = shared(1)
x.default_update = x-1 x.default_update = x - 1
y.default_update = y+1 y.default_update = y + 1
f1 = pfunc([], [x,y]) f1 = pfunc([], [x, y])
f1() f1()
assert x.get_value() == -1 assert x.get_value() == -1
assert y.get_value() == 2 assert y.get_value() == 2
f2 = pfunc([], [x,y], updates=[(x, x-2)], no_default_updates=[y]) f2 = pfunc([], [x, y], updates=[(x, (x - 2))], no_default_updates=[y])
f2() f2()
assert x.get_value() == -3 assert x.get_value() == -3
assert y.get_value() == 2 assert y.get_value() == 2
f3 = pfunc([], [x,y], updates=[(x, x-2)], no_default_updates=True) f3 = pfunc([], [x, y], updates=[(x, (x - 2))], no_default_updates=True)
f3() f3()
assert x.get_value() == -5 assert x.get_value() == -5
assert y.get_value() == 2 assert y.get_value() == 2
f4 = pfunc([], [x,y], updates=[(y, y-2)]) f4 = pfunc([], [x, y], updates=[(y, (y - 2))])
f4() f4()
assert x.get_value() == -6 assert x.get_value() == -6
assert y.get_value() == 0 assert y.get_value() == 0
...@@ -509,9 +518,9 @@ class Test_pfunc(unittest.TestCase): ...@@ -509,9 +518,9 @@ class Test_pfunc(unittest.TestCase):
y = shared(1) y = shared(1)
z = shared(-1) z = shared(-1)
x.default_update = x-y x.default_update = x - y
y.default_update = z y.default_update = z
z.default_update = z-1 z.default_update = z - 1
f1 = pfunc([], [x]) f1 = pfunc([], [x])
f1() f1()
...@@ -532,29 +541,28 @@ class Test_pfunc(unittest.TestCase): ...@@ -532,29 +541,28 @@ class Test_pfunc(unittest.TestCase):
assert y.get_value() == -3 assert y.get_value() == -3
assert z.get_value() == -4 assert z.get_value() == -4
f4 = pfunc([], [x,y], no_default_updates=[x]) f4 = pfunc([], [x, y], no_default_updates=[x])
f4() f4()
assert x.get_value() == 2 assert x.get_value() == 2
assert y.get_value() == -4 assert y.get_value() == -4
assert z.get_value() == -5 assert z.get_value() == -5
f5 = pfunc([], [x,y,z], no_default_updates=[z]) f5 = pfunc([], [x, y, z], no_default_updates=[z])
f5() f5()
assert x.get_value() == 6 assert x.get_value() == 6
assert y.get_value() == -5 assert y.get_value() == -5
assert z.get_value() == -5 assert z.get_value() == -5
def test_default_updates_input(self): def test_default_updates_input(self):
x = shared(0) x = shared(0)
y = shared(1) y = shared(1)
if theano.gof.cmodule.local_bitwidth()==32: if theano.gof.cmodule.local_bitwidth() == 32:
a = iscalar('a') a = iscalar('a')
else: else:
a = lscalar('a') a = lscalar('a')
x.default_update = y x.default_update = y
y.default_update = y+a y.default_update = y + a
f1 = pfunc([], x, no_default_updates=True) f1 = pfunc([], x, no_default_updates=True)
f1() f1()
...@@ -576,7 +584,7 @@ class Test_pfunc(unittest.TestCase): ...@@ -576,7 +584,7 @@ class Test_pfunc(unittest.TestCase):
assert x.get_value() == 1 assert x.get_value() == 1
assert y.get_value() == 3 assert y.get_value() == 3
f5 = pfunc([], x, updates={y:y-1}) f5 = pfunc([], x, updates={y: (y - 1)})
f5() f5()
assert x.get_value() == 3 assert x.get_value() == 3
assert y.get_value() == 2 assert y.get_value() == 2
...@@ -586,8 +594,8 @@ class Test_pfunc(unittest.TestCase): ...@@ -586,8 +594,8 @@ class Test_pfunc(unittest.TestCase):
def test_default_updates_partial_graph(self): def test_default_updates_partial_graph(self):
a = shared(0) a = shared(0)
a.default_update = a+1 # Increment a each time it is used a.default_update = a + 1 # Increment a each time it is used
b = 2*a b = 2 * a
# Use only the tip of the graph, a is not used # Use only the tip of the graph, a is not used
f = pfunc([b], b) f = pfunc([b], b)
print 'a.get_value() =', a.get_value() print 'a.get_value() =', a.get_value()
...@@ -596,22 +604,21 @@ class Test_pfunc(unittest.TestCase): ...@@ -596,22 +604,21 @@ class Test_pfunc(unittest.TestCase):
print 'a.get_value() =', a.get_value() print 'a.get_value() =', a.get_value()
assert a.get_value() == 0 assert a.get_value() == 0
def test_givens_replaces_shared_variable(self): def test_givens_replaces_shared_variable(self):
a = shared(1.,'a') a = shared(1., 'a')
a.default_update = a+3. a.default_update = a + 3.
b = tensor.dscalar('b') b = tensor.dscalar('b')
c = a + 10 c = a + 10
f = pfunc([b],c, givens = {a:b}) f = pfunc([b], c, givens={a: b})
assert len(f.maker.env.inputs) == 1 assert len(f.maker.env.inputs) == 1
assert len(f.maker.env.outputs) == 1 assert len(f.maker.env.outputs) == 1
def test_givens_replaces_shared_variable2(self): def test_givens_replaces_shared_variable2(self):
a = shared(1.,'a') a = shared(1., 'a')
a.default_update = a+3 a.default_update = a + 3
c = a+ 10 c = a + 10
f = pfunc([],c, givens = { a: a+10} ) f = pfunc([], c, givens={a: (a + 10)})
assert f() == 21 assert f() == 21
assert f() == 34 assert f() == 34
...@@ -622,29 +629,28 @@ class Test_pfunc(unittest.TestCase): ...@@ -622,29 +629,28 @@ class Test_pfunc(unittest.TestCase):
theano.function, [x, x, x], x) theano.function, [x, x, x], x)
class Test_aliasing_rules(unittest.TestCase): class Test_aliasing_rules(unittest.TestCase):
""" """
1. Theano manages its own memory space, which typically does not overlap with the memory of 1. Theano manages its own memory space, which typically does not overlap
normal python variables that the user uses. with the memory of normal python variables that the user uses.
2. shared variables are allocated in this memory space, as are the temporaries used for 2. shared variables are allocated in this memory space, as are the
Function evalution. temporaries used for Function evalution.
3. Physically, this managed memory space may be spread across the host, on a GPU device(s), 3. Physically, this managed memory space may be spread across the host,
or even on a remote machine. on a GPU device(s), or even on a remote machine.
4. Theano assumes that shared variables are never aliased to one another, and tries to make 4. Theano assumes that shared variables are never aliased to one another,
it impossible to accidentally alias them. and tries to make it impossible to accidentally alias them.
5. Theano's managed data is constant while Theano Functions are not running and theano 5. Theano's managed data is constant while Theano Functions are not running
library code is not running. and theano library code is not running.
6. The default behaviour of Function is to return user-space values for outputs, but this 6. The default behaviour of Function is to return user-space values for
can be overridden (borrow=True) for better performance, in which case the returned value outputs, but this can be overridden (borrow=True) for better performance,
may be aliased to managed memory, and potentially invalidated by the next Theano Function in which case the returned value may be aliased to managed memory, and
call or call to theano library code. potentially invalidated by the next Theano Function call or call to theano
library code.
""" """
def shared(self, x): def shared(self, x):
...@@ -653,12 +659,13 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -653,12 +659,13 @@ class Test_aliasing_rules(unittest.TestCase):
def test_shared_constructor_copies(self): def test_shared_constructor_copies(self):
# shared constructor makes copy # shared constructor makes copy
# (rule #2) # (rule #2)
orig_a = numpy.zeros((2,2)) orig_a = numpy.zeros((2, 2))
A = self.shared(orig_a) A = self.shared(orig_a)
assert not numpy.may_share_memory(orig_a, data_of(A)) assert not numpy.may_share_memory(orig_a, data_of(A))
# rule #2 reading back from theano-managed memory # rule #2 reading back from theano-managed memory
assert not numpy.may_share_memory(A.get_value(borrow=False), data_of(A)) assert not numpy.may_share_memory(A.get_value(borrow=False),
data_of(A))
def test_sparse_input_aliasing_affecting_inplace_operations(self): def test_sparse_input_aliasing_affecting_inplace_operations(self):
## ##
...@@ -681,30 +688,32 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -681,30 +688,32 @@ class Test_aliasing_rules(unittest.TestCase):
# operations are used) and to break the elemwise composition # operations are used) and to break the elemwise composition
# with some non-elemwise op (here dot) # with some non-elemwise op (here dot)
x = sparse.SparseType('csc', dtype = 'float64')() x = sparse.SparseType('csc', dtype='float64')()
y = sparse.SparseType('csc', dtype = 'float64')() y = sparse.SparseType('csc', dtype='float64')()
f = theano.function( [theano.In(x, mutable = True), f = theano.function([theano.In(x, mutable=True),
theano.In(y, mutable = True)], theano.In(y, mutable=True)],
(x+y)+(x+y)) (x + y) + (x + y))
## Test 1. If the same variable is given twice ## Test 1. If the same variable is given twice
# Compute bogus values # Compute bogus values
m = sp.csc_matrix(numpy.asarray([[1,0,0,0,0], m = sp.csc_matrix(numpy.asarray(
[0,1,0,0,0], [[1, 0, 0, 0, 0],
[0,0,1,0,0], [0, 1, 0, 0, 0],
[0,0,0,1,0], [0, 0, 1, 0, 0],
[0,0,0,0,1]], dtype = 'float64')) [0, 0, 0, 1, 0],
bogus_vals = f(m,m) [0, 0, 0, 0, 1]], dtype='float64'))
bogus_vals = f(m, m)
# Since we used inplace operation v and m may be corrupted # Since we used inplace operation v and m may be corrupted
# so we need to recreate them # so we need to recreate them
m = sp.csc_matrix(numpy.asarray([[1,0,0,0,0], m = sp.csc_matrix(numpy.asarray(
[0,1,0,0,0], [[1, 0, 0, 0, 0],
[0,0,1,0,0], [0, 1, 0, 0, 0],
[0,0,0,1,0], [0, 0, 1, 0, 0],
[0,0,0,0,1]], dtype = 'float64')) [0, 0, 0, 1, 0],
[0, 0, 0, 0, 1]], dtype='float64'))
m_copy = m.copy() m_copy = m.copy()
vals = f(m,m_copy) vals = f(m, m_copy)
assert numpy.allclose(vals.todense(), bogus_vals.todense()) assert numpy.allclose(vals.todense(), bogus_vals.todense())
...@@ -714,37 +723,37 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -714,37 +723,37 @@ class Test_aliasing_rules(unittest.TestCase):
# you need to make in inputs mutable (so that inplace # you need to make in inputs mutable (so that inplace
# operations are used) and to break the elemwise composition # operations are used) and to break the elemwise composition
# with some non-elemwise op (here dot) # with some non-elemwise op (here dot)
x = theano.tensor.dvector() x = theano.tensor.dvector()
y = theano.tensor.dvector() y = theano.tensor.dvector()
m1 = theano.tensor.dmatrix() m1 = theano.tensor.dmatrix()
m2 = theano.tensor.dmatrix() m2 = theano.tensor.dmatrix()
f = theano.function( [theano.In(x, mutable = True), f = theano.function([theano.In(x, mutable=True),
theano.In(y, mutable = True), theano.In(y, mutable=True),
theano.In(m1, mutable = True), theano.In(m1, mutable=True),
theano.In(m2, mutable = True)], theano.In(m2, mutable=True)],
theano.dot(x*2,m1)+theano.dot(y*3,m2)) theano.dot((x * 2), m1) + theano.dot((y * 3), m2))
## Test 1. If the same variable is given twice ## Test 1. If the same variable is given twice
# Compute bogus values # Compute bogus values
v = numpy.asarray( [1,2,3,4,5], dtype = 'float64') v = numpy.asarray([1, 2, 3, 4, 5], dtype='float64')
m = numpy.asarray([[1,0,0,0,0], m = numpy.asarray([[1, 0, 0, 0, 0],
[0,1,0,0,0], [0, 1, 0, 0, 0],
[0,0,1,0,0], [0, 0, 1, 0, 0],
[0,0,0,1,0], [0, 0, 0, 1, 0],
[0,0,0,0,1]], dtype = 'float64') [0, 0, 0, 0, 1]], dtype='float64')
bogus_vals = f(v,v,m,m) bogus_vals = f(v, v, m, m)
# Since we used inplace operation v and m may be corrupted # Since we used inplace operation v and m may be corrupted
# so we need to recreate them # so we need to recreate them
v = numpy.asarray( [1,2,3,4,5], dtype = 'float64') v = numpy.asarray([1, 2, 3, 4, 5], dtype='float64')
m = numpy.asarray([[1,0,0,0,0], m = numpy.asarray([[1, 0, 0, 0, 0],
[0,1,0,0,0], [0, 1, 0, 0, 0],
[0,0,1,0,0], [0, 0, 1, 0, 0],
[0,0,0,1,0], [0, 0, 0, 1, 0],
[0,0,0,0,1]], dtype = 'float64') [0, 0, 0, 0, 1]], dtype='float64')
m_copy = m.copy() m_copy = m.copy()
v_copy = v.copy() v_copy = v.copy()
vals = f(v,v_copy,m,m_copy) vals = f(v, v_copy, m, m_copy)
assert numpy.allclose(vals, bogus_vals) assert numpy.allclose(vals, bogus_vals)
...@@ -754,9 +763,9 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -754,9 +763,9 @@ class Test_aliasing_rules(unittest.TestCase):
# you need to make in inputs mutable ( so that inplace # you need to make in inputs mutable ( so that inplace
# operations are used) and to break the elemwise composition # operations are used) and to break the elemwise composition
# with some non-elemwise op ( here dot ) # with some non-elemwise op ( here dot )
x = theano.tensor.dvector() x = theano.tensor.dvector()
y = theano.tensor.dvector() y = theano.tensor.dvector()
z = theano.tensor.dvector() z = theano.tensor.dvector()
m1 = theano.tensor.dmatrix() m1 = theano.tensor.dmatrix()
m2 = theano.tensor.dmatrix() m2 = theano.tensor.dmatrix()
m3 = theano.tensor.dmatrix() m3 = theano.tensor.dmatrix()
...@@ -766,118 +775,121 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -766,118 +775,121 @@ class Test_aliasing_rules(unittest.TestCase):
# and a shares memory with b, b shares memory with c, but # and a shares memory with b, b shares memory with c, but
# c does not share memory with a # c does not share memory with a
f = theano.function(
[theano.In(x, mutable=True),
theano.In(y, mutable=True),
theano.In(z, mutable=True),
theano.In(m1, mutable=True),
theano.In(m2, mutable=True),
theano.In(m3, mutable=True)],
(theano.dot((x * 2), m1)
+ theano.dot((y * 3), m2)
+ theano.dot((z * 4), m3)))
f = theano.function( [theano.In(x, mutable = True),
theano.In(y, mutable = True),
theano.In(z, mutable = True),
theano.In(m1, mutable = True),
theano.In(m2, mutable = True),
theano.In(m3, mutable = True)],
theano.dot(x*2,m1)+theano.dot(y*3,m2)+theano.dot(z*4,m3))
# Compute bogus values # Compute bogus values
v = numpy.asarray( [1,2,3,4,5], dtype = 'float64') v = numpy.asarray([1, 2, 3, 4, 5], dtype='float64')
m = numpy.asarray([[1,0], m = numpy.asarray([[1, 0],
[0,1]], dtype = 'float64') [0, 1]], dtype='float64')
bogus_vals = f(v[:2],v[1:3],v[2:4],m,m,m) bogus_vals = f(v[:2], v[1:3], v[2:4], m, m, m)
# Since we used inplace operation v and m may be corrupted # Since we used inplace operation v and m may be corrupted
# so we need to recreate them # so we need to recreate them
v = numpy.asarray( [1,2,3,4,5], dtype = 'float64') v = numpy.asarray([1, 2, 3, 4, 5], dtype='float64')
m = numpy.asarray([[1,0], m = numpy.asarray([[1, 0],
[0,1]], dtype = 'float64') [0, 1]], dtype='float64')
m_copy1 = m.copy() m_copy1 = m.copy()
v_copy1 = v.copy() v_copy1 = v.copy()
m_copy2 = m.copy() m_copy2 = m.copy()
v_copy2 = v.copy() v_copy2 = v.copy()
vals = f(v[:2],v_copy1[1:3],v_copy2[2:4],m,m_copy1, m_copy2) vals = f(v[:2], v_copy1[1:3], v_copy2[2:4], m, m_copy1, m_copy2)
assert numpy.allclose(vals, bogus_vals) assert numpy.allclose(vals, bogus_vals)
def test_potential_output_aliasing_induced_by_updates(self): def test_potential_output_aliasing_induced_by_updates(self):
A = self.shared(numpy.zeros((2,2))) A = self.shared(numpy.zeros((2, 2)))
B = self.shared(numpy.zeros((2,2))) B = self.shared(numpy.zeros((2, 2)))
C = numpy.zeros((2,2)) C = numpy.zeros((2, 2))
D = tensor.dmatrix() D = tensor.dmatrix()
DD = D + 5 DD = D + 5
f = pfunc([D], [], updates=[ (A,D), (B,D) ]) f = pfunc([D], [], updates=[(A, D), (B, D)])
f(C) f(C)
assert not numpy.may_share_memory(data_of(A),data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
f = pfunc([D], [], updates=[ (A,D[:]), (B,D) ]) f = pfunc([D], [], updates=[(A, D[:]), (B, D)])
f(C) f(C)
assert not numpy.may_share_memory(data_of(A),data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
f = pfunc([D], [], updates=[ (A,D+5), (B,D[:]) ]) f = pfunc([D], [], updates=[(A, (D + 5)), (B, D[:])])
f(C) f(C)
assert not numpy.may_share_memory(data_of(A),data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
f = pfunc([D], [], updates=[ (A,D+5), (B,D) ]) f = pfunc([D], [], updates=[(A, (D + 5)), (B, D)])
f(C) f(C)
assert not numpy.may_share_memory(data_of(A),data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
f = pfunc([D], DD, updates=[ (A,DD[:1]), (B,DD) ]) f = pfunc([D], DD, updates=[(A, DD[:1]), (B, DD)])
R=f(C) R = f(C)
assert not numpy.may_share_memory(data_of(A),data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
assert not numpy.may_share_memory(R,data_of(B)) assert not numpy.may_share_memory(R, data_of(B))
assert not numpy.may_share_memory(R,data_of(A)) assert not numpy.may_share_memory(R, data_of(A))
f = pfunc([D], DD, updates=[ (A,DD[:1]), (B,DD[:1]*2) ]) f = pfunc([D], DD, updates=[(A, DD[:1]), (B, (DD[:1] * 2))])
R=f(C) R = f(C)
assert not numpy.may_share_memory(data_of(A),data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
assert not numpy.may_share_memory(R,data_of(B)) assert not numpy.may_share_memory(R, data_of(B))
assert not numpy.may_share_memory(R,data_of(A)) assert not numpy.may_share_memory(R, data_of(A))
f = pfunc([D], DD*4, updates=[ (A,DD[:1]*3), (B,DD[:1]*2) ]) f = pfunc([D], (DD * 4),
R=f(C) updates=[(A, (DD[:1] * 3)), (B, (DD[:1] * 2))])
assert not numpy.may_share_memory(data_of(A),data_of(B)) R = f(C)
assert not numpy.may_share_memory(R,data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
assert not numpy.may_share_memory(R,data_of(A)) assert not numpy.may_share_memory(R, data_of(B))
assert not numpy.may_share_memory(R, data_of(A))
f = pfunc([D], DD*4, updates=[ (A,DD[:1]*3), (B,DD[:1]*3) ])
R=f(C) f = pfunc([D], (DD * 4),
assert not numpy.may_share_memory(data_of(A),data_of(B)) updates=[(A, (DD[:1] * 3)), (B, (DD[:1] * 3))])
assert not numpy.may_share_memory(R,data_of(B)) R = f(C)
assert not numpy.may_share_memory(R,data_of(A)) assert not numpy.may_share_memory(data_of(A), data_of(B))
assert not numpy.may_share_memory(R, data_of(B))
assert not numpy.may_share_memory(R, data_of(A))
def test_no_aliasing_0(self): def test_no_aliasing_0(self):
# B is a shared variable, A is updated with B's contents # B is a shared variable, A is updated with B's contents
# we need A to be copied to avoid aliasing # we need A to be copied to avoid aliasing
A = self.shared(numpy.zeros((2,2))+.5) A = self.shared(numpy.zeros((2, 2)) + .5)
B = self.shared(numpy.zeros((2,2))-.5) B = self.shared(numpy.zeros((2, 2)) - .5)
f = pfunc([], [], updates=[(A,B)]) f = pfunc([], [], updates=[(A, B)])
f() f()
assert not numpy.may_share_memory(data_of(A), data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
def test_no_aliasing_1(self): def test_no_aliasing_1(self):
# B is a shared variable, A is updated with B's contents # B is a shared variable, A is updated with B's contents
# since B is being updated as well, we don't need to copy anything to avoid aliasing # since B is being updated as well, we don't need to copy anything
# shared variables. # to avoid aliasing shared variables.
A = self.shared(numpy.zeros((2,2))+.5) A = self.shared(numpy.zeros((2, 2)) + .5)
B = self.shared(numpy.zeros((2,2))-.5) B = self.shared(numpy.zeros((2, 2)) - .5)
C = tensor.dmatrix() C = tensor.dmatrix()
f = pfunc([C], [], updates=[ (A,B), (B,C) ]) f = pfunc([C], [], updates=[(A, B), (B, C)])
z = numpy.zeros((2,2)) z = numpy.zeros((2, 2))
f(z) f(z)
assert not numpy.may_share_memory(data_of(A),data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
assert not numpy.may_share_memory(z,data_of(B)) # Theano tries to maintain its own memory space. # Theano tries to maintain its own memory space.
assert not numpy.may_share_memory(z, data_of(B))
assert numpy.all(data_of(B) == z) assert numpy.all(data_of(B) == z)
def test_no_aliasing_2(self): def test_no_aliasing_2(self):
# B and A take one another's values # B and A take one another's values
# no copying is necessary since each one is updated. # no copying is necessary since each one is updated.
orig_a = numpy.zeros((2,2))+.5 orig_a = numpy.zeros((2, 2)) + .5
orig_b = numpy.zeros((2,2))-.5 orig_b = numpy.zeros((2, 2)) - .5
A = self.shared(orig_a) A = self.shared(orig_a)
B = self.shared(orig_b) B = self.shared(orig_b)
data_of_a = data_of(A) data_of_a = data_of(A)
data_of_b = data_of(B) data_of_b = data_of(B)
f = pfunc([], [], updates=[(A,B),(B,A)]) f = pfunc([], [], updates=[(A, B), (B, A)])
f() f()
# correctness # correctness
assert numpy.all(data_of(A) == -.5) assert numpy.all(data_of(A) == -.5)
...@@ -893,18 +905,18 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -893,18 +905,18 @@ class Test_aliasing_rules(unittest.TestCase):
def test_no_aliasing_2b(self): def test_no_aliasing_2b(self):
# B and A take one another's values # B and A take one another's values
# no copying is necessary since each one is updated. # no copying is necessary since each one is updated.
# The twist one `test_no_aliasing_2` is that each shared var is updated with a view of # The twist one `test_no_aliasing_2` is that each shared var is updated
# the other one. # with a view of the other one.
orig_a = numpy.zeros((2,2))+.5 orig_a = numpy.zeros((2, 2)) + .5
orig_b = numpy.zeros((2,2))-.5 orig_b = numpy.zeros((2, 2)) - .5
A = self.shared(orig_a) A = self.shared(orig_a)
B = self.shared(orig_b) B = self.shared(orig_b)
data_of_a = data_of(A) data_of_a = data_of(A)
data_of_b = data_of(B) data_of_b = data_of(B)
f = pfunc([], [], updates=[(A,B[:,::-1]),(B,A.T)]) f = pfunc([], [], updates=[(A, B[:, ::-1]), (B, A.T)])
theano.printing.debugprint(f) theano.printing.debugprint(f)
f() f()
# correctness (doesn't actually test the view...) # correctness (doesn't actually test the view...)
...@@ -915,8 +927,10 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -915,8 +927,10 @@ class Test_aliasing_rules(unittest.TestCase):
assert not numpy.may_share_memory(data_of(A), data_of(B)) assert not numpy.may_share_memory(data_of(A), data_of(B))
# theano should have been smart enough to not make copies # theano should have been smart enough to not make copies
if theano.config.mode not in ['DebugMode', 'DEBUG_MODE', 'FAST_COMPILE']: if theano.config.mode not in [
#we don't ask DebugMode and FAST_COMPILE to don't make copy. We have the right to do so. 'DebugMode', 'DEBUG_MODE', 'FAST_COMPILE']:
# We don't ask DebugMode and FAST_COMPILE not to make copy.
# We have the right to do so.
assert numpy.all(data_of(A) < 5) assert numpy.all(data_of(A) < 5)
data_of_b += 10 data_of_b += 10
assert numpy.all(data_of(A) > 5) assert numpy.all(data_of(A) > 5)
...@@ -932,11 +946,11 @@ class Test_aliasing_rules(unittest.TestCase): ...@@ -932,11 +946,11 @@ class Test_aliasing_rules(unittest.TestCase):
assert numpy.may_share_memory(data_of(A), data_of_b) assert numpy.may_share_memory(data_of(A), data_of_b)
assert numpy.may_share_memory(data_of(B), data_of_a) assert numpy.may_share_memory(data_of(B), data_of_a)
# N.B. This pattern could form a memory leak - each shared variable always points to a # N.B. This pattern could form a memory leak - each shared
# view, and that view gets further and further from the (e.g. data_of_a) with each # variable always points to a view, and that view gets
# call. The memory leak is in the increasing number of view objects forming a chain to # further and further from the (e.g. data_of_a) with each
# the underlying data. # call. The memory leak is in the increasing number of view
# objects forming a chain to the underlying data.
if __name__ == '__main__': if __name__ == '__main__':
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论