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 Numpy-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/numpy-discussion