Changes to bools under Numexpr

Colin J. Williams cjw at sympatico.ca
Thu Oct 26 13:35:06 CDT 2006



Ivan Vilata i Balaguer wrote:
> 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.
>   
I'm puzzled.
Python already has constants True and False of the bool type.  bool is a 
subclass of the int type.
Any instance of the bool type can be converted to the int type.
 >>> a=1==0
 >>> type(a)
<type 'bool'>
 >>> int(a)
0
 >>> a
False
 >>>

Colin W.

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

-------------------------------------------------------------------------
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




More information about the Numpy-discussion mailing list