Unverified 提交 2601e7ac authored 作者: Nicolas Legrand's avatar Nicolas Legrand 提交者: GitHub

Remove Python 2 style int division (#217)

* Remove `int_division` from `configdefaults.py` * * remove `div_proxy`, replace by either `true_div` or `int_div` * TestArithmeticCast : remove references to `config.int_division` and interger division * Remove __intdiv__ method from scalar.basic.py * Rebase * Fix merging conflicts
上级 50c60b6b
...@@ -35,7 +35,6 @@ from theano.scalar.basic import ( ...@@ -35,7 +35,6 @@ from theano.scalar.basic import (
cos, cos,
cosh, cosh,
deg2rad, deg2rad,
div_proxy,
eq, eq,
exp, exp,
exp2, exp2,
...@@ -66,9 +65,9 @@ from theano.scalar.basic import ( ...@@ -66,9 +65,9 @@ from theano.scalar.basic import (
) )
def test_mul_add_div_proxy(): def test_mul_add_true():
x, y, z = floats("xyz") x, y, z = floats("xyz")
e = mul(add(x, y), div_proxy(x, y)) e = mul(add(x, y), true_div(x, y))
g = FunctionGraph([x, y], [e]) g = FunctionGraph([x, y], [e])
fn = gof.DualLinker().accept(g).make_function() fn = gof.DualLinker().accept(g).make_function()
assert fn(1.0, 2.0) == 1.5 assert fn(1.0, 2.0) == 1.5
...@@ -114,7 +113,7 @@ class TestComposite: ...@@ -114,7 +113,7 @@ class TestComposite:
def test_straightforward(self): def test_straightforward(self):
x, y, z = floats("xyz") x, y, z = floats("xyz")
e = mul(add(x, y), div_proxy(x, y)) e = mul(add(x, y), true_div(x, y))
C = Composite([x, y], [e]) C = Composite([x, y], [e])
c = C.make_node(x, y) c = C.make_node(x, y)
# print c.c_code(['x', 'y'], ['z'], dict(id = 0)) # print c.c_code(['x', 'y'], ['z'], dict(id = 0))
...@@ -136,7 +135,7 @@ class TestComposite: ...@@ -136,7 +135,7 @@ class TestComposite:
def test_with_constants(self): def test_with_constants(self):
x, y, z = floats("xyz") x, y, z = floats("xyz")
e = mul(add(70.0, y), div_proxy(x, y)) e = mul(add(70.0, y), true_div(x, y))
C = Composite([x, y], [e]) C = Composite([x, y], [e])
c = C.make_node(x, y) c = C.make_node(x, y)
assert "70.0" in c.op.c_code(c, "dummy", ["x", "y"], ["z"], dict(id=0)) assert "70.0" in c.op.c_code(c, "dummy", ["x", "y"], ["z"], dict(id=0))
......
...@@ -5486,15 +5486,7 @@ class TestArithmeticCast: ...@@ -5486,15 +5486,7 @@ class TestArithmeticCast:
): ):
for a_type in dtypes: for a_type in dtypes:
for b_type in dtypes: for b_type in dtypes:
# Note that we do not test division between
# integers if it is forbidden.
# Theano deals with integer division in its own
# special way (depending on `config.int_division`).
is_int_division = (
op is operator.truediv
and a_type in tt.discrete_dtypes
and b_type in tt.discrete_dtypes
)
# We will test all meaningful combinations of # We will test all meaningful combinations of
# scalar and array operations. # scalar and array operations.
for combo in ( for combo in (
...@@ -5511,25 +5503,11 @@ class TestArithmeticCast: ...@@ -5511,25 +5503,11 @@ class TestArithmeticCast:
numpy_args = list( numpy_args = list(
map(eval, [f"numpy_{c}" for c in combo]) map(eval, [f"numpy_{c}" for c in combo])
) )
try:
theano_dtype = op( theano_dtype = op(
theano_args[0](a_type), theano_args[0](a_type),
theano_args[1](b_type), theano_args[1](b_type),
).type.dtype ).type.dtype
# Should have crashed if it is an integer
# division and `config.int_division` does
# not allow it.
assert not (
is_int_division
and config.int_division == "raise"
)
except theano.scalar.IntegerDivisionError:
assert (
is_int_division
and config.int_division == "raise"
)
# This is the expected behavior.
continue
# For numpy we have a problem: # For numpy we have a problem:
# http://projects.scipy.org/numpy/ticket/1827 # http://projects.scipy.org/numpy/ticket/1827
# As a result we only consider the highest data # As a result we only consider the highest data
...@@ -5587,12 +5565,7 @@ class TestArithmeticCast: ...@@ -5587,12 +5565,7 @@ class TestArithmeticCast:
# Then we accept this difference in # Then we accept this difference in
# behavior. # behavior.
continue continue
if (
is_int_division
and config.int_division == "floatX"
):
assert theano_dtype == config.floatX
continue
if ( if (
cfg == "numpy+floatX" cfg == "numpy+floatX"
and a_type == "complex128" and a_type == "complex128"
......
...@@ -659,19 +659,6 @@ def add_basic_configvars(): ...@@ -659,19 +659,6 @@ def add_basic_configvars():
), ),
) )
# python 2.* define int / int to return int and int // int to return int.
# python 3* define int / int to return float and int // int to return int.
# numpy 1.6.1 behaves as python 2.*. I think we should not change it faster
# than numpy. When we will do the transition, we should create an int_warn
# and floatX_warn option.
config.add(
"int_division",
"What to do when one computes x / y, where both x and y are of "
"integer types",
EnumStr("int", ["raise", "floatX"]),
in_c_key=False,
)
config.add( config.add(
"deterministic", "deterministic",
"If `more`, sometimes we will select some implementation that " "If `more`, sometimes we will select some implementation that "
......
...@@ -11,7 +11,6 @@ you probably want to use theano.tensor.[c,z,f,d,b,w,i,l,]scalar! ...@@ -11,7 +11,6 @@ you probably want to use theano.tensor.[c,z,f,d,b,w,i,l,]scalar!
""" """
import math import math
import warnings
from collections.abc import Callable from collections.abc import Callable
from copy import copy from copy import copy
from functools import partial from functools import partial
...@@ -798,10 +797,7 @@ class _scalar_py_operators: ...@@ -798,10 +797,7 @@ class _scalar_py_operators:
return mul(self, other) return mul(self, other)
def __truediv__(self, other): def __truediv__(self, other):
return div_proxy(self, other) return true_div(self, other)
def __div__(self, other):
return div_proxy(self, other)
def __floordiv__(self, other): def __floordiv__(self, other):
return int_div(self, other) return int_div(self, other)
...@@ -822,9 +818,6 @@ class _scalar_py_operators: ...@@ -822,9 +818,6 @@ class _scalar_py_operators:
def __rmul__(self, other): def __rmul__(self, other):
return mul(other, self) return mul(other, self)
def __rdiv__(self, other):
return div_proxy(other, self)
def __rmod__(self, other): def __rmod__(self, other):
return mod(other, self) return mod(other, self)
...@@ -1947,71 +1940,6 @@ class Sub(BinaryScalarOp): ...@@ -1947,71 +1940,6 @@ class Sub(BinaryScalarOp):
sub = Sub(upcast_out_nobool, name="sub") sub = Sub(upcast_out_nobool, name="sub")
def int_or_true_div(x_discrete, y_discrete):
"""
Return 'int' or 'true' depending on the type of division used for x / y.
Parameters
----------
x_discrete : bool
True if `x` is discrete ([unsigned] integer).
y_discrete : bool
True if `y` is discrete ([unsigned] integer).
Returns
-------
str
'int' if `x / y` should be an integer division, or `true` if it
should be a true division.
Raises
------
IntegerDivisionError
If both `x_discrete` and `y_discrete` are True and `config.int_division`
is set to 'raise'.
Notes
-----
This function is used by both scalar/basic.py and tensor/basic.py.
"""
if x_discrete and y_discrete:
if config.int_division == "raise":
raise IntegerDivisionError(
"With `config.int_division` set to 'raise', dividing two "
"integer types with '/' is forbidden to avoid confusion "
"between integer and floating point divisions. Please "
"use // for integer division, or if you want a float result "
"either cast one of the arguments to a float or directly call "
"`x.__truediv__(y)`."
)
elif config.int_division == "int":
warnings.warn(
"Division of two integer types with x / y is deprecated, "
"please use x // y for an integer division.",
DeprecationWarning,
stacklevel=4,
)
return int_div
elif config.int_division == "floatX":
return true_div
else:
raise NotImplementedError(config.int_division)
else:
return true_div
def div_proxy(x, y):
"""
Proxy for either true_div or int_div, depending on types of x, y.
"""
f = int_or_true_div(
as_scalar(x).type in discrete_types, as_scalar(y).type in discrete_types
)
return f(x, y)
class TrueDiv(BinaryScalarOp): class TrueDiv(BinaryScalarOp):
nfunc_spec = ("true_divide", 2, 1) nfunc_spec = ("true_divide", 2, 1)
......
...@@ -3670,18 +3670,6 @@ def minimum(x, y): ...@@ -3670,18 +3670,6 @@ def minimum(x, y):
# see decorator for function body # see decorator for function body
def div_proxy(x, y):
"""Proxy for either true_div or int_div, depending on types of x, y."""
f = scal.int_or_true_div(
as_tensor_variable(x).dtype in discrete_dtypes,
as_tensor_variable(y).dtype in discrete_dtypes,
)
if f is scal.int_div:
return int_div(x, y)
else:
return true_div(x, y)
def divmod(x, y): def divmod(x, y):
"""elementvise divmod, using floor_div and mod_check""" """elementvise divmod, using floor_div and mod_check"""
return floor_div(x, y), mod_check(x, y) return floor_div(x, y), mod_check(x, y)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论