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 (
cos,
cosh,
deg2rad,
div_proxy,
eq,
exp,
exp2,
......@@ -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")
e = mul(add(x, y), div_proxy(x, y))
e = mul(add(x, y), true_div(x, y))
g = FunctionGraph([x, y], [e])
fn = gof.DualLinker().accept(g).make_function()
assert fn(1.0, 2.0) == 1.5
......@@ -114,7 +113,7 @@ class TestComposite:
def test_straightforward(self):
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 = C.make_node(x, y)
# print c.c_code(['x', 'y'], ['z'], dict(id = 0))
......@@ -136,7 +135,7 @@ class TestComposite:
def test_with_constants(self):
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 = C.make_node(x, y)
assert "70.0" in c.op.c_code(c, "dummy", ["x", "y"], ["z"], dict(id=0))
......
......@@ -5486,15 +5486,7 @@ class TestArithmeticCast:
):
for a_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
# scalar and array operations.
for combo in (
......@@ -5511,25 +5503,11 @@ class TestArithmeticCast:
numpy_args = list(
map(eval, [f"numpy_{c}" for c in combo])
)
try:
theano_dtype = op(
theano_args[0](a_type),
theano_args[1](b_type),
).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
theano_dtype = op(
theano_args[0](a_type),
theano_args[1](b_type),
).type.dtype
# For numpy we have a problem:
# http://projects.scipy.org/numpy/ticket/1827
# As a result we only consider the highest data
......@@ -5587,12 +5565,7 @@ class TestArithmeticCast:
# Then we accept this difference in
# behavior.
continue
if (
is_int_division
and config.int_division == "floatX"
):
assert theano_dtype == config.floatX
continue
if (
cfg == "numpy+floatX"
and a_type == "complex128"
......
......@@ -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(
"deterministic",
"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!
"""
import math
import warnings
from collections.abc import Callable
from copy import copy
from functools import partial
......@@ -798,10 +797,7 @@ class _scalar_py_operators:
return mul(self, other)
def __truediv__(self, other):
return div_proxy(self, other)
def __div__(self, other):
return div_proxy(self, other)
return true_div(self, other)
def __floordiv__(self, other):
return int_div(self, other)
......@@ -822,9 +818,6 @@ class _scalar_py_operators:
def __rmul__(self, other):
return mul(other, self)
def __rdiv__(self, other):
return div_proxy(other, self)
def __rmod__(self, other):
return mod(other, self)
......@@ -1947,71 +1940,6 @@ class Sub(BinaryScalarOp):
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):
nfunc_spec = ("true_divide", 2, 1)
......
......@@ -3670,18 +3670,6 @@ def minimum(x, y):
# 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):
"""elementvise divmod, using floor_div and mod_check"""
return floor_div(x, y), mod_check(x, y)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论