Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

result types of bool matrix operations #2980

Closed
JeffBezanson opened this issue Apr 30, 2013 · 8 comments
Closed

result types of bool matrix operations #2980

JeffBezanson opened this issue Apr 30, 2013 · 8 comments
Labels
needs decision A decision on this change is needed

Comments

@JeffBezanson
Copy link
Member

Gunnar's issues 5 and 6:

5. Complex booleans seem somewhat brittle.

julia> true * true
true

julia> true * complex(true)
true + falseim

julia> complex(true) * complex(true)
1 + 0im

6. Boolean matrix arithmetic is unpredictable.

julia> [true,true]' == [true true]
true

julia> [true,true]' * [true,true]
1-element Int64 Array:
 2

julia> [true true] * [true,true]
1-element Bool Array:
 true

julia> ([true,true] .== true)' * [true,true]
1-element BitArray:
 true

We have true+true === 2 but true*true === true. Maybe it's best just to give an Int for all bool arithmetic.

Then there is a further problem, that functions like dot and matrix * use the input type to determine the output type, but for Bool this is wrong. One thing that works is

resulttype(T::Type) = typeof(zero(T)*zero(T)+zero(T))

to be pedantic.

@stevengj
Copy link
Member

stevengj commented May 1, 2013

Regarding arithmetic, I can see three options.

  1. All arithmetic operations (except bitwise operations) promote Bool to Int, (i.e. true*true == 1).
  2. Arithmetic operations on Boolean values are defined by interpreting the value as an integer modulo 2 (i.e. true + true == false etc.).
  3. The C-ish style in which we to do the arithmetic as Int but convert the result back to Bool (via != 0), i.e. true+true=true, true*true=true etcetera.

@StefanKarpinski
Copy link
Member

I think that the following makes the most sense to me:

  1. Arithmetic operations on Bools promote to Ints: true+true => 2, false+false=>0 etc.
  2. Bitwise operations on Bools produce bools: true & true => true.

Currently, arrays of bools are the only ones for which vectorized arrays don't preserve the size and type of their operands, which is a bit inconsistent, but probably much more useful than the alternative of doing Int arithmetic and then casting back to Bool – if you want that, you can always express it more clearly using bitwise operators.

Side issue: can we replace im = ImaginaryUnit() with the complex(false,true)? That would be a nice way to simplify the complex hierarchy now that Complex is memory-compatible with C99 complex numbers.

@JeffBezanson
Copy link
Member Author

Agree on the arithmetic, since it's what we do for all other integer types.

It'd be nice to get rid of ImaginaryUnit, but it does have useful special behavior:

julia> Inf*im
complex(0.0,Inf)

julia> Inf*complex(false,true)
NaN + Inf*im

I don't yet see a way around this.

@StefanKarpinski
Copy link
Member

One option would be to introduce pure imaginary numbers, Imaginary{T<:Real} and then let im = imaginary(true) which would be an element of Imaginary{Bool}. That could sanely have the Inf*im => complex(0.0,Inf) behavior and would be more generally useful for allowing the compact representation of purely imaginary values and array.

@StefanKarpinski
Copy link
Member

Of course, that proposal doesn't actually simplify the type hierarchy, but it does generalize it to be more useful.

JeffBezanson added a commit that referenced this issue May 1, 2013
@GunnarFarneback
Copy link
Contributor

Amusingly my suggestion to have false * x = zero(typeof(x)) and true * x = x is a perfect fit with the desire to have Inf * complex(false, true) = complex(0.0, Inf).

@JeffBezanson
Copy link
Member Author

I did notice that, and it does make me stop and think. But my current impression is that it's mostly a coincidence.

@StefanKarpinski
Copy link
Member

Thanks, Jeff. I think the right approach for supporting things like matmul in GF(2) is to make a new type whose addition and multiplication are appropriate to that field.

StefanKarpinski added a commit that referenced this issue Jan 22, 2014
This change requires giving multiplition by Bools special behavior.
Approximately, `true * x = x` and `false * x = zero(x)`, but a bit
complicated for the sake of promotion, the only non-trivial example
of which is `Bool * MathConst`, which is promoted to Float64.

Idea originally due to @GunnarFarneback:

    https://groups.google.com/forum/#!topic/julia-dev/VkGrqnrAdaY
    #2980
    #3728
StefanKarpinski added a commit that referenced this issue Jan 22, 2014
This change requires giving multiplition by Bools special behavior.
Approximately, `true * x = x` and `false * x = zero(x)`, but a bit
complicated for the sake of promotion, the only non-trivial example
of which is `Bool * MathConst`, which is promoted to Float64.

Idea originally due to @GunnarFarneback:

    https://groups.google.com/forum/#!topic/julia-dev/VkGrqnrAdaY
    #2980
    #3728
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs decision A decision on this change is needed
Projects
None yet
Development

No branches or pull requests

4 participants