提交 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):
"""elementwise integer-division"""
# 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):
"""Make sure we do not try to use complex numbers."""
if (as_tensor_variable(x).dtype in complex_dtypes or
......
......@@ -541,34 +541,48 @@ MulInplaceTester = makeBroadcastTester(op = inplace.mul_inplace,
grad = _grad_broadcast_binary_normal,
inplace = True)
_good_broadcast_div_mod_normal_float_inplace = dict(same_shapes = (rand(2, 3), rand(2, 3)),
scalar = (rand(2, 3), rand(1, 1)),
row = (rand(2, 3), rand(1, 3)),
column = (rand(2, 3), rand(2, 1)),
dtype_mixup_1 = (rand(2, 3), randint_nonzero(2, 3)),
dtype_mixup_2 = (randint_nonzero(2, 3), rand(2, 3)),
#integers_positive = (randint_ranged(4, 10, (2, 3)), randint_ranged(1, 6, (2, 3))),
#integers_known_to_fail = (numpy.array(-1), numpy.array(5))
complex1 = (randcomplex(2,3),randcomplex(2,3)),
complex2 = (randcomplex(2,3),rand(2,3)),
#complex3 = (rand(2,3),randcomplex(2,3)),# Inplace on the first element. Must have the same type.
empty1 = (numpy.asarray([]), numpy.asarray([1])),
#empty2 = (numpy.asarray([0]), numpy.asarray([])),
)
_good_broadcast_div_mod_normal_float = dict(empty2 = (numpy.asarray([0]), numpy.asarray([])),
**_good_broadcast_div_mod_normal_float_inplace
)
def no_complex(d):
"""Remove pairs from dictionary d when the value contains complex data."""
return dict((k, v) for k, v in d.iteritems()
if all(str(x.dtype) not in tensor.complex_dtypes for x in v))
# 'No-complex' versions.
_good_broadcast_div_mod_normal_float_no_complex = no_complex(
_good_broadcast_div_mod_normal_float)
_good_broadcast_div_mod_normal_float_inplace_no_complex = no_complex(
_good_broadcast_div_mod_normal_float_inplace)
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():
rval[kw] = val
return rval
_good_broadcast_div_mod_normal_float_no_complex = dict(
same_shapes=(rand(2, 3), rand(2, 3)),
scalar=(rand(2, 3), rand(1, 1)),
row=(rand(2, 3), rand(1, 3)),
column=(rand(2, 3), rand(2, 1)),
dtype_mixup_1=(rand(2, 3), randint_nonzero(2, 3)),
dtype_mixup_2=(randint_nonzero(2, 3), rand(2, 3)),
# Fix problem with integers and uintegers and add them.
# Them remove their specific addition to CeilIntDivTester tests.
# integer=(randint(2, 3), randint_nonzero(2, 3)),
# uinteger=(randint(2, 3).astype("uint8"),
# randint_nonzero(2, 3).astype("uint8")),
# This empty2 doesn't work for some tests. I don't remember why
#empty2=(numpy.asarray([0]), numpy.asarray([])),
)
_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)),
scalar = (rand(2, 3), rand(1, 1)),
......@@ -605,17 +619,36 @@ TrueDivInplaceTester = makeBroadcastTester(op = inplace.true_div_inplace,
grad_rtol=div_grad_rtol,
inplace = True)
ModTester = makeBroadcastTester(op = tensor.mod,
expected = lambda x, y: numpy.asarray(x % y, dtype=theano.scalar.basic.upcast(x.dtype, y.dtype)),
good = _good_broadcast_div_mod_normal_float_no_complex,
# integers = (randint(2, 3), randint_nonzero(2, 3)),
# dtype_mixup_1 = (rand(2, 3), randint_nonzero(2, 3)),
# dtype_mixup_2 = (randint_nonzero(2, 3), rand(2, 3))),
)
ModInplaceTester = makeBroadcastTester(op = inplace.mod_inplace,
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,
inplace = True)
CeilIntDivTester = makeBroadcastTester(
op=tensor.ceil_intdiv,
expected=lambda x, y: check_floatX((x, y), (x // y) + ((x % y) != 0)),
good=copymod(_good_broadcast_div_mod_normal_float_no_complex,
integer=(randint(2, 3), randint_nonzero(2, 3)),
uinteger=(randint(2, 3).astype("uint8"),
randint_nonzero(2, 3).astype("uint8")),
),
# As we implement this function with neq, the gradient returned is always 0.
# 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))),
scalar = (rand_ranged(1, 5, (2, 3)), rand_ranged(-3, 3, (1, 1))),
......@@ -670,18 +703,6 @@ _good_broadcast_unary_normal_float = dict(
complex=[randcomplex(2,3)],
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,
without=['empty'])
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论