提交 c36ce7b0 authored 作者: Olivier Delalleau's avatar Olivier Delalleau

Merge pull request #192 from nouiz/ceil_intdiv

Add ceil_intdiv with associated tests.
...@@ -2822,6 +2822,27 @@ def int_div(a, b): ...@@ -2822,6 +2822,27 @@ def int_div(a, b):
"""elementwise integer-division""" """elementwise integer-division"""
# see decorator for function body # see decorator for function body
def ceil_intdiv(a, b):
"""
Safely compute ceil(float_division(a, b)).
Works for all dtypes, but mostly useful when a and b are int.
"""
# If a and b are int with not many significant bits, we could
# cast them to float to avoid doing the modulo. We do not know if this
# is faster or not. But this is not safe for int64 as the cast will
# lose precision.
# e.g.: cast(cast(a, scalar.upcast(a, 'float32')) / b, scal.upcast(a, b))
# We cast for the case when a and b are uint*. Otherwise neq will
# force their upcast to int.
div = int_div(a, b)
ret = cast(neq(a % b, 0), div.dtype) + div
assert ret.dtype == scal.upcast(a.dtype, b.dtype)
return ret
def mod_check(x, y): def mod_check(x, y):
"""Make sure we do not try to use complex numbers.""" """Make sure we do not try to use complex numbers."""
if (as_tensor_variable(x).dtype in complex_dtypes or if (as_tensor_variable(x).dtype in complex_dtypes or
......
...@@ -541,34 +541,48 @@ MulInplaceTester = makeBroadcastTester(op = inplace.mul_inplace, ...@@ -541,34 +541,48 @@ MulInplaceTester = makeBroadcastTester(op = inplace.mul_inplace,
grad = _grad_broadcast_binary_normal, grad = _grad_broadcast_binary_normal,
inplace = True) inplace = True)
_good_broadcast_div_mod_normal_float_inplace = dict(same_shapes = (rand(2, 3), rand(2, 3)), def copymod(dct, without=[], **kwargs):
scalar = (rand(2, 3), rand(1, 1)), """Return dct but with the keys named by args removed, and with
row = (rand(2, 3), rand(1, 3)), kwargs added.
column = (rand(2, 3), rand(2, 1)), """
dtype_mixup_1 = (rand(2, 3), randint_nonzero(2, 3)), rval = copy(dct)
dtype_mixup_2 = (randint_nonzero(2, 3), rand(2, 3)), for a in without:
#integers_positive = (randint_ranged(4, 10, (2, 3)), randint_ranged(1, 6, (2, 3))), if a in rval:
#integers_known_to_fail = (numpy.array(-1), numpy.array(5)) del rval[a]
complex1 = (randcomplex(2,3),randcomplex(2,3)), for kw, val in kwargs.items():
complex2 = (randcomplex(2,3),rand(2,3)), rval[kw] = val
#complex3 = (rand(2,3),randcomplex(2,3)),# Inplace on the first element. Must have the same type. return rval
empty1 = (numpy.asarray([]), numpy.asarray([1])),
#empty2 = (numpy.asarray([0]), numpy.asarray([])), _good_broadcast_div_mod_normal_float_no_complex = dict(
) same_shapes=(rand(2, 3), rand(2, 3)),
_good_broadcast_div_mod_normal_float = dict(empty2 = (numpy.asarray([0]), numpy.asarray([])), scalar=(rand(2, 3), rand(1, 1)),
**_good_broadcast_div_mod_normal_float_inplace row=(rand(2, 3), rand(1, 3)),
) column=(rand(2, 3), rand(2, 1)),
def no_complex(d): dtype_mixup_1=(rand(2, 3), randint_nonzero(2, 3)),
"""Remove pairs from dictionary d when the value contains complex data.""" dtype_mixup_2=(randint_nonzero(2, 3), rand(2, 3)),
return dict((k, v) for k, v in d.iteritems() # Fix problem with integers and uintegers and add them.
if all(str(x.dtype) not in tensor.complex_dtypes for x in v)) # Them remove their specific addition to CeilIntDivTester tests.
# integer=(randint(2, 3), randint_nonzero(2, 3)),
# uinteger=(randint(2, 3).astype("uint8"),
# 'No-complex' versions. # randint_nonzero(2, 3).astype("uint8")),
_good_broadcast_div_mod_normal_float_no_complex = no_complex( # This empty2 doesn't work for some tests. I don't remember why
_good_broadcast_div_mod_normal_float) #empty2=(numpy.asarray([0]), numpy.asarray([])),
_good_broadcast_div_mod_normal_float_inplace_no_complex = no_complex( )
_good_broadcast_div_mod_normal_float_inplace)
_good_broadcast_div_mod_normal_float_inplace = copymod(
_good_broadcast_div_mod_normal_float_no_complex,
empty1=(numpy.asarray([]), numpy.asarray([1])),
complex1=(randcomplex(2, 3), randcomplex(2, 3)),
complex2=(randcomplex(2, 3), rand(2, 3)),
# Inplace on the first element. Must have the same type.
#complex3=(rand(2, 3) ,randcomplex(2, 3)),
)
_good_broadcast_div_mod_normal_float = copymod(
_good_broadcast_div_mod_normal_float_inplace,
empty2=(numpy.asarray([0]), numpy.asarray([]))
)
_grad_broadcast_div_mod_normal = dict(same_shapes = (rand(2, 3), rand(2, 3)), _grad_broadcast_div_mod_normal = dict(same_shapes = (rand(2, 3), rand(2, 3)),
scalar = (rand(2, 3), rand(1, 1)), scalar = (rand(2, 3), rand(1, 1)),
...@@ -605,17 +619,36 @@ TrueDivInplaceTester = makeBroadcastTester(op = inplace.true_div_inplace, ...@@ -605,17 +619,36 @@ TrueDivInplaceTester = makeBroadcastTester(op = inplace.true_div_inplace,
grad_rtol=div_grad_rtol, grad_rtol=div_grad_rtol,
inplace = True) inplace = True)
ModTester = makeBroadcastTester(op = tensor.mod,
expected = lambda x, y: numpy.asarray(x % y, dtype=theano.scalar.basic.upcast(x.dtype, y.dtype)), CeilIntDivTester = makeBroadcastTester(
good = _good_broadcast_div_mod_normal_float_no_complex, op=tensor.ceil_intdiv,
# integers = (randint(2, 3), randint_nonzero(2, 3)), expected=lambda x, y: check_floatX((x, y), (x // y) + ((x % y) != 0)),
# dtype_mixup_1 = (rand(2, 3), randint_nonzero(2, 3)), good=copymod(_good_broadcast_div_mod_normal_float_no_complex,
# dtype_mixup_2 = (randint_nonzero(2, 3), rand(2, 3))), integer=(randint(2, 3), randint_nonzero(2, 3)),
) uinteger=(randint(2, 3).astype("uint8"),
ModInplaceTester = makeBroadcastTester(op = inplace.mod_inplace, randint_nonzero(2, 3).astype("uint8")),
expected = lambda x, y: numpy.asarray(x % y, dtype=theano.scalar.basic.upcast(x.dtype, y.dtype)), ),
good = _good_broadcast_div_mod_normal_float_inplace_no_complex, # As we implement this function with neq, the gradient returned is always 0.
inplace = True) # grad=_grad_broadcast_div_mod_normal,
# grad_rtol=div_grad_rtol,
)
ModTester = makeBroadcastTester(
op=tensor.mod,
expected=lambda x, y: numpy.asarray(
x % y, dtype=theano.scalar.basic.upcast(x.dtype, y.dtype)),
good=copymod(_good_broadcast_div_mod_normal_float,
['complex1', 'complex2']),
)
ModInplaceTester = makeBroadcastTester(
op=inplace.mod_inplace,
expected=lambda x, y: numpy.asarray(
x % y, dtype=theano.scalar.basic.upcast(x.dtype, y.dtype)),
good=copymod(_good_broadcast_div_mod_normal_float_inplace,
["complex1", "complex2"]),
inplace=True)
_good_broadcast_pow_normal_float = dict(same_shapes = (rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (2, 3))), _good_broadcast_pow_normal_float = dict(same_shapes = (rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (2, 3))),
scalar = (rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (1, 1))), scalar = (rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (1, 1))),
...@@ -670,18 +703,6 @@ _good_broadcast_unary_normal_float = dict( ...@@ -670,18 +703,6 @@ _good_broadcast_unary_normal_float = dict(
complex=[randcomplex(2,3)], complex=[randcomplex(2,3)],
empty=[numpy.asarray([])]) empty=[numpy.asarray([])])
def copymod(dct, without=[], **kwargs):
"""Return dct but with the keys named by args removed, and with
kwargs added.
"""
rval = copy(dct)
for a in without:
if a in rval:
del rval[a]
for kw, val in kwargs.items():
dct[kw] = val
return rval
_good_broadcast_unary_normal_float_no_empty = copymod( _good_broadcast_unary_normal_float_no_empty = copymod(
_good_broadcast_unary_normal_float, _good_broadcast_unary_normal_float,
without=['empty']) without=['empty'])
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论