Hi all. The attached diff makes some changes to Numexpr support for booleans. The changes and their rationale are below.
1. New ``True`` and ``False`` boolean constants. This is so that 1 and
0 are always proper integer constants. It is also for completeness,
but I don't envision any usage for them that couldn't be expressed
without the constants.
2. The only comparisons supported with booleans are ``==`` and ``!=``,
so that you can compare boolean variables. Just as NumPy supports
complex order comparisons and Numexpr doesn't, so goes for bools.
Being relatively new, I think there is no need to keep
integer-boolean compatibility in Numexpr. What was the meaning of
``True > False`` or ``2 > True`` anyway?
3. This is also why casting booleans to normal numbers is not allowed,
so ``prod()`` and ``sum()`` on booleans aren't either. What is the
meaning of boolean addition anyway?
To make it short, this patch is kind of a strengthening of boolean
values. I expect some people to disagree with the changes, and that's
why I would really like to hear your opinions on it.
Regards,
::
Ivan Vilata i Balaguer >qo< http://www.carabos.com/
Cárabos Coop. V. V V Enjoy Data
""
Index: interp_body.c
===================================================================
--- interp_body.c (revisión: 2299)
+++ interp_body.c (copia de trabajo)
@@ -130,21 +130,22 @@
ci_dest = c1i);
case OP_INVERT_BB: VEC_ARG1(b_dest = !b1);
+ case OP_AND_BBB: VEC_ARG2(b_dest = (b1 && b2));
+ case OP_OR_BBB: VEC_ARG2(b_dest = (b1 || b2));
- case OP_AND_BBB: VEC_ARG2(b_dest = b1 && b2);
- case OP_OR_BBB: VEC_ARG2(b_dest = b1 || b2);
+ case OP_EQ_BBB: VEC_ARG2(b_dest = (b1 == b2));
+ case OP_NE_BBB: VEC_ARG2(b_dest = (b1 != b2));
- case OP_GT_BII: VEC_ARG2(b_dest = (i1 > i2) ? 1 : 0);
- case OP_GE_BII: VEC_ARG2(b_dest = (i1 >= i2) ? 1 : 0);
- case OP_EQ_BII: VEC_ARG2(b_dest = (i1 == i2) ? 1 : 0);
- case OP_NE_BII: VEC_ARG2(b_dest = (i1 != i2) ? 1 : 0);
+ case OP_GT_BII: VEC_ARG2(b_dest = (i1 > i2));
+ case OP_GE_BII: VEC_ARG2(b_dest = (i1 >= i2));
+ case OP_EQ_BII: VEC_ARG2(b_dest = (i1 == i2));
+ case OP_NE_BII: VEC_ARG2(b_dest = (i1 != i2));
- case OP_GT_BFF: VEC_ARG2(b_dest = (f1 > f2) ? 1 : 0);
- case OP_GE_BFF: VEC_ARG2(b_dest = (f1 >= f2) ? 1 : 0);
- case OP_EQ_BFF: VEC_ARG2(b_dest = (f1 == f2) ? 1 : 0);
- case OP_NE_BFF: VEC_ARG2(b_dest = (f1 != f2) ? 1 : 0);
+ case OP_GT_BFF: VEC_ARG2(b_dest = (f1 > f2));
+ case OP_GE_BFF: VEC_ARG2(b_dest = (f1 >= f2));
+ case OP_EQ_BFF: VEC_ARG2(b_dest = (f1 == f2));
+ case OP_NE_BFF: VEC_ARG2(b_dest = (f1 != f2));
- case OP_CAST_IB: VEC_ARG1(i_dest = (long)b1);
case OP_ONES_LIKE_II: VEC_ARG1(i_dest = 1);
case OP_NEG_II: VEC_ARG1(i_dest = -i1);
@@ -157,7 +158,6 @@
case OP_WHERE_IFII: VEC_ARG3(i_dest = f1 ? i2 : i3);
- case OP_CAST_FB: VEC_ARG1(f_dest = (long)b1);
case OP_CAST_FI: VEC_ARG1(f_dest = (double)(i1));
case OP_ONES_LIKE_FF: VEC_ARG1(f_dest = 1.0);
case OP_NEG_FF: VEC_ARG1(f_dest = -f1);
@@ -180,8 +180,6 @@
case OP_FUNC_FF: VEC_ARG1(f_dest = functions_f[arg2](f1));
case OP_FUNC_FFF: VEC_ARG2(f_dest = functions_ff[arg3](f1, f2));
- case OP_CAST_CB: VEC_ARG1(cr_dest = (double)b1;
- ci_dest = 0);
case OP_CAST_CI: VEC_ARG1(cr_dest = (double)(i1);
ci_dest = 0);
case OP_CAST_CF: VEC_ARG1(cr_dest = f1;
@@ -203,8 +201,8 @@
ci_dest = (c1i*c2r - c1r*c2i) / fa;
cr_dest = fb);
- case OP_EQ_BCC: VEC_ARG2(b_dest = (c1r == c2r && c1i == c2i) ? 1 : 0);
- case OP_NE_BCC: VEC_ARG2(b_dest = (c1r != c2r || c1i != c2i) ? 1 : 0);
+ case OP_EQ_BCC: VEC_ARG2(b_dest = (c1r == c2r && c1i == c2i));
+ case OP_NE_BCC: VEC_ARG2(b_dest = (c1r != c2r || c1i != c2i));
case OP_WHERE_CFCC: VEC_ARG3(cr_dest = f1 ? c2r : c3r;
ci_dest = f1 ? c2i : c3i);
Index: compiler.py
===================================================================
--- compiler.py (revisión: 2299)
+++ compiler.py (copia de trabajo)
@@ -217,6 +217,10 @@
for name in c.co_names:
if name == "None":
names[name] = None
+ elif name == "True":
+ names[name] = True
+ elif name == "False":
+ names[name] = False
else:
t = types.get(name, float)
names[name] = expr.VariableNode(name, type_to_kind[t])
Index: tests/test_numexpr.py
===================================================================
--- tests/test_numexpr.py (revisión: 2299)
+++ tests/test_numexpr.py (copia de trabajo)
@@ -67,10 +67,6 @@
x = x + 5j
assert_equal(evaluate("sum(x**2+2,axis=0)"), sum(x**2+2,axis=0))
assert_equal(evaluate("prod(x**2+2,axis=0)"), prod(x**2+2,axis=0))
- # Check boolean (should cast to integer)
- x = (arange(10) % 2).astype(bool)
- assert_equal(evaluate("prod(x,axis=0)"), prod(x,axis=0))
- assert_equal(evaluate("sum(x,axis=0)"), sum(x,axis=0))
def check_axis(self):
y = arange(9.0).reshape(3,3)
Index: interpreter.c
===================================================================
--- interpreter.c (revisión: 2299)
+++ interpreter.c (copia de trabajo)
@@ -25,6 +25,9 @@
OP_AND_BBB,
OP_OR_BBB,
+ OP_EQ_BBB,
+ OP_NE_BBB,
+
OP_GT_BII,
OP_GE_BII,
OP_EQ_BII,
@@ -35,7 +38,6 @@
OP_EQ_BFF,
OP_NE_BFF,
- OP_CAST_IB,
OP_COPY_II,
OP_ONES_LIKE_II,
OP_NEG_II,
@@ -47,7 +49,6 @@
OP_MOD_III,
OP_WHERE_IFII,
- OP_CAST_FB,
OP_CAST_FI,
OP_COPY_FF,
OP_ONES_LIKE_FF,
@@ -70,7 +71,6 @@
OP_EQ_BCC,
OP_NE_BCC,
- OP_CAST_CB,
OP_CAST_CI,
OP_CAST_CF,
OP_ONES_LIKE_CC,
@@ -115,6 +115,8 @@
break;
case OP_AND_BBB:
case OP_OR_BBB:
+ case OP_EQ_BBB:
+ case OP_NE_BBB:
if (n == 0 || n == 1 || n == 2) return 'b';
break;
case OP_GT_BII:
@@ -131,10 +133,6 @@
if (n == 0) return 'b';
if (n == 1 || n == 2) return 'f';
break;
- case OP_CAST_IB:
- if (n == 0) return 'i';
- if (n == 1) return 'b';
- break;
case OP_COPY_II:
case OP_ONES_LIKE_II:
case OP_NEG_II:
@@ -152,10 +150,6 @@
if (n == 0 || n == 2 || n == 3) return 'i';
if (n == 1) return 'f';
break;
- case OP_CAST_FB:
- if (n == 0) return 'f';
- if (n == 1) return 'b';
- break;
case OP_CAST_FI:
if (n == 0) return 'f';
if (n == 1) return 'i';
@@ -194,10 +188,6 @@
if (n == 0) return 'b';
if (n == 1 || n == 2) return 'c';
break;
- case OP_CAST_CB:
- if (n == 0) return 'c';
- if (n == 1) return 'b';
- break;
case OP_CAST_CI:
if (n == 0) return 'c';
if (n == 1) return 'i';
@@ -1296,6 +1286,10 @@
add_op("invert_bb", OP_INVERT_BB);
add_op("and_bbb", OP_AND_BBB);
add_op("or_bbb", OP_OR_BBB);
+
+ add_op("eq_bbb", OP_EQ_BBB);
+ add_op("ne_bbb", OP_NE_BBB);
+
add_op("gt_bii", OP_GT_BII);
add_op("ge_bii", OP_GE_BII);
add_op("eq_bii", OP_EQ_BII);
@@ -1306,7 +1300,6 @@
add_op("eq_bff", OP_EQ_BFF);
add_op("ne_bff", OP_NE_BFF);
- add_op("cast_ib", OP_CAST_IB);
add_op("ones_like_ii", OP_ONES_LIKE_II);
add_op("copy_ii", OP_COPY_II);
add_op("neg_ii", OP_NEG_II);
@@ -1318,7 +1311,6 @@
add_op("mod_iii", OP_MOD_III);
add_op("where_ifii", OP_WHERE_IFII);
- add_op("cast_fb", OP_CAST_FB);
add_op("cast_fi", OP_CAST_FI);
add_op("copy_ff", OP_COPY_FF);
add_op("ones_like_ff", OP_ONES_LIKE_FF);
@@ -1342,7 +1334,6 @@
add_op("eq_bcc", OP_EQ_BCC);
add_op("ne_bcc", OP_NE_BCC);
- add_op("cast_cb", OP_CAST_CB);
add_op("cast_ci", OP_CAST_CI);
add_op("cast_cf", OP_CAST_CF);
add_op("copy_cc", OP_COPY_CC);
Index: expressions.py
===================================================================
--- expressions.py (revisión: 2299)
+++ expressions.py (copia de trabajo)
@@ -62,7 +62,13 @@
return kind_rank[n]
def bestConstantType(x):
- for converter in bool, int, float, complex:
+ # Numeric conversion to boolean values is not tried because
+ # ``bool(1) == True`` (same for 0 and False), so 0 and 1 would be
+ # interpreted as booleans when ``False`` and ``True`` are already
+ # supported.
+ if isinstance(x, bool):
+ return bool
+ for converter in int, float, complex:
try:
y = converter(x)
except StandardError, err:
@@ -122,10 +128,7 @@
return a
if isinstance(a, (bool, int, float, complex)):
a = ConstantNode(a)
- kind = a.astKind
- if kind == 'bool':
- kind = 'int'
- return FuncNode('sum', [a, axis], kind=kind)
+ return FuncNode('sum', [a, axis], kind=a.astKind)
def prod_func(a, axis=-1):
axis = encode_axis(axis)
@@ -133,10 +136,7 @@
a = ConstantNode(a)
if isinstance(a, ConstantNode):
return a
- kind = a.astKind
- if kind == 'bool':
- kind = 'int'
- return FuncNode('prod', [a, axis], kind=kind)
+ return FuncNode('prod', [a, axis], kind=a.astKind)
@ophelper
def div_op(a, b):
signature.asc
Description: OpenPGP digital signature
------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________ Numpy-discussion mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/numpy-discussion
